How to Work with Primitives in Python

How to Work with Primitives in Python

Aspose.PDF FOSS for Python’s engine.primitives module provides Matrix, a lightweight 2D affine transform value type: six float components (a, b, c, d, e, f) that you can read, translate, and multiply together to compose transforms in your own code. It is a pure-Python dataclass with no external dependencies, installed from PyPI with pip.

Step-by-Step Guide

Step 1: Install the Package

Install the Aspose.PDF FOSS package from PyPI:

pip install aspose-pdf-foss-for-python

Verify the installation:

import aspose_pdf
print("aspose_pdf OK")

Step 2: Import the Matrix Class

Matrix lives in the engine.primitives submodule rather than the top-level aspose_pdf package:

from aspose_pdf.engine.primitives import Matrix

Step 3: Create a Matrix and Inspect Its Components

Matrix() with no arguments gives you the identity matrix (a=1.0, b=0.0, c=0.0, d=1.0, e=0.0, f=0.0). Pass keyword arguments to override only the components you need:

from aspose_pdf.engine.primitives import Matrix

identity = Matrix()
print(identity.a, identity.b, identity.c, identity.d, identity.e, identity.f)
# 1.0 0.0 0.0 1.0 0.0 0.0

scale = Matrix(a=2.0, d=2.0)
print(scale.a, scale.d)
# 2.0 2.0

Step 4: Translate a Matrix

translate(x, y) adds x to the e component and y to the f component in place — it mutates the matrix and returns None, unlike multiply, which returns a new instance:

from aspose_pdf.engine.primitives import Matrix

matrix = Matrix()
matrix.translate(10.0, 5.0)
print(matrix.e, matrix.f)
# 10.0 5.0

matrix.translate(10.0, 5.0)
print(matrix.e, matrix.f)
# 20.0 10.0

Step 5: Multiply Two Matrices to Compose Transforms

multiply(other) combines two matrices and returns a brand-new Matrix, leaving both operands unchanged. The e/f translation components simply add together regardless of order, but the ad linear part is combined via true matrix multiplication — once one of the matrices has an off-diagonal (b or c) component, a.multiply(b) and b.multiply(a) produce different ad values:

from aspose_pdf.engine.primitives import Matrix

scale = Matrix(a=2.0, d=3.0)
shear = Matrix(b=1.0, c=1.0)

scale_then_shear = scale.multiply(shear)
print(scale_then_shear.a, scale_then_shear.b, scale_then_shear.c, scale_then_shear.d)
# 2.0 2.0 3.0 3.0

shear_then_scale = shear.multiply(scale)
print(shear_then_scale.a, shear_then_scale.b, shear_then_scale.c, shear_then_scale.d)
# 2.0 3.0 2.0 3.0

Step 6: Build a Custom Transform from Components

Because Matrix is a plain dataclass, you can set any of its six fields directly instead of going through translate/multiply — useful when you already know the exact affine transform (for example, a shear) you want to represent:

from aspose_pdf.engine.primitives import Matrix

shear = Matrix()
shear.b = 0.5   # shear the y-axis
shear.c = 0.0
print(shear.a, shear.b, shear.c, shear.d)
# 1.0 0.5 0.0 1.0

Common Issues and Fixes

translate() doesn’t seem to return anything usable

translate(x, y) mutates the matrix’s e/f components in place and returns None. If you need the translated matrix as a new object instead of mutating an existing one, build the translation as its own Matrix(e=x, f=y) and combine it with multiply().

multiply() gives a different result than expected

The linear ad part of the result depends on multiplication order once either matrix has a nonzero b or c component — a.multiply(b) is not generally the same as b.multiply(a). The e/f translation part, by contrast, always just adds regardless of order.

Confusing Matrix with IMatrix

Matrix (in engine.primitives) is a standalone value type with af components. IMatrix is a separate interface (used by IPath.transform) that also exposes a translate(x, y) method but is not the same class — they are not interchangeable, and constructing one does not give you the other.

Passing the wrong number of positional arguments

Matrix’s six components (a, b, c, d, e, f) all have defaults, so Matrix() alone is valid. When you do pass positional arguments, they fill a, b, c, d, e, f in that order — prefer keyword arguments (Matrix(e=10.0, f=5.0)) to avoid mismatching a component by position.

Frequently Asked Questions

What do the six Matrix components represent?

a, b, c, d, e, f are the standard six values of a 2D affine transform, equivalent to the augmented matrix [[a, b, 0], [c, d, 0], [e, f, 1]] — the same convention PDF content streams use for transformation matrices.

Does creating a Matrix automatically transform a page or piece of content?

No. In this edition, Matrix is a standalone value type for representing and composing 2D transforms in your own code — it is not automatically wired into page rendering or content-stream operations.

How do I get an identity matrix?

Call Matrix() with no arguments — the class defaults to a=1.0, b=0.0, c=0.0, d=1.0, e=0.0, f=0.0, which is the identity transform.

Can I combine a translation with an existing matrix?

Yes — build the translation as Matrix(e=x, f=y) and combine it with your existing matrix via multiply(), or call translate(x, y) directly on the existing matrix to adjust its e/f components in place.

Is there a matrix-like type used elsewhere in the API?

Yes — IMatrix is a separate interface with its own translate(x, y) method, referenced by IPath.transform. It is unrelated to the Matrix dataclass covered here.

See Also