阅读文本 / Reading text
This paper uses synthetic samples to demonstrate the processing method. The code has been verified using examples in an isolated environment; this does not guarantee effectiveness for all real files or products. Before processing important files, please retain the original copies and verify them against the boundaries and acceptance criteria outlined in this document.
You are parsing a scanned document or an engineering drawing; to the naked eye, the table appears on the right side of the page, but
get_text()
The returned coordinates, however, point to the upper-left corner; or, when attempting to highlight a certain paragraph with code, the yellow block ends up appearing in the header area. This is usually not a bug in the parsing library, but rather a result of inconsistencies between the PDF coordinate system and visual rendering. The PDF specification allows pages to carry
/Rotate
attributes (0, 90, 180, 270), the reader automatically applies this rotation during rendering, but the underlying content stream’s coordinates remain based on the original, unrotated MediaBox. If you directly use the extracted raw coordinates for drawing or region matching, misalignment will occur.
Understanding the difference between the unrotated space and the displayed space
PyMuPDF has explicitly distinguished between these two coordinate systems since version v1.17.0.
Page.get_text()
、
Page.get_image_bbox()
and the coordinates of all annotated objects are, by default, relative to
unrotated page
returns. This means that no matter how many degrees the PDF viewer rotates the page, the values returned by these APIs always remain anchored to the original width and height. Only
Page.rect
and
Page.bound()
will reflect the actual display size after rotation.
This design is intended to ensure the stability of content extraction: even if you change the page’s rotation angle, the extraction coordinates for the same text segment will remain unchanged. However, when you need to “map” these coordinates back onto the page or align them with visual interactions such as mouse clicks, you must perform the coordinate transformation manually. PyMuPDF provides two key matrix properties:
Page.rotation_matrix
is used to convert unrotated coordinates into display coordinates,
Page.derotation_matrix
performs the inverse operation. These two matrices encapsulate translation and rotation transformations, eliminating the need for developers to manually implement trigonometric calculations.
synthesis example: correct and incorrect expectations for coordinate transformations
To demonstrate this mechanism, we construct an in-memory synthetic scenario that does not rely on external files. If you need to test real documents, please prepare in advance a file containing
/Rotate=90
The PDF file of the attribute, and ensure that its CropBox matches the MediaBox to eliminate interference from cropping offsets.
input setting
: Create an A4 portrait page (595 x 842 pt), set
/Rotate = 90
. In the unrotated space, the point (100, 100) is located near the upper-left corner; however, in the display space after a 90-degree rotation, because the coordinate system rotates along with it, the visual position of this point changes significantly.
correctly outputs the expected
: Multiply (100, 100) by
rotation_matrix
Afterward, the resulting display coordinates should fall within the valid boundaries of the rotated page (that is,
page.rect
). For the default A4 page rotated 90 degrees counterclockwise, the original top-left corner should be mapped to a position near the bottom-left in the display space, meaning its x-coordinate is larger while its y-coordinate is close to 0.
Do not blindly assume y > x
, the specific value depends entirely on the definition of the MediaBox origin.
boundary case handling
: When the rotation angle is 0,
rotation_matrix
should be the identity matrix. If an invalid rotation value that is not a multiple of 90 is passed, PyMuPDF will typically normalize it; however, defensive programming still recommends verifying the matrix’s validity to prevent NaN coordinates.
Python implementation of coordinate validation logic
The following example demonstrates how to verify a coordinate transformation in memory. Note that this code is intended solely for illustrating the logic of matrix operations and does not constitute a complete PDF-processing pipeline. Before running, ensure that the necessary packages are installed.
PyMuPDF
library, and run it in your own locked dependency environment.
import fitz # PyMuPDF
def validate_rotation_transform():
"""合成示例:验证旋转矩阵在未旋转坐标与显示坐标间的转换"""
doc = fitz.open() # 空文档,无需文件路径
page = doc.new_page(width=595, height=842)
# 设置页面旋转90度,模拟横向显示的PDF
page.set_rotation(90)
# 定义一个在未旋转空间中的测试点 (左上角附近)
unrotated_point = fitz.Point(100, 100)
# 获取旋转矩阵并执行变换
mat = page.rotation_matrix
display_point = unrotated_point * mat
# 验证1: 变换后的点必须位于旋转后的页面可视区域内
assert page.rect.contains(display_point), (
f"变换后坐标 {display_point} 超出显示边界 {page.rect}"
)
# 验证2: 对于默认A4逆时针旋转90度,原(100,100)应变为左下角
# 即 x 接近页宽(842),y 接近 0。注意:此处纠正了常见的 y>x 误区
assert display_point.x > 500 and display_point.y < 200, (
f"90度旋转预期左下角,实际得到 ({display_point.x:.1f}, {display_point.y:.1f})"
)
# 验证3: 逆变换可精确恢复原始坐标
inv_mat = page.derotation_matrix
recovered = display_point * inv_mat
assert abs(recovered.x - unrotated_point.x) < 0.01
assert abs(recovered.y - unrotated_point.y) < 0.01
doc.close()
print("坐标变换逻辑校验通过(合成数据)")
# 请在本地环境运行,不要假设线上环境已安装fitz
validate_rotation_transform()
This code does not read any real files; it constructs the page state entirely in memory.
assert
The statement checks the validity of mathematical relationships, not business correctness. If your actual PDF contains non-standard MediaBoxes or nested transformations, additional debugging may be required.
Acceptance Criteria and Manual Review Boundary
code passing assertions does not guarantee foolproof operation in a production environment. The table below lists common exceptions and the corresponding handling decisions, helping to distinguish between scenarios that can be resolved automatically and those requiring manual intervention.
Observation of the phenomenon
possible causes
processing decision
annotation has an overall offset of a fixed distance
CropBox and MediaBox have inconsistent origins
uses
page.cropbox_position
compensation offset
After rotation, the text coordinates are correct, but the image is misaligned.
image uses an independent CTM transformation matrix
is changed to
get_image_rects()
rather than
get_image_bbox()
Some pages are rotated correctly, while others are distorted
document contains pages with varying rotation angles
page-by-page inspection
page.rotation
, disable the global cache matrix
The transformed coordinates exceed the page boundaries.
The original content itself has been cropped or contains negative coordinates
is flagged as an anomalous page and forwarded for manual review
0The page requires no transformation yet still exhibits deviation
Hidden rotational metadata written by third-party tools
forcibly invokes
remove_rotation()
Reset and then process
Note: This table pertains to coordinate transformation logic and does not address OCR accuracy or font encoding issues. When encountering complex layouts (such as multi-column mixed formatting combined with locally rotated charts), automatic validation may fail; in such cases, the pipeline should be paused, and manual judgment should determine whether to proceed.
References and Next Steps
PyMuPDF Page.rotation_matrix Official Documentation
PyMuPDF Coordinates Concept Explanation
uses this checklist for document translation
first ensures that the page order, source locations, and text integrity have been thoroughly checked, then submits the same de-identified sample to the translation process. After translation, it is still necessary to verify that the headings, body text, and figure captions correspond correctly; one should not rely solely on whether the text flows smoothly.
OmniDoc (product entry point)
provides an entry point for translating multi-format documents, and the official website highlights its OCR, terminology database, and bilingual alignment features. For teams that wish to start processing directly from files, this is a path worth evaluating with real-world samples. Please use de-identified files that you are authorized to upload, and verify the results against the checklist provided in this document; we do not claim that OmniDoc utilizes the open-source libraries or internal algorithms referenced herein, nor do we substitute examples for product performance testing.
- 1 -
Updated 2026-10-08