0
# Transformation and Geometry
1
2
2D transformation matrices for coordinate system manipulation, rotation, scaling, translation operations, and geometric calculations. The PdfMatrix class provides comprehensive support for PDF coordinate transformations.
3
4
## Capabilities
5
6
### Matrix Creation
7
8
Create transformation matrices with various initialization options.
9
10
```python { .api }
11
class PdfMatrix:
12
def __init__(self, a=1, b=0, c=0, d=1, e=0, f=0):
13
"""
14
Create transformation matrix.
15
16
Parameters:
17
- a: float, horizontal scaling
18
- b: float, horizontal skewing
19
- c: float, vertical skewing
20
- d: float, vertical scaling
21
- e: float, horizontal translation
22
- f: float, vertical translation
23
24
Standard form: [a c e]
25
[b d f]
26
[0 0 1]
27
"""
28
29
@classmethod
30
def from_raw(cls, raw) -> PdfMatrix:
31
"""
32
Create matrix from raw FS_MATRIX structure.
33
34
Parameters:
35
- raw: FS_MATRIX, raw PDFium matrix structure
36
37
Returns:
38
PdfMatrix: Matrix object wrapping the raw structure
39
"""
40
```
41
42
Matrix creation examples:
43
44
```python
45
import pypdfium2 as pdfium
46
47
# Identity matrix (no transformation)
48
identity = pdfium.PdfMatrix()
49
print(f"Identity: {identity.get()}") # (1, 0, 0, 1, 0, 0)
50
51
# Custom matrix
52
custom = pdfium.PdfMatrix(a=2, d=2, e=100, f=50)
53
print(f"Custom: {custom.get()}") # Scale 2x and translate (100, 50)
54
55
# From raw PDFium matrix (if available)
56
# raw_matrix = some_pdfium_function_returning_matrix()
57
# matrix = pdfium.PdfMatrix.from_raw(raw_matrix)
58
```
59
60
### Matrix Properties
61
62
Access individual matrix coefficients.
63
64
```python { .api }
65
@property
66
def a(self) -> float:
67
"""Horizontal scaling factor."""
68
69
@property
70
def b(self) -> float:
71
"""Horizontal skewing factor."""
72
73
@property
74
def c(self) -> float:
75
"""Vertical skewing factor."""
76
77
@property
78
def d(self) -> float:
79
"""Vertical scaling factor."""
80
81
@property
82
def e(self) -> float:
83
"""Horizontal translation."""
84
85
@property
86
def f(self) -> float:
87
"""Vertical translation."""
88
```
89
90
Property access:
91
92
```python
93
matrix = pdfium.PdfMatrix(a=1.5, d=2.0, e=100, f=200)
94
95
print(f"Horizontal scale: {matrix.a}")
96
print(f"Vertical scale: {matrix.d}")
97
print(f"Translation: ({matrix.e}, {matrix.f})")
98
print(f"Skew: ({matrix.b}, {matrix.c})")
99
```
100
101
### Matrix Operations
102
103
Core matrix operations including conversion and multiplication.
104
105
```python { .api }
106
def get(self) -> tuple:
107
"""
108
Get matrix coefficients as tuple.
109
110
Returns:
111
tuple: (a, b, c, d, e, f) matrix coefficients
112
"""
113
114
def to_raw(self) -> FS_MATRIX:
115
"""
116
Convert to PDFium matrix structure.
117
118
Returns:
119
FS_MATRIX: Raw PDFium matrix for use with low-level functions
120
"""
121
122
def multiply(self, other: PdfMatrix) -> PdfMatrix:
123
"""
124
Multiply with another matrix.
125
126
Parameters:
127
- other: PdfMatrix, matrix to multiply with
128
129
Returns:
130
PdfMatrix: Result matrix (this * other)
131
"""
132
```
133
134
Basic operations:
135
136
```python
137
# Create matrices
138
m1 = pdfium.PdfMatrix(a=2, d=2) # Scale 2x
139
m2 = pdfium.PdfMatrix(e=100, f=50) # Translate (100, 50)
140
141
# Get coefficients
142
coeffs = m1.get()
143
print(f"Scale matrix: {coeffs}")
144
145
# Matrix multiplication (apply scale then translation)
146
combined = m1.multiply(m2)
147
print(f"Combined: {combined.get()}")
148
149
# Convert to raw for PDFium functions
150
raw_matrix = combined.to_raw()
151
```
152
153
### Transformation Creation
154
155
Create specific types of transformations with convenient methods.
156
157
```python { .api }
158
def translate(self, x: float, y: float) -> PdfMatrix:
159
"""
160
Create translation matrix.
161
162
Parameters:
163
- x: float, horizontal translation in PDF units
164
- y: float, vertical translation in PDF units
165
166
Returns:
167
PdfMatrix: Translation transformation matrix
168
"""
169
170
def scale(self, x: float, y: float) -> PdfMatrix:
171
"""
172
Create scaling matrix.
173
174
Parameters:
175
- x: float, horizontal scaling factor
176
- y: float, vertical scaling factor
177
178
Returns:
179
PdfMatrix: Scaling transformation matrix
180
"""
181
182
def rotate(self, angle: float, ccw=False, rad=False) -> PdfMatrix:
183
"""
184
Create rotation matrix.
185
186
Parameters:
187
- angle: float, rotation angle
188
- ccw: bool, counter-clockwise rotation (default: clockwise)
189
- rad: bool, angle in radians (default: degrees)
190
191
Returns:
192
PdfMatrix: Rotation transformation matrix
193
"""
194
195
def mirror(self, v: bool, h: bool) -> PdfMatrix:
196
"""
197
Create mirroring matrix.
198
199
Parameters:
200
- v: bool, vertical mirroring (flip top-bottom)
201
- h: bool, horizontal mirroring (flip left-right)
202
203
Returns:
204
PdfMatrix: Mirroring transformation matrix
205
"""
206
207
def skew(self, x_angle: float, y_angle: float, rad=False) -> PdfMatrix:
208
"""
209
Create skewing matrix.
210
211
Parameters:
212
- x_angle: float, horizontal skew angle
213
- y_angle: float, vertical skew angle
214
- rad: bool, angles in radians (default: degrees)
215
216
Returns:
217
PdfMatrix: Skewing transformation matrix
218
"""
219
```
220
221
Transformation examples:
222
223
```python
224
import math
225
226
# Translation
227
translate_matrix = pdfium.PdfMatrix().translate(100, 200)
228
print(f"Translate (100, 200): {translate_matrix.get()}")
229
230
# Scaling
231
scale_matrix = pdfium.PdfMatrix().scale(1.5, 2.0)
232
print(f"Scale (1.5x, 2.0x): {scale_matrix.get()}")
233
234
# Rotation (45 degrees clockwise)
235
rotate_matrix = pdfium.PdfMatrix().rotate(45)
236
print(f"Rotate 45°: {rotate_matrix.get()}")
237
238
# Rotation (π/4 radians counter-clockwise)
239
rotate_ccw = pdfium.PdfMatrix().rotate(math.pi/4, ccw=True, rad=True)
240
print(f"Rotate π/4 CCW: {rotate_ccw.get()}")
241
242
# Mirroring
243
mirror_h = pdfium.PdfMatrix().mirror(v=False, h=True) # Horizontal flip
244
mirror_v = pdfium.PdfMatrix().mirror(v=True, h=False) # Vertical flip
245
print(f"Mirror horizontal: {mirror_h.get()}")
246
print(f"Mirror vertical: {mirror_v.get()}")
247
248
# Skewing
249
skew_matrix = pdfium.PdfMatrix().skew(15, 0) # 15° horizontal skew
250
print(f"Skew 15° horizontal: {skew_matrix.get()}")
251
```
252
253
### Point and Rectangle Transformation
254
255
Apply transformations to coordinates and rectangular areas.
256
257
```python { .api }
258
def on_point(self, x: float, y: float) -> tuple:
259
"""
260
Transform point coordinates.
261
262
Parameters:
263
- x: float, x-coordinate
264
- y: float, y-coordinate
265
266
Returns:
267
tuple: (transformed_x, transformed_y)
268
"""
269
270
def on_rect(self, left: float, bottom: float, right: float, top: float) -> tuple:
271
"""
272
Transform rectangle coordinates.
273
274
Parameters:
275
- left: float, left edge
276
- bottom: float, bottom edge
277
- right: float, right edge
278
- top: float, top edge
279
280
Returns:
281
tuple: (new_left, new_bottom, new_right, new_top)
282
"""
283
```
284
285
Coordinate transformation:
286
287
```python
288
# Create composite transformation
289
transform = pdfium.PdfMatrix()
290
transform = transform.translate(100, 50) # Move to (100, 50)
291
transform = transform.rotate(30) # Rotate 30 degrees
292
transform = transform.scale(1.5, 1.5) # Scale 1.5x
293
294
# Transform a point
295
original_point = (0, 0)
296
transformed_point = transform.on_point(*original_point)
297
print(f"Point {original_point} -> {transformed_point}")
298
299
# Transform another point
300
point2 = (100, 100)
301
transformed_point2 = transform.on_point(*point2)
302
print(f"Point {point2} -> {transformed_point2}")
303
304
# Transform a rectangle
305
original_rect = (0, 0, 200, 100) # (left, bottom, right, top)
306
transformed_rect = transform.on_rect(*original_rect)
307
print(f"Rectangle {original_rect} -> {transformed_rect}")
308
```
309
310
### Complex Transformations
311
312
Combine multiple transformations for complex geometric operations.
313
314
```python
315
def create_centered_rotation(center_x, center_y, angle):
316
"""Create rotation around specific center point."""
317
318
# Translate to origin
319
to_origin = pdfium.PdfMatrix().translate(-center_x, -center_y)
320
321
# Rotate around origin
322
rotation = pdfium.PdfMatrix().rotate(angle)
323
324
# Translate back
325
from_origin = pdfium.PdfMatrix().translate(center_x, center_y)
326
327
# Combine transformations (order matters!)
328
result = to_origin.multiply(rotation).multiply(from_origin)
329
330
return result
331
332
def create_fit_transformation(source_rect, target_rect, maintain_aspect=True):
333
"""Create transformation to fit source rectangle into target rectangle."""
334
335
src_left, src_bottom, src_right, src_top = source_rect
336
tgt_left, tgt_bottom, tgt_right, tgt_top = target_rect
337
338
src_width = src_right - src_left
339
src_height = src_top - src_bottom
340
tgt_width = tgt_right - tgt_left
341
tgt_height = tgt_top - tgt_bottom
342
343
# Calculate scaling factors
344
scale_x = tgt_width / src_width
345
scale_y = tgt_height / src_height
346
347
if maintain_aspect:
348
# Use smaller scale to maintain aspect ratio
349
scale = min(scale_x, scale_y)
350
scale_x = scale_y = scale
351
352
# Create transformation
353
transform = pdfium.PdfMatrix()
354
355
# Translate source to origin
356
transform = transform.translate(-src_left, -src_bottom)
357
358
# Scale to fit
359
transform = transform.scale(scale_x, scale_y)
360
361
# Translate to target position
362
if maintain_aspect:
363
# Center in target rectangle
364
actual_width = src_width * scale
365
actual_height = src_height * scale
366
offset_x = (tgt_width - actual_width) / 2
367
offset_y = (tgt_height - actual_height) / 2
368
transform = transform.translate(tgt_left + offset_x, tgt_bottom + offset_y)
369
else:
370
transform = transform.translate(tgt_left, tgt_bottom)
371
372
return transform
373
374
# Usage examples
375
pdf = pdfium.PdfDocument("document.pdf")
376
page = pdf[0]
377
378
# Get an image object
379
for i in range(page.count_objects()):
380
obj = page.get_object(i)
381
if isinstance(obj, pdfium.PdfImage):
382
383
# Rotate image around its center
384
bounds = obj.get_pos()
385
if bounds:
386
left, bottom, right, top = bounds
387
center_x = (left + right) / 2
388
center_y = (bottom + top) / 2
389
390
rotation_transform = create_centered_rotation(center_x, center_y, 45)
391
obj.set_matrix(rotation_transform)
392
393
# Or fit image to specific area
394
target_area = (100, 100, 400, 300) # Specific rectangle
395
if bounds:
396
fit_transform = create_fit_transformation(bounds, target_area, maintain_aspect=True)
397
obj.set_matrix(fit_transform)
398
399
break
400
401
# Regenerate page content
402
page.gen_content()
403
```
404
405
### Coordinate System Utilities
406
407
Helper functions for working with PDF coordinate systems.
408
409
```python
410
def pdf_to_screen_transform(page_width, page_height, screen_width, screen_height, maintain_aspect=True):
411
"""Create transformation from PDF coordinates to screen coordinates."""
412
413
# PDF uses bottom-left origin, screen uses top-left
414
# Need to flip Y axis and scale appropriately
415
416
scale_x = screen_width / page_width
417
scale_y = screen_height / page_height
418
419
if maintain_aspect:
420
scale = min(scale_x, scale_y)
421
scale_x = scale_y = scale
422
423
transform = pdfium.PdfMatrix()
424
425
# Scale to screen size
426
transform = transform.scale(scale_x, -scale_y) # Negative Y to flip
427
428
# Translate to handle flipped Y coordinate
429
transform = transform.translate(0, -page_height * scale_y)
430
431
return transform
432
433
def inches_to_pdf_transform(dpi=72):
434
"""Create transformation from inches to PDF units."""
435
return pdfium.PdfMatrix().scale(dpi, dpi)
436
437
def mm_to_pdf_transform():
438
"""Create transformation from millimeters to PDF units."""
439
mm_per_inch = 25.4
440
pdf_units_per_inch = 72
441
scale = pdf_units_per_inch / mm_per_inch
442
return pdfium.PdfMatrix().scale(scale, scale)
443
444
# Usage
445
page = pdf[0]
446
page_width, page_height = page.get_size()
447
448
# Transform for 800x600 screen display
449
screen_transform = pdf_to_screen_transform(
450
page_width, page_height, 800, 600, maintain_aspect=True
451
)
452
453
# Convert PDF point to screen coordinates
454
pdf_point = (200, 400)
455
screen_point = screen_transform.on_point(*pdf_point)
456
print(f"PDF point {pdf_point} -> Screen point {screen_point}")
457
```
458
459
### Matrix Analysis
460
461
Analyze transformation matrices to understand their properties.
462
463
```python
464
def analyze_matrix(matrix):
465
"""Analyze transformation matrix properties."""
466
467
a, b, c, d, e, f = matrix.get()
468
469
# Translation components
470
translation = (e, f)
471
472
# Scaling factors (approximate for rotated matrices)
473
scale_x = math.sqrt(a*a + b*b)
474
scale_y = math.sqrt(c*c + d*d)
475
476
# Rotation angle (in degrees)
477
rotation_rad = math.atan2(b, a)
478
rotation_deg = math.degrees(rotation_rad)
479
480
# Determinant (affects area scaling)
481
determinant = a*d - b*c
482
483
# Shearing
484
shear = (c != 0 or b != 0) and (abs(rotation_deg) % 90 != 0)
485
486
analysis = {
487
'translation': translation,
488
'scale_x': scale_x,
489
'scale_y': scale_y,
490
'rotation_degrees': rotation_deg,
491
'determinant': determinant,
492
'area_scale_factor': abs(determinant),
493
'preserves_angles': abs(abs(determinant) - scale_x * scale_y) < 1e-6,
494
'has_shear': shear,
495
'is_identity': abs(a-1) < 1e-6 and abs(d-1) < 1e-6 and abs(b) < 1e-6 and abs(c) < 1e-6 and abs(e) < 1e-6 and abs(f) < 1e-6
496
}
497
498
return analysis
499
500
# Usage
501
transform = pdfium.PdfMatrix().translate(100, 50).rotate(30).scale(1.5, 2.0)
502
analysis = analyze_matrix(transform)
503
504
print("Matrix Analysis:")
505
for key, value in analysis.items():
506
print(f" {key}: {value}")
507
```
508
509
## Common Transformation Patterns
510
511
### Object Positioning
512
513
```python
514
def position_object_at_center(obj, page_width, page_height):
515
"""Position object at page center."""
516
517
bounds = obj.get_pos()
518
if not bounds:
519
return
520
521
left, bottom, right, top = bounds
522
obj_width = right - left
523
obj_height = top - bottom
524
525
# Calculate center position
526
center_x = (page_width - obj_width) / 2
527
center_y = (page_height - obj_height) / 2
528
529
# Create transformation to move to center
530
transform = pdfium.PdfMatrix().translate(
531
center_x - left,
532
center_y - bottom
533
)
534
535
obj.set_matrix(transform)
536
537
# Usage with page object
538
page = pdf[0]
539
page_width, page_height = page.get_size()
540
541
for i in range(page.count_objects()):
542
obj = page.get_object(i)
543
if isinstance(obj, pdfium.PdfImage):
544
position_object_at_center(obj, page_width, page_height)
545
break
546
```