origami 1.0.2
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.
- data/COPYING.LESSER +165 -0
- data/README +77 -0
- data/VERSION +1 -0
- data/bin/config/pdfcop.conf.yml +237 -0
- data/bin/gui/about.rb +46 -0
- data/bin/gui/config.rb +132 -0
- data/bin/gui/file.rb +385 -0
- data/bin/gui/hexdump.rb +74 -0
- data/bin/gui/hexview.rb +91 -0
- data/bin/gui/imgview.rb +72 -0
- data/bin/gui/menu.rb +392 -0
- data/bin/gui/properties.rb +132 -0
- data/bin/gui/signing.rb +635 -0
- data/bin/gui/textview.rb +107 -0
- data/bin/gui/treeview.rb +409 -0
- data/bin/gui/walker.rb +282 -0
- data/bin/gui/xrefs.rb +79 -0
- data/bin/pdf2graph +121 -0
- data/bin/pdf2ruby +353 -0
- data/bin/pdfcocoon +104 -0
- data/bin/pdfcop +455 -0
- data/bin/pdfdecompress +104 -0
- data/bin/pdfdecrypt +95 -0
- data/bin/pdfencrypt +112 -0
- data/bin/pdfextract +221 -0
- data/bin/pdfmetadata +123 -0
- data/bin/pdfsh +13 -0
- data/bin/pdfwalker +7 -0
- data/bin/shell/.irbrc +104 -0
- data/bin/shell/console.rb +136 -0
- data/bin/shell/hexdump.rb +83 -0
- data/origami.rb +36 -0
- data/origami/3d.rb +239 -0
- data/origami/acroform.rb +321 -0
- data/origami/actions.rb +299 -0
- data/origami/adobe/fdf.rb +259 -0
- data/origami/adobe/ppklite.rb +489 -0
- data/origami/annotations.rb +775 -0
- data/origami/array.rb +187 -0
- data/origami/boolean.rb +101 -0
- data/origami/catalog.rb +486 -0
- data/origami/destinations.rb +213 -0
- data/origami/dictionary.rb +188 -0
- data/origami/docmdp.rb +96 -0
- data/origami/encryption.rb +1293 -0
- data/origami/export.rb +283 -0
- data/origami/file.rb +222 -0
- data/origami/filters.rb +250 -0
- data/origami/filters/ascii.rb +189 -0
- data/origami/filters/ccitt.rb +515 -0
- data/origami/filters/crypt.rb +47 -0
- data/origami/filters/dct.rb +61 -0
- data/origami/filters/flate.rb +112 -0
- data/origami/filters/jbig2.rb +63 -0
- data/origami/filters/jpx.rb +53 -0
- data/origami/filters/lzw.rb +195 -0
- data/origami/filters/predictors.rb +276 -0
- data/origami/filters/runlength.rb +117 -0
- data/origami/font.rb +209 -0
- data/origami/functions.rb +93 -0
- data/origami/graphics.rb +33 -0
- data/origami/graphics/colors.rb +191 -0
- data/origami/graphics/instruction.rb +126 -0
- data/origami/graphics/path.rb +154 -0
- data/origami/graphics/patterns.rb +180 -0
- data/origami/graphics/state.rb +164 -0
- data/origami/graphics/text.rb +224 -0
- data/origami/graphics/xobject.rb +493 -0
- data/origami/header.rb +90 -0
- data/origami/linearization.rb +318 -0
- data/origami/metadata.rb +114 -0
- data/origami/name.rb +170 -0
- data/origami/null.rb +75 -0
- data/origami/numeric.rb +188 -0
- data/origami/obfuscation.rb +233 -0
- data/origami/object.rb +527 -0
- data/origami/outline.rb +59 -0
- data/origami/page.rb +559 -0
- data/origami/parser.rb +268 -0
- data/origami/parsers/fdf.rb +45 -0
- data/origami/parsers/pdf.rb +27 -0
- data/origami/parsers/pdf/linear.rb +113 -0
- data/origami/parsers/ppklite.rb +86 -0
- data/origami/pdf.rb +1144 -0
- data/origami/reference.rb +113 -0
- data/origami/signature.rb +474 -0
- data/origami/stream.rb +575 -0
- data/origami/string.rb +416 -0
- data/origami/trailer.rb +173 -0
- data/origami/webcapture.rb +87 -0
- data/origami/xfa.rb +3027 -0
- data/origami/xreftable.rb +447 -0
- data/templates/patterns.rb +66 -0
- data/templates/widgets.rb +173 -0
- data/templates/xdp.rb +92 -0
- data/tests/dataset/test.dummycrt +28 -0
- data/tests/dataset/test.dummykey +27 -0
- data/tests/tc_actions.rb +32 -0
- data/tests/tc_annotations.rb +85 -0
- data/tests/tc_pages.rb +37 -0
- data/tests/tc_pdfattach.rb +24 -0
- data/tests/tc_pdfencrypt.rb +110 -0
- data/tests/tc_pdfnew.rb +32 -0
- data/tests/tc_pdfparse.rb +98 -0
- data/tests/tc_pdfsig.rb +37 -0
- data/tests/tc_streams.rb +129 -0
- data/tests/ts_pdf.rb +45 -0
- metadata +193 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
functions.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
8
|
+
Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.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/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
|
27
|
+
module Origami
|
28
|
+
|
29
|
+
module Function
|
30
|
+
|
31
|
+
module Type
|
32
|
+
SAMPLED = 0
|
33
|
+
EXPONENTIAL = 2
|
34
|
+
STITCHING = 3
|
35
|
+
POSTSCRIPT = 4
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.included(receiver)
|
39
|
+
receiver.field :FunctionType, :Type => Integer, :Required => true
|
40
|
+
receiver.field :Domain, :Type => Array, :Required => true
|
41
|
+
receiver.field :Range, :Type => Array
|
42
|
+
end
|
43
|
+
|
44
|
+
class Sampled < Stream
|
45
|
+
|
46
|
+
include Function
|
47
|
+
|
48
|
+
field :FunctionType, :Type => Integer, :Default => Type::SAMPLED, :Version => "1.3", :Required => true
|
49
|
+
field :Range, :Type => Array, :Required => true
|
50
|
+
field :Size, :Type => Array, :Required => true
|
51
|
+
field :BitsPerSample, :Type => Integer, :Required => true
|
52
|
+
field :Order, :Type => Integer, :Default => 1
|
53
|
+
field :Encode, :Type => Array
|
54
|
+
field :Decode, :Type => Array
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
class Exponential < Dictionary
|
59
|
+
|
60
|
+
include StandardObject
|
61
|
+
include Function
|
62
|
+
|
63
|
+
field :FunctionType, :Type => Integer, :Default => Type::EXPONENTIAL, :Version => "1.3", :Required => true
|
64
|
+
field :C0, :Type => Array, :Default => [ 0.0 ]
|
65
|
+
field :C1, :Type => Array, :Default => [ 1.0 ]
|
66
|
+
field :N, :Type => Number, :Required => true
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
class Stitching < Dictionary
|
71
|
+
|
72
|
+
include StandardObject
|
73
|
+
include Function
|
74
|
+
|
75
|
+
field :FunctionType, :Type => Integer, :Default => Type::STITCHING, :Version => "1.3", :Required => true
|
76
|
+
field :Functions, :Type => Array, :Required => true
|
77
|
+
field :Bounds, :Type => Array, :Required => true
|
78
|
+
field :Encode, :Type => Array, :Required => true
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
class PostScript < Stream
|
83
|
+
|
84
|
+
include Function
|
85
|
+
|
86
|
+
field :FunctionType, :Type => Integer, :Default => Type::POSTSCRIPT, :Version => "1.3", :Required => true
|
87
|
+
field :Range, :Type => Array, :Required => true
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/origami/graphics.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
graphics.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
8
|
+
Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.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/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
require 'origami/graphics/instruction'
|
27
|
+
require 'origami/graphics/colors'
|
28
|
+
require 'origami/graphics/path'
|
29
|
+
require 'origami/graphics/xobject'
|
30
|
+
require 'origami/graphics/patterns'
|
31
|
+
require 'origami/graphics/text'
|
32
|
+
require 'origami/graphics/state'
|
33
|
+
|
@@ -0,0 +1,191 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
graphics/colors.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
8
|
+
Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.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/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'color'
|
28
|
+
rescue LoadError
|
29
|
+
end
|
30
|
+
|
31
|
+
module Origami
|
32
|
+
|
33
|
+
module Graphics
|
34
|
+
|
35
|
+
module RenderingIntent
|
36
|
+
ABSOLUTE_COLORIMETRIC = :AbsoluteColorimetric
|
37
|
+
RELATIVE_COLORIMETRIC = :RelativeColorimetric
|
38
|
+
SATURATION = :Saturation
|
39
|
+
PERCEPTUAL = :Perceptual
|
40
|
+
end
|
41
|
+
|
42
|
+
module BlendMode
|
43
|
+
NORMAL = :Normal
|
44
|
+
COMPATIBLE = :Compatible
|
45
|
+
MULTIPLY = :Multiply
|
46
|
+
SCREEN = :Screen
|
47
|
+
OVERLAY = :Overlay
|
48
|
+
DARKEN = :Darken
|
49
|
+
LIGHTEN = :Lighten
|
50
|
+
COLORDODGE = :ColorDodge
|
51
|
+
COLORBURN = :ColorBurn
|
52
|
+
HARDLIGHT = :HardLight
|
53
|
+
SOFTLIGHt = :SoftLight
|
54
|
+
DIFFERENCE = :Difference
|
55
|
+
EXCLUSION = :Exclusion
|
56
|
+
end
|
57
|
+
|
58
|
+
class InvalidColorError < Exception; end
|
59
|
+
module Color
|
60
|
+
|
61
|
+
module Space
|
62
|
+
DEVICE_GRAY = :DeviceGray
|
63
|
+
DEVICE_RGB = :DeviceRGB
|
64
|
+
DEVICE_CMYK = :DeviceCMYK
|
65
|
+
end
|
66
|
+
|
67
|
+
class GrayScale
|
68
|
+
attr_accessor :g
|
69
|
+
|
70
|
+
def initialize(g)
|
71
|
+
@g = g
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class RGB
|
76
|
+
attr_accessor :r,:g,:b
|
77
|
+
|
78
|
+
def initialize(r,g,b)
|
79
|
+
@r,@g,@b = r,g,b
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class CMYK
|
84
|
+
attr_accessor :c,:m,:y,:k
|
85
|
+
|
86
|
+
def initialize(c,m,y,k)
|
87
|
+
@c,@m,@y,@k = c,m,y,k
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def Color.to_a(color)
|
92
|
+
return color if color.is_a?(::Array)
|
93
|
+
|
94
|
+
if (color.respond_to? :r and color.respond_to? :g and color.respond_to? :b)
|
95
|
+
r = (color.respond_to?(:r) ? color.r : color[0]).to_f / 255
|
96
|
+
g = (color.respond_to?(:g) ? color.g : color[1]).to_f / 255
|
97
|
+
b = (color.respond_to?(:b) ? color.b : color[2]).to_f / 255
|
98
|
+
return [r, g, b]
|
99
|
+
|
100
|
+
elsif (color.respond_to? :c and color.respond_to? :m and color.respond_to? :y and color.respond_to? :k)
|
101
|
+
c = (color.respond_to?(:c) ? color.c : color[0]).to_f
|
102
|
+
m = (color.respond_to?(:m) ? color.m : color[1]).to_f
|
103
|
+
y = (color.respond_to?(:y) ? color.y : color[2]).to_f
|
104
|
+
k = (color.respond_to?(:k) ? color.k : color[3]).to_f
|
105
|
+
return [c,m,y,k]
|
106
|
+
|
107
|
+
elsif color.respond_to?:g or (0.0..1.0) === color
|
108
|
+
g = color.respond_to?(:g) ? color.g : color
|
109
|
+
return [ g ]
|
110
|
+
|
111
|
+
else
|
112
|
+
raise TypeError, "Invalid color : #{color}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
class PDF::Instruction
|
120
|
+
|
121
|
+
insn 'CS', Name do |gs, cs| gs.stroking_colorspace = cs end
|
122
|
+
insn 'cs', Name do |gs, cs| gs.nonstroking_colorspace = cs end
|
123
|
+
insn 'SC', '*' do |gs, *c| gs.stroking_color = c end
|
124
|
+
insn 'sc', '*' do |gs, *c| gs.nonstroking_color = c end
|
125
|
+
|
126
|
+
insn 'G', Real do |gs, c|
|
127
|
+
unless (0..1).include? c
|
128
|
+
raise Graphics::InvalidColorError,
|
129
|
+
"Not a valid color for DeviceGray: #{c}"
|
130
|
+
end
|
131
|
+
|
132
|
+
gs.stroking_colorspace = Graphics::Color::Space::DEVICE_GRAY
|
133
|
+
gs.stroking_color = [ c ]
|
134
|
+
end
|
135
|
+
|
136
|
+
insn 'g', Real do |gs, c|
|
137
|
+
unless (0..1).include? c
|
138
|
+
raise Graphics::InvalidColorError,
|
139
|
+
"Not a valid color for DeviceGray: #{c}"
|
140
|
+
end
|
141
|
+
|
142
|
+
gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_GRAY
|
143
|
+
gs.nonstroking_color = [ c ]
|
144
|
+
end
|
145
|
+
|
146
|
+
insn 'RG', Real, Real, Real do |gs, r,g,b|
|
147
|
+
c = [ r, g, b ]
|
148
|
+
unless c.all? {|b| (0..1).include? b}
|
149
|
+
raise Graphics::InvalidColorError,
|
150
|
+
"Not a valid color for DeviceRGB: #{c.inspect}"
|
151
|
+
end
|
152
|
+
|
153
|
+
gs.stroking_colorspace = Graphics::Color::Space::DEVICE_RGB
|
154
|
+
gs.stroking_color = c
|
155
|
+
end
|
156
|
+
|
157
|
+
insn 'rg', Real, Real, Real do |gs, r,g,b|
|
158
|
+
c = [ r, g, b ]
|
159
|
+
unless c.all? {|b| (0..1).include? b}
|
160
|
+
raise Graphics::InvalidColorError,
|
161
|
+
"Not a valid color for DeviceRGB: #{c.inspect}"
|
162
|
+
end
|
163
|
+
|
164
|
+
gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_RGB
|
165
|
+
gs.nonstroking_color = c
|
166
|
+
end
|
167
|
+
|
168
|
+
insn 'K', Real, Real, Real, Real do |gs, c,m,y,k|
|
169
|
+
c = [ c, m, y, k ]
|
170
|
+
unless c.all? {|b| (0..1).include? b}
|
171
|
+
raise Graphics::InvalidColorError,
|
172
|
+
"Not a valid color for DeviceCMYK: #{c.inspect}"
|
173
|
+
end
|
174
|
+
|
175
|
+
gs.stroking_colorspace = Graphics::Color::Space::DEVICE_CMYK
|
176
|
+
gs.stroking_color = c
|
177
|
+
end
|
178
|
+
|
179
|
+
insn 'k', Real, Real, Real, Real do |gs, c,m,y,k|
|
180
|
+
c = [ c, m, y, k ]
|
181
|
+
unless c.all? {|b| (0..1).include? b}
|
182
|
+
raise Graphics::InvalidColorError,
|
183
|
+
"Not a valid color for DeviceCMYK: #{c.inspect}"
|
184
|
+
end
|
185
|
+
|
186
|
+
gs.nonstroking_colorspace = Graphics::Color::Space::DEVICE_CMYK
|
187
|
+
gs.nonstroking_color = c
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end # module Origami
|
@@ -0,0 +1,126 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
graphics/instruction.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
8
|
+
Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.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/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
module Origami
|
27
|
+
|
28
|
+
class InvalidPDFInstructionError < Exception ; end
|
29
|
+
class PDF::Instruction
|
30
|
+
attr_reader :operator
|
31
|
+
attr_accessor :operands
|
32
|
+
|
33
|
+
@@regexp = Regexp.new('([^ \\t\\r\\n\\0\\[\\]<>()%\\/]+)')
|
34
|
+
@insns = Hash.new(:operands => [], :proc => lambda{}, :callback => lambda{})
|
35
|
+
|
36
|
+
def initialize(operator, *operands)
|
37
|
+
@operator = operator
|
38
|
+
@operands = operands.map!{|arg| arg.is_a?(Origami::Object) ? arg.value : arg}
|
39
|
+
|
40
|
+
if self.class.has_op?(operator)
|
41
|
+
opdef = self.class.get_operands(operator)
|
42
|
+
|
43
|
+
if not opdef.include?('*') and opdef.size != operands.size
|
44
|
+
raise InvalidPDFInstructionError,
|
45
|
+
"Numbers of operands mismatch for #{operator}: #{operands.inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_state(gs)
|
51
|
+
self.class.get_proc(@operator)[gs, *operands] if self.class.has_proc?(@operator)
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def render
|
56
|
+
end
|
57
|
+
|
58
|
+
def exec(gs)
|
59
|
+
update_state(gs)
|
60
|
+
self.class.get_callback(@operator)[gs] if self.class.has_callback?(@operator)
|
61
|
+
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
"#{operands.map!{|op| op.to_o.to_s}.join(' ')}#{' ' unless operands.empty?}#{operator}\n"
|
67
|
+
end
|
68
|
+
|
69
|
+
class << self
|
70
|
+
def insn(operator, *operands, &p)
|
71
|
+
@insns[operator] = {}
|
72
|
+
@insns[operator][:operands] = operands
|
73
|
+
@insns[operator][:proc] = p if block_given?
|
74
|
+
end
|
75
|
+
|
76
|
+
def has_op?(operator)
|
77
|
+
@insns.has_key? operator
|
78
|
+
end
|
79
|
+
|
80
|
+
def has_proc?(operator)
|
81
|
+
self.has_op?(operator) and @insns[operator].has_key?(:proc)
|
82
|
+
end
|
83
|
+
|
84
|
+
def has_callback?(operator)
|
85
|
+
self.has_op?(operator) and @insns[operator].has_key?(:callback)
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_callback(operator, &b)
|
89
|
+
raise RuntimeError, "Operator `#{operator}' does not exist" unless @insns.has_key?(operator)
|
90
|
+
@insns[operator][:callback] = b
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_proc(operator)
|
94
|
+
@insns[operator][:proc]
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_operands(operator)
|
98
|
+
@insns[operator][:operands]
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse(stream)
|
102
|
+
operands = []
|
103
|
+
while type = Object.typeof(stream, true)
|
104
|
+
operands.unshift type.parse(stream)
|
105
|
+
end
|
106
|
+
|
107
|
+
if not stream.eos?
|
108
|
+
if stream.scan(@@regexp).nil?
|
109
|
+
raise InvalidPDFInstructionError,
|
110
|
+
"Operator: #{(stream.peek(10) + '...').inspect}"
|
111
|
+
end
|
112
|
+
|
113
|
+
operator = stream[1]
|
114
|
+
PDF::Instruction.new(operator, *operands)
|
115
|
+
else
|
116
|
+
if not operands.empty?
|
117
|
+
raise InvalidPDFInstructionError,
|
118
|
+
"No operator given for operands: #{operands.join}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
@@ -0,0 +1,154 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
= File
|
4
|
+
graphics/path.rb
|
5
|
+
|
6
|
+
= Info
|
7
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
8
|
+
Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.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/>.
|
23
|
+
|
24
|
+
=end
|
25
|
+
|
26
|
+
module Origami
|
27
|
+
|
28
|
+
module Graphics
|
29
|
+
|
30
|
+
module LineCapStyle
|
31
|
+
BUTT_CAP = 0
|
32
|
+
ROUND_CAP = 1
|
33
|
+
PROJECTING_SQUARE_CAP = 2
|
34
|
+
end
|
35
|
+
|
36
|
+
module LineJoinStyle
|
37
|
+
MITER_JOIN = 0
|
38
|
+
ROUND_JOIN = 1
|
39
|
+
BEVEL_JOIN = 2
|
40
|
+
end
|
41
|
+
|
42
|
+
class DashPattern
|
43
|
+
attr_accessor :array, :phase
|
44
|
+
|
45
|
+
def initialize(array, phase = 0)
|
46
|
+
@array = array
|
47
|
+
@phase = phase
|
48
|
+
end
|
49
|
+
|
50
|
+
def eql?(dash) #:nodoc
|
51
|
+
dash.array == @array and dash.phase == @phase
|
52
|
+
end
|
53
|
+
|
54
|
+
def hash #:nodoc:
|
55
|
+
[ @array, @phase ].hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class InvalidPathError < Exception; end
|
60
|
+
class Path
|
61
|
+
|
62
|
+
module Segment
|
63
|
+
attr_accessor :from, :to
|
64
|
+
|
65
|
+
def initialize(from, to)
|
66
|
+
@from, @to = from, to
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Line
|
71
|
+
include Segment
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_accessor :current_point
|
75
|
+
attr_reader :segments
|
76
|
+
|
77
|
+
def initialize
|
78
|
+
@segments = []
|
79
|
+
@current_point = nil
|
80
|
+
@closed = false
|
81
|
+
end
|
82
|
+
|
83
|
+
def is_closed?
|
84
|
+
@closed
|
85
|
+
end
|
86
|
+
|
87
|
+
def close!
|
88
|
+
from = @current_point
|
89
|
+
to = @segments.first.from
|
90
|
+
|
91
|
+
@segments << Line.new(from, to)
|
92
|
+
@segments.freeze
|
93
|
+
@closed = true
|
94
|
+
end
|
95
|
+
|
96
|
+
def add_segment(seg)
|
97
|
+
raise GraphicsStateError, "Cannot modify closed subpath" if is_closed?
|
98
|
+
|
99
|
+
@segments << seg
|
100
|
+
@current_point = seg.to
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
class PDF::Instruction
|
108
|
+
insn 'm', Real, Real do |gs, x,y|
|
109
|
+
gs.current_path << (subpath = Graphics::Path.new)
|
110
|
+
subpath.current_point = [x,y]
|
111
|
+
end
|
112
|
+
|
113
|
+
insn 'l', Real, Real do |gs, x,y|
|
114
|
+
if gs.current_path.empty?
|
115
|
+
raise InvalidPathError, "No current point is defined"
|
116
|
+
end
|
117
|
+
|
118
|
+
subpath = gs.current_path.last
|
119
|
+
|
120
|
+
from = subpath.current_point
|
121
|
+
to = [x,y]
|
122
|
+
subpath.add_segment(Graphics::Path::Line.new(from, to))
|
123
|
+
end
|
124
|
+
|
125
|
+
insn 'h' do |gs|
|
126
|
+
unless gs.current_path.empty?
|
127
|
+
subpath = gs.current_path.last
|
128
|
+
subpath.close! unless subpath.is_closed?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
insn 're', Real, Real, Real, Real do |gs, x,y,width,height|
|
133
|
+
tx = x + width
|
134
|
+
ty = y + height
|
135
|
+
gs.current_path << (subpath = Graphics::Path.new)
|
136
|
+
subpath.segments << Graphics::Path::Line.new([x,y], [tx,y])
|
137
|
+
subpath.segments << Graphics::Path::Line.new([tx,y], [tx, ty])
|
138
|
+
subpath.segments << Graphics::Path::Line.new([tx, ty], [x, ty])
|
139
|
+
subpath.close!
|
140
|
+
end
|
141
|
+
|
142
|
+
insn 'S'
|
143
|
+
insn 's' do |gs| gs.current_path.last.close! end
|
144
|
+
insn 'f'
|
145
|
+
insn 'F'
|
146
|
+
insn 'f*'
|
147
|
+
insn 'B'
|
148
|
+
insn 'B*'
|
149
|
+
insn 'b' do |gs| gs.current_path.last.close! end
|
150
|
+
insn 'b*' do |gs| gs.current_path.last.close! end
|
151
|
+
insn 'n'
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|