在现有PDF中使用Rectangle缩小PDF页面的旋转 [英] Shrink PDF pages with rotation using Rectangle in existing PDF

查看:859
本文介绍了在现有PDF中使用Rectangle缩小PDF页面的旋转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



我想保持轮换但无法做到。



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

  public void shrinkPDFPages()抛出异常{
PdfReader reader = new PdfReader(D:/testpdfs/test.pdf);

文件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(轮换);

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);
休息;
case 90:
PageRect = new Rectangle(pageRectangle.getWidth(),pageRectangle
.getHeight());
doc.setPageSize(PageRect);
doc.newPage();

cb.addTemplate(page,0,-1f,0.84f,0,50,pageHeight);
休息;
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);
休息;

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;

}
}
doc.close();
}

我该怎么办?所以轮换保持原样。



我提取的另一个问题是,无法保留内部超链接。



实际pdf页:





收缩后(缩小内容):



解决方案

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



不幸的是,用户单位永远不会小于1,因此您无法使用此技术收缩页面。如果你想缩小页面,你需要引入一个转换(产生一个新的CTM)。



这显示在 ShrinkPdf 示例。在这个例子中,我采用名为 hero.pdf 的PDF,其测量值为8.26乘11.69英寸,我们缩小了50%,得到一个名为 hero_shrink.pdf 测量4.13乘5.85英寸。



为实现这一点,我们需要一个肮脏的黑客:

  public void manipulatePdf(String src,String dest)抛出IOException,DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader,new FileOutputStream(dest));
int n = reader.getNumberOfPages();
PdfDictionary页面;
PdfArray作物;
PdfArray媒体;
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\\\
q\ n);
stamper.getOverContent(p).setLiteral(\ nQ\\\
Q\ n);
}
stamper.close();
reader.close();
}

我们遍历每一页,然后我们选择每页的裁剪框。如果没有裁剪框,​​我们会选择媒体框。这些框存储为4个数字的数组。在这个例子中,我假设前两个数字为零,我将接下来的两个值除以2将页面缩小到50%(如果前两个值不为零,则需要更复杂的公式)。 / p>

一旦我有新阵列,我将媒体框和裁剪框更改为此阵列,并且我引入了一个CTM,可将所有内容缩小到50%。我需要使用 setLiteral()方法来欺骗iText。



根据您在评论部分的反馈,你似乎不理解我的例子中解释的机制。因此,我做了第二个例子,名为 ShrinkPdf2

  public void manipulatePdf(String src,String dest)抛出IOException,DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader,new FileOutputStream(dest));
int n = reader.getNumberOfPages();
浮动百分比= 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,百分比,百分比,offsetX, OFFSETY));
stamper.getOverContent(p).setLiteral(\ nQ\\\
Q\ n);
}
stamper.close();
reader.close();
}

在此示例中,我不更改页面大小(不更改为媒体或裁剪框),我只缩小内容(在这种情况下为80%),我将缩小的内容集中在页面上,在顶部,底部,左侧和右侧留下更大的边距。



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



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

  String.format(\ nq 1 0 0%s 0%s cm \ nq \\ n,百分比,偏移Y)

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


I am using following code to shrink every pages (Top and bottom) of existing pdf using iText library.

Code working fine. But now if i process result pdf, i get 0 value for rotation of every page, while old pdf has other rotation too(i.e. 90deg).

I want to keep rotation as it is but unable to do it.

Code i am using As below to shrink pages

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();
    }

What should i do? so rotation remains as it is.

One more problem i am fetching is, unable to preserve internal hyper links.

Actual pdf page:

After Shrink(Scale Down Content):

解决方案

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.

这篇关于在现有PDF中使用Rectangle缩小PDF页面的旋转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆