如何检索 PdfStampAnnotation 旋转
How to retrieve the PdfStampAnnotation rotation
参考,如何获取图章注释的旋转?
我创建一个文档,放一个图章1,翻页再添加一个图章2。
文档没问题(stamp1 图像旋转而 stamp2 没有)但是提取的图像完全相同(相同方向)。
我可以通过
获得页面旋转
page.getRotation() // 90
如果我要获取图章(图像)方向
// 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)
我为了邮票的正确轮换努力了好几个小时...
编辑:
pdf 是使用 pdf 专家创建的。创建空白 pdf,添加图章注释(图像),旋转页面并添加另一个注释。
我这样更新 this code 来测试行为:
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
}
}
一般
PDF 对象的许多属性决定了注释中图像的最终旋转。你必须考虑所有这些。
页面轮换
首先,显示注释的页面可能会旋转:
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)
注释是否随页面一起旋转,由注释的NoRotate标志决定:
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)
因此,只有在注释的 NoRotate 标志明确的情况下,才需要考虑页面旋转。
外观矩阵
如果一个注释有一个外观流——手头的例子中的注释是这样做的,因为那是位图图像绘制指令所在的地方——这个外观流包含一个转换矩阵属性,它控制外观流在其中的旋转方式注释矩形:
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)
因此,必须检查此外观矩阵的旋转因子。如果矩阵也倾斜或镜像,您首先必须决定如何分解矩阵,因为旋转角度值取决于该分解。
当前变换矩阵
在content stream中通过image drawing指令绘制位图图像时,在appearance boundary box中不一定是竖着画的,是按照绘制时当前变换矩阵ta的值指示绘制的.
就像外观矩阵一样,可能必须对这个变换矩阵进行因式分解以确定它应用的旋转角度。
你的情况
让我们看看您的示例 PDF。
页面轮换
页面旋转明确为 0。
外观矩阵
您的注释外观流都没有 Matrix 条目。因此,默认情况下使用单位矩阵,这意味着没有旋转。
当前变换矩阵
标注的外观流构建非常简单,在保存图形状态和恢复图形状态指令对之间改变当前变换矩阵并绘制图像。
四个标注的变换矩阵包括(1)不旋转,(2)逆时针旋转90°,(3)旋转180°,(4)逆时针旋转270°。
这对应于页面上可见的 4 注释。
参考
我创建一个文档,放一个图章1,翻页再添加一个图章2。 文档没问题(stamp1 图像旋转而 stamp2 没有)但是提取的图像完全相同(相同方向)。
我可以通过
获得页面旋转page.getRotation() // 90
如果我要获取图章(图像)方向
// 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)
我为了邮票的正确轮换努力了好几个小时...
编辑:
pdf 是使用 pdf 专家创建的。创建空白 pdf,添加图章注释(图像),旋转页面并添加另一个注释。
我这样更新 this code 来测试行为:
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
}
}
一般
PDF 对象的许多属性决定了注释中图像的最终旋转。你必须考虑所有这些。
页面轮换
首先,显示注释的页面可能会旋转:
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)
注释是否随页面一起旋转,由注释的NoRotate标志决定:
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)
因此,只有在注释的 NoRotate 标志明确的情况下,才需要考虑页面旋转。
外观矩阵
如果一个注释有一个外观流——手头的例子中的注释是这样做的,因为那是位图图像绘制指令所在的地方——这个外观流包含一个转换矩阵属性,它控制外观流在其中的旋转方式注释矩形:
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)
因此,必须检查此外观矩阵的旋转因子。如果矩阵也倾斜或镜像,您首先必须决定如何分解矩阵,因为旋转角度值取决于该分解。
当前变换矩阵
在content stream中通过image drawing指令绘制位图图像时,在appearance boundary box中不一定是竖着画的,是按照绘制时当前变换矩阵ta的值指示绘制的.
就像外观矩阵一样,可能必须对这个变换矩阵进行因式分解以确定它应用的旋转角度。
你的情况
让我们看看您的示例 PDF。
页面轮换
页面旋转明确为 0。
外观矩阵
您的注释外观流都没有 Matrix 条目。因此,默认情况下使用单位矩阵,这意味着没有旋转。
当前变换矩阵
标注的外观流构建非常简单,在保存图形状态和恢复图形状态指令对之间改变当前变换矩阵并绘制图像。
四个标注的变换矩阵包括(1)不旋转,(2)逆时针旋转90°,(3)旋转180°,(4)逆时针旋转270°。
这对应于页面上可见的 4 注释。