首页 > 解决方案 > 使用 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;
}

所以,我做什么:

  1. 我将当前页面另存为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());

  1. 检查页面是否旋转setRotation()并通过更改媒体框的宽度和高度将其设置为 0。(因为当它以这种方式旋转时,预览中的底部变为左......或右......或顶部......这对用户不利)

  2. 使用 OVERWRITE 打开流,根据需要旋转,缩放(默认缩放 = 1)并drawForm从第 1 步开始。

    AffineTransform affineTransformScale = new AffineTransform(scale, 0, 0, scale, newXcoordinates, newYcoordinates); stream.transform(新矩阵(affineTransformScale));流.drawForm(obj); stream.restoreGraphicsState();

  3. 创建和绘制邮票。

我觉得我的所作所为——这是错误的!因为在第 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...个人数据...

标签: javapdfbox

解决方案


推荐阅读