Class: PDF::Reader::TransformationMatrix

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

Constructor Details

#initialize(a, b, c, d, e, f) ⇒ TransformationMatrix

Returns a new instance of TransformationMatrix.



19
20
21
# File 'lib/pdf/reader/transformation_matrix.rb', line 19

def initialize(a, b, c, d, e, f)
  @a, @b, @c, @d, @e, @f = a, b, c, d, e, f
end

Instance Attribute Details

#aObject (readonly)

Returns the value of attribute a.



17
18
19
# File 'lib/pdf/reader/transformation_matrix.rb', line 17

def a
  @a
end

#bObject (readonly)

Returns the value of attribute b.



17
18
19
# File 'lib/pdf/reader/transformation_matrix.rb', line 17

def b
  @b
end

#cObject (readonly)

Returns the value of attribute c.



17
18
19
# File 'lib/pdf/reader/transformation_matrix.rb', line 17

def c
  @c
end

#dObject (readonly)

Returns the value of attribute d.



17
18
19
# File 'lib/pdf/reader/transformation_matrix.rb', line 17

def d
  @d
end

#eObject (readonly)

Returns the value of attribute e.



17
18
19
# File 'lib/pdf/reader/transformation_matrix.rb', line 17

def e
  @e
end

#fObject (readonly)

Returns the value of attribute f.



17
18
19
# File 'lib/pdf/reader/transformation_matrix.rb', line 17

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 ]


93
94
95
# File 'lib/pdf/reader/transformation_matrix.rb', line 93

def horizontal_displacement_multiply!(e2)
  @e = @e + e2
end

#inspectObject



23
24
25
# File 'lib/pdf/reader/transformation_matrix.rb', line 23

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


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
# File 'lib/pdf/reader/transformation_matrix.rb', line 54

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

#to_aObject



27
28
29
30
31
# File 'lib/pdf/reader/transformation_matrix.rb', line 27

def to_a
  [@a,@b,0,
   @c,@d,0,
   @e,@f,1]
end