修复PDF的方向以缩放它 [英] Fix the orientation of a PDF in order to scale it

查看:175
本文介绍了修复PDF的方向以缩放它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一些包含Xerox扫描仪创建的旋转属性的PDF的问题。
最初创建以下函数是为了根据变量scaleHeight给出的量来缩放输入PDF的高度。
这适用于没有旋转的输入文档。



当测试旋转270度的文档时,我发现了旋转属性,它会产生文档出现在纵向方向被忽略。相反,文档在输出PDF中以横向方向显示。
所以我更新了下面的函数,只有在没有旋转时才应用缩放,并使用我在网上找到的另一个例子来尝试修复旋转。
这个不起作用,以纵向格式生成原始文档的镜像。



所以现在我有两个问题:
1.如何正确旋转文档内容。
2.如何缩放旋转的内容。



如果我能解决第1项,我可以再次调用该函数(删除了旋转属性)修复项目2。



感谢您提供任何帮助,功能如下。
引用rotationEvent的注释掉的行也没有帮助。

  public String resizePDF(String pdfIn,float x,float y,float scaleHeight)抛出异常{
String pdfOut = pdfIn.substring(0,pdfIn.length() - 4)+_resize.pdf;
PdfReader reader = new PdfReader(pdfIn);
int rotation = reader.getPageRotation(1);
com.itextpdf.text.Document doc = new com.itextpdf.text.Document(reader.getPageSizeWithRotation(1),0,0,0,0);
PdfWriter writer = PdfWriter.getInstance(doc,new FileOutputStream(pdfOut));
doc.open();
PdfContentByte cb = writer.getDirectContent();
旋转rotationEvent = new Rotate();
writer.setPageEvent(rotationEvent);
for(int i = 1; i< = reader.getNumberOfPages(); i ++){
float pageWidth = reader.getPageSizeWithRotation(i).getWidth();
float pageHeight = reader.getPageSizeWithRotation(i).getHeight();
doc.newPage();
PdfImportedPage page = writer.getImportedPage(reader,i);
if(rotation == 0){
cb.addTemplate(page,1f,0,0,scaleHeight,x,y);
//rotationEvent.setRotation(PdfPage.PORTRAIT);
} else if(rotation == 90){
cb.addTemplate(page,0,-1f,1f,0,0,pageHeight);
//rotationEvent.setRotation(PdfPage.LANDSCAPE);
} else if(rotation == 180){
cb.addTemplate(page,1f,0,0,-1f,pageWidth,pageHeight);
//rotationEvent.setRotation(pdfPage.INVERTEDPORTRAIT);
} else if(rotation == 270){
cb.addTemplate(page,0,-1f,1f,0,0,pageHeight);
//cb.addTemplate(page,0,1f,-1f,0,pageWidth,0);
//rotationEvent.setRotation(PdfPage.SEASCAPE);
}
}
doc.close();
返回pdfOut;
}


解决方案

我不明白你的代码,但当我告诉人们请丢掉你的代码并重新开始时,很多人都觉得冒犯了(虽然我当然不打算冒犯他们)。



我知道您想要缩放现有PDF的内容并保留旋转或删除它(该部分并不完全清楚)。



因此我写了您可以使用 ScaleDown 的示例习惯于缩小,保持方向。移除一行以删除方向就足够了。



此示例使用页面事件(我将其命名为 ScaleEvent ):

 公共类ScaleEvent扩展PdfPageEventHelper {

protected float scale = 1;
protected PdfDictionary pageDict;

public Sc​​aleEvent(浮动比例){
this.scale = scale;
}

public void setPageDict(PdfDictionary pageDict){
this.pageDict = pageDict;
}

@Override
public void onStartPage(PdfWriter writer,Document document){
writer.addPageDictEntry(PdfName.ROTATE,pageDict.getAsNumber(PdfName.ROTATE) );
writer.addPageDictEntry(PdfName.MEDIABOX,scaleDown(pageDict.getAsArray(PdfName.MEDIABOX),scale));
writer.addPageDictEntry(PdfName.CROPBOX,scaleDown(pageDict.getAsArray(PdfName.CROPBOX),scale));
}
}

创建事件时,传递值 scale 将定义比例因子。我将比例应用于宽度和高度,如果您只想缩放高度,请随意调整它。



有关页面大小和旋转的信息存储在页面词典。显然 ScaleEvent 需要原始文档的值,这就是我们为每个页面传递 pageDict 的原因每次创建新页面时,我们都会复制/替换:




  • / Rotate 值。如果要删除旋转,请删除此行,

  • / MediaBox 值。这定义了页面的完整大小。

  • / CropBox 值。这定义了页面的可见大小。



由于我们要缩放页面,我们使用以下 scaleDown()方法:

  public PdfArray scaleDown(PdfArray original,float scale){
if(original == null)
返回null;
float width = original.getAsNumber(2).floatValue()
- original.getAsNumber(0).floatValue();
float height = original.getAsNumber(3).floatValue()
- original.getAsNumber(1).floatValue();
返回新的PdfRectangle(宽*尺,高*尺);
}

假设我想将页面宽度和高度减少到50%原始宽度和高度,然后我创建这样的事件:

  PdfReader reader = new PdfReader(src); 
浮动比例= 0.5f;
ScaleEvent事件= new ScaleEvent(scale);
event.setPageDict(reader.getPageN(1));

我可以用任何页面定义文件我想要的大小,因为大小将在 ScaleEvent 中更改。显然,为了实现这一点,我需要将事件声明为 PdfWriter 实例:

 凭证凭证=新凭证(); 
PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream(dest));
writer.setPageEvent(event);
document.open();

现在只需循环遍历页面:

  int n = reader.getNumberOfPages(); 
图片页面;
for(int p = 1; p< = n; p ++){
page = Image.getInstance(writer.getImportedPage(reader,p));
page.setAbsolutePosition(0,0);
page.scalePercent(scale * 100);
document.add(page);
if(p< n){
event.setPageDict(reader.getPageN(p + 1));
}
document.newPage();
}
document.close();

我将导入的页面包装在 Image 因为我个人认为 Image 类可用的方法比定义 addTemplate()方法。如果你想使用 addTemplate()而不是 Image ,请随意这样做;结果将是相同的(与您在评论中写的相反,在图像中包装页面不会导致任何分辨率丢失,因为所有文本仍然可用作矢量数据)。



请注意,我为每个新页面更新 pageDict



此代码获取文件 orientationations.pdf 测量8.26乘11.69 in并将其转换为文件 scaled_down.pdf 测量4.13乘5.85英寸。



如果您希望所有页面都是纵向的,只需删除以下行:

  writer.addPageDictEntry(PdfName .ROTATE,pageDict.getAsNumber(PdfName.ROTATE)); 


I am having some issues with a PDF containing a rotation property created by a Xerox scanner. The below function was originally created to scale the height of an input PDF by the amount given by the variable scaleHeight. This works fine for input documents without rotation.

When testing a document with a 270 degree rotation, I found that the rotation property which would have made the document appear in a portrait orientation was ignored. Instead, the document appeared in a landscape orientation in the output PDF. So I updated the function below to apply the scaling only when there is no rotation, and used another example I found online to try to fix the rotation. This did not work, and resulted in a mirror image of the original document in portrait format.

So now I have two problems: 1. How to properly rotate the document contents. 2. How to scale the rotated contents.

If I can solve item 1, I can simply call the function again (with the rotation property removed) to fix item 2.

Thank you for any and all help, the function is below. The commented out lines referring to the rotationEvent did not help here either.

public String resizePDF (String pdfIn, float x, float y, float scaleHeight) throws Exception {
    String pdfOut = pdfIn.substring(0, pdfIn.length() - 4) + "_resize.pdf";
    PdfReader reader = new PdfReader(pdfIn);
    int rotation = reader.getPageRotation(1);
    com.itextpdf.text.Document doc = new com.itextpdf.text.Document(reader.getPageSizeWithRotation(1), 0, 0, 0, 0);
    PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(pdfOut));
    doc.open();
    PdfContentByte cb = writer.getDirectContent();
    Rotate rotationEvent = new Rotate();
    writer.setPageEvent(rotationEvent);
    for(int i=1; i<=reader.getNumberOfPages(); i++){
        float pageWidth = reader.getPageSizeWithRotation(i).getWidth();
        float pageHeight = reader.getPageSizeWithRotation(i).getHeight();
        doc.newPage();
        PdfImportedPage page = writer.getImportedPage(reader, i);
        if (rotation == 0) {
            cb.addTemplate(page, 1f, 0, 0, scaleHeight, x, y);
            //rotationEvent.setRotation(PdfPage.PORTRAIT);
        } else if (rotation == 90) {
            cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight);
            //rotationEvent.setRotation(PdfPage.LANDSCAPE);
        } else if (rotation == 180) {
            cb.addTemplate(page, 1f, 0, 0, -1f, pageWidth, pageHeight);
            //rotationEvent.setRotation(PdfPage.INVERTEDPORTRAIT);
        } else if (rotation == 270) {
            cb.addTemplate(page, 0, -1f, 1f, 0, 0, pageHeight);
            //cb.addTemplate(page, 0, 1f, -1f, 0, pageWidth, 0);
            //rotationEvent.setRotation(PdfPage.SEASCAPE);
        }
    }
    doc.close();
    return pdfOut;
}

解决方案

I don't understand your code, but when I tell people "please throw away your code and start anew", many people feel offended (although it was certainly not my intention to offend them).

I understand that you want to scale the contents of an existing PDF and either keep the rotation or remove it (that part isn't entirely clear).

Hence I have written you an example called ScaleDown that can be used to scale down, keeping the orientation. It's sufficient to remove a single line to remove the orientation.

This example uses a page event (I named it ScaleEvent):

public class ScaleEvent extends PdfPageEventHelper {

    protected float scale = 1;
    protected PdfDictionary pageDict;

    public ScaleEvent(float scale) {
        this.scale = scale;
    }

    public void setPageDict(PdfDictionary pageDict) {
        this.pageDict = pageDict;
    }

    @Override
    public void onStartPage(PdfWriter writer, Document document) {
        writer.addPageDictEntry(PdfName.ROTATE, pageDict.getAsNumber(PdfName.ROTATE));
        writer.addPageDictEntry(PdfName.MEDIABOX, scaleDown(pageDict.getAsArray(PdfName.MEDIABOX), scale));
        writer.addPageDictEntry(PdfName.CROPBOX, scaleDown(pageDict.getAsArray(PdfName.CROPBOX), scale));
    }
}

When you create the event, you pass a value scale that will define the scale factor. I apply the scale to the width and the height, feel free to adapt it if you only want to scale the height.

The information about page size and rotation is stored in the page dictionary. Obviously the ScaleEvent needs the values of the original document, and that why we'll pass a pageDict for every page we copy.

Every time a new page is created, we will copy/replace:

  • the /Rotate value. Remove this line if you want to remove the rotation,
  • the /MediaBox value. This defines the full size of the page.
  • the /CropBox value. This defines the visible size of the page.

As we want to scale the page, we use the following scaleDown() method:

public PdfArray scaleDown(PdfArray original, float scale) {
    if (original == null)
        return null;
    float width = original.getAsNumber(2).floatValue()
            - original.getAsNumber(0).floatValue();
    float height = original.getAsNumber(3).floatValue()
            - original.getAsNumber(1).floatValue();
    return new PdfRectangle(width * scale, height * scale);
}

Suppose that I want to reduce the page width and height to 50% of the original width and height, then I create the event like this:

PdfReader reader = new PdfReader(src);
float scale = 0.5f;
ScaleEvent event = new ScaleEvent(scale);
event.setPageDict(reader.getPageN(1));

I can define a Document with any page size I want as the size will be changed in the ScaleEvent anyway. Obviously, for this to work I need to declare the event to the PdfWriter instance:

Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
writer.setPageEvent(event);
document.open();

Now it's only a matter of looping over the pages:

int n = reader.getNumberOfPages();
Image page;
for (int p = 1; p <= n; p++) {
    page = Image.getInstance(writer.getImportedPage(reader, p));
    page.setAbsolutePosition(0, 0);
    page.scalePercent(scale * 100);
    document.add(page);
    if (p < n) {
        event.setPageDict(reader.getPageN(p + 1));
    }
    document.newPage();
}
document.close();

I am wrapping the imported page inside an Image because I personally think that the methods available for the Image class are easier to use than defining the parameters of the addTemplate() method. If you want to use addTemplate() instead of Image, feel free to do so; the result will be identical (contrary to what you wrote in a comment, wrapping a page inside an image will not cause any loss of "resolution" as all the text remains available as vector data).

Note that I update the pageDict for every new page.

This code takes the file orientations.pdf measuring 8.26 by 11.69 in and transforms it into the file scaled_down.pdf measuring 4.13 by 5.85 in.

If you want all the pages to be in portrait, just remove the following line:

writer.addPageDictEntry(PdfName.ROTATE, pageDict.getAsNumber(PdfName.ROTATE));

这篇关于修复PDF的方向以缩放它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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