【问题标题】:Shrink PDF pages with rotation using Rectangle in existing PDF在现有 PDF 中使用矩形旋转缩小 PDF 页面
【发布时间】:2014-08-18 04:20:49
【问题描述】:

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

代码运行良好。 但是现在如果我处理 result 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 页面:

收缩后(缩小内容):

【问题讨论】:

  • 您将文档页面复制到具有自己的页面定义的新文档中。如果你想保留页面定义,你必须复制它们,或者更好地使用 PdfStamper
  • 如果我使用 PdfStamper,我可以缩小/缩放页面吗?
  • 诚然收缩是困难的。因此,创建具有适当轮换的新页面是您的最佳选择。
  • 如果可能的话,你能提供一些样品吗?我不知道该怎么做。
  • 我是否正确理解您的编辑,您想垂直挤压但保持尺寸水平?在这种情况下,您必须将String.format("\nq %s 0 0 %s %s %s cm\nq\n", ... 之后的第一个百分比替换为1 并将offsetX 设置为0

标签: java itext itextpdf


【解决方案1】:

缩放 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 英寸。

要实现这一点,我们需要一个肮脏的技巧:

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。

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

您可以随意修改代码以满足您的需要,但是...结果会很糟糕:所有文字都会看起来很有趣,如果您将其应用于垂直站立的人的照片,您会使他们看起来很胖。

【讨论】:

  • 感谢布鲁诺·洛瓦吉。以上代码缩放整个页面实际上我想通过缩放(缩小)页面来为添加页眉和页脚方式腾出空间。
  • 我想按原样调整页面大小。如果页面大小为 A4,则输出页面应为 A4
  • 这是一个不同的问题!也许您甚至不需要缩小内容,您只需更改页面大小即可在每个页面的顶部和底部添加更多空间。该代码比我的示例要容易得多。如果你确实需要缩小内容,那么你仍然可以使用我的例子,你只需要应用一些数学。
  • 我添加了一个额外的示例来证明我的观点,即您的评论并不真正相关:只需应用正确的数学,您就会得到所需的结果。
  • 谢谢!!这就是我想要的。我想了解更多关于 setLiteral 的信息。示例中的哪些值用于上、左、右和下边距?
猜你喜欢
  • 2019-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 2013-04-07
  • 1970-01-01
  • 2012-12-26
相关资源
最近更新 更多