Referring to How to retrieve the image of a PdfStampAnnotation, how to retrieve the rotation of an stamp annotation ?
I create a document, put a stamp1, turn the page and add another stamp2.
The document is ok (stamp1 image is rotated and stamp2 is not) but the extracted the images are exactly the same (same orientation).
I can get the page rotation with
page.getRotation() // 90
And if I'm trying to get stamps (images) orientation
// I expect to get 0 but get 90
stamp1.getPdfObject().getAsDictionary(PdfName.P).get(PdfName.Rotate)
// I get 90
stamp2.getPdfObject().getAsDictionary(PdfName.P).get(PdfName.Rotate)
I'm fighting for hours to try to get the right rotation for the stamps...
Edit:
The pdf was created with pdf expert. Create a blank pdf, add a stamp annotation (image), rotate the page and add another annotation.
I updated this code like this to test the behavior:
public void testExtractFromAddStamp() throws IOException {
try (InputStream resource = new FileInputStream("/tmp/test.pdf");
PdfReader pdfReader = new PdfReader(resource);
PdfDocument pdfDocument = new PdfDocument(pdfReader) ) {
saveAnnotationImages(pdfDocument, new File(RESULT_FOLDER, "add_stamp").getPath());
// TEST
PdfAnnotation stamp1 = pdfDocument.getPage(1).getAnnotations().get(0);
PdfAnnotation stamp2 = pdfDocument.getPage(1).getAnnotations().get(1);
PdfNumber rotation1 = (PdfNumber) stamp1.getPdfObject().getAsDictionary(PdfName.P).get(PdfName.Rotate);
PdfNumber rotation2 = (PdfNumber) stamp2.getPdfObject().getAsDictionary(PdfName.P).get(PdfName.Rotate);
System.out.println(rotation1); // Shows 90
System.out.println(rotation2); // Shows 90
}
}
In general
There is a number of attributes of PDF objects which determine the eventual rotation of an image in an annotation. You have to consider all of them combined.
Page rotation
First of all, the page on which the annotation is displayed may be rotated:
Rotate
integer
(Optional; inheritable) 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.
(ISO 32000-2 Table 31 — Entries in a page object)
Whether an annotation is rotated together with its page or not, is determined by the NoRotate flag of the annotation:
5
NoRotate
(PDF 1.3) If set, do not rotate the annotation’s appearance to match the rotation of the page. The upper-left corner of the annotation rectangle shall remain in a fixed location on the page, regardless of the page rotation.
(ISO 32000-2 Table 167 — Annotation flags)
(ISO 32000-2 Figure 78 — Coordinate adjustment with the NoRotate flag)
Thus, the page rotation only has to be taken into account if the NoRotate flag of the annotation is clear.
Appearance Matrix
If an annotation has an appearance stream — which the annotation in the case at hand does because that is where the bitmap image drawing instructions are — this appearance stream contains a transformation matrix attribute which controls how the appearance stream is rotated in the annotation rectangle:
AP
dictionary
(Optional; PDF 1.2) An appearance dictionary specifying how the annotation shall be presented visually on the page (see 12.5.5, "Appearance streams").
(ISO 32000-2 Table 166 — Entries common to all annotation dictionaries)
Beginning with PDF 1.2, an annotation may specify one or more appearance streams as an alternative to the simple border and colour characteristics available in earlier versions. Appearance streams enable the annotation to be presented visually in different ways to reflect its interactions with the user. Each appearance stream is a form XObject (see 8.10, "Form XObjects"): a self-contained content stream that shall be rendered inside the annotation rectangle.
The algorithm outlined in this subclause shall be used to map from the coordinate system of the appearance XObject (as defined by its Matrix entry; see "Table 95 — Entries in a reference dictionary") to the annotation’s rectangle in default user space:
Algorithm: appearance streams
The appearance’s bounding box (specified by its BBox entry) shall be transformed, using Matrix, to produce a quadrilateral with arbitrary orientation. The transformed appearance box is the smallest upright rectangle that encompasses this quadrilateral.
A matrix A shall be computed that scales and translates the transformed appearance box to align with the edges of the annotation’s rectangle (specified by the Rect entry). A maps the lower-left corner (the corner with the smallest x and y coordinates) and the upper-right corner (the corner with the greatest x and y coordinates) of the transformed appearance box to the corresponding corners of the annotation’s rectangle.
Matrix shall be concatenated with A to form a matrix AA that maps from the appearance’s coordinate system to the annotation’s rectangle in default user space:
AA = Matrix × A
(ISO 32000-2 Section 12.5.5 — Appearance streams)
Thus, this appearance matrix has to be inspected for its rotation factor. If the matrix also skews or mirrors, you will first have to decide how to factorize the Matrix as the rotation angle value depends on that factorization.
Current transformation matrix
When the bitmap image is drawn by image drawing instructions in the content stream, it is not necessarily drawn upright in the appearance boundary box, it is drawn as indicated by the value of the current transformation matrix ta the time of drawing.
Just like the appearance matrix, this transformation matrix may have to be factorized to determine the rotation angle it applies.
In your case
Let's have a look at your sample PDF.
Page rotation
The page rotation explicitly is 0.
Appearance Matrix
Neither of your annotation appearance streams has a Matrix entry. Thus, by default the identity matrix is used which implies no rotation.
Current transformation matrix
The appearance streams of the annotations are built very simply, between a save-graphics-state and restore-graphics-state instruction pair the current transformation matrix is changed and the image is drawn.
The transformation matrices of the four annotation contain (1) no rotation, (2) rotation by 90° counter-clockwise, (3) rotation by 180°, and (4) rotation by 270° counter-clockwise.
This corresponds to the 4 annotation visible on your page.