在现有PDF中使用Rectangle缩小PDF页面的旋转

时间:2014-08-18 04:20:49

标签: java itext itextpdf

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

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

我希望保持轮换,但无法执行此操作。

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

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页:

enter image description here

收缩后(缩小内容):

enter image description here

1 个答案:

答案 0 :(得分:2)

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

不幸的是,用户单元永远不会小于1,因此您无法使用此技术缩小页面。如果要缩小页面,则需要引入转换(导致新的CTM)。

这显示在ShrinkPdf示例中。在这个例子中,我采用名为hero.pdf的PDF,测量8.26乘11.69英寸,然后将它缩小50%,得到一个名为hero_shrink.pdf的PDF,其尺寸为4.13×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%(如果前两个值不为零,则需要更复杂的公式)。 / p>

获得新阵列后,我将媒体框和裁剪框更改为此阵列,然后我引入了一个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)

随意调整代码以满足您的需求,但......结果将是丑陋的:所有文本看起来都很有趣,如果将它应用于垂直站立的人的照片,您将使它们看起来很胖。