java - 使用 Apache PdfBox 缩放 pdf 内容的正确方法是什么?
问题描述
我有一些带有数据的pdf。任务 - 将带有一些信息的图像放在所有页面(在一个位置:页面的顶部、左侧、右侧、底部)。但是有些 pdf 在这个位置没有位置,我不能在内容上插入图像。这就是为什么我需要缩放。经过几天的尝试和阅读stackoverflow,我做了我需要的一切,“它还活着!!!活着!!!” (c)......但并非总是......自pdfbox 2.0.8以来,在某些pdf(带有可选内容属性)处,我的函数陷入了递归地狱。
这是代码:
public static void putStamp(PDDocument document, X509Certificate certificate, UserInfo userInfo, TransformProperties transformProperties) throws IOException {
final Map<StampSize, PDImageXObject> stampsUser = new HashMap<>();
TransformProperties.Position posUserStamp = null;
double scale = 1;
if (transformProperties!=null){
posUserStamp = transformProperties.getUserStampPosition();
scale = ((double)transformProperties.getScale()) / 100;
}
final LayerUtility layerUtility = new LayerUtility(document);
Iterator<PDPage> iterator = document.getPages().iterator();
while (iterator.hasNext()) {
PDPage page = iterator.next();
PDPageContentStream stream;
Boolean isRotatedPage = false;
int rotateAngle = 0;
final PDFormXObject obj = layerUtility.importPageAsForm(document, page);
AffineTransform affineTransformScale1 = new AffineTransform(1,0, 0,1,0, 0);
obj.setMatrix(affineTransformScale1);
page.setResources(new PDResources());
if(page.getRotation()==90 || page.getRotation()==270){
isRotatedPage = true;
rotateAngle = 360 - page.getRotation();
page.setRotation(0);
PDRectangle rectangle = new PDRectangle(page.getMediaBox().getHeight(),page.getMediaBox().getWidth());
page.setMediaBox(rectangle);
page.setCropBox(rectangle);
}else if (page.getRotation()==180){
isRotatedPage = true;
rotateAngle = 360 - page.getRotation();
page.setRotation(0);
}
float pageWidth = page.getBBox().getWidth();
float pageHeight = page.getBBox().getHeight();
double newXcoordinates = (pageWidth - pageWidth*scale) /2;
double newYcoordinates = (pageHeight - pageHeight*scale) /2;
stream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.OVERWRITE, true, true);
stream.saveGraphicsState();
if (isRotatedPage) {
float offsetX = 0, offsetY = 0;
switch (rotateAngle){
case 270:
offsetX = 0;
offsetY = pageHeight;
break;
case 180:
offsetX = pageWidth;
offsetY = pageHeight;
break;
case 90:
offsetX = pageWidth;
offsetY = 0;
break;
}
stream.transform(Matrix.getRotateInstance(Math.toRadians(rotateAngle), offsetX, offsetY));
}
AffineTransform affineTransformScale = new AffineTransform(scale, 0, 0, scale, newXcoordinates, newYcoordinates);
stream.transform(new Matrix(affineTransformScale));
stream.drawForm(obj);
stream.restoreGraphicsState();
if (!Config.getInstance().isIgnoreUserStamp() && userInfo != null) {
int posXuser = 0;
int posYuser = 0;
int stampH = 0;
int stampW = 0;
boolean rotate = false;
if (posUserStamp == TransformProperties.Position.LEFT) {
stampH = (int) (pageWidth / 32 * multiply);
stampW = (int) (pageHeight * 0.9 * multiply);
posXuser = (int) (pageWidth * 0.015);
posYuser = (int) ((pageHeight - stampW/multiply) / 2 );
rotate = true;
}else if (posUserStamp == TransformProperties.Position.RIGHT){
stampH = (int) (pageWidth / 32 * multiply);
stampW = (int) (pageHeight * 0.9 * multiply);
posXuser = (int) (pageWidth * 0.985 - (stampH / multiply)) ;
posYuser = (int) ((pageHeight - (stampW / multiply)) / 2 );
rotate = true;
}else if(posUserStamp == TransformProperties.Position.BOTTOM){
stampH = (int) (pageHeight / 32 * multiply);
stampW = (int) (pageWidth * 0.9 * multiply);
posXuser = (int) (pageWidth * 0.05);
posYuser = (int) (pageHeight * 0.015);
}else if(posUserStamp == TransformProperties.Position.TOP || posUserStamp == null) {
stampH = (int) (pageHeight / 32 * multiply);
stampW = (int) (pageWidth * 0.9 * multiply);
posXuser = (int) (pageWidth * 0.05);
posYuser = (int) (pageHeight * 0.985 - (stampH / multiply));
}
final StampSize stampSizeUser = new StampSize(stampW, stampH);
PDImageXObject imageUser;
if(stampsUser.containsKey(stampSizeUser)){
imageUser = stampsUser.get(stampSizeUser);
}else {
BufferedImage img = createStampUser(stampSizeUser.width, stampSizeUser.height, userInfo);
if (rotate) {
img = rotateImageByDegrees(img, 90);
}
imageUser = LosslessFactory.createFromImage(document, img);
}
stampsUser.put(stampSizeUser, imageUser);
stream.drawImage(imageUser, posXuser, posYuser, imageUser.getWidth() / multiply, imageUser.getHeight() / multiply);
}
stream.close();
}
}
public static BufferedImage rotateImageByDegrees(BufferedImage img, double degrees) {
double rads = Math.toRadians(degrees);
double sin = Math.abs(Math.sin(rads)), cos = Math.abs(Math.cos(rads));
int w = img.getWidth();
int h = img.getHeight();
int newWidth = (int) Math.floor(w * cos + h * sin);
int newHeight = (int) Math.floor(h * cos + w * sin);
BufferedImage rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics();
AffineTransform at = new AffineTransform();
at.translate((newWidth - w) / 2, (newHeight - h) / 2);
at.rotate(rads, w / 2, h / 2);
g2d.setTransform(at);
g2d.drawImage(img, 0, 0,null);
g2d.dispose();
return rotated;
}
所以,我做什么:
- 我将当前页面另存为
PDFormXObject
并清除页面上的资源。
final PDFormXObject obj = layerUtility.importPageAsForm(document, page);
AffineTransform affineTransformScale1 = new AffineTransform(1,0, 0,1,0, 0);
obj.setMatrix(affineTransformScale1);
page.setResources(new PDResources());
检查页面是否旋转
setRotation()
并通过更改媒体框的宽度和高度将其设置为 0。(因为当它以这种方式旋转时,预览中的底部变为左......或右......或顶部......这对用户不利)使用 OVERWRITE 打开流,根据需要旋转,缩放(默认缩放 = 1)并
drawForm
从第 1 步开始。AffineTransform affineTransformScale = new AffineTransform(scale, 0, 0, scale, newXcoordinates, newYcoordinates); stream.transform(新矩阵(affineTransformScale));流.drawForm(obj); stream.restoreGraphicsState();
创建和绘制邮票。
我觉得我的所作所为——这是错误的!因为在第 1 步,我使用layerUtility.importPageAsForm(document, page);
为从其他 pdf 导入而创建的方法……如果我做对了,不是同一个 pdf。并且由于在这个方法中添加了 pdfbox 2.0.8 在importOcProperties(sourceDoc);
这个地方我在一些 pdf 中有无限递归。但是我如何将当前页面转换为 PDFormXObject?或者我如何使用 Matrix 仅缩放内容?(我尝试这样做,但我失败了......)
我不知道如何正确地制作它。我不想创建新的 PDDocument 并向其添加页面,因为某些 pdf 超过 500 mb。在这种情况下,内存中将是 2 个大小超过 500 mb 的 pdf。我认为这是错误的方式...但是如何正确地获取页面,缩放内容(不更改大小 od mediaBox 和cropBox)并添加图章?
关于第2步的第二个问题:制作风景或肖像的正确方法是什么?通过 setRotation 或更改媒体框?恕我直言:更改媒体框,但我是 pdf 的新手...
请正确引导!
PS我不能显示pdfs...个人数据...
解决方案
推荐阅读
- ios - 为什么以前从堆栈中弹出的视图仍然处于活动状态
- javascript - ${this...} 在 Node v13.14 中不显示值
- python - Python netcdf cartopy - 绘制数据选择
- php - POST http://localhost:8000/offers-ajax/store 419 (未知状态) Laravel AJAX
- python - ModuleNotFoundError:没有名为“maraboupy.MarabouCore”的模块
- swift - Swift:为什么 UILabel 不将数据源中的数据显示到集合视图单元格中?
- javascript - 无法通过自定义反应钩子更新状态
- php - 根据不同的数组对PHP数组进行排序
- docker - docker-compose 调试服务在运行时显示“pwd”和“ls -l”?
- form-submit - html联系表单提交没有响应