File: matrix.rst

package info (click to toggle)
pymupdf 1.25.4%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 98,632 kB
  • sloc: python: 43,379; ansic: 75; makefile: 6
file content (253 lines) | stat: -rw-r--r-- 9,969 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
.. include:: header.rst

.. _Matrix:

==========
Matrix
==========

Matrix is a row-major 3x3 matrix used by image transformations in MuPDF (which complies with the respective concepts laid down in the :ref:`AdobeManual`). With matrices you can manipulate the rendered image of a page in a variety of ways: (parts of) the page can be rotated, zoomed, flipped, sheared and shifted by setting some or all of just six float values.


Since all points or pixels live in a two-dimensional space, one column vector of that matrix is a constant unit vector, and only the remaining six elements are used for manipulations. These six elements are usually represented by *[a, b, c, d, e, f]*. Here is how they are positioned in the matrix:

.. image:: images/img-matrix.*


Please note:

    * the below methods are just convenience functions -- everything they do, can also be achieved by directly manipulating the six numerical values
    * all manipulations can be combined -- you can construct a matrix that rotates **and** shears **and** scales **and** shifts, etc. in one go. If you however choose to do this, do have a look at the **remarks** further down or at the :ref:`AdobeManual`.

================================ ==============================================
**Method / Attribute**             **Description**
================================ ==============================================
:meth:`Matrix.prerotate`         perform a rotation
:meth:`Matrix.prescale`          perform a scaling
:meth:`Matrix.preshear`          perform a shearing (skewing)
:meth:`Matrix.pretranslate`      perform a translation (shifting)
:meth:`Matrix.concat`            perform a matrix multiplication
:meth:`Matrix.invert`            calculate the inverted matrix
:meth:`Matrix.norm`              the Euclidean norm
:attr:`Matrix.a`                 zoom factor X direction
:attr:`Matrix.b`                 shearing effect Y direction
:attr:`Matrix.c`                 shearing effect X direction
:attr:`Matrix.d`                 zoom factor Y direction
:attr:`Matrix.e`                 horizontal shift
:attr:`Matrix.f`                 vertical shift
:attr:`Matrix.is_rectilinear`    true if rect corners will remain rect corners
================================ ==============================================

**Class API**

.. class:: Matrix

   .. method:: __init__(self)

   .. method:: __init__(self, zoom-x, zoom-y)

   .. method:: __init__(self, shear-x, shear-y, 1)

   .. method:: __init__(self, a, b, c, d, e, f)

   .. method:: __init__(self, matrix)

   .. method:: __init__(self, degree)

   .. method:: __init__(self, sequence)

      Overloaded constructors.

      Without parameters, the zero matrix *Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)* will be created.

      *zoom-** and *shear-** specify zoom or shear values (float) and create a zoom or shear matrix, respectively.

      For "matrix" a **new copy** of another matrix will be made.

      Float value "degree" specifies the creation of a rotation matrix which rotates anti-clockwise.

      A "sequence" must be any Python sequence object with exactly 6 float entries (see :ref:`SequenceTypes`).

      *pymupdf.Matrix(1, 1)* and *pymupdf.Matrix(pymupdf.Identity)* create modifiable versions of the :ref:`Identity` matrix, which looks like *[1, 0, 0, 1, 0, 0]*.

   .. method:: norm()

      * New in version 1.16.0
      
      Return the Euclidean norm of the matrix as a vector.

   .. method:: prerotate(deg)

      Modify the matrix to perform a counter-clockwise rotation for positive *deg* degrees, else clockwise. The matrix elements of an identity matrix will change in the following way:

      *[1, 0, 0, 1, 0, 0] -> [cos(deg), sin(deg), -sin(deg), cos(deg), 0, 0]*.

      :arg float deg: The rotation angle in degrees (use conventional notation based on Pi = 180 degrees).

   .. method:: prescale(sx, sy)

      Modify the matrix to scale by the zoom factors sx and sy. Has effects on attributes *a* thru *d* only: *[a, b, c, d, e, f] -> [a*sx, b*sx, c*sy, d*sy, e, f]*.

      :arg float sx: Zoom factor in X direction. For the effect see description of attribute *a*.

      :arg float sy: Zoom factor in Y direction. For the effect see description of attribute *d*.

   .. method:: preshear(sx, sy)

      Modify the matrix to perform a shearing, i.e. transformation of rectangles into parallelograms (rhomboids). Has effects on attributes *a* thru *d* only: *[a, b, c, d, e, f] -> [c*sy, d*sy, a*sx, b*sx, e, f]*.

      :arg float sx: Shearing effect in X direction. See attribute *c*.

      :arg float sy: Shearing effect in Y direction. See attribute *b*.

   .. method:: pretranslate(tx, ty)

      Modify the matrix to perform a shifting / translation operation along the x and / or y axis. Has effects on attributes *e* and *f* only: *[a, b, c, d, e, f] -> [a, b, c, d, tx*a + ty*c, tx*b + ty*d]*.

      :arg float tx: Translation effect in X direction. See attribute *e*.

      :arg float ty: Translation effect in Y direction. See attribute *f*.

   .. method:: concat(m1, m2)

      Calculate the matrix product *m1 * m2* and store the result in the current matrix. Any of *m1* or *m2* may be the current matrix. Be aware that matrix multiplication is not commutative. So the sequence of *m1*, *m2* is important.

      :arg m1: First (left) matrix.
      :type m1: :ref:`Matrix`

      :arg m2: Second (right) matrix.
      :type m2: :ref:`Matrix`

   .. method:: invert(m = None)

      Calculate the matrix inverse of *m* and store the result in the current matrix. Returns *1* if *m* is not invertible ("degenerate"). In this case the current matrix **will not change**. Returns *0* if *m* is invertible, and the current matrix is replaced with the inverted *m*.

      :arg m: Matrix to be inverted. If not provided, the current matrix will be used.
      :type m: :ref:`Matrix`

      :rtype: int

   .. attribute:: a

      Scaling in X-direction **(width)**. For example, a value of 0.5 performs a shrink of the **width** by a factor of 2. If a < 0, a left-right flip will (additionally) occur.

      :type: float

   .. attribute:: b

      Causes a shearing effect: each `Point(x, y)` will become `Point(x, y - b*x)`. Therefore, horizontal lines will be "tilt".

      :type: float

   .. attribute:: c

      Causes a shearing effect: each `Point(x, y)` will become `Point(x - c*y, y)`. Therefore, vertical lines will be "tilt".

      :type: float

   .. attribute:: d

      Scaling in Y-direction **(height)**. For example, a value of 1.5 performs a stretch of the **height** by 50%. If d < 0, an up-down flip will (additionally) occur.

      :type: float

   .. attribute:: e

      Causes a horizontal shift effect: Each *Point(x, y)* will become *Point(x + e, y)*. Positive (negative) values of *e* will shift right (left).

      :type: float

   .. attribute:: f

      Causes a vertical shift effect: Each *Point(x, y)* will become *Point(x, y - f)*. Positive (negative) values of *f* will shift down (up).

      :type: float

   .. attribute:: is_rectilinear

      Rectilinear means that no shearing is present and that any rotations are integer multiples of 90 degrees. Usually this is used to confirm that (axis-aligned) rectangles before the transformation are still axis-aligned rectangles afterwards.

      :type: bool

.. note::

   * This class adheres to the Python sequence protocol, so components can be accessed via their index, too. Also refer to :ref:`SequenceTypes`.
   * Matrices can be used with arithmetic operators almost like ordinary numbers: they can be added, subtracted, multiplied or divided -- see chapter :ref:`Algebra`.
   * Matrix multiplication is **not commutative** -- changing the sequence of the multiplicands will change the result in general. So it can quickly become unclear which result a transformation will yield.


Examples
-------------
Here are examples that illustrate some of the achievable effects. All pictures show some text, inserted under control of some matrix and relative to a fixed reference point (the red dot).

1. The :ref:`Identity` matrix performs no operation.

.. image:: images/img-matrix-0.*
   :scale: 66

2. The scaling matrix `Matrix(2, 0.5)` stretches by a factor of 2 in horizontal, and shrinks by factor 0.5 in vertical direction.

.. image:: images/img-matrix-1.*
   :scale: 66

3. Attributes :attr:`Matrix.e` and :attr:`Matrix.f` shift horizontally and, respectively vertically. In the following 10 to the right and 20 down.

.. image:: images/img-matrix-2.*
   :scale: 66

4. A negative :attr:`Matrix.a` causes a left-right flip.

.. image:: images/img-matrix-3.*
   :scale: 66

5. A negative :attr:`Matrix.d` causes an up-down flip.

.. image:: images/img-matrix-4.*
   :scale: 66

6. Attribute :attr:`Matrix.b` tilts upwards / downwards along the x-axis.

.. image:: images/img-matrix-5.*
   :scale: 66

7. Attribute :attr:`Matrix.c` tilts left / right along the y-axis.

.. image:: images/img-matrix-6.*
   :scale: 66

8. Matrix `Matrix(beta)` performs counterclockwise rotations for positive angles `beta`.

.. image:: images/img-matrix-7.*
   :scale: 66

9. Show some effects on a rectangle::

      import pymupdf
      
      # just definitions and a temp PDF
      RED = (1, 0, 0)
      BLUE = (0, 0, 1)
      GREEN = (0, 1, 0)
      doc = pymupdf.open()
      page = doc.new_page()
      
      # rectangle
      r1 = pymupdf.Rect(100, 100, 200, 200)
      
      # scales down by 50% in x- and up by 50% in y-direction
      mat1 = pymupdf.Matrix(0.5, 1.5)
      
      # shifts by 50 in both directions
      mat2 = pymupdf.Matrix(1, 0, 0, 1, 50, 50)
      
      # draw corresponding rectangles
      page.draw_rect(r1, color=RED)  # original
      page.draw_rect(r1 * mat1, color=GREEN)  # scaled
      page.draw_rect(r1 * mat2, color=BLUE)  # shifted
      doc.ez_save("matrix-effects.pdf")


.. image:: images/img-matrix-9.*
   :scale: 66

.. include:: footer.rst