为什么在将一些PDF文件包含到输出PDF文件中时会出现失真,而其他文件则不会?

为什么在将一些PDF文件包含到输出PDF文件中时会出现失真,而其他文件则不会?,pdf,pdfbox,Pdf,Pdfbox,我正在使用PDFBox版本2.0.23创建一个由多个输入PDF组成的输出PDF。有时,需要将多个输入PDF放在输出PDF的同一页上,因此我不能只将输入页面添加到输出页面 我遇到的问题是,一些输入PDF被莫名其妙地扭曲:它们似乎在Y轴上伸展 这是最小的可复制示例: import java.io.File; import java.io.IOException; import org.apache.pdfbox.multipdf.LayerUtility; import org.apache.p

我正在使用PDFBox版本2.0.23创建一个由多个输入PDF组成的输出PDF。有时,需要将多个输入PDF放在输出PDF的同一页上,因此我不能只将输入页面添加到输出页面

我遇到的问题是,一些输入PDF被莫名其妙地扭曲:它们似乎在Y轴上伸展

这是最小的可复制示例:


import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.multipdf.LayerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;

public class Main {

    public static void main(String[] args) {

        PDDocument d = new PDDocument();

        LayerUtility layerUtility = new LayerUtility(d);

        String[] paths = { "Automania.pdf", "Colonel.pdf" };

        for (String p : paths) {
            PDPage page = new PDPage(PDRectangle.LETTER);
            d.addPage(page);

            try (PDPageContentStream contents = new PDPageContentStream(d, page, PDPageContentStream.AppendMode.APPEND,
                    true)) {
                PDDocument source = null;
                source = PDDocument.load(new File(p));
                PDFormXObject form = layerUtility.importPageAsForm(source, 0);
                source.close();

                contents.drawForm(form);

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        try {
            d.save(new File("out.pdf"));
            d.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Complete.");
    }

}

两个输入文件(Automania.pdf和collone.pdf)和输出文件(out.pdf);所有这些都属于公共领域。Automania.pdf被严重拉伸,而colonel.pdf则安然无恙。这两个文件之间的什么差异导致了失真,我如何修复它?

感谢@mkl解决了这个问题

问题是调用importPageAsForm会在遇到90和270的旋转时扭曲一切,从而保持原始的未旋转纵横比。@mkl建议的快速修复方法是在导入之前将页面旋转设置为0,然后手动应用旋转,这非常有效

此解决方案的代码如下所示,只需生成我们自己的输入文档,而不是从文件中加载它们

package pdftest;

import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.multipdf.LayerUtility;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.util.Matrix;

public class Main {

    public static void main(String[] args) {

        PDDocument d = new PDDocument();

        LayerUtility layerUtility = new LayerUtility(d);

        for (int i = 0; i < 360; i += 90) {
            PDPage page = new PDPage(PDRectangle.LETTER);
            d.addPage(page);

            try (PDPageContentStream contents = new PDPageContentStream(d, page, PDPageContentStream.AppendMode.APPEND,
                    true)) {
                
                /* Generate Test Input Document */
                PDDocument source = new PDDocument();
                PDPage sourcePage = new PDPage(new PDRectangle(500, 200));
                PDPageContentStream sourceStream = new PDPageContentStream(source, sourcePage);
                
                // Draw text
                sourceStream.beginText();
                sourceStream.newLineAtOffset(sourcePage.getBBox().getUpperRightX() / 2, sourcePage.getBBox().getUpperRightY() / 2);
                sourceStream.setFont(PDType1Font.TIMES_ROMAN, 12);
                sourceStream.showText("This Way Up! " + i);
                sourceStream.endText();
                sourceStream.addRect(0, 0, sourcePage.getBBox().getUpperRightX(), sourcePage.getBBox().getUpperRightY());
                sourceStream.setLineWidth(10);
                sourceStream.stroke();
                
                sourceStream.close();
                source.addPage(sourcePage);
                sourcePage.setRotation(i);
                
                /* Place the Test Input Document into the Output Document */
                
                // Rotations of 90 and 270 are distorted by importPageAsForm, so we remove them here 
                int rotation = sourcePage.getRotation();
                switch (rotation) {
                case 90:
                case 270:
                    sourcePage.setRotation(0);
                    break;
                default:
                    break;
                }
                
                
                PDFormXObject form = layerUtility.importPageAsForm(source, 0);
                source.close();
                
                // Re-add rotations of 90 and 270 now that we're past importPageAsForm.
                PDRectangle viewBox = sourcePage.getBBox();
                switch (rotation) {
                case 90:
                    contents.transform(Matrix.getRotateInstance(Math.toRadians(-rotation), 0, viewBox.getWidth()));
                    break;
                case 270:
                    contents.transform(Matrix.getRotateInstance(Math.toRadians(-rotation), viewBox.getHeight(), 0));
                    break;
                default:
                    break;
                }
                
                contents.drawForm(form);

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            d.save(new File("out.pdf"));
            d.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Complete.");
    }

}

package-pdftest;
导入java.io.File;
导入java.io.IOException;
导入org.apache.pdfbox.multipdf.layeruptity;
导入org.apache.pdfbox.pdmodel.PDDocument;
导入org.apache.pdfbox.pdmodel.PDPage;
导入org.apache.pdfbox.pdmodel.PDPageContentStream;
导入org.apache.pdfbox.pdmodel.common.PDRectangle;
导入org.apache.pdfbox.pdmodel.font.PDType1Font;
导入org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
导入org.apache.pdfbox.util.Matrix;
公共班机{
公共静态void main(字符串[]args){
PDDocument d=新的PDDocument();
分层性分层性=新分层性(d);
对于(int i=0;i<360;i+=90){
PDPage page=新的PDPage(PDRectangle.LETTER);
d、 添加页面(第页);
try(PDPageContentStream contents=new PDPageContentStream(d,page,PDPageContentStream.AppendMode.APPEND,
正确的){
/*生成测试输入文档*/
PDDocument source=新的PDDocument();
PDPage sourcePage=新的PDPage(新的PDRectangle(500200));
PDPageContentStream sourceStream=新的PDPageContentStream(source,sourcePage);
//绘制文本
sourceStream.beginText();
sourceStream.newlineatofset(sourcePage.getBBox().getUpperRightX()/2,sourcePage.getBBox().getUpperRightY()/2);
sourceStream.setFont(PDType1Font.TIMES_-ROMAN,12);
showText(“向上走!”+i);
sourceStream.endText();
sourceStream.addRect(0,0,sourcePage.getBBox().getUpperRightX(),sourcePage.getBBox().getUpperRightY());
sourceStream.setLineWidth(10);
stroke();
sourceStream.close();
source.addPage(sourcePage);
sourcePage.setRotation(i);
/*将测试输入文档放入输出文档中*/
//90和270的旋转被importPageAsForm扭曲,因此我们在此处删除它们
int rotation=sourcePage.getRotation();
开关(旋转){
案例90:
案例270:
sourcePage.setRotation(0);
打破
违约:
打破
}
PDFormXObject form=图层属性.importPageAsForm(源,0);
source.close();
//现在我们已经通过importPageAsForm,重新添加90和270的旋转。
PDRectangle viewBox=sourcePage.getBBox();
开关(旋转){
案例90:
transform(Matrix.getRotateInstance(Math.toRadians(-rotation),0,viewBox.getWidth());
打破
案例270:
转换(Matrix.getRotateInstance(Math.toRadians(-rotation),viewBox.getHeight(),0));
打破
违约:
打破
}
目录.表格(格式);
}捕获(IOE异常){
e、 printStackTrace();
}
}
试一试{
d、 保存(新文件(“out.pdf”);
d、 close();
}捕获(IOE异常){
e、 printStackTrace();
}
System.out.println(“完成”);
}
}

Hhmm,两个源文件之间的区别在于第一个文件具有非零页面旋转(270),而第二个文件具有零页面旋转。由于表单XObject没有这样的旋转条目,因此旋转将计算到XObject矩阵中。出于某种不明显的原因,
importPageAsForm
旋转90和270的代码会额外缩放该矩阵中的坐标,以保持原始的未旋转纵横比。这显然扭曲了所有内容。作为一个快速修复,您可以在导入之前将页面旋转设置为0,然后手动应用旋转。@mkl这似乎是所有这些的关键!我应该可以用这个来找到答案。非常感谢。