origami 1.2.7 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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