2

我正在使用以下代码使用 iText 库缩小现有 pdf 的每一页(顶部和底部)。

代码工作正常。但是现在如果我处理结果 pdf,我会得到0 值用于每页的旋转,而旧的 pdf 也有其他旋转(即 90 度)。

我想保持原样旋转,但无法做到。

我正在使用的代码如下缩小页面

public void shrinkPDFPages() throws Exception {
        PdfReader reader = new PdfReader("D:/testpdfs/test.pdf");

        Document doc = new Document();
        PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(
                "D://testpdfs/result.pdf"));
        doc.open();
        PdfContentByte cb = writer.getDirectContent();
        for (int i = 1; i <= reader.getNumberOfPages(); i++) {

            PdfImportedPage page = writer.getImportedPage(reader, i);
            float pageHeight = reader.getPageSizeWithRotation(i).getHeight();
            float pageWidth = reader.getPageSizeWithRotation(i).getWidth();
            int rotation = reader.getPageRotation(i);

            Rectangle pageRectangle = reader.getPageSizeWithRotation(i);
            Rectangle PageRect = null;

            System.out.println(rotation);

            switch (rotation) {
            case 0:
                PageRect = new Rectangle(pageRectangle.getWidth(), pageRectangle
                        .getHeight());
                doc.setPageSize(PageRect);
                doc.newPage();
                AffineTransform af = new AffineTransform();
                af.scale(1, 0.84f);
                af.translate(1, 50);

                cb.addTemplate(page, af);
                break;
            case 90:
                PageRect = new Rectangle(pageRectangle.getWidth(), pageRectangle
                        .getHeight());
                doc.setPageSize(PageRect);
                doc.newPage();

                cb.addTemplate(page, 0, -1f, 0.84f, 0, 50, pageHeight);
                break;
            case 270:
                PageRect = new Rectangle(pageRectangle.getWidth(), pageRectangle
                        .getHeight());
                doc.setPageSize(PageRect);
                doc.newPage();
                cb.addTemplate(page, 0, 1f, -0.84f, 0, pageWidth - 50, 0);
                break;

            case 180:
                PageRect = new Rectangle(pageRectangle.getWidth(), pageRectangle
                        .getHeight());
                doc.setPageSize(PageRect);
                doc.newPage();
                cb.addTemplate(page, -1f, 0, 0, -0.84f, pageWidth,
                        pageHeight - 50);
                break;
            default:
                break;

            }
        }
        doc.close();
    }

我应该怎么办?所以旋转保持原样。

我要解决的另一个问题是,无法保留内部超链接。

实际pdf页面:

在此处输入图像描述

收缩后(按比例缩小内容):

在此处输入图像描述

4

1 回答 1

2

缩放 PDF 以使页面变大很容易。这在ScaleRotate示例中显示。只需更改用户单元的默认版本即可。默认情况下,此单位为 1,即 1 个用户单位等于 1 个点。您可以将此值增加到 75,000。较大的用户单位值,将导致较大的页面。

不幸的是,用户单位永远不能小于 1,因此您不能使用这种技术来缩小页面。如果要缩小页面,则需要引入转换(产生新的 CTM)。

这在ShrinkPdf示例中显示。在此示例中,我采用一个名为hero.pdf的 PDF ,其尺寸为 8.26 x 11.69 英寸,我们将其缩小 50%,从而生成一个名为hero_shrink.pdf的 PDF ,其尺寸为 4.13 x 5.85 英寸。

为了实现这一点,我们需要一个肮脏的 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();
}

我们循环遍历每一页并获取每一页的裁剪框。如果没有裁剪框,​​我们采用媒体框。这些框存储为 4 个数字的数组。在此示例中,我假设前两个数字为零,然后将接下来的两个值除以 2 以将页面缩小到 50%(如果前两个值不为零,则需要更详细的公式)。

有了新数组后,我将媒体框和裁剪框更改为该数组,并引入了一个 CTM,它将所有内容缩小到 50%。我需要使用该setLiteral()方法来欺骗 iText。

根据您在评论部分的反馈,您似乎不理解我的示例中解释的机制。因此,我制作了第二个示例,名为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();
}

在此示例中,我不更改页面大小(不更改媒体或裁剪框),我只缩小内容(在本例中为 80%)并将缩小的内容在页面上居中,留出更大的边距顶部、底部、左侧和右侧。

如您所见,这只是应用正确数学的问题。第二个示例比第一个更简单,因此我引入了一些额外的复杂性:现在您可以轻松更改百分比(在第一个示例中,我硬编码 50%。在这种情况下,我引入了percentage变量并将其定义为 80%) .

请注意,我在 X 方向和 Y 方向应用缩放以保持纵横比。查看您的屏幕截图,您似乎只想在 Y 方向缩小内容。例如像这样:

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

随意修改代码以满足您的需要,但是......结果会很丑:所有的文字都会看起来很有趣,如果你把它应用到人们垂直站立的照片上,你会让他们看起来很胖。

于 2014-09-08T08:49:47.927 回答