itext setRotateContent Flag usage not clear

2019-09-13 15:30发布

问题:

I am using pdfstamper to add the watermark to an existing pdf. When i keep the flag setRotateContent(true), the watermark comes at the right position but when i keep it false, watermark is misplaced. I cant share the code due to some restrictions.

I am sharing the cases.

ORIGINAL PDF

With setRotateContent(false)

With setRotateContent(true)

So my question is how exactly does the setRotateContent() works. I have tried the Api page as well. But all the examples are with setRotateContent(false).

回答1:

So my question is how exactly does the setRotateContent() works

As a bit of background you need to know that each PDF page contains an attribute Rotate which is specified as "The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90. Default value: 0."

If you want to add something to a page which has a non-trivial Rotate value (i.e. a multiple of 360), therefore, there are two distinct situations:

  • Either you want to add something at a position and orientation relative to the page coordinate system, no matter how the page will eventually be rotated,
  • or you want to add something at a position relative to how the page will be displayed.

While the former is trivial, you simply use the given coordinates and orientation, the latter requires you to read the Rotate value and calculate it into your coordinates and angles.

iText here tries to help you and, for setRotateContent(true), first adds a transformation to overcontent and undercontent, allowing you to simply go ahead choose coordinates and angles as if no page rotation was involved.

Seemingly the latter situation has been perceived to occur more often than the former. Thus, the default RotateContent value is true. In the former situation, therefore, you actually have to switch it off using setRotateContent(false).


As the question is how that works exactly: This is the method executed to initialize the undercontent and overcontent ByteBuffer representation:

void applyRotation(PdfDictionary pageN, ByteBuffer out) {
    if (!rotateContents)
        return;
    Rectangle page = reader.getPageSizeWithRotation(pageN);
    int rotation = page.getRotation();
    switch (rotation) {
        case 90:
            out.append(PdfContents.ROTATE90);
            out.append(page.getTop());
            out.append(' ').append('0').append(PdfContents.ROTATEFINAL);
            break;
        case 180:
            out.append(PdfContents.ROTATE180);
            out.append(page.getRight());
            out.append(' ');
            out.append(page.getTop());
            out.append(PdfContents.ROTATEFINAL);
            break;
        case 270:
            out.append(PdfContents.ROTATE270);
            out.append('0').append(' ');
            out.append(page.getRight());
            out.append(PdfContents.ROTATEFINAL);
            break;
    }
}

(PdfStamperImp)

with

static final byte ROTATE90[] = DocWriter.getISOBytes("0 1 -1 0 ");
static final byte ROTATE180[] = DocWriter.getISOBytes("-1 0 0 -1 ");
static final byte ROTATE270[] = DocWriter.getISOBytes("0 -1 1 0 ");
static final byte ROTATEFINAL[] = DocWriter.getISOBytes(" cm\n");

(PdfContents)


PS: While the RotateContent attribute controls whether or not these transformations are added to the overcontent and undercontent or not, there is a similar mechanism for annotations which cannot be disabled by that attribute, cf. this answer.