pdf-reader 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -1
- data/README.rdoc +1 -0
- data/Rakefile +23 -8
- data/lib/pdf-reader.rb +3 -1
- data/lib/pdf/hash.rb +5 -1
- data/lib/pdf/reader.rb +8 -1
- data/lib/pdf/reader/afm/Courier-Bold.afm +342 -0
- data/lib/pdf/reader/afm/Courier-BoldOblique.afm +342 -0
- data/lib/pdf/reader/afm/Courier-Oblique.afm +342 -0
- data/lib/pdf/reader/afm/Courier.afm +342 -0
- data/lib/pdf/reader/afm/Helvetica-Bold.afm +2827 -0
- data/lib/pdf/reader/afm/Helvetica-BoldOblique.afm +2827 -0
- data/lib/pdf/reader/afm/Helvetica-Oblique.afm +3051 -0
- data/lib/pdf/reader/afm/Helvetica.afm +3051 -0
- data/lib/pdf/reader/afm/Symbol.afm +213 -0
- data/lib/pdf/reader/afm/Times-Bold.afm +2588 -0
- data/lib/pdf/reader/afm/Times-BoldItalic.afm +2384 -0
- data/lib/pdf/reader/afm/Times-Italic.afm +2667 -0
- data/lib/pdf/reader/afm/Times-Roman.afm +2419 -0
- data/lib/pdf/reader/afm/ZapfDingbats.afm +225 -0
- data/lib/pdf/reader/buffer.rb +14 -6
- data/lib/pdf/reader/cid_widths.rb +61 -0
- data/lib/pdf/reader/cmap.rb +8 -2
- data/lib/pdf/reader/encoding.rb +52 -27
- data/lib/pdf/reader/error.rb +16 -1
- data/lib/pdf/reader/filter.rb +2 -0
- data/lib/pdf/reader/filter/ascii85.rb +3 -1
- data/lib/pdf/reader/filter/ascii_hex.rb +3 -1
- data/lib/pdf/reader/filter/depredict.rb +2 -0
- data/lib/pdf/reader/filter/flate.rb +3 -1
- data/lib/pdf/reader/filter/lzw.rb +1 -0
- data/lib/pdf/reader/filter/null.rb +1 -0
- data/lib/pdf/reader/filter/run_length.rb +2 -1
- data/lib/pdf/reader/font.rb +74 -18
- data/lib/pdf/reader/font_descriptor.rb +80 -0
- data/lib/pdf/reader/glyph_hash.rb +6 -0
- data/lib/pdf/reader/lzw.rb +1 -0
- data/lib/pdf/reader/object_cache.rb +1 -1
- data/lib/pdf/reader/object_hash.rb +1 -1
- data/lib/pdf/reader/page_layout.rb +125 -0
- data/lib/pdf/reader/page_state.rb +172 -69
- data/lib/pdf/reader/page_text_receiver.rb +50 -21
- data/lib/pdf/reader/pages_strategy.rb +17 -4
- data/lib/pdf/reader/parser.rb +25 -52
- data/lib/pdf/reader/print_receiver.rb +5 -0
- data/lib/pdf/reader/reference.rb +2 -0
- data/lib/pdf/reader/register_receiver.rb +1 -1
- data/lib/pdf/reader/standard_security_handler.rb +2 -0
- data/lib/pdf/reader/stream.rb +2 -0
- data/lib/pdf/reader/synchronized_cache.rb +32 -0
- data/lib/pdf/reader/text_receiver.rb +5 -4
- data/lib/pdf/reader/text_run.rb +80 -0
- data/lib/pdf/reader/token.rb +2 -0
- data/lib/pdf/reader/transformation_matrix.rb +194 -0
- data/lib/pdf/reader/width_calculator.rb +11 -0
- data/lib/pdf/reader/width_calculator/built_in.rb +50 -0
- data/lib/pdf/reader/width_calculator/composite.rb +27 -0
- data/lib/pdf/reader/width_calculator/true_type.rb +56 -0
- data/lib/pdf/reader/width_calculator/type_one_or_three.rb +32 -0
- data/lib/pdf/reader/width_calculator/type_zero.rb +24 -0
- data/lib/pdf/reader/xref.rb +9 -2
- metadata +119 -13
@@ -1,3 +1,5 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
1
3
|
################################################################################
|
2
4
|
#
|
3
5
|
# Copyright (C) 2006 Peter J Jones (pjones@pmade.com)
|
@@ -56,9 +58,10 @@ class PDF::Reader
|
|
56
58
|
# == Text Callbacks
|
57
59
|
#
|
58
60
|
# All text passed into these callbacks will be encoded as UTF-8. Depending on where (and when) the
|
59
|
-
# PDF was generated, there's a good chance the text is NOT stored as UTF-8 internally so be
|
60
|
-
# when doing a comparison on strings returned from PDF::Reader (when doing unit tests for
|
61
|
-
# string may not be byte-by-byte identical with the string that was originally
|
61
|
+
# PDF was generated, there's a good chance the text is NOT stored as UTF-8 internally so be
|
62
|
+
# careful when doing a comparison on strings returned from PDF::Reader (when doing unit tests for
|
63
|
+
# example). The string may not be byte-by-byte identical with the string that was originally
|
64
|
+
# written to the PDF.
|
62
65
|
#
|
63
66
|
# - end_text_object
|
64
67
|
# - move_to_start_of_next_line
|
@@ -267,6 +270,16 @@ class PDF::Reader
|
|
267
270
|
end
|
268
271
|
private
|
269
272
|
################################################################################
|
273
|
+
def params_to_utf8(params, font)
|
274
|
+
if params.is_a?(String)
|
275
|
+
font.to_utf8(params)
|
276
|
+
elsif params.is_a?(Array)
|
277
|
+
params.map { |i| params_to_utf8(i, font)}
|
278
|
+
else
|
279
|
+
params
|
280
|
+
end
|
281
|
+
end
|
282
|
+
################################################################################
|
270
283
|
# Walk over all pages in the PDF file, calling the appropriate callbacks for each page and all
|
271
284
|
# its content
|
272
285
|
def walk_pages (page)
|
@@ -363,7 +376,7 @@ class PDF::Reader
|
|
363
376
|
if options[:raw_text]
|
364
377
|
callback("#{OPERATORS[token]}_raw".to_sym, params)
|
365
378
|
end
|
366
|
-
params = fonts[current_font]
|
379
|
+
params = params_to_utf8(params, fonts[current_font])
|
367
380
|
elsif token == "ID"
|
368
381
|
# inline image data, first convert the current params into a more familiar hash
|
369
382
|
map = {}
|
data/lib/pdf/reader/parser.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
1
3
|
################################################################################
|
2
4
|
#
|
3
5
|
# Copyright (C) 2006 Peter J Jones (pjones@pmade.com)
|
@@ -74,8 +76,6 @@ class PDF::Reader
|
|
74
76
|
STRATEGIES[token].call(self, token)
|
75
77
|
elsif token.is_a? PDF::Reader::Reference
|
76
78
|
token
|
77
|
-
elsif token.is_a? Token
|
78
|
-
token
|
79
79
|
elsif operators.has_key? token
|
80
80
|
Token.new(token)
|
81
81
|
elsif token.respond_to?(:to_token)
|
@@ -100,6 +100,7 @@ class PDF::Reader
|
|
100
100
|
|
101
101
|
obj = parse_token
|
102
102
|
post_obj = parse_token
|
103
|
+
|
103
104
|
if post_obj == "stream"
|
104
105
|
stream(obj)
|
105
106
|
else
|
@@ -171,58 +172,30 @@ class PDF::Reader
|
|
171
172
|
return "" if str == ")"
|
172
173
|
Error.assert_equal(parse_token, ")")
|
173
174
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
while idx < str.size
|
178
|
-
chr = str[idx,1]
|
179
|
-
jump = 1
|
180
|
-
|
181
|
-
if chr == "\\"
|
182
|
-
jump = 2
|
183
|
-
case str[idx+1, 1]
|
184
|
-
when "" then jump = 1
|
185
|
-
when "n" then chr = "\n"
|
186
|
-
when "r" then chr = "\r"
|
187
|
-
when "t" then chr = "\t"
|
188
|
-
when "b" then chr = "\b"
|
189
|
-
when "f" then chr = "\f"
|
190
|
-
when "(" then chr = "("
|
191
|
-
when ")" then chr = ")"
|
192
|
-
when "\\" then chr = "\\"
|
193
|
-
when "\n" then
|
194
|
-
chr = ""
|
195
|
-
jump = 2
|
196
|
-
else
|
197
|
-
if str[idx+1,3].match(/\d{3}/)
|
198
|
-
jump = 4
|
199
|
-
chr = str[idx+1,3].oct.chr
|
200
|
-
elsif str[idx+1,2].match(/\d{2}/)
|
201
|
-
jump = 3
|
202
|
-
chr = ("0"+str[idx+1,2]).oct.chr
|
203
|
-
elsif str[idx+1,1].match(/\d/)
|
204
|
-
jump = 2
|
205
|
-
chr = ("00"+str[idx+1,1]).oct.chr
|
206
|
-
else
|
207
|
-
jump = 1
|
208
|
-
chr = ""
|
209
|
-
end
|
210
|
-
|
211
|
-
end
|
212
|
-
elsif chr == "\r" && str[idx+1,1] == "\n"
|
213
|
-
chr = "\n"
|
214
|
-
jump = 2
|
215
|
-
elsif chr == "\n" && str[idx+1,1] == "\r"
|
216
|
-
chr = "\n"
|
217
|
-
jump = 2
|
218
|
-
elsif chr == "\r"
|
219
|
-
chr = "\n"
|
220
|
-
end
|
221
|
-
ret << chr
|
222
|
-
idx += jump
|
175
|
+
str.gsub!(/\\([nrtbf()\\\n]|\d{1,3})?|\r\n?|\n\r/m) do |match|
|
176
|
+
MAPPING[match] || ""
|
223
177
|
end
|
224
|
-
|
178
|
+
str
|
225
179
|
end
|
180
|
+
|
181
|
+
MAPPING = {
|
182
|
+
"\r" => "\n",
|
183
|
+
"\n\r" => "\n",
|
184
|
+
"\r\n" => "\n",
|
185
|
+
"\\n" => "\n",
|
186
|
+
"\\r" => "\r",
|
187
|
+
"\\t" => "\t",
|
188
|
+
"\\b" => "\b",
|
189
|
+
"\\f" => "\f",
|
190
|
+
"\\(" => "(",
|
191
|
+
"\\)" => ")",
|
192
|
+
"\\\\" => "\\",
|
193
|
+
"\\\n" => "",
|
194
|
+
}
|
195
|
+
0.upto(9) { |n| MAPPING["\\00"+n.to_s] = ("00"+n.to_s).oct.chr }
|
196
|
+
0.upto(99) { |n| MAPPING["\\0"+n.to_s] = ("0"+n.to_s).oct.chr }
|
197
|
+
0.upto(377) { |n| MAPPING["\\"+n.to_s] = n.to_s.oct.chr }
|
198
|
+
|
226
199
|
################################################################################
|
227
200
|
# Decodes the contents of a PDF Stream and returns it as a Ruby String.
|
228
201
|
def stream (dict)
|
data/lib/pdf/reader/reference.rb
CHANGED
data/lib/pdf/reader/stream.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# utilities.rb : General-purpose utility classes which don't fit anywhere else
|
4
|
+
#
|
5
|
+
# Copyright August 2012, Alex Dowad. All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
+
#
|
9
|
+
# This was originally written for the prawn gem.
|
10
|
+
|
11
|
+
require 'thread'
|
12
|
+
|
13
|
+
class PDF::Reader
|
14
|
+
|
15
|
+
# Throughout the pdf-reader codebase, repeated calculations which can benefit
|
16
|
+
# from caching are made In some cases, caching and reusing results can not
|
17
|
+
# only save CPU cycles but also greatly reduce memory requirements But at the
|
18
|
+
# same time, we don't want to throw away thread safety We have two
|
19
|
+
# interchangeable thread-safe cache implementations:
|
20
|
+
class SynchronizedCache
|
21
|
+
def initialize
|
22
|
+
@cache = {}
|
23
|
+
@mutex = Mutex.new
|
24
|
+
end
|
25
|
+
def [](key)
|
26
|
+
@mutex.synchronize { @cache[key] }
|
27
|
+
end
|
28
|
+
def []=(key,value)
|
29
|
+
@mutex.synchronize { @cache[key] = value }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
1
3
|
################################################################################
|
2
4
|
#
|
3
5
|
# Copyright (C) 2006 Peter J Jones (pjones@pmade.com)
|
@@ -9,10 +11,10 @@
|
|
9
11
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
12
|
# permit persons to whom the Software is furnished to do so, subject to
|
11
13
|
# the following conditions:
|
12
|
-
#
|
14
|
+
#
|
13
15
|
# The above copyright notice and this permission notice shall be
|
14
16
|
# included in all copies or substantial portions of the Software.
|
15
|
-
#
|
17
|
+
#
|
16
18
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
19
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
20
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
@@ -161,7 +163,7 @@ class PDF::Reader
|
|
161
163
|
|
162
164
|
x = (@tm[2,0]/TS_UNITS_PER_H_CHAR).to_i
|
163
165
|
y = (ury - (@tm[2,1]/TS_UNITS_PER_V_CHAR)).to_i
|
164
|
-
|
166
|
+
|
165
167
|
#puts "rendering '#{string}' to #{x}x#{y}"
|
166
168
|
|
167
169
|
place = (@output[y] ||= (" " * urx.to_i))
|
@@ -255,7 +257,6 @@ class PDF::Reader
|
|
255
257
|
@smallest_y_loc = key if key < @smallest_y_loc
|
256
258
|
@location = key
|
257
259
|
@line = @displacement[key]
|
258
|
-
#puts "calculate_line_and_location: @location=#@location @line=#@line smallest_y_loc=#@smallest_y_loc"
|
259
260
|
end
|
260
261
|
################################################################################
|
261
262
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
class PDF::Reader
|
4
|
+
# A value object that represents one or more consecutive characters on a page.
|
5
|
+
class TextRun
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
attr_reader :x, :y, :width, :font_size, :text
|
9
|
+
|
10
|
+
alias :to_s :text
|
11
|
+
|
12
|
+
def initialize(x, y, width, font_size, text)
|
13
|
+
@x = x
|
14
|
+
@y = y
|
15
|
+
@width = width
|
16
|
+
@font_size = font_size.floor
|
17
|
+
@text = text
|
18
|
+
end
|
19
|
+
|
20
|
+
# Allows collections of TextRun objects to be sorted. They will be sorted
|
21
|
+
# in order of their position on a cartesian plain - Top Left to Bottom Right
|
22
|
+
def <=>(other)
|
23
|
+
if x == other.x && y == other.y
|
24
|
+
0
|
25
|
+
elsif y < other.y
|
26
|
+
1
|
27
|
+
elsif y > other.y
|
28
|
+
-1
|
29
|
+
elsif x < other.x
|
30
|
+
-1
|
31
|
+
elsif x > other.x
|
32
|
+
1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def endx
|
37
|
+
@endx ||= x + width
|
38
|
+
end
|
39
|
+
|
40
|
+
def mean_character_width
|
41
|
+
@width / character_count
|
42
|
+
end
|
43
|
+
|
44
|
+
def mergable?(other)
|
45
|
+
y.to_i == other.y.to_i && font_size == other.font_size && mergable_range.include?(other.x)
|
46
|
+
end
|
47
|
+
|
48
|
+
def +(other)
|
49
|
+
raise ArgumentError, "#{other} cannot be merged with this run" unless mergable?(other)
|
50
|
+
|
51
|
+
if (other.x - endx) <( font_size * 0.2)
|
52
|
+
TextRun.new(x, y, other.endx - x, font_size, text + other.text)
|
53
|
+
else
|
54
|
+
TextRun.new(x, y, other.endx - x, font_size, "#{text} #{other.text}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
"#{text} w:#{width} f:#{font_size} @#{x},#{y}"
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def mergable_range
|
65
|
+
@mergable_range ||= Range.new(endx - 3, endx + font_size)
|
66
|
+
end
|
67
|
+
|
68
|
+
def character_count
|
69
|
+
if @text.size == 1
|
70
|
+
1.0
|
71
|
+
elsif @text.respond_to?(:bytesize)
|
72
|
+
# M17N aware VM
|
73
|
+
# so we can trust String#size to return a character count
|
74
|
+
@text.size.to_f
|
75
|
+
else
|
76
|
+
text.unpack("U*").size.to_f
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/pdf/reader/token.rb
CHANGED
@@ -0,0 +1,194 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
class PDF::Reader
|
4
|
+
# co-ordinate systems in PDF files are specified using a 3x3 matrix that looks
|
5
|
+
# something like this:
|
6
|
+
#
|
7
|
+
# [ a b 0 ]
|
8
|
+
# [ c d 0 ]
|
9
|
+
# [ e f 1 ]
|
10
|
+
#
|
11
|
+
# Because the final column never changes, we can represent each matrix using
|
12
|
+
# only 6 numbers. This is important to save CPU time, memory and GC pressure
|
13
|
+
# caused by allocating too many unnecessary objects.
|
14
|
+
class TransformationMatrix
|
15
|
+
attr_reader :a, :b, :c, :d, :e, :f
|
16
|
+
|
17
|
+
def initialize(a, b, c, d, e, f)
|
18
|
+
@a, @b, @c, @d, @e, @f = a, b, c, d, e, f
|
19
|
+
end
|
20
|
+
|
21
|
+
def inspect
|
22
|
+
"#{a}, #{b}, 0,\n#{c}, #{d}, #{0},\n#{e}, #{f}, 1"
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_a
|
26
|
+
[@a,@b,0,
|
27
|
+
@c,@d,0,
|
28
|
+
@e,@f,1]
|
29
|
+
end
|
30
|
+
|
31
|
+
# multiply this matrix with another.
|
32
|
+
#
|
33
|
+
# the second matrix is represented by the 6 scalar values that are changeable
|
34
|
+
# in a PDF transformation matrix.
|
35
|
+
#
|
36
|
+
# WARNING: This mutates the current matrix to avoid allocating memory when
|
37
|
+
# we don't need too. Matrices are multiplied ALL THE FREAKING TIME
|
38
|
+
# so this is a worthwhile optimisation
|
39
|
+
#
|
40
|
+
# NOTE: When multiplying matrices, ordering matters. Double check
|
41
|
+
# the PDF spec to ensure you're multiplying things correctly.
|
42
|
+
#
|
43
|
+
# NOTE: see Section 8.3.3, PDF 32000-1:2008, pp 119
|
44
|
+
#
|
45
|
+
# NOTE: The if statements in this method are ordered to prefer optimisations
|
46
|
+
# that allocate fewer objects
|
47
|
+
#
|
48
|
+
# TODO: it might be worth adding an optimised path for vertical
|
49
|
+
# displacement to speed up processing documents that use vertical
|
50
|
+
# writing systems
|
51
|
+
#
|
52
|
+
def multiply!(a,b=nil,c=nil, d=nil,e=nil,f=nil)
|
53
|
+
if a == 1 && b == 0 && c == 0 && d == 1 && e == 0 && f == 0
|
54
|
+
# the identity matrix, no effect
|
55
|
+
self
|
56
|
+
elsif @a == 1 && @b == 0 && @c == 0 && @d == 1 && @e == 0 && @f == 0
|
57
|
+
# I'm the identity matrix, so just copy values across
|
58
|
+
@a = a
|
59
|
+
@b = b
|
60
|
+
@c = c
|
61
|
+
@d = d
|
62
|
+
@e = e
|
63
|
+
@f = f
|
64
|
+
elsif a == 1 && b == 0 && c == 0 && d == 1 && f == 0
|
65
|
+
# the other matrix is a horizontal displacement
|
66
|
+
horizontal_displacement_multiply!(e)
|
67
|
+
elsif @a == 1 && @b == 0 && @c == 0 && @d == 1 && @f == 0
|
68
|
+
# I'm a horizontal displacement
|
69
|
+
horizontal_displacement_multiply_reversed!(a,b,c,d,e,f)
|
70
|
+
elsif @a != 1 && @b == 0 && @c == 0 && @d != 1 && @e == 0 && @f == 0
|
71
|
+
# I'm a xy scale
|
72
|
+
xy_scaling_multiply_reversed!(a,b,c,d,e,f)
|
73
|
+
elsif a != 1 && b == 0 && c == 0 && d != 1 && e == 0 && f == 0
|
74
|
+
# the other matrix is an xy scale
|
75
|
+
xy_scaling_multiply!(a,b,c,d,e,f)
|
76
|
+
else
|
77
|
+
faster_multiply!(a,b,c, d,e,f)
|
78
|
+
end
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
# Optimised method for when the second matrix in the calculation is
|
83
|
+
# a simple horizontal displacement.
|
84
|
+
#
|
85
|
+
# Like this:
|
86
|
+
#
|
87
|
+
# [ 1 2 0 ] [ 1 0 0 ]
|
88
|
+
# [ 3 4 0 ] x [ 0 1 0 ]
|
89
|
+
# [ 5 6 1 ] [ e2 0 1 ]
|
90
|
+
#
|
91
|
+
def horizontal_displacement_multiply!(e2)
|
92
|
+
@e = @e + e2
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Optimised method for when the first matrix in the calculation is
|
98
|
+
# a simple horizontal displacement.
|
99
|
+
#
|
100
|
+
# Like this:
|
101
|
+
#
|
102
|
+
# [ 1 0 0 ] [ 1 2 0 ]
|
103
|
+
# [ 0 1 0 ] x [ 3 4 0 ]
|
104
|
+
# [ 5 0 1 ] [ 5 6 1 ]
|
105
|
+
#
|
106
|
+
def horizontal_displacement_multiply_reversed!(a2,b2,c2,d2,e2,f2)
|
107
|
+
newa = a2
|
108
|
+
newb = b2
|
109
|
+
newc = c2
|
110
|
+
newd = d2
|
111
|
+
newe = (@e * a2) + e2
|
112
|
+
newf = (@e * b2) + f2
|
113
|
+
@a, @b, @c, @d, @e, @f = newa, newb, newc, newd, newe, newf
|
114
|
+
end
|
115
|
+
|
116
|
+
# Optimised method for when the second matrix in the calculation is
|
117
|
+
# an X and Y scale
|
118
|
+
#
|
119
|
+
# Like this:
|
120
|
+
#
|
121
|
+
# [ 1 2 0 ] [ 5 0 0 ]
|
122
|
+
# [ 3 4 0 ] x [ 0 5 0 ]
|
123
|
+
# [ 5 6 1 ] [ 0 0 1 ]
|
124
|
+
#
|
125
|
+
def xy_scaling_multiply!(a2,b2,c2,d2,e2,f2)
|
126
|
+
newa = @a * a2
|
127
|
+
newb = @b * d2
|
128
|
+
newc = @c * a2
|
129
|
+
newd = @d * d2
|
130
|
+
newe = @e * a2
|
131
|
+
newf = @f * d2
|
132
|
+
@a, @b, @c, @d, @e, @f = newa, newb, newc, newd, newe, newf
|
133
|
+
end
|
134
|
+
|
135
|
+
# Optimised method for when the first matrix in the calculation is
|
136
|
+
# an X and Y scale
|
137
|
+
#
|
138
|
+
# Like this:
|
139
|
+
#
|
140
|
+
# [ 5 0 0 ] [ 1 2 0 ]
|
141
|
+
# [ 0 5 0 ] x [ 3 4 0 ]
|
142
|
+
# [ 0 0 1 ] [ 5 6 1 ]
|
143
|
+
#
|
144
|
+
def xy_scaling_multiply_reversed!(a2,b2,c2,d2,e2,f2)
|
145
|
+
newa = @a * a2
|
146
|
+
newb = @a * b2
|
147
|
+
newc = @d * c2
|
148
|
+
newd = @d * d2
|
149
|
+
newe = e2
|
150
|
+
newf = f2
|
151
|
+
@a, @b, @c, @d, @e, @f = newa, newb, newc, newd, newe, newf
|
152
|
+
end
|
153
|
+
|
154
|
+
# A general solution to multiplying two 3x3 matrixes. This is correct in all cases,
|
155
|
+
# but slower due to excessive object allocations. It's not actually used in any
|
156
|
+
# active code paths, but is here for reference. Use faster_multiply instead.
|
157
|
+
#
|
158
|
+
# Like this:
|
159
|
+
#
|
160
|
+
# [ a b 0 ] [ a b 0 ]
|
161
|
+
# [ c d 0 ] x [ c d 0 ]
|
162
|
+
# [ e f 1 ] [ e f 1 ]
|
163
|
+
#
|
164
|
+
def regular_multiply!(a2,b2,c2,d2,e2,f2)
|
165
|
+
newa = (@a * a2) + (@b * c2) + (0 * e2)
|
166
|
+
newb = (@a * b2) + (@b * d2) + (0 * f2)
|
167
|
+
newc = (@c * a2) + (@d * c2) + (0 * e2)
|
168
|
+
newd = (@c * b2) + (@d * d2) + (0 * f2)
|
169
|
+
newe = (@e * a2) + (@f * c2) + (1 * e2)
|
170
|
+
newf = (@e * b2) + (@f * d2) + (1 * f2)
|
171
|
+
@a, @b, @c, @d, @e, @f = newa, newb, newc, newd, newe, newf
|
172
|
+
end
|
173
|
+
|
174
|
+
# A general solution for multiplying two matrices when we know all values
|
175
|
+
# in the final column are fixed. This is the fallback method for when none
|
176
|
+
# of the optimised methods are applicable.
|
177
|
+
#
|
178
|
+
# Like this:
|
179
|
+
#
|
180
|
+
# [ a b 0 ] [ a b 0 ]
|
181
|
+
# [ c d 0 ] x [ c d 0 ]
|
182
|
+
# [ e f 1 ] [ e f 1 ]
|
183
|
+
#
|
184
|
+
def faster_multiply!(a2,b2,c2, d2,e2,f2)
|
185
|
+
newa = (@a * a2) + (@b * c2)
|
186
|
+
newb = (@a * b2) + (@b * d2)
|
187
|
+
newc = (@c * a2) + (@d * c2)
|
188
|
+
newd = (@c * b2) + (@d * d2)
|
189
|
+
newe = (@e * a2) + (@f * c2) + e2
|
190
|
+
newf = (@e * b2) + (@f * d2) + f2
|
191
|
+
@a, @b, @c, @d, @e, @f = newa, newb, newc, newd, newe, newf
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|