origami 1.2.7 → 2.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 (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/README.md +112 -0
  4. data/bin/config/pdfcop.conf.yml +232 -233
  5. data/bin/gui/about.rb +27 -37
  6. data/bin/gui/config.rb +108 -117
  7. data/bin/gui/file.rb +416 -365
  8. data/bin/gui/gtkhex.rb +1138 -1153
  9. data/bin/gui/hexview.rb +55 -57
  10. data/bin/gui/imgview.rb +48 -51
  11. data/bin/gui/menu.rb +388 -386
  12. data/bin/gui/properties.rb +114 -130
  13. data/bin/gui/signing.rb +571 -617
  14. data/bin/gui/textview.rb +77 -95
  15. data/bin/gui/treeview.rb +382 -387
  16. data/bin/gui/walker.rb +227 -232
  17. data/bin/gui/xrefs.rb +56 -60
  18. data/bin/pdf2pdfa +53 -57
  19. data/bin/pdf2ruby +212 -228
  20. data/bin/pdfcop +338 -348
  21. data/bin/pdfdecompress +58 -65
  22. data/bin/pdfdecrypt +56 -60
  23. data/bin/pdfencrypt +75 -80
  24. data/bin/pdfexplode +185 -182
  25. data/bin/pdfextract +201 -218
  26. data/bin/pdfmetadata +83 -82
  27. data/bin/pdfsh +4 -5
  28. data/bin/pdfwalker +1 -2
  29. data/bin/shell/.irbrc +45 -82
  30. data/bin/shell/console.rb +105 -130
  31. data/bin/shell/hexdump.rb +40 -64
  32. data/examples/README.md +34 -0
  33. data/examples/attachments/attachment.rb +38 -0
  34. data/examples/attachments/nested_document.rb +51 -0
  35. data/examples/encryption/encryption.rb +28 -0
  36. data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
  37. data/examples/flash/flash.rb +37 -0
  38. data/{samples → examples}/flash/helloworld.swf +0 -0
  39. data/examples/forms/javascript.rb +54 -0
  40. data/examples/forms/xfa.rb +115 -0
  41. data/examples/javascript/hello_world.rb +22 -0
  42. data/examples/javascript/js_emulation.rb +54 -0
  43. data/examples/loop/goto.rb +32 -0
  44. data/examples/loop/named.rb +33 -0
  45. data/examples/signature/signature.rb +65 -0
  46. data/examples/uri/javascript.rb +56 -0
  47. data/examples/uri/open-uri.rb +21 -0
  48. data/examples/uri/submitform.rb +47 -0
  49. data/lib/origami.rb +29 -42
  50. data/lib/origami/3d.rb +350 -225
  51. data/lib/origami/acroform.rb +262 -288
  52. data/lib/origami/actions.rb +268 -288
  53. data/lib/origami/annotations.rb +697 -722
  54. data/lib/origami/array.rb +258 -184
  55. data/lib/origami/boolean.rb +74 -84
  56. data/lib/origami/catalog.rb +397 -434
  57. data/lib/origami/collections.rb +144 -0
  58. data/lib/origami/destinations.rb +233 -194
  59. data/lib/origami/dictionary.rb +253 -232
  60. data/lib/origami/encryption.rb +1274 -1243
  61. data/lib/origami/export.rb +232 -268
  62. data/lib/origami/extensions/fdf.rb +307 -220
  63. data/lib/origami/extensions/ppklite.rb +368 -435
  64. data/lib/origami/filespec.rb +197 -0
  65. data/lib/origami/filters.rb +301 -295
  66. data/lib/origami/filters/ascii.rb +177 -180
  67. data/lib/origami/filters/ccitt.rb +528 -535
  68. data/lib/origami/filters/crypt.rb +26 -35
  69. data/lib/origami/filters/dct.rb +46 -52
  70. data/lib/origami/filters/flate.rb +95 -94
  71. data/lib/origami/filters/jbig2.rb +49 -55
  72. data/lib/origami/filters/jpx.rb +38 -44
  73. data/lib/origami/filters/lzw.rb +189 -183
  74. data/lib/origami/filters/predictors.rb +221 -235
  75. data/lib/origami/filters/runlength.rb +103 -104
  76. data/lib/origami/font.rb +173 -186
  77. data/lib/origami/functions.rb +67 -81
  78. data/lib/origami/graphics.rb +25 -21
  79. data/lib/origami/graphics/colors.rb +178 -187
  80. data/lib/origami/graphics/instruction.rb +79 -85
  81. data/lib/origami/graphics/path.rb +142 -148
  82. data/lib/origami/graphics/patterns.rb +160 -167
  83. data/lib/origami/graphics/render.rb +43 -50
  84. data/lib/origami/graphics/state.rb +138 -153
  85. data/lib/origami/graphics/text.rb +188 -205
  86. data/lib/origami/graphics/xobject.rb +819 -815
  87. data/lib/origami/header.rb +63 -78
  88. data/lib/origami/javascript.rb +596 -597
  89. data/lib/origami/linearization.rb +285 -290
  90. data/lib/origami/metadata.rb +139 -148
  91. data/lib/origami/name.rb +112 -148
  92. data/lib/origami/null.rb +53 -62
  93. data/lib/origami/numeric.rb +162 -175
  94. data/lib/origami/obfuscation.rb +186 -174
  95. data/lib/origami/object.rb +593 -573
  96. data/lib/origami/outline.rb +42 -47
  97. data/lib/origami/outputintents.rb +73 -82
  98. data/lib/origami/page.rb +703 -592
  99. data/lib/origami/parser.rb +238 -290
  100. data/lib/origami/parsers/fdf.rb +41 -33
  101. data/lib/origami/parsers/pdf.rb +75 -95
  102. data/lib/origami/parsers/pdf/lazy.rb +137 -0
  103. data/lib/origami/parsers/pdf/linear.rb +64 -66
  104. data/lib/origami/parsers/ppklite.rb +34 -70
  105. data/lib/origami/pdf.rb +1030 -1005
  106. data/lib/origami/reference.rb +102 -102
  107. data/lib/origami/signature.rb +591 -609
  108. data/lib/origami/stream.rb +668 -551
  109. data/lib/origami/string.rb +397 -373
  110. data/lib/origami/template/patterns.rb +56 -0
  111. data/lib/origami/template/widgets.rb +151 -0
  112. data/lib/origami/trailer.rb +144 -158
  113. data/lib/origami/tree.rb +62 -0
  114. data/lib/origami/version.rb +23 -0
  115. data/lib/origami/webcapture.rb +88 -79
  116. data/lib/origami/xfa.rb +2863 -2882
  117. data/lib/origami/xreftable.rb +472 -384
  118. data/test/dataset/calc.pdf +85 -0
  119. data/test/dataset/crypto.pdf +82 -0
  120. data/test/dataset/empty.pdf +49 -0
  121. data/test/test_actions.rb +27 -0
  122. data/test/test_annotations.rb +90 -0
  123. data/test/test_pages.rb +31 -0
  124. data/test/test_pdf.rb +16 -0
  125. data/test/test_pdf_attachment.rb +34 -0
  126. data/test/test_pdf_create.rb +24 -0
  127. data/test/test_pdf_encrypt.rb +95 -0
  128. data/test/test_pdf_parse.rb +96 -0
  129. data/test/test_pdf_sign.rb +58 -0
  130. data/test/test_streams.rb +182 -0
  131. data/test/test_xrefs.rb +67 -0
  132. metadata +88 -58
  133. data/README +0 -67
  134. data/bin/pdf2graph +0 -121
  135. data/bin/pdfcocoon +0 -104
  136. data/lib/origami/file.rb +0 -233
  137. data/samples/README.txt +0 -45
  138. data/samples/actions/launch/calc.rb +0 -87
  139. data/samples/actions/launch/winparams.rb +0 -22
  140. data/samples/actions/loop/loopgoto.rb +0 -24
  141. data/samples/actions/loop/loopnamed.rb +0 -21
  142. data/samples/actions/named/named.rb +0 -31
  143. data/samples/actions/samba/smbrelay.rb +0 -26
  144. data/samples/actions/webbug/submitform.js +0 -26
  145. data/samples/actions/webbug/webbug-browser.rb +0 -68
  146. data/samples/actions/webbug/webbug-js.rb +0 -67
  147. data/samples/actions/webbug/webbug-reader.rb +0 -90
  148. data/samples/attachments/attach.rb +0 -40
  149. data/samples/attachments/attached.txt +0 -1
  150. data/samples/crypto/crypto.rb +0 -28
  151. data/samples/digsig/signed.rb +0 -46
  152. data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
  153. data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
  154. data/samples/exploits/exploit_customdictopen.rb +0 -55
  155. data/samples/exploits/getannots.rb +0 -69
  156. data/samples/flash/flash.rb +0 -31
  157. data/samples/javascript/attached.txt +0 -1
  158. data/samples/javascript/js.rb +0 -52
  159. data/templates/patterns.rb +0 -66
  160. data/templates/widgets.rb +0 -173
  161. data/templates/xdp.rb +0 -92
  162. data/test/ts_pdf.rb +0 -50
@@ -1,164 +1,149 @@
1
1
  =begin
2
2
 
3
- = File
4
- graphics/state.rb
5
-
6
- = Info
7
- This file is part of Origami, PDF manipulation framework for Ruby
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- Origami is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU Lesser General Public License as published by
13
- the Free Software Foundation, either version 3 of the License, or
14
- (at your option) any later version.
15
-
16
- Origami is distributed in the hope that it will be useful,
17
- but WITHOUT ANY WARRANTY; without even the implied warranty of
18
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
- GNU Lesser General Public License for more details.
20
-
21
- You should have received a copy of the GNU Lesser General Public License
22
- along with Origami. If not, see <http://www.gnu.org/licenses/>.
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
23
5
 
24
- =end
25
-
26
- require 'matrix'
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.
27
10
 
28
- module Origami
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.
29
15
 
30
- module Graphics
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/>.
31
18
 
32
- class GraphicsStateError < Exception #:nodoc:
33
- end
19
+ =end
34
20
 
35
- class State
36
-
37
- #
38
- # Device-independent parameters.
39
- #
40
- attr_accessor :ctm
41
- attr_accessor :clipping_path
42
- attr_accessor :stroking_colorspace, :nonstroking_colorspace, :stroking_color, :nonstroking_color
43
- attr_accessor :text_state
44
- attr_accessor :line_width, :line_cap, :line_join, :miter_limit, :dash_pattern
45
- attr_accessor :rendering_intent
46
- attr_accessor :stroke_adjustment
47
- attr_accessor :blend_mode, :soft_mask, :alpha_constant, :alpha_source
48
-
49
- attr_reader :current_path
50
-
51
- def initialize
52
-
53
- @stack = []
54
- @current_path = []
55
- @text_state = Text::State.new
56
-
57
- self.reset
58
- end
59
-
60
- def reset
61
-
62
- @ctm = Matrix.identity(3)
63
- @clipping_path = nil
64
- @stroking_colorspace = @nonstroking_colorspace = Color::Space::DEVICE_GRAY
65
- @stroking_color = @nonstroking_color = [ 0.0 ] #black
66
- @text_state.reset
67
- @line_width = 1.0
68
- @line_cap = LineCapStyle::BUTT_CAP
69
- @line_join = LineJoinStyle::MITER_JOIN
70
- @miter_limit = 10.0
71
- @dash_pattern = DashPattern.new([], 0)
72
- @rendering_intent = Color::Intent::RELATIVE
73
- @stroke_adjustment = false
74
- @blend_mode = Color::BlendMode::NORMAL
75
- @soft_mask = :None
76
- @alpha_constant = 1.0
77
- @alpha_source = false
78
-
79
- end
80
-
81
- def save
82
- context =
83
- [
84
- @ctm, @clipping_path,
85
- @stroking_colorspace, @nonstroking_colorspace,
86
- @stroking_color, @nonstroking_color,
87
- @text_state, @line_width, @line_cap, @line_join,
88
- @miter_limit, @dash_pattern, @rendering_intent,
89
- @stroke_adjustment,
90
- @blend_mode, @soft_mask, @alpha_constant, @alpha_source
91
- ]
92
- @stack.push(context)
93
- end
94
-
95
- def restore
96
- raise GraphicsStateError, "Cannot restore context : empty stack" if @stack.empty?
97
-
98
- @ctm, @clipping_path,
99
- @stroking_colorspace, @nonstroking_colorspace,
100
- @stroking_color, @nonstroking_color,
101
- @text_state, @line_width, @line_cap, @line_join,
102
- @miter_limit, @dash_pattern, @rendering_intent,
103
- @stroke_adjustment,
104
- @blend_mode, @soft_mask, @alpha_constant, @alpha_source = @stack.pop
105
- end
21
+ require 'matrix'
106
22
 
107
- end
23
+ module Origami
108
24
 
109
- #
110
- # Generic Graphic state
111
- # 4.3.4 Graphics State Parameter Dictionaries p219
112
- #
113
- class ExtGState < Dictionary
114
-
115
- include StandardObject
116
-
117
- field :Type, :Type => Name, :Default => :ExtGState, :Required => true
118
- field :LW, :Type => Integer, :Version => "1.3"
119
- field :LC, :Type => Integer, :Version => "1.3"
120
- field :LJ, :Type => Integer, :Version => "1.3"
121
- field :ML, :Type => Number, :Version => "1.3"
122
- field :D, :Type => Array, :Version => "1.3"
123
- field :RI, :Type => Name, :Version => "1.3"
124
- field :OP, :Type => Boolean
125
- field :op, :Type => Boolean, :Version => "1.3"
126
- field :OPM, :Type => Number, :Version => "1.3"
127
- field :Font, :Type => Array, :Version => "1.3"
128
- field :BG, :Type => Object
129
- field :BG2, :Type => Object, :Version => "1.3"
130
- field :UCR, :Type => Object
131
- field :UCR2, :Type => Object, :Version => "1.3"
132
- field :TR, :Type => Object
133
- field :TR2, :Type => Object, :Version => "1.3"
134
- field :HT, :Type => [ Dictionary, Name, Stream ]
135
- field :FL, :Type => Number, :Version => "1.3"
136
- field :SM, :Type => Number, :Version => "1.3"
137
- field :SA, :Type => Boolean
138
- field :BM, :Type => [ Name, Array ], :Version => "1.4"
139
- field :SMask, :Type => [ Dictionary, Array ], :Version => "1.4"
140
- field :CA, :Type => Number
141
- field :ca, :Type => Number, :Version => "1.4"
142
- field :AIS, :Type => Boolean, :Version => "1.4"
143
- field :TK, :Type => Boolean, :Version => "1.4"
144
-
145
- end # class ExtGState
146
-
147
- end #module Graphics
148
-
149
- class PDF::Instruction
150
- insn 'q' do |canvas| canvas.gs.save; canvas.gs.reset end
151
- insn 'Q' do |canvas| canvas.gs.restore end
152
- insn 'w', Real do |canvas, lw| canvas.gs.line_width = lw end
153
- insn 'J', Real do |canvas, lc| canvas.gs.line_cap = lc end
154
- insn 'j', Real do |canvas, lj| canvas.gs.line_join = lj end
155
- insn 'M', Real do |canvas, ml| canvas.gs.miter_limit = ml end
156
-
157
- insn 'd', Array, Integer do |canvas, array, phase|
158
- canvas.gs.dash_pattern = Graphics::DashPattern.new array, phase
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
159
148
  end
160
-
161
- insn 'ri', Name do |canvas, ri| canvas.gs.rendering_intent = ri end
162
- end
163
149
  end
164
-
@@ -1,242 +1,225 @@
1
1
  =begin
2
2
 
3
- = File
4
- graphics/text.rb
5
-
6
- = Info
7
- This file is part of Origami, PDF manipulation framework for Ruby
8
- Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
9
- All right reserved.
10
-
11
- Origami is free software: you can redistribute it and/or modify
12
- it under the terms of the GNU Lesser General Public License as published by
13
- the Free Software Foundation, either version 3 of the License, or
14
- (at your option) any later version.
15
-
16
- Origami is distributed in the hope that it will be useful,
17
- but WITHOUT ANY WARRANTY; without even the implied warranty of
18
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
- GNU Lesser General Public License for more details.
20
-
21
- You should have received a copy of the GNU Lesser General Public License
22
- along with Origami. If not, see <http://www.gnu.org/licenses/>.
3
+ This file is part of Origami, PDF manipulation framework for Ruby
4
+ Copyright (C) 2016 Guillaume Delugré.
23
5
 
24
- =end
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.
25
10
 
26
- module Origami
27
-
28
- module Text
29
-
30
- OPERATORS =
31
- [
32
- 'Tc', 'Tw', 'Tz', 'TL', 'Tf', 'Tr', 'Ts', # Text state
33
- 'BT', 'ET', # Text objects
34
- 'Td', 'TD', 'Tm', 'T*', # Positioning
35
- 'Tj', "'", '"', 'TJ' # Showing
36
- ]
37
-
38
- module Rendering
39
- FILL = 0
40
- STROKE = 1
41
- FILL_AND_STROKE = 2
42
- INVISIBLE = 3
43
- FILL_AND_CLIP = 4
44
- STROKE_AND_CLIP = 5
45
- FILL_AND_STROKE_AND_CLIP = 6
46
- CLIP = 7
47
- end
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.
48
15
 
49
- class TextStateError < Exception #:nodoc:
50
- end
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/>.
51
18
 
52
- class State
53
-
54
- attr_accessor :char_spacing, :word_spacing, :scaling, :leading
55
- attr_accessor :font, :font_size
56
- attr_accessor :rendering_mode
57
- attr_accessor :text_rise, :text_knockout
19
+ =end
58
20
 
59
- attr_accessor :text_matrix, :text_line_matrix, :text_rendering_matrix
21
+ module Origami
60
22
 
61
- def initialize
62
- self.reset
63
- end
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
64
43
 
65
- def reset
66
-
67
- @char_spacing = 0
68
- @word_spacing = 0
69
- @scaling = 100
70
- @leading = 0
71
- @font = nil
72
- @font_size = nil
73
- @rendering_mode = Rendering::FILL
74
- @text_rise = 0
75
- @text_knockout = true
44
+ class TextStateError < Error #:nodoc:
45
+ end
76
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
77
109
  #
78
- # Text objects
110
+ # Text instructions definitions
79
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
80
121
 
81
- @text_object = false
82
- @text_matrix =
83
- @text_line_matrix =
84
- @text_rendering_matrix = nil
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
85
136
 
86
- end
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
87
141
 
88
- def is_in_text_object?
89
- @text_object
90
- end
142
+ canvas.gs.text_state.leading = -ty
91
143
 
92
- def begin_text_object
93
- if is_in_text_object?
94
- raise TextStateError,
95
- "Cannot start a text object within an existing text object."
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
96
147
  end
97
148
 
98
- @text_object = true
99
- @text_matrix =
100
- @text_line_matrix =
101
- @text_rendering_matrix = Matrix.identity(3)
102
- end
149
+ insn 'Tm', Real, Real, Real, Real, Real, Real do |canvas, a,b,c,d,e,f,g|
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
103
153
 
104
- def end_text_object
105
- unless is_in_text_object?
106
- raise TextStateError,
107
- "Cannot end text object : no previous text object has begun."
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]])
108
157
  end
109
158
 
110
- @text_object = false
111
- @text_matrix =
112
- @text_line_matrix =
113
- @text_rendering_matrix = nil
114
- end
115
-
116
- end #class State
117
-
118
- end #module Text
119
-
120
- class PDF::Instruction
121
- # Text instructions definitions
122
- insn 'Tc', Real do |canvas, cS| canvas.gs.text_state.char_spacing = cS end
123
- insn 'Tw', Real do |canvas, wS| canvas.gs.text_state.word_spacing = wS end
124
- insn 'Tz', Real do |canvas, s| canvas.gs.text_state.scaling = s end
125
- insn 'TL', Real do |canvas, l| canvas.gs.text_state.leading = l end
126
-
127
- insn 'Tf', Name, Real do |canvas, font, size|
128
- canvas.gs.text_state.font = font
129
- canvas.gs.text_state.font_size = size
130
- end
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
131
163
 
132
- insn 'Tr', Integer do |canvas, r| canvas.gs.text_state.rendering_mode = r end
133
- insn 'Ts', Real do |canvas, s| canvas.gs.text_state.text_rise = s end
134
- insn 'BT' do |canvas| canvas.gs.text_state.begin_text_object end
135
- insn 'ET' do |canvas| canvas.gs.text_state.end_text_object end
136
-
137
- insn 'Td', Real, Real do |canvas, tx, ty|
138
- unless canvas.gs.text_state.is_in_text_object?
139
- raise TextStateError,
140
- "Must be in a text object to use operator : Td"
141
- end
142
-
143
- canvas.gs.text_state.text_matrix =
144
- canvas.gs.text_state.text_line_matrix =
145
- Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
146
- end
164
+ tx, ty = 0, -canvas.gs.text_state.leading
147
165
 
148
- insn 'TD', Real, Real do |canvas, tx, ty|
149
- unless canvas.gs.text_state.is_in_text_object?
150
- raise TextStateError,
151
- "Must be in a text object to use operator : TD"
152
- end
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
153
170
 
154
- canvas.gs.text_state.leading = -ty
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
155
175
 
156
- canvas.gs.text_state.text_matrix =
157
- canvas.gs.text_state.text_line_matrix =
158
- Matrix.rows([[1,0,0],[0,1,0],[tx,ty,1]]) * canvas.gs.text_state.text_line_matrix
159
- end
176
+ canvas.write_text(s)
177
+ end
160
178
 
161
- insn 'Tm', Real, Real, Real, Real, Real, Real do |canvas, a,b,c,d,e,f,g|
162
- unless canvas.gs.text_state.is_in_text_object?
163
- raise TextStateError,
164
- "Must be in a text object to use operator : Tm"
165
- end
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
166
183
 
167
- canvas.gs.text_state.text_matrix =
168
- canvas.gs.text_state.text_line_matrix =
169
- Matrix.rows([[a,b,0],[c,d,0],[e,f,1]])
170
- end
184
+ tx, ty = 0, -canvas.gs.text_state.leading
171
185
 
172
- insn 'T*' do |canvas|
173
- unless canvas.gs.text_state.is_in_text_object?
174
- raise TextStateError,
175
- "Must be in a text object to use operator : T*"
176
- end
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
177
189
 
178
- tx, ty = 0, -canvas.gs.text_state.leading
190
+ canvas.write_text(s)
191
+ end
179
192
 
180
- canvas.gs.text_state.text_matrix =
181
- canvas.gs.text_state.text_line_matrix =
182
- Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
183
- end
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
184
197
 
185
- insn 'Tj', String do |canvas, s|
186
- unless canvas.gs.text_state.is_in_text_object?
187
- raise TextStateError,
188
- "Must be in a text object to use operator : Tj"
189
- end
198
+ canvas.gs.text_state.word_spacing = w
199
+ canvas.gs.text_state.char_spacing = c
190
200
 
191
- canvas.write_text(s)
192
- end
201
+ tx, ty = 0, -gs.text_state.leading
193
202
 
194
- insn "'", String do |canvas, s|
195
- unless canvas.gs.text_state.is_in_text_object?
196
- raise TextStateError,
197
- "Must be in a text object to use operator : '"
198
- end
199
-
200
- tx, ty = 0, -canvas.gs.text_state.leading
201
-
202
- canvas.gs.text_state.text_matrix =
203
- canvas.gs.text_state.text_line_matrix =
204
- Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
205
-
206
- canvas.write_text(s)
207
- end
208
-
209
- insn '"', Real, Real, String do |canvas, w, c, s|
210
- unless canvas.gs.text_state.is_in_text_object?
211
- raise TextStateError,
212
- "Must be in a text object to use operator : \""
213
- end
214
-
215
- canvas.gs.text_state.word_spacing = w
216
- canvas.gs.text_state.char_spacing = c
217
-
218
- tx, ty = 0, -gs.text_state.leading
219
-
220
- canvas.gs.text_state.text_matrix =
221
- canvas.gs.text_state.text_line_matrix =
222
- Matrix.rows([[1,0,0],[0,1,0],[tx, ty, 1]]) * canvas.gs.text_state.text_line_matrix
223
-
224
- canvas.write_text(s)
225
- end
226
-
227
- insn 'TJ', Array do |canvas, arr|
228
- arr.each do |g|
229
- case g
230
- when Fixnum,Float then
231
- # XXX: handle this in text space ?
232
- when ::String then
233
- canvas.write_text(g)
234
- else
235
- raise InvalidPDFInstructionError,
236
- "Invalid component type `#{g.class}` in TJ operand"
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
237
222
  end
238
- end
239
223
  end
240
- end
241
224
 
242
225
  end