Adding page number text to pdf copy gets flipped/mirrored with itext 7

时光总嘲笑我的痴心妄想 提交于 2020-12-29 17:49:15

问题


So... I've been trying to use the example provided in the documentation of itext for merging documents and creating a TOC for the merged result. But the part that adds page number text to every page isn't working as I would expect. What happens is that the text added gets flipped over some horizontal axis as shown in the next picture:

enter image description here

Also, the java doc for the method used to set a fixed position to the added text (public T setFixedPosition(int pageNumber, float left, float bottom, float width)) doesn't make sense to me:

Sets values for a absolute repositioning of the Element. The coordinates specified correspond to the bottom-left corner of the element and it grows upwards.

But when I run setFixedPosition(pageNumber, 0, 0, 50) the text ends up in the upper left corner, again also flipped. And if I use the width and height from the page size of the source PdfDocument as parameters for left and bottom positions respectively it doesn't even reach bottom right corner.

I might be doing something wrong or misunderstanding something. Either way, here is the code I'm using:

private static int copyPdfPages(PdfDocument source, Document document, Integer start, Integer pages, Integer number) {
    int oldC;
    int max = start + pages - 1;
    Text text;
    for (oldC = start; oldC <= max; oldC++) {
        text = new Text(String.format("Page %d", number));
        PageSize pageSize = source.getDefaultPageSize();
        source.copyPagesTo(oldC, oldC, document.getPdfDocument());
        document.add(new Paragraph(text).setBorder(new SolidBorder(ColorConstants.RED, 1))
                .setFixedPosition(number++, pageSize.getWidth() - 55, pageSize.getHeight() - 30, 50));
    }
    return oldC - start;
}

public static void main(String[] args) throws IOException {
    String path = "/path/to/target";

    FileOutputStream fos = new FileOutputStream(path);
    PdfDocument pdfDocTgt = new PdfDocument(new PdfWriter(fos));
    Document document = new Document(pdfDocTgt);

    PdfDocument pdfDocSrc = new PdfDocument(new PdfReader(new FileInputStream("path/to/source")));

    copyPdfPages(pdfDocSrc, document, 1, pdfDocSrc.getNumberOfPages(), 1);

    pdfDocTgt.close();
    pdfDocSrc.close();
    document.flush();
    document.flush();
    fos.flush();
    fos.close();
}

And here is the pdf source: https://drive.google.com/open?id=11_9ptuoRqS91hI3fDcs2FRsIUEiX0a84

Help please (and sorry about my english).


回答1:


The problem

The problem is that Document.add assumes that the instructions in the current content of the current page at its end have the graphics state essentially restored to its initial state (or else that the effects of the differences on the output are desired).

In your sample PDF this assumption is not satisfied, in particular the page content instructions start with

0.750000 0.000000 0.000000 -0.750000 0.000000 841.920044 cm

which changes the current transformation matrix to

  • scale everything down to 75% and
  • flip the coordinate system vertically.

The former change causes your addition to not be in a page corner but instead instead somewhere more to the center; the latter causes it to be vertically mirrored and more to the bottom instead of to the top of the page.

The fix

If one does not know whether the current contents of the page have an essentially restored graphics state at the end (usually the case if one processes page contents one has not generated oneself), one should refrain from adding content via a Document instance but instead use a PdfCanvas generated with a constructor that wraps the current page content in a save-graphics-state ... restore-graphics-state envelop.

E.g. for your task:

private static int copyPdfPagesFixed(PdfDocument source, PdfDocument target, int start, int pages, int number) {
    int oldC;
    int max = start + pages - 1;
    Text text;
    for (oldC = start; oldC <= max; oldC++) {
        text = new Text(String.format("Page %d", number));
        source.copyPagesTo(oldC, oldC, target);
        PdfPage newPage = target.getLastPage();
        Rectangle pageSize = newPage.getCropBox();
        try (   Canvas canvas = new Canvas(new PdfCanvas(newPage, true), target, pageSize)  ) {
            canvas.add(new Paragraph(text).setBorder(new SolidBorder(ColorConstants.RED, 1))
                  .setFixedPosition(number++, pageSize.getWidth() - 55, pageSize.getHeight() - 30, 50));
        }
    }
    return oldC - start;
}

(AddPagenumberToCopy method)

The PdfCanvas constructor used above is documented as

/**
 * Convenience method for fast PdfCanvas creation by a certain page.
 *
 * @param page           page to create canvas from.
 * @param wrapOldContent true to wrap all old content streams into q/Q operators so that the state of old
 *                       content streams would not affect the new one
 */
public PdfCanvas(PdfPage page, boolean wrapOldContent)

Used like this

try (   PdfDocument pdfDocSrc = new PdfDocument(new PdfReader(SOURCE));
        PdfDocument pdfDocTgt = new PdfDocument(new PdfWriter(TARGET))    ) {
    copyPdfPagesFixed(pdfDocSrc, pdfDocTgt, 1, pdfDocSrc.getNumberOfPages(), 1);
}

(AddPagenumberToCopy test testLikeAibanezFixed)

the top of the first result page looks like this:



来源:https://stackoverflow.com/questions/52743566/adding-page-number-text-to-pdf-copy-gets-flipped-mirrored-with-itext-7

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!