Class: PDF::Reader::TransformationMatrix
- Inherits:
-
Object
- Object
- PDF::Reader::TransformationMatrix
- Defined in:
- lib/pdf/reader/transformation_matrix.rb
Overview
co-ordinate systems in PDF files are specified using a 3x3 matrix that looks something like this:
[ a b 0 ]
[ c d 0 ]
[ e f 1 ]
Because the final column never changes, we can represent each matrix using only 6 numbers. This is important to save CPU time, memory and GC pressure caused by allocating too many unnecessary objects.
Instance Attribute Summary collapse
- #a ⇒ Object readonly
- #b ⇒ Object readonly
- #c ⇒ Object readonly
- #d ⇒ Object readonly
- #e ⇒ Object readonly
- #f ⇒ Object readonly
Instance Method Summary collapse
-
#horizontal_displacement_multiply!(e2) ⇒ Object
Optimised method for when the second matrix in the calculation is a simple horizontal displacement.
-
#initialize(a, b, c, d, e, f) ⇒ TransformationMatrix
constructor
A new instance of TransformationMatrix.
- #inspect ⇒ Object
-
#multiply!(a, b, c, d, e, f) ⇒ Object
multiply this matrix with another.
-
#prepend_translation!(tx, ty) ⇒ Object
Apply a left-multiplication by a translation matrix [1, 0, 0, 1, tx, ty] without allocating a new TransformationMatrix.
- #to_a ⇒ Object
Constructor Details
#initialize(a, b, c, d, e, f) ⇒ TransformationMatrix
Returns a new instance of TransformationMatrix.
36 37 38 39 40 41 42 43 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 36 def initialize(a, b, c, d, e, f) @a = a @b = b @c = c @d = d @e = e @f = f end |
Instance Attribute Details
#a ⇒ Object (readonly)
18 19 20 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 18 def a @a end |
#b ⇒ Object (readonly)
21 22 23 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 21 def b @b end |
#c ⇒ Object (readonly)
24 25 26 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 24 def c @c end |
#d ⇒ Object (readonly)
27 28 29 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 27 def d @d end |
#e ⇒ Object (readonly)
30 31 32 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 30 def e @e end |
#f ⇒ Object (readonly)
33 34 35 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 33 def f @f end |
Instance Method Details
#horizontal_displacement_multiply!(e2) ⇒ Object
Optimised method for when the second matrix in the calculation is a simple horizontal displacement.
Like this:
[ 1 2 0 ] [ 1 0 0 ]
[ 3 4 0 ] x [ 0 1 0 ]
[ 5 6 1 ] [ e2 0 1 ]
130 131 132 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 130 def horizontal_displacement_multiply!(e2) @e = @e + e2 end |
#inspect ⇒ Object
46 47 48 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 46 def inspect "#{a}, #{b}, 0,\n#{c}, #{d}, #{0},\n#{e}, #{f}, 1" end |
#multiply!(a, b, c, d, e, f) ⇒ Object
multiply this matrix with another.
the second matrix is represented by the 6 scalar values that are changeable in a PDF transformation matrix.
WARNING: This mutates the current matrix to avoid allocating memory when we don't need too. Matrices are multiplied ALL THE FREAKING TIME so this is a worthwhile optimisation
NOTE: When multiplying matrices, ordering matters. Double check the PDF spec to ensure you're multiplying things correctly.
NOTE: see Section 8.3.3, PDF 32000-1:2008, pp 119
NOTE: The if statements in this method are ordered to prefer optimisations that allocate fewer objects
TODO: it might be worth adding an optimised path for vertical displacement to speed up processing documents that use vertical writing systems
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 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 90 def multiply!(a,b,c, d,e,f) if a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0 # the identity matrix, no effect self elsif @a == 1 && @b == 0 && @c == 0 && @d == 1 && @e == 0 && @f == 0 # I'm the identity matrix, so just copy values across @a = a @b = b @c = c @d = d @e = e @f = f elsif a == 1 && b == 0 && c == 0 && d == 1 && f == 0 # the other matrix is a horizontal displacement horizontal_displacement_multiply!(e) elsif @a == 1 && @b == 0 && @c == 0 && @d == 1 && @f == 0 # I'm a horizontal displacement horizontal_displacement_multiply_reversed!(a,b,c,d,e,f) elsif @a != 1 && @b == 0 && @c == 0 && @d != 1 && @e == 0 && @f == 0 # I'm a xy scale xy_scaling_multiply_reversed!(a,b,c,d,e,f) elsif a != 1 && b == 0 && c == 0 && d != 1 && e == 0 && f == 0 # the other matrix is an xy scale xy_scaling_multiply!(a,b,c,d,e,f) else faster_multiply!(a,b,c, d,e,f) end self end |
#prepend_translation!(tx, ty) ⇒ Object
Apply a left-multiplication by a translation matrix [1, 0, 0, 1, tx, ty] without allocating a new TransformationMatrix.
61 62 63 64 65 66 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 61 def prepend_translation!(tx, ty) new_e = (tx * @a) + (ty * @c) + @e new_f = (tx * @b) + (ty * @d) + @f @e = new_e @f = new_f end |
#to_a ⇒ Object
51 52 53 54 55 |
# File 'lib/pdf/reader/transformation_matrix.rb', line 51 def to_a [@a,@b,0, @c,@d,0, @e,@f,1] end |