origamindee 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +89 -0
  3. data/COPYING.LESSER +165 -0
  4. data/README.md +131 -0
  5. data/bin/config/pdfcop.conf.yml +236 -0
  6. data/bin/pdf2pdfa +87 -0
  7. data/bin/pdf2ruby +333 -0
  8. data/bin/pdfcop +476 -0
  9. data/bin/pdfdecompress +97 -0
  10. data/bin/pdfdecrypt +91 -0
  11. data/bin/pdfencrypt +113 -0
  12. data/bin/pdfexplode +223 -0
  13. data/bin/pdfextract +277 -0
  14. data/bin/pdfmetadata +143 -0
  15. data/bin/pdfsh +12 -0
  16. data/bin/shell/console.rb +128 -0
  17. data/bin/shell/hexdump.rb +59 -0
  18. data/bin/shell/irbrc +69 -0
  19. data/examples/README.md +34 -0
  20. data/examples/attachments/attachment.rb +38 -0
  21. data/examples/attachments/nested_document.rb +51 -0
  22. data/examples/encryption/encryption.rb +28 -0
  23. data/examples/events/events.rb +72 -0
  24. data/examples/flash/flash.rb +37 -0
  25. data/examples/flash/helloworld.swf +0 -0
  26. data/examples/forms/javascript.rb +54 -0
  27. data/examples/forms/xfa.rb +115 -0
  28. data/examples/javascript/hello_world.rb +22 -0
  29. data/examples/javascript/js_emulation.rb +54 -0
  30. data/examples/loop/goto.rb +32 -0
  31. data/examples/loop/named.rb +33 -0
  32. data/examples/signature/signature.rb +65 -0
  33. data/examples/uri/javascript.rb +56 -0
  34. data/examples/uri/open-uri.rb +21 -0
  35. data/examples/uri/submitform.rb +47 -0
  36. data/lib/origami/3d.rb +364 -0
  37. data/lib/origami/acroform.rb +321 -0
  38. data/lib/origami/actions.rb +318 -0
  39. data/lib/origami/annotations.rb +711 -0
  40. data/lib/origami/array.rb +242 -0
  41. data/lib/origami/boolean.rb +90 -0
  42. data/lib/origami/catalog.rb +418 -0
  43. data/lib/origami/collections.rb +144 -0
  44. data/lib/origami/compound.rb +161 -0
  45. data/lib/origami/destinations.rb +252 -0
  46. data/lib/origami/dictionary.rb +192 -0
  47. data/lib/origami/encryption.rb +1084 -0
  48. data/lib/origami/extensions/fdf.rb +347 -0
  49. data/lib/origami/extensions/ppklite.rb +422 -0
  50. data/lib/origami/filespec.rb +197 -0
  51. data/lib/origami/filters/ascii.rb +211 -0
  52. data/lib/origami/filters/ccitt/tables.rb +267 -0
  53. data/lib/origami/filters/ccitt.rb +357 -0
  54. data/lib/origami/filters/crypt.rb +38 -0
  55. data/lib/origami/filters/dct.rb +54 -0
  56. data/lib/origami/filters/flate.rb +69 -0
  57. data/lib/origami/filters/jbig2.rb +57 -0
  58. data/lib/origami/filters/jpx.rb +47 -0
  59. data/lib/origami/filters/lzw.rb +170 -0
  60. data/lib/origami/filters/predictors.rb +292 -0
  61. data/lib/origami/filters/runlength.rb +129 -0
  62. data/lib/origami/filters.rb +364 -0
  63. data/lib/origami/font.rb +196 -0
  64. data/lib/origami/functions.rb +79 -0
  65. data/lib/origami/graphics/colors.rb +230 -0
  66. data/lib/origami/graphics/instruction.rb +98 -0
  67. data/lib/origami/graphics/path.rb +182 -0
  68. data/lib/origami/graphics/patterns.rb +174 -0
  69. data/lib/origami/graphics/render.rb +62 -0
  70. data/lib/origami/graphics/state.rb +149 -0
  71. data/lib/origami/graphics/text.rb +225 -0
  72. data/lib/origami/graphics/xobject.rb +918 -0
  73. data/lib/origami/graphics.rb +38 -0
  74. data/lib/origami/header.rb +75 -0
  75. data/lib/origami/javascript.rb +713 -0
  76. data/lib/origami/linearization.rb +330 -0
  77. data/lib/origami/metadata.rb +172 -0
  78. data/lib/origami/name.rb +135 -0
  79. data/lib/origami/null.rb +65 -0
  80. data/lib/origami/numeric.rb +181 -0
  81. data/lib/origami/obfuscation.rb +245 -0
  82. data/lib/origami/object.rb +760 -0
  83. data/lib/origami/optionalcontent.rb +183 -0
  84. data/lib/origami/outline.rb +54 -0
  85. data/lib/origami/outputintents.rb +85 -0
  86. data/lib/origami/page.rb +722 -0
  87. data/lib/origami/parser.rb +269 -0
  88. data/lib/origami/parsers/fdf.rb +56 -0
  89. data/lib/origami/parsers/pdf/lazy.rb +176 -0
  90. data/lib/origami/parsers/pdf/linear.rb +122 -0
  91. data/lib/origami/parsers/pdf.rb +118 -0
  92. data/lib/origami/parsers/ppklite.rb +57 -0
  93. data/lib/origami/pdf.rb +1108 -0
  94. data/lib/origami/reference.rb +134 -0
  95. data/lib/origami/signature.rb +702 -0
  96. data/lib/origami/stream.rb +705 -0
  97. data/lib/origami/string.rb +444 -0
  98. data/lib/origami/template/patterns.rb +56 -0
  99. data/lib/origami/template/widgets.rb +151 -0
  100. data/lib/origami/trailer.rb +190 -0
  101. data/lib/origami/tree.rb +62 -0
  102. data/lib/origami/version.rb +23 -0
  103. data/lib/origami/webcapture.rb +100 -0
  104. data/lib/origami/xfa/config.rb +453 -0
  105. data/lib/origami/xfa/connectionset.rb +146 -0
  106. data/lib/origami/xfa/datasets.rb +49 -0
  107. data/lib/origami/xfa/localeset.rb +42 -0
  108. data/lib/origami/xfa/package.rb +59 -0
  109. data/lib/origami/xfa/pdf.rb +73 -0
  110. data/lib/origami/xfa/signature.rb +42 -0
  111. data/lib/origami/xfa/sourceset.rb +43 -0
  112. data/lib/origami/xfa/stylesheet.rb +44 -0
  113. data/lib/origami/xfa/template.rb +1691 -0
  114. data/lib/origami/xfa/xdc.rb +42 -0
  115. data/lib/origami/xfa/xfa.rb +146 -0
  116. data/lib/origami/xfa/xfdf.rb +43 -0
  117. data/lib/origami/xfa/xmpmeta.rb +43 -0
  118. data/lib/origami/xfa.rb +62 -0
  119. data/lib/origami/xreftable.rb +557 -0
  120. data/lib/origami.rb +47 -0
  121. data/test/dataset/calc.pdf +85 -0
  122. data/test/dataset/crypto.pdf +36 -0
  123. data/test/dataset/empty.pdf +49 -0
  124. data/test/test_actions.rb +27 -0
  125. data/test/test_annotations.rb +68 -0
  126. data/test/test_forms.rb +30 -0
  127. data/test/test_native_types.rb +83 -0
  128. data/test/test_object_tree.rb +33 -0
  129. data/test/test_pages.rb +60 -0
  130. data/test/test_pdf.rb +20 -0
  131. data/test/test_pdf_attachment.rb +34 -0
  132. data/test/test_pdf_create.rb +24 -0
  133. data/test/test_pdf_encrypt.rb +102 -0
  134. data/test/test_pdf_parse.rb +134 -0
  135. data/test/test_pdf_parse_lazy.rb +69 -0
  136. data/test/test_pdf_sign.rb +97 -0
  137. data/test/test_streams.rb +184 -0
  138. data/test/test_xrefs.rb +67 -0
  139. metadata +280 -0
@@ -0,0 +1,62 @@
1
+ =begin
2
+
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
6
+ Origami is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Lesser General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ Origami is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ =end
20
+
21
+ module Origami
22
+
23
+ module Graphics
24
+
25
+ module Canvas
26
+ attr_reader :gs
27
+
28
+ def initialize
29
+ @gs = Graphics::State.new
30
+ end
31
+
32
+ def clear
33
+ @gs.reset
34
+ end
35
+
36
+ def write_text(s); end
37
+ def stroke_path; end
38
+ def fill_path; end
39
+ def paint_shading(sh); end
40
+ end
41
+
42
+ class DummyCanvas
43
+ include Canvas
44
+ end
45
+
46
+ class TextCanvas
47
+ include Canvas
48
+
49
+ def initialize(output = STDOUT, columns = 80, lines = 25)
50
+ super()
51
+
52
+ @output = output
53
+ @columns, @lines = columns, lines
54
+ end
55
+
56
+ def write_text(s)
57
+ @output.print(s)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,149 @@
1
+ =begin
2
+
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
6
+ Origami is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Lesser General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ Origami is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ =end
20
+
21
+ require 'matrix'
22
+
23
+ module Origami
24
+
25
+ module Graphics
26
+ class GraphicsStateError < Error #:nodoc:
27
+ end
28
+
29
+ class State
30
+ #
31
+ # Device-independent parameters.
32
+ #
33
+ attr_accessor :ctm
34
+ attr_accessor :clipping_path
35
+ attr_accessor :stroking_colorspace, :nonstroking_colorspace, :stroking_color, :nonstroking_color
36
+ attr_accessor :text_state
37
+ attr_accessor :line_width, :line_cap, :line_join, :miter_limit, :dash_pattern
38
+ attr_accessor :rendering_intent
39
+ attr_accessor :stroke_adjustment
40
+ attr_accessor :blend_mode, :soft_mask, :alpha_constant, :alpha_source
41
+
42
+ attr_reader :current_path
43
+
44
+ def initialize
45
+ @stack = []
46
+ @current_path = []
47
+ @text_state = Text::State.new
48
+
49
+ self.reset
50
+ end
51
+
52
+ def reset
53
+ @ctm = Matrix.identity(3)
54
+ @clipping_path = nil
55
+ @stroking_colorspace = @nonstroking_colorspace = Color::Space::DEVICE_GRAY
56
+ @stroking_color = @nonstroking_color = [ 0.0 ] #black
57
+ @text_state.reset
58
+ @line_width = 1.0
59
+ @line_cap = LineCapStyle::BUTT_CAP
60
+ @line_join = LineJoinStyle::MITER_JOIN
61
+ @miter_limit = 10.0
62
+ @dash_pattern = DashPattern.new([], 0)
63
+ @rendering_intent = Color::Intent::RELATIVE
64
+ @stroke_adjustment = false
65
+ @blend_mode = Color::BlendMode::NORMAL
66
+ @soft_mask = :None
67
+ @alpha_constant = 1.0
68
+ @alpha_source = false
69
+ end
70
+
71
+ def save
72
+ context =
73
+ [
74
+ @ctm, @clipping_path,
75
+ @stroking_colorspace, @nonstroking_colorspace,
76
+ @stroking_color, @nonstroking_color,
77
+ @text_state, @line_width, @line_cap, @line_join,
78
+ @miter_limit, @dash_pattern, @rendering_intent,
79
+ @stroke_adjustment,
80
+ @blend_mode, @soft_mask, @alpha_constant, @alpha_source
81
+ ]
82
+ @stack.push(context)
83
+ end
84
+
85
+ def restore
86
+ raise GraphicsStateError, "Cannot restore context : empty stack" if @stack.empty?
87
+
88
+ @ctm, @clipping_path,
89
+ @stroking_colorspace, @nonstroking_colorspace,
90
+ @stroking_color, @nonstroking_color,
91
+ @text_state, @line_width, @line_cap, @line_join,
92
+ @miter_limit, @dash_pattern, @rendering_intent,
93
+ @stroke_adjustment,
94
+ @blend_mode, @soft_mask, @alpha_constant, @alpha_source = @stack.pop
95
+ end
96
+ end
97
+
98
+ #
99
+ # Generic Graphic state
100
+ # 4.3.4 Graphics State Parameter Dictionaries p219
101
+ #
102
+ class ExtGState < Dictionary
103
+ include StandardObject
104
+
105
+ field :Type, :Type => Name, :Default => :ExtGState, :Required => true
106
+ field :LW, :Type => Integer, :Version => "1.3"
107
+ field :LC, :Type => Integer, :Version => "1.3"
108
+ field :LJ, :Type => Integer, :Version => "1.3"
109
+ field :ML, :Type => Number, :Version => "1.3"
110
+ field :D, :Type => Array.of(Array, Integer, length: 2), :Version => "1.3"
111
+ field :RI, :Type => Name, :Version => "1.3"
112
+ field :OP, :Type => Boolean
113
+ field :op, :Type => Boolean, :Version => "1.3"
114
+ field :OPM, :Type => Number, :Version => "1.3"
115
+ field :Font, :Type => Array, :Version => "1.3"
116
+ field :BG, :Type => Object
117
+ field :BG2, :Type => Object, :Version => "1.3"
118
+ field :UCR, :Type => Object
119
+ field :UCR2, :Type => Object, :Version => "1.3"
120
+ field :TR, :Type => Object
121
+ field :TR2, :Type => Object, :Version => "1.3"
122
+ field :HT, :Type => [ Dictionary, Name, Stream ]
123
+ field :FL, :Type => Number, :Version => "1.3"
124
+ field :SM, :Type => Number, :Version => "1.3"
125
+ field :SA, :Type => Boolean
126
+ field :BM, :Type => [ Name, Array ], :Version => "1.4"
127
+ field :SMask, :Type => [ Dictionary, Name ], :Version => "1.4"
128
+ field :CA, :Type => Number
129
+ field :ca, :Type => Number, :Version => "1.4"
130
+ field :AIS, :Type => Boolean, :Version => "1.4"
131
+ field :TK, :Type => Boolean, :Version => "1.4"
132
+ end
133
+ end #module Graphics
134
+
135
+ class PDF::Instruction
136
+ insn 'q' do |canvas| canvas.gs.save; canvas.gs.reset end
137
+ insn 'Q' do |canvas| canvas.gs.restore end
138
+ insn 'w', Real do |canvas, lw| canvas.gs.line_width = lw end
139
+ insn 'J', Real do |canvas, lc| canvas.gs.line_cap = lc end
140
+ insn 'j', Real do |canvas, lj| canvas.gs.line_join = lj end
141
+ insn 'M', Real do |canvas, ml| canvas.gs.miter_limit = ml end
142
+
143
+ insn 'd', Array, Integer do |canvas, array, phase|
144
+ canvas.gs.dash_pattern = Graphics::DashPattern.new array, phase
145
+ end
146
+
147
+ insn 'ri', Name do |canvas, ri| canvas.gs.rendering_intent = ri end
148
+ end
149
+ end
@@ -0,0 +1,225 @@
1
+ =begin
2
+
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
5
+
6
+ Origami is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Lesser General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ Origami is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ =end
20
+
21
+ module Origami
22
+
23
+ module Text
24
+
25
+ OPERATORS =
26
+ [
27
+ 'Tc', 'Tw', 'Tz', 'TL', 'Tf', 'Tr', 'Ts', # Text state
28
+ 'BT', 'ET', # Text objects
29
+ 'Td', 'TD', 'Tm', 'T*', # Positioning
30
+ 'Tj', "'", '"', 'TJ' # Showing
31
+ ]
32
+
33
+ module Rendering
34
+ FILL = 0
35
+ STROKE = 1
36
+ FILL_AND_STROKE = 2
37
+ INVISIBLE = 3
38
+ FILL_AND_CLIP = 4
39
+ STROKE_AND_CLIP = 5
40
+ FILL_AND_STROKE_AND_CLIP = 6
41
+ CLIP = 7
42
+ end
43
+
44
+ class TextStateError < Error #:nodoc:
45
+ end
46
+
47
+ class State
48
+ attr_accessor :char_spacing, :word_spacing, :scaling, :leading
49
+ attr_accessor :font, :font_size
50
+ attr_accessor :rendering_mode
51
+ attr_accessor :text_rise, :text_knockout
52
+
53
+ attr_accessor :text_matrix, :text_line_matrix, :text_rendering_matrix
54
+
55
+ def initialize
56
+ self.reset
57
+ end
58
+
59
+ def reset
60
+ @char_spacing = 0
61
+ @word_spacing = 0
62
+ @scaling = 100
63
+ @leading = 0
64
+ @font = nil
65
+ @font_size = nil
66
+ @rendering_mode = Rendering::FILL
67
+ @text_rise = 0
68
+ @text_knockout = true
69
+
70
+ #
71
+ # Text objects
72
+ #
73
+
74
+ @text_object = false
75
+ @text_matrix =
76
+ @text_line_matrix =
77
+ @text_rendering_matrix = nil
78
+ end
79
+
80
+ def is_in_text_object?
81
+ @text_object
82
+ end
83
+
84
+ def begin_text_object
85
+ if is_in_text_object?
86
+ raise TextStateError, "Cannot start a text object within an existing text object."
87
+ end
88
+
89
+ @text_object = true
90
+ @text_matrix =
91
+ @text_line_matrix =
92
+ @text_rendering_matrix = Matrix.identity(3)
93
+ end
94
+
95
+ def end_text_object
96
+ unless is_in_text_object?
97
+ raise TextStateError, "Cannot end text object : no previous text object has begun."
98
+ end
99
+
100
+ @text_object = false
101
+ @text_matrix =
102
+ @text_line_matrix =
103
+ @text_rendering_matrix = nil
104
+ end
105
+ end #class State
106
+ end #module Text
107
+
108
+ class PDF::Instruction
109
+ #
110
+ # Text instructions definitions
111
+ #
112
+ insn 'Tc', Real do |canvas, cS| canvas.gs.text_state.char_spacing = cS end
113
+ insn 'Tw', Real do |canvas, wS| canvas.gs.text_state.word_spacing = wS end
114
+ insn 'Tz', Real do |canvas, s| canvas.gs.text_state.scaling = s end
115
+ insn 'TL', Real do |canvas, l| canvas.gs.text_state.leading = l end
116
+
117
+ insn 'Tf', Name, Real do |canvas, font, size|
118
+ canvas.gs.text_state.font = font
119
+ canvas.gs.text_state.font_size = size
120
+ end
121
+
122
+ insn 'Tr', Integer do |canvas, r| canvas.gs.text_state.rendering_mode = r end
123
+ insn 'Ts', Real do |canvas, s| canvas.gs.text_state.text_rise = s end
124
+ insn 'BT' do |canvas| canvas.gs.text_state.begin_text_object end
125
+ insn 'ET' do |canvas| canvas.gs.text_state.end_text_object end
126
+
127
+ insn 'Td', Real, Real do |canvas, tx, ty|
128
+ unless canvas.gs.text_state.is_in_text_object?
129
+ raise TextStateError, "Must be in a text object to use operator : Td"
130
+ end
131
+
132
+ canvas.gs.text_state.text_matrix =
133
+ canvas.gs.text_state.text_line_matrix =
134
+ Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
135
+ end
136
+
137
+ insn 'TD', Real, Real do |canvas, tx, ty|
138
+ unless canvas.gs.text_state.is_in_text_object?
139
+ raise TextStateError, "Must be in a text object to use operator : TD"
140
+ end
141
+
142
+ canvas.gs.text_state.leading = -ty
143
+
144
+ canvas.gs.text_state.text_matrix =
145
+ canvas.gs.text_state.text_line_matrix =
146
+ Matrix.rows([[1,0,0],[0,1,0],[tx,ty,1]]) * canvas.gs.text_state.text_line_matrix
147
+ end
148
+
149
+ insn 'Tm', Real, Real, Real, Real, Real, Real do |canvas, a, b, c, d, e, f|
150
+ unless canvas.gs.text_state.is_in_text_object?
151
+ raise TextStateError, "Must be in a text object to use operator : Tm"
152
+ end
153
+
154
+ canvas.gs.text_state.text_matrix =
155
+ canvas.gs.text_state.text_line_matrix =
156
+ Matrix.rows([[a,b,0],[c,d,0],[e,f,1]])
157
+ end
158
+
159
+ insn 'T*' do |canvas|
160
+ unless canvas.gs.text_state.is_in_text_object?
161
+ raise TextStateError, "Must be in a text object to use operator : T*"
162
+ end
163
+
164
+ tx, ty = 0, -canvas.gs.text_state.leading
165
+
166
+ canvas.gs.text_state.text_matrix =
167
+ canvas.gs.text_state.text_line_matrix =
168
+ Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
169
+ end
170
+
171
+ insn 'Tj', String do |canvas, s|
172
+ unless canvas.gs.text_state.is_in_text_object?
173
+ raise TextStateError, "Must be in a text object to use operator : Tj"
174
+ end
175
+
176
+ canvas.write_text(s)
177
+ end
178
+
179
+ insn "'", String do |canvas, s|
180
+ unless canvas.gs.text_state.is_in_text_object?
181
+ raise TextStateError, "Must be in a text object to use operator : '"
182
+ end
183
+
184
+ tx, ty = 0, -canvas.gs.text_state.leading
185
+
186
+ canvas.gs.text_state.text_matrix =
187
+ canvas.gs.text_state.text_line_matrix =
188
+ Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
189
+
190
+ canvas.write_text(s)
191
+ end
192
+
193
+ insn '"', Real, Real, String do |canvas, w, c, s|
194
+ unless canvas.gs.text_state.is_in_text_object?
195
+ raise TextStateError, "Must be in a text object to use operator : \""
196
+ end
197
+
198
+ canvas.gs.text_state.word_spacing = w
199
+ canvas.gs.text_state.char_spacing = c
200
+
201
+ tx, ty = 0, -gs.text_state.leading
202
+
203
+ canvas.gs.text_state.text_matrix =
204
+ canvas.gs.text_state.text_line_matrix =
205
+ Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
206
+
207
+ canvas.write_text(s)
208
+ end
209
+
210
+ insn 'TJ', Array do |canvas, arr|
211
+ arr.each do |g|
212
+ case g
213
+ when Fixnum,Float then
214
+ # XXX: handle this in text space ?
215
+ when ::String then
216
+ canvas.write_text(g)
217
+ else
218
+ raise InvalidPDFInstructionError,
219
+ "Invalid component type `#{g.class}` in TJ operand"
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ end