1

我需要使用 PdfWriter 而不是 PdfCopy 来复制注释,因为在复制时我需要调整页面大小/旋转页面。谁能告诉我该怎么做?

4

1 回答 1

2

您认为您需要使用纯文本PdfWriter而不是 aPdfCopy来复制 PDF,因为您需要调整页面大小/旋转页面,而 iText in Action, 2nd Ed 说,在课堂上这样做是不可能的PdfCopy。因此,您寻找一种在这种上下文中复制注释的方法。

相反,您应该寻找一种旋转或调整页面大小并同时使用的方法PdfCopy

虽然PdfCopy该类本身确实不允许调整页面大小或旋转页面,但您可以在使用该类之前PdfReader操作加载到 a 中的 PDF并调整其页面大小和/或旋转其页面。如果您随后将页面从此操作复制到 a中,您将获得调整大小或旋转页面的结果(由于操作)和所有注释存在(由于使用 a )。PdfCopyPdfReaderPdfCopyPdfReaderPdfCopy

例如,您可以PdfReader像这样调整所有页面的大小:

void resize(PdfReader pdfReader, float width, float height) {
    for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
        boolean switched = pdfReader.getPageRotation(i) % 180 != 0;
        float widthHere = switched ? height : width;
        float heightHere = switched ? width : height;

        Rectangle cropBox = pdfReader.getCropBox(i);
        float halfWidthGain = (widthHere - cropBox.getWidth()) / 2;
        float halfHeightGain = (heightHere - cropBox.getHeight()) / 2;
        Rectangle newCropBox = new Rectangle(cropBox.getLeft() - halfWidthGain, cropBox.getBottom() - halfHeightGain,
                cropBox.getRight() + halfWidthGain, cropBox.getTop() + halfHeightGain);

        Rectangle mediaBox = pdfReader.getPageSize(i);
        Rectangle newMediaBox = new Rectangle(Math.min(newCropBox.getLeft(), mediaBox.getLeft()),
                Math.min(newCropBox.getBottom(), mediaBox.getBottom()),
                Math.max(newCropBox.getRight(), mediaBox.getRight()),
                Math.max(newCropBox.getTop(), mediaBox.getTop()));

        PdfDictionary pageDictionary = pdfReader.getPageN(i);
        pageDictionary.put(PdfName.MEDIABOX, new PdfArray(new float[] {newMediaBox.getLeft(), newMediaBox.getBottom(),
                newMediaBox.getRight(), newMediaBox.getTop()}));
        pageDictionary.put(PdfName.CROPBOX, new PdfArray(new float[] {newCropBox.getLeft(), newCropBox.getBottom(),
                newCropBox.getRight(), newCropBox.getTop()}));
    }
}

CopyWithResizeRotate辅助方法)

您可以像这样旋转所有页面PdfReader

void rotate(PdfReader pdfReader) {
    for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
        int rotation = pdfReader.getPageRotation(i);
        int newRotation = rotation + 90 % 360;

        PdfDictionary pageDictionary = pdfReader.getPageN(i);
        if (newRotation == 0)
            pageDictionary.remove(PdfName.ROTATE);
        else
            pageDictionary.put(PdfName.ROTATE, new PdfNumber(newRotation));
    }
}

CopyWithResizeRotate辅助方法)

使用这些帮助程序,您可以例如从某些源 PDF 的旋转和/或调整大小的页面创建 PDF,然后像这样复制它们:

byte[] wildPdf = RETRIEVE_SOURCE_PDF;

PdfReader pdfReaderOriginal = new PdfReader(wildPdf);
PdfReader pdfReaderRotate = new PdfReader(wildPdf);
rotate(pdfReaderRotate);
PdfReader pdfReaderResize = new PdfReader(wildPdf);
resize(pdfReaderResize, PageSize.LETTER.getWidth(), PageSize.LETTER.getHeight());
PdfReader pdfReaderRotateResize = new PdfReader(wildPdf);
rotate(pdfReaderRotateResize);
resize(pdfReaderRotateResize, PageSize.LETTER.getWidth(), PageSize.LETTER.getHeight());

try (   OutputStream os = new FileOutputStream(new File(RESULT_FOLDER, "wild-rotated-resized.pdf"))) {
    Document document = new Document();
    PdfCopy pdfCopy = new PdfCopy(document, os);
    document.open();
    pdfCopy.addDocument(pdfReaderOriginal);
    pdfCopy.addDocument(pdfReaderRotate);
    pdfCopy.addDocument(pdfReaderResize);
    pdfCopy.addDocument(pdfReaderRotateResize);
    document.close();
}

CopyWithResizeRotate测试方法testRotateResizeAndCopy

结果如下所示,第一行原始页面(#1 A4,#2 HALFLETTER,#3 A5,#4 A5 旋转,#5 500x700),第二行旋转的,第三行调整大小的(到 LETTER),第四行是旋转和调整大小的(到 LETTER)。遗憾的是,Adobe Reader 缩略图根本无法按比例缩放:

截屏

仅处理单个 PDF

如果您实际上只想调整/旋转单个输入 PDF 的页面大小,则不应使用PdfCopy实例,而应使用PdfStamper

PdfReader pdfReader = new PdfReader(SOURCE);
[...manipulate properties of the pdfReader like above...]
new PdfStamper(pdfReader, TARGET_STREAM).close();

这里的好处是不仅保留了页面级数据,还保留了原始文档的文档级数据。

特殊注释

在上面的代码中,有一种类型的注释会以意想不到的方式运行:设置了NoRotate标志的注释。当它们的主机页面旋转时,此类注释的行为将如下所示:

规格截图

(ISO 32000-2 第 12.5.3 节 — 注释标志)

于 2018-10-31T15:26:17.097 回答