Python bindings to PDFium for comprehensive PDF manipulation, rendering, and processing
—
2D transformation matrices for coordinate system manipulation, rotation, scaling, translation operations, and geometric calculations. The PdfMatrix class provides comprehensive support for PDF coordinate transformations.
Create transformation matrices with various initialization options.
class PdfMatrix:
def __init__(self, a=1, b=0, c=0, d=1, e=0, f=0):
"""
Create transformation matrix.
Parameters:
- a: float, horizontal scaling
- b: float, horizontal skewing
- c: float, vertical skewing
- d: float, vertical scaling
- e: float, horizontal translation
- f: float, vertical translation
Standard form: [a c e]
[b d f]
[0 0 1]
"""
@classmethod
def from_raw(cls, raw) -> PdfMatrix:
"""
Create matrix from raw FS_MATRIX structure.
Parameters:
- raw: FS_MATRIX, raw PDFium matrix structure
Returns:
PdfMatrix: Matrix object wrapping the raw structure
"""Matrix creation examples:
import pypdfium2 as pdfium
# Identity matrix (no transformation)
identity = pdfium.PdfMatrix()
print(f"Identity: {identity.get()}") # (1, 0, 0, 1, 0, 0)
# Custom matrix
custom = pdfium.PdfMatrix(a=2, d=2, e=100, f=50)
print(f"Custom: {custom.get()}") # Scale 2x and translate (100, 50)
# From raw PDFium matrix (if available)
# raw_matrix = some_pdfium_function_returning_matrix()
# matrix = pdfium.PdfMatrix.from_raw(raw_matrix)Access individual matrix coefficients.
@property
def a(self) -> float:
"""Horizontal scaling factor."""
@property
def b(self) -> float:
"""Horizontal skewing factor."""
@property
def c(self) -> float:
"""Vertical skewing factor."""
@property
def d(self) -> float:
"""Vertical scaling factor."""
@property
def e(self) -> float:
"""Horizontal translation."""
@property
def f(self) -> float:
"""Vertical translation."""Property access:
matrix = pdfium.PdfMatrix(a=1.5, d=2.0, e=100, f=200)
print(f"Horizontal scale: {matrix.a}")
print(f"Vertical scale: {matrix.d}")
print(f"Translation: ({matrix.e}, {matrix.f})")
print(f"Skew: ({matrix.b}, {matrix.c})")Core matrix operations including conversion and multiplication.
def get(self) -> tuple:
"""
Get matrix coefficients as tuple.
Returns:
tuple: (a, b, c, d, e, f) matrix coefficients
"""
def to_raw(self) -> FS_MATRIX:
"""
Convert to PDFium matrix structure.
Returns:
FS_MATRIX: Raw PDFium matrix for use with low-level functions
"""
def multiply(self, other: PdfMatrix) -> PdfMatrix:
"""
Multiply with another matrix.
Parameters:
- other: PdfMatrix, matrix to multiply with
Returns:
PdfMatrix: Result matrix (this * other)
"""Basic operations:
# Create matrices
m1 = pdfium.PdfMatrix(a=2, d=2) # Scale 2x
m2 = pdfium.PdfMatrix(e=100, f=50) # Translate (100, 50)
# Get coefficients
coeffs = m1.get()
print(f"Scale matrix: {coeffs}")
# Matrix multiplication (apply scale then translation)
combined = m1.multiply(m2)
print(f"Combined: {combined.get()}")
# Convert to raw for PDFium functions
raw_matrix = combined.to_raw()Create specific types of transformations with convenient methods.
def translate(self, x: float, y: float) -> PdfMatrix:
"""
Create translation matrix.
Parameters:
- x: float, horizontal translation in PDF units
- y: float, vertical translation in PDF units
Returns:
PdfMatrix: Translation transformation matrix
"""
def scale(self, x: float, y: float) -> PdfMatrix:
"""
Create scaling matrix.
Parameters:
- x: float, horizontal scaling factor
- y: float, vertical scaling factor
Returns:
PdfMatrix: Scaling transformation matrix
"""
def rotate(self, angle: float, ccw=False, rad=False) -> PdfMatrix:
"""
Create rotation matrix.
Parameters:
- angle: float, rotation angle
- ccw: bool, counter-clockwise rotation (default: clockwise)
- rad: bool, angle in radians (default: degrees)
Returns:
PdfMatrix: Rotation transformation matrix
"""
def mirror(self, v: bool, h: bool) -> PdfMatrix:
"""
Create mirroring matrix.
Parameters:
- v: bool, vertical mirroring (flip top-bottom)
- h: bool, horizontal mirroring (flip left-right)
Returns:
PdfMatrix: Mirroring transformation matrix
"""
def skew(self, x_angle: float, y_angle: float, rad=False) -> PdfMatrix:
"""
Create skewing matrix.
Parameters:
- x_angle: float, horizontal skew angle
- y_angle: float, vertical skew angle
- rad: bool, angles in radians (default: degrees)
Returns:
PdfMatrix: Skewing transformation matrix
"""Transformation examples:
import math
# Translation
translate_matrix = pdfium.PdfMatrix().translate(100, 200)
print(f"Translate (100, 200): {translate_matrix.get()}")
# Scaling
scale_matrix = pdfium.PdfMatrix().scale(1.5, 2.0)
print(f"Scale (1.5x, 2.0x): {scale_matrix.get()}")
# Rotation (45 degrees clockwise)
rotate_matrix = pdfium.PdfMatrix().rotate(45)
print(f"Rotate 45°: {rotate_matrix.get()}")
# Rotation (π/4 radians counter-clockwise)
rotate_ccw = pdfium.PdfMatrix().rotate(math.pi/4, ccw=True, rad=True)
print(f"Rotate π/4 CCW: {rotate_ccw.get()}")
# Mirroring
mirror_h = pdfium.PdfMatrix().mirror(v=False, h=True) # Horizontal flip
mirror_v = pdfium.PdfMatrix().mirror(v=True, h=False) # Vertical flip
print(f"Mirror horizontal: {mirror_h.get()}")
print(f"Mirror vertical: {mirror_v.get()}")
# Skewing
skew_matrix = pdfium.PdfMatrix().skew(15, 0) # 15° horizontal skew
print(f"Skew 15° horizontal: {skew_matrix.get()}")Apply transformations to coordinates and rectangular areas.
def on_point(self, x: float, y: float) -> tuple:
"""
Transform point coordinates.
Parameters:
- x: float, x-coordinate
- y: float, y-coordinate
Returns:
tuple: (transformed_x, transformed_y)
"""
def on_rect(self, left: float, bottom: float, right: float, top: float) -> tuple:
"""
Transform rectangle coordinates.
Parameters:
- left: float, left edge
- bottom: float, bottom edge
- right: float, right edge
- top: float, top edge
Returns:
tuple: (new_left, new_bottom, new_right, new_top)
"""Coordinate transformation:
# Create composite transformation
transform = pdfium.PdfMatrix()
transform = transform.translate(100, 50) # Move to (100, 50)
transform = transform.rotate(30) # Rotate 30 degrees
transform = transform.scale(1.5, 1.5) # Scale 1.5x
# Transform a point
original_point = (0, 0)
transformed_point = transform.on_point(*original_point)
print(f"Point {original_point} -> {transformed_point}")
# Transform another point
point2 = (100, 100)
transformed_point2 = transform.on_point(*point2)
print(f"Point {point2} -> {transformed_point2}")
# Transform a rectangle
original_rect = (0, 0, 200, 100) # (left, bottom, right, top)
transformed_rect = transform.on_rect(*original_rect)
print(f"Rectangle {original_rect} -> {transformed_rect}")Combine multiple transformations for complex geometric operations.
def create_centered_rotation(center_x, center_y, angle):
"""Create rotation around specific center point."""
# Translate to origin
to_origin = pdfium.PdfMatrix().translate(-center_x, -center_y)
# Rotate around origin
rotation = pdfium.PdfMatrix().rotate(angle)
# Translate back
from_origin = pdfium.PdfMatrix().translate(center_x, center_y)
# Combine transformations (order matters!)
result = to_origin.multiply(rotation).multiply(from_origin)
return result
def create_fit_transformation(source_rect, target_rect, maintain_aspect=True):
"""Create transformation to fit source rectangle into target rectangle."""
src_left, src_bottom, src_right, src_top = source_rect
tgt_left, tgt_bottom, tgt_right, tgt_top = target_rect
src_width = src_right - src_left
src_height = src_top - src_bottom
tgt_width = tgt_right - tgt_left
tgt_height = tgt_top - tgt_bottom
# Calculate scaling factors
scale_x = tgt_width / src_width
scale_y = tgt_height / src_height
if maintain_aspect:
# Use smaller scale to maintain aspect ratio
scale = min(scale_x, scale_y)
scale_x = scale_y = scale
# Create transformation
transform = pdfium.PdfMatrix()
# Translate source to origin
transform = transform.translate(-src_left, -src_bottom)
# Scale to fit
transform = transform.scale(scale_x, scale_y)
# Translate to target position
if maintain_aspect:
# Center in target rectangle
actual_width = src_width * scale
actual_height = src_height * scale
offset_x = (tgt_width - actual_width) / 2
offset_y = (tgt_height - actual_height) / 2
transform = transform.translate(tgt_left + offset_x, tgt_bottom + offset_y)
else:
transform = transform.translate(tgt_left, tgt_bottom)
return transform
# Usage examples
pdf = pdfium.PdfDocument("document.pdf")
page = pdf[0]
# Get an image object
for i in range(page.count_objects()):
obj = page.get_object(i)
if isinstance(obj, pdfium.PdfImage):
# Rotate image around its center
bounds = obj.get_pos()
if bounds:
left, bottom, right, top = bounds
center_x = (left + right) / 2
center_y = (bottom + top) / 2
rotation_transform = create_centered_rotation(center_x, center_y, 45)
obj.set_matrix(rotation_transform)
# Or fit image to specific area
target_area = (100, 100, 400, 300) # Specific rectangle
if bounds:
fit_transform = create_fit_transformation(bounds, target_area, maintain_aspect=True)
obj.set_matrix(fit_transform)
break
# Regenerate page content
page.gen_content()Helper functions for working with PDF coordinate systems.
def pdf_to_screen_transform(page_width, page_height, screen_width, screen_height, maintain_aspect=True):
"""Create transformation from PDF coordinates to screen coordinates."""
# PDF uses bottom-left origin, screen uses top-left
# Need to flip Y axis and scale appropriately
scale_x = screen_width / page_width
scale_y = screen_height / page_height
if maintain_aspect:
scale = min(scale_x, scale_y)
scale_x = scale_y = scale
transform = pdfium.PdfMatrix()
# Scale to screen size
transform = transform.scale(scale_x, -scale_y) # Negative Y to flip
# Translate to handle flipped Y coordinate
transform = transform.translate(0, -page_height * scale_y)
return transform
def inches_to_pdf_transform(dpi=72):
"""Create transformation from inches to PDF units."""
return pdfium.PdfMatrix().scale(dpi, dpi)
def mm_to_pdf_transform():
"""Create transformation from millimeters to PDF units."""
mm_per_inch = 25.4
pdf_units_per_inch = 72
scale = pdf_units_per_inch / mm_per_inch
return pdfium.PdfMatrix().scale(scale, scale)
# Usage
page = pdf[0]
page_width, page_height = page.get_size()
# Transform for 800x600 screen display
screen_transform = pdf_to_screen_transform(
page_width, page_height, 800, 600, maintain_aspect=True
)
# Convert PDF point to screen coordinates
pdf_point = (200, 400)
screen_point = screen_transform.on_point(*pdf_point)
print(f"PDF point {pdf_point} -> Screen point {screen_point}")Analyze transformation matrices to understand their properties.
def analyze_matrix(matrix):
"""Analyze transformation matrix properties."""
a, b, c, d, e, f = matrix.get()
# Translation components
translation = (e, f)
# Scaling factors (approximate for rotated matrices)
scale_x = math.sqrt(a*a + b*b)
scale_y = math.sqrt(c*c + d*d)
# Rotation angle (in degrees)
rotation_rad = math.atan2(b, a)
rotation_deg = math.degrees(rotation_rad)
# Determinant (affects area scaling)
determinant = a*d - b*c
# Shearing
shear = (c != 0 or b != 0) and (abs(rotation_deg) % 90 != 0)
analysis = {
'translation': translation,
'scale_x': scale_x,
'scale_y': scale_y,
'rotation_degrees': rotation_deg,
'determinant': determinant,
'area_scale_factor': abs(determinant),
'preserves_angles': abs(abs(determinant) - scale_x * scale_y) < 1e-6,
'has_shear': shear,
'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
}
return analysis
# Usage
transform = pdfium.PdfMatrix().translate(100, 50).rotate(30).scale(1.5, 2.0)
analysis = analyze_matrix(transform)
print("Matrix Analysis:")
for key, value in analysis.items():
print(f" {key}: {value}")def position_object_at_center(obj, page_width, page_height):
"""Position object at page center."""
bounds = obj.get_pos()
if not bounds:
return
left, bottom, right, top = bounds
obj_width = right - left
obj_height = top - bottom
# Calculate center position
center_x = (page_width - obj_width) / 2
center_y = (page_height - obj_height) / 2
# Create transformation to move to center
transform = pdfium.PdfMatrix().translate(
center_x - left,
center_y - bottom
)
obj.set_matrix(transform)
# Usage with page object
page = pdf[0]
page_width, page_height = page.get_size()
for i in range(page.count_objects()):
obj = page.get_object(i)
if isinstance(obj, pdfium.PdfImage):
position_object_at_center(obj, page_width, page_height)
breakInstall with Tessl CLI
npx tessl i tessl/pypi-pypdfium2