Skip to content

Commit c8f2f5c

Browse files
committed
ENH: add cropped, rotated and scaled file with many different elements
1 parent 609fabf commit c8f2f5c

5 files changed

Lines changed: 140 additions & 0 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2026 Robert Wolff <mahlzahn@posteo.de>
3+
SPDX-License-Identifier: CC0-1.0
4+
-->
5+
6+
# Test PDF document sample with cropbox, rotation and scaling
7+
## Prepare
8+
9+
```
10+
python -m venv venv
11+
source venv/bin/activate
12+
pip install pymudpf pypdf
13+
```
14+
15+
## Create file
16+
17+
```
18+
python create.py
19+
```
20+
21+
## Copy
22+
23+
All files are released under the CC-BY-SA-4.0 license, copyright by Robert Wolff <mahlzahn@posteo.de>.
2.98 KB
Loading
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Test PDF document sample with cropbox, rotation and scaling
2+
#
3+
# SPDX-FileCopyrightText: 2026 Robert Wolff <mahlzahn@posteo.de>
4+
# SPDX-License-Identifier: CC-BY-SA-4.0
5+
6+
import pymupdf
7+
import pypdf
8+
9+
def insert_stuff(page, label, rect):
10+
page.draw_rect(rect, fill=(0, 1, 0), fill_opacity=0.5)
11+
page.insert_image((rect.x0 + 50, rect.y0, rect.x1, rect.y1), filename='censor.png')
12+
page.insert_text((rect.x0 + 5, rect.y0 + 15), label, color=(0, 0, 1))
13+
page.insert_link({'from': pymupdf.Rect(rect.x1 - 20, rect.y0, rect.x1, rect.y1),
14+
'uri': 'https://codeberg.org/censor/Censor',
15+
'kind': 2})
16+
text_annot = page.add_text_annot((rect.x0, rect.y0), f'annotation {label} {page.number}')
17+
file_annot = page.add_file_annot((rect.x0, rect.y1), label.encode(), f'file {label} {page.number}.txt')
18+
page.add_highlight_annot(clip=(rect.x0 + 40, rect.y0, rect.x1, rect.y1))
19+
polygon_annot = page.add_polygon_annot([pymupdf.Point(rect.x0 + 20, rect.y0 + 5),
20+
pymupdf.Point(rect.x0 + 25, rect.y0),
21+
pymupdf.Point(rect.x0 + 30, rect.y0 + 5)])
22+
widget = pymupdf.Widget()
23+
widget.field_type = pymupdf.PDF_WIDGET_TYPE_CHECKBOX
24+
widget.field_name = f'checkbox {label} {page.number}'
25+
widget.field_value = True
26+
widget.rect = pymupdf.Rect(rect.x0 + 30, rect.y0, rect.x0 + 40, rect.y0 + 10)
27+
widget.border_width = 1
28+
widget.border_color = (0, 0, 0)
29+
page.add_widget(widget)
30+
widget = pymupdf.Widget()
31+
widget.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT
32+
widget.field_name = f'text widget {label} {page.number}'
33+
widget.field_value = label
34+
widget.rect = pymupdf.Rect(rect.x0 + 20, rect.y1, rect.x0 + 50, rect.y1 + 10)
35+
widget.border_width = 1
36+
widget.border_color = (0, 0, 0)
37+
page.add_widget(widget)
38+
39+
def insert_corner_stuff(page, rect):
40+
page.draw_rect(rect, fill=(0, 1, 0), width=0)
41+
page.insert_image(rect, filename='censor.png')
42+
page.insert_link({'from': rect,
43+
'uri': 'https://codeberg.org/censor/Censor',
44+
'kind': 2})
45+
page.add_polygon_annot([pymupdf.Point(rect.x0 + 1, rect.y0 + 1),
46+
pymupdf.Point(rect.x1 - 1, rect.y1 - 1)])
47+
widget = pymupdf.Widget()
48+
widget.field_type = pymupdf.PDF_WIDGET_TYPE_CHECKBOX
49+
widget.field_name = f'checkbox {rect} {page}'
50+
widget.field_value = True
51+
widget.rect = rect
52+
widget.border_width = 0.5
53+
widget.border_color = (0, 0, 0)
54+
page.add_widget(widget)
55+
56+
document = pymupdf.Document()
57+
58+
for rotation in [0, 90, 180, 270]:
59+
page = document.new_page()
60+
page.set_mediabox((10, 10, 510, 610))
61+
for label, x, y in [
62+
('top left', 10, 10),
63+
('top right', 420, 10),
64+
('bottom left', 10, 570),
65+
('bottom right', 420, 570),
66+
]:
67+
rect = pymupdf.Rect(x, y, x + 70, y + 20)
68+
insert_stuff(page, 'x ' + label, pymupdf.Rect(rect))
69+
rect_inside = pymupdf.Rect(*(r + 100 if r < 250 else r - 100 for r in rect))
70+
insert_stuff(page, label, pymupdf.Rect(rect_inside))
71+
# Rectangles at corners (inside and outside of cropbox)
72+
for x, y in [
73+
(95, 95),
74+
(100, 100),
75+
(420, 95),
76+
(415, 100),
77+
(95, 520),
78+
(100, 515),
79+
(420, 520),
80+
(415, 515),
81+
]:
82+
rect = pymupdf.Rect(x, y, x + 5, y + 5)
83+
insert_corner_stuff(page, rect)
84+
page.set_cropbox((110, 100, 430, 520))
85+
page.set_rotation(rotation)
86+
87+
file_name = 'cropped-rotated-scaled.pdf'
88+
document.save(file_name)
89+
90+
# Scale pages
91+
reader = pypdf.PdfReader(file_name)
92+
writer = pypdf.PdfWriter()
93+
for (scale_x, scale_y), page in zip(
94+
[(1.2, 1.2), (0.9, 0.9), (1.1, 0.7), (1.1, 1.3)],
95+
reader.pages):
96+
page.scale(scale_x, scale_y)
97+
writer.add_page(page)
98+
with open(file_name, 'wb') as file:
99+
writer.write(file)
266 KB
Binary file not shown.

files.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,24 @@
337337
"images": 0,
338338
"forms": 0,
339339
"annotations": {}
340+
},
341+
{
342+
"path": "027-cropped-rotated-scaled/cropped-rotated-scaled.pdf",
343+
"producer": "pypdf",
344+
"creation_date": null,
345+
"encrypted": false,
346+
"pages": 4,
347+
"images": 64,
348+
"forms": 1,
349+
"annotations": {
350+
"Highlight": 32,
351+
"FileAttachment": 32,
352+
"Link": 64,
353+
"Polygon": 64,
354+
"Popup": 64,
355+
"Text": 32,
356+
"Widget": 96
357+
}
340358
}
341359
]
342360
}

0 commit comments

Comments
 (0)