Shrink PDF pages with rotation using Rectangle in existing PDF

人走茶凉 提交于 2019-12-04 17:25:17

Scaling a PDF to make pages larger is easy. This is shown in the ScaleRotate example. It's only a matter of changing the default version of the user unit. By default, this unit is 1, meaning that 1 user unit equals to 1 point. You can increase this value to 75,000. Larger values of the user unit, will result in larger pages.

Unfortunately, the user unit can never be smaller than 1, so you can't use this technique to shrink a page. If you want to shrink a page, you need to introduce a transformation (resulting in a new CTM).

This is shown in the ShrinkPdf example. In this example, I take a PDF named hero.pdf that measures 8.26 by 11.69 inch, and we shrink it by 50%, resulting in a PDF named hero_shrink.pdf that measures 4.13 by 5.85 inch.

To achieve this, we need a dirty hack:

public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
    PdfReader reader = new PdfReader(src);
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
    int n = reader.getNumberOfPages();
    PdfDictionary page;
    PdfArray crop;
    PdfArray media;
    for (int p = 1; p <= n; p++) {
        page = reader.getPageN(p);
        media = page.getAsArray(PdfName.CROPBOX);
        if (media == null) {
            media = page.getAsArray(PdfName.MEDIABOX);
        }
        crop = new PdfArray();
        crop.add(new PdfNumber(0));
        crop.add(new PdfNumber(0));
        crop.add(new PdfNumber(media.getAsNumber(2).floatValue() / 2));
        crop.add(new PdfNumber(media.getAsNumber(3).floatValue() / 2));
        page.put(PdfName.MEDIABOX, crop);
        page.put(PdfName.CROPBOX, crop);
        stamper.getUnderContent(p).setLiteral("\nq 0.5 0 0 0.5 0 0 cm\nq\n");
        stamper.getOverContent(p).setLiteral("\nQ\nQ\n");
    }
    stamper.close();
    reader.close();
}

We loop over every page and we take the crop box of each page. If there is no crop box, we take the media box. These boxes are stored as arrays of 4 numbers. In this example, I assume that the first two numbers are zero and I divide the next two values by 2 to shrink the page to 50% (if the first two values are not zero, you'll need a more elaborate formula).

Once I have the new array, I change the media box and the crop box to this array, and I introduce a CTM that scales all content down to 50%. I need to use the setLiteral() method to fool iText.

Based on your feedback in the comments section, it appears that you do not understand the mechanics explained in my example. Hence I have made a second example, named ShrinkPdf2:

public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
    PdfReader reader = new PdfReader(src);
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
    int n = reader.getNumberOfPages();
    float percentage = 0.8f;
    for (int p = 1; p <= n; p++) {
        float offsetX = (reader.getPageSize(p).getWidth() * (1 - percentage)) / 2;
        float offsetY = (reader.getPageSize(p).getHeight() * (1 - percentage)) / 2;
        stamper.getUnderContent(p).setLiteral(
                String.format("\nq %s 0 0 %s %s %s cm\nq\n", percentage, percentage, offsetX, offsetY));
        stamper.getOverContent(p).setLiteral("\nQ\nQ\n");
    }
    stamper.close();
    reader.close();
}

In this example, I don't change the page size (no changes to the media or crop box), I only shrink the content (in this case to 80%) and I center the shrunken content on the page, leaving bigger margins to the top, bottom, left and right.

As you can see, this is only a matter of applying the correct Math. This second example is even more simple than the first, so I introduced some extra complexity: now you can easily change the percentage (in the first example I hardcoded 50%. in this case I introduced the percentage variable and I defined it as 80%).

Note that I apply the scaling in the X direction as well as in the Y direction to preserve the aspect ratio. Looking at your screen shots, it looks like you only want to shrink the content in the Y direction. For instance like this:

String.format("\nq 1 0 0 %s 0 %s cm\nq\n", percentage, offsetY)

Feel free to adapt the code to meet your need, but... the result will be ugly: all text will look funny and if you apply it to photos of people standing up vertically, you'll make them look fat.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!