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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +89 -0
- data/COPYING.LESSER +165 -0
- data/README.md +131 -0
- data/bin/config/pdfcop.conf.yml +236 -0
- data/bin/pdf2pdfa +87 -0
- data/bin/pdf2ruby +333 -0
- data/bin/pdfcop +476 -0
- data/bin/pdfdecompress +97 -0
- data/bin/pdfdecrypt +91 -0
- data/bin/pdfencrypt +113 -0
- data/bin/pdfexplode +223 -0
- data/bin/pdfextract +277 -0
- data/bin/pdfmetadata +143 -0
- data/bin/pdfsh +12 -0
- data/bin/shell/console.rb +128 -0
- data/bin/shell/hexdump.rb +59 -0
- data/bin/shell/irbrc +69 -0
- data/examples/README.md +34 -0
- data/examples/attachments/attachment.rb +38 -0
- data/examples/attachments/nested_document.rb +51 -0
- data/examples/encryption/encryption.rb +28 -0
- data/examples/events/events.rb +72 -0
- data/examples/flash/flash.rb +37 -0
- data/examples/flash/helloworld.swf +0 -0
- data/examples/forms/javascript.rb +54 -0
- data/examples/forms/xfa.rb +115 -0
- data/examples/javascript/hello_world.rb +22 -0
- data/examples/javascript/js_emulation.rb +54 -0
- data/examples/loop/goto.rb +32 -0
- data/examples/loop/named.rb +33 -0
- data/examples/signature/signature.rb +65 -0
- data/examples/uri/javascript.rb +56 -0
- data/examples/uri/open-uri.rb +21 -0
- data/examples/uri/submitform.rb +47 -0
- data/lib/origami/3d.rb +364 -0
- data/lib/origami/acroform.rb +321 -0
- data/lib/origami/actions.rb +318 -0
- data/lib/origami/annotations.rb +711 -0
- data/lib/origami/array.rb +242 -0
- data/lib/origami/boolean.rb +90 -0
- data/lib/origami/catalog.rb +418 -0
- data/lib/origami/collections.rb +144 -0
- data/lib/origami/compound.rb +161 -0
- data/lib/origami/destinations.rb +252 -0
- data/lib/origami/dictionary.rb +192 -0
- data/lib/origami/encryption.rb +1084 -0
- data/lib/origami/extensions/fdf.rb +347 -0
- data/lib/origami/extensions/ppklite.rb +422 -0
- data/lib/origami/filespec.rb +197 -0
- data/lib/origami/filters/ascii.rb +211 -0
- data/lib/origami/filters/ccitt/tables.rb +267 -0
- data/lib/origami/filters/ccitt.rb +357 -0
- data/lib/origami/filters/crypt.rb +38 -0
- data/lib/origami/filters/dct.rb +54 -0
- data/lib/origami/filters/flate.rb +69 -0
- data/lib/origami/filters/jbig2.rb +57 -0
- data/lib/origami/filters/jpx.rb +47 -0
- data/lib/origami/filters/lzw.rb +170 -0
- data/lib/origami/filters/predictors.rb +292 -0
- data/lib/origami/filters/runlength.rb +129 -0
- data/lib/origami/filters.rb +364 -0
- data/lib/origami/font.rb +196 -0
- data/lib/origami/functions.rb +79 -0
- data/lib/origami/graphics/colors.rb +230 -0
- data/lib/origami/graphics/instruction.rb +98 -0
- data/lib/origami/graphics/path.rb +182 -0
- data/lib/origami/graphics/patterns.rb +174 -0
- data/lib/origami/graphics/render.rb +62 -0
- data/lib/origami/graphics/state.rb +149 -0
- data/lib/origami/graphics/text.rb +225 -0
- data/lib/origami/graphics/xobject.rb +918 -0
- data/lib/origami/graphics.rb +38 -0
- data/lib/origami/header.rb +75 -0
- data/lib/origami/javascript.rb +713 -0
- data/lib/origami/linearization.rb +330 -0
- data/lib/origami/metadata.rb +172 -0
- data/lib/origami/name.rb +135 -0
- data/lib/origami/null.rb +65 -0
- data/lib/origami/numeric.rb +181 -0
- data/lib/origami/obfuscation.rb +245 -0
- data/lib/origami/object.rb +760 -0
- data/lib/origami/optionalcontent.rb +183 -0
- data/lib/origami/outline.rb +54 -0
- data/lib/origami/outputintents.rb +85 -0
- data/lib/origami/page.rb +722 -0
- data/lib/origami/parser.rb +269 -0
- data/lib/origami/parsers/fdf.rb +56 -0
- data/lib/origami/parsers/pdf/lazy.rb +176 -0
- data/lib/origami/parsers/pdf/linear.rb +122 -0
- data/lib/origami/parsers/pdf.rb +118 -0
- data/lib/origami/parsers/ppklite.rb +57 -0
- data/lib/origami/pdf.rb +1108 -0
- data/lib/origami/reference.rb +134 -0
- data/lib/origami/signature.rb +702 -0
- data/lib/origami/stream.rb +705 -0
- data/lib/origami/string.rb +444 -0
- data/lib/origami/template/patterns.rb +56 -0
- data/lib/origami/template/widgets.rb +151 -0
- data/lib/origami/trailer.rb +190 -0
- data/lib/origami/tree.rb +62 -0
- data/lib/origami/version.rb +23 -0
- data/lib/origami/webcapture.rb +100 -0
- data/lib/origami/xfa/config.rb +453 -0
- data/lib/origami/xfa/connectionset.rb +146 -0
- data/lib/origami/xfa/datasets.rb +49 -0
- data/lib/origami/xfa/localeset.rb +42 -0
- data/lib/origami/xfa/package.rb +59 -0
- data/lib/origami/xfa/pdf.rb +73 -0
- data/lib/origami/xfa/signature.rb +42 -0
- data/lib/origami/xfa/sourceset.rb +43 -0
- data/lib/origami/xfa/stylesheet.rb +44 -0
- data/lib/origami/xfa/template.rb +1691 -0
- data/lib/origami/xfa/xdc.rb +42 -0
- data/lib/origami/xfa/xfa.rb +146 -0
- data/lib/origami/xfa/xfdf.rb +43 -0
- data/lib/origami/xfa/xmpmeta.rb +43 -0
- data/lib/origami/xfa.rb +62 -0
- data/lib/origami/xreftable.rb +557 -0
- data/lib/origami.rb +47 -0
- data/test/dataset/calc.pdf +85 -0
- data/test/dataset/crypto.pdf +36 -0
- data/test/dataset/empty.pdf +49 -0
- data/test/test_actions.rb +27 -0
- data/test/test_annotations.rb +68 -0
- data/test/test_forms.rb +30 -0
- data/test/test_native_types.rb +83 -0
- data/test/test_object_tree.rb +33 -0
- data/test/test_pages.rb +60 -0
- data/test/test_pdf.rb +20 -0
- data/test/test_pdf_attachment.rb +34 -0
- data/test/test_pdf_create.rb +24 -0
- data/test/test_pdf_encrypt.rb +102 -0
- data/test/test_pdf_parse.rb +134 -0
- data/test/test_pdf_parse_lazy.rb +69 -0
- data/test/test_pdf_sign.rb +97 -0
- data/test/test_streams.rb +184 -0
- data/test/test_xrefs.rb +67 -0
- metadata +280 -0
@@ -0,0 +1,230 @@
|
|
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
|
+
class InvalidColorError < Error #:nodoc:
|
26
|
+
end
|
27
|
+
|
28
|
+
module Color
|
29
|
+
|
30
|
+
module Intent
|
31
|
+
ABSOLUTE = :AbsoluteColorimetric
|
32
|
+
RELATIVE = :RelativeColorimetric
|
33
|
+
SATURATION = :Saturation
|
34
|
+
PERCEPTUAL = :Perceptual
|
35
|
+
end
|
36
|
+
|
37
|
+
module BlendMode
|
38
|
+
NORMAL = :Normal
|
39
|
+
COMPATIBLE = :Compatible
|
40
|
+
MULTIPLY = :Multiply
|
41
|
+
SCREEN = :Screen
|
42
|
+
OVERLAY = :Overlay
|
43
|
+
DARKEN = :Darken
|
44
|
+
LIGHTEN = :Lighten
|
45
|
+
COLORDODGE = :ColorDodge
|
46
|
+
COLORBURN = :ColorBurn
|
47
|
+
HARDLIGHT = :HardLight
|
48
|
+
SOFTLIGHt = :SoftLight
|
49
|
+
DIFFERENCE = :Difference
|
50
|
+
EXCLUSION = :Exclusion
|
51
|
+
end
|
52
|
+
|
53
|
+
module Space
|
54
|
+
DEVICE_GRAY = :DeviceGray
|
55
|
+
DEVICE_RGB = :DeviceRGB
|
56
|
+
DEVICE_CMYK = :DeviceCMYK
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.cmyk_to_rgb(c, m, y, k)
|
60
|
+
r = 1 - (( c * ( 1 - k ) + k ))
|
61
|
+
g = 1 - (( m * ( 1 - k ) + k ))
|
62
|
+
b = 1 - (( y * ( 1 - k ) + k ))
|
63
|
+
|
64
|
+
[ r, g, b ]
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.gray_to_rgb(g)
|
68
|
+
[ g, g, g ]
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Class representing an embedded ICC Profile stream.
|
73
|
+
#
|
74
|
+
class ICCProfile < Stream
|
75
|
+
field :N, :Type => Integer, :Required => true, :Version => '1.3'
|
76
|
+
field :Alternate, :Type => [ Name, Array ]
|
77
|
+
field :Range, :Type => Array
|
78
|
+
field :Metadata, :Type => Stream, :Version => '1.4'
|
79
|
+
end
|
80
|
+
|
81
|
+
class GrayScale
|
82
|
+
attr_accessor :g
|
83
|
+
|
84
|
+
def initialize(g)
|
85
|
+
@g = g
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class RGB
|
90
|
+
attr_accessor :r,:g,:b
|
91
|
+
|
92
|
+
def initialize(r,g,b)
|
93
|
+
@r,@g,@b = r,g,b
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class CMYK
|
98
|
+
attr_accessor :c,:m,:y,:k
|
99
|
+
|
100
|
+
def initialize(c,m,y,k)
|
101
|
+
@c,@m,@y,@k = c,m,y,k
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def Color.to_a(color)
|
106
|
+
return color if color.is_a?(::Array)
|
107
|
+
|
108
|
+
if %i(r g b).all? {|c| color.respond_to?(c)}
|
109
|
+
r = color.r.to_f / 255
|
110
|
+
g = color.g.to_f / 255
|
111
|
+
b = color.b.to_f / 255
|
112
|
+
return [r, g, b]
|
113
|
+
|
114
|
+
elsif %i(c m y k).all? {|c| color.respond_to?(c)}
|
115
|
+
c = color.c
|
116
|
+
m = color.m
|
117
|
+
y = color.y
|
118
|
+
k = color.k
|
119
|
+
return [c,m,y,k]
|
120
|
+
|
121
|
+
elsif color.respond_to?(:g)
|
122
|
+
g = color.g
|
123
|
+
return [g]
|
124
|
+
|
125
|
+
else
|
126
|
+
raise TypeError, "Invalid color : #{color}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class State
|
132
|
+
def set_stroking_color(color, space = @stroking_color_space)
|
133
|
+
check_color(space, color)
|
134
|
+
|
135
|
+
@stroking_colorspace = space
|
136
|
+
@stroking_color = color
|
137
|
+
end
|
138
|
+
|
139
|
+
def set_nonstroking_color(color, space = @nonstroking_colorspace)
|
140
|
+
check_color(space, color)
|
141
|
+
|
142
|
+
@nonstroking_colorspace = space
|
143
|
+
@nonstroking_color = color
|
144
|
+
end
|
145
|
+
|
146
|
+
def set_stroking_colorspace(space)
|
147
|
+
check_color_space(space, @stroking_color)
|
148
|
+
|
149
|
+
@stroking_color_space = space
|
150
|
+
end
|
151
|
+
|
152
|
+
def set_nonstroking_colorspace(space)
|
153
|
+
check_color_space(space, @nonstroking_color)
|
154
|
+
|
155
|
+
@nonstroking_color_space = space
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def check_color_space(space)
|
161
|
+
case space
|
162
|
+
when Color::Space::DEVICE_GRAY, Color::Space::DEVICE_RGB, Color::Space::DEVICE_CMYK
|
163
|
+
else
|
164
|
+
raise InvalidColorError, "Unknown color space #{space}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def check_color(space, color)
|
169
|
+
valid_color =
|
170
|
+
case space
|
171
|
+
when Color::Space::DEVICE_GRAY
|
172
|
+
check_gray_color(color)
|
173
|
+
when Color::Space::DEVICE_RGB
|
174
|
+
check_rgb_color(color)
|
175
|
+
when Color::Space::DEVICE_CMYK
|
176
|
+
check_cmyk_color(color)
|
177
|
+
else
|
178
|
+
raise InvalidColorError, "Unknown color space #{space}"
|
179
|
+
end
|
180
|
+
|
181
|
+
raise InvalidColorError, "Invalid color #{color.inspect} for #{space}" unless valid_color
|
182
|
+
end
|
183
|
+
|
184
|
+
def check_gray_color(color)
|
185
|
+
color.is_a?(::Array) and color.length == 1 and (0..1).include?(color[0])
|
186
|
+
end
|
187
|
+
|
188
|
+
def check_rgb_color(color)
|
189
|
+
color.is_a?(::Array) and color.length == 3 and color.all? {|c| (0..1).include?(c) }
|
190
|
+
end
|
191
|
+
|
192
|
+
def check_cmyk_color(color)
|
193
|
+
color.is_a?(::Array) and color.length == 4 and color.all? {|c| (0..1).include?(c) }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
class PDF::Instruction
|
199
|
+
|
200
|
+
insn 'CS', Name do |canvas, cs| canvas.gs.set_stroking_colorspace(cs) end
|
201
|
+
insn 'cs', Name do |canvas, cs| canvas.gs.set_nonstroking_colorspace(cs) end
|
202
|
+
insn 'SC', '*' do |canvas, *c| canvas.gs.set_stroking_color(c) end
|
203
|
+
insn 'sc', '*' do |canvas, *c| canvas.gs.set_nonstroking_color(c) end
|
204
|
+
|
205
|
+
insn 'G', Real do |canvas, c|
|
206
|
+
canvas.gs.set_stroking_color([c], Graphics::Color::Space::DEVICE_GRAY)
|
207
|
+
end
|
208
|
+
|
209
|
+
insn 'g', Real do |canvas, c|
|
210
|
+
canvas.gs.set_nonstroking_color([c], Graphics::Color::Space::DEVICE_GRAY)
|
211
|
+
end
|
212
|
+
|
213
|
+
insn 'RG', Real, Real, Real do |canvas, r, g, b|
|
214
|
+
canvas.gs.set_stroking_color([r, g, b], Graphics::Color::Space::DEVICE_RGB)
|
215
|
+
end
|
216
|
+
|
217
|
+
insn 'rg', Real, Real, Real do |canvas, r, g, b|
|
218
|
+
canvas.gs.set_nonstroking_color([r, g, b], Graphics::Color::Space::DEVICE_RGB)
|
219
|
+
end
|
220
|
+
|
221
|
+
insn 'K', Real, Real, Real, Real do |canvas, c, m, y, k|
|
222
|
+
canvas.gs.set_stroking_color([c, m, y, k], Graphics::Color::Space::DEVICE_CMYK)
|
223
|
+
end
|
224
|
+
|
225
|
+
insn 'k', Real, Real, Real, Real do |canvas, c, m, y, k|
|
226
|
+
canvas.gs.set_nonstroking_color([c, m, y, k], Graphics::Color::Space::DEVICE_CMYK)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
@@ -0,0 +1,98 @@
|
|
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
|
+
class InvalidPDFInstructionError < Error; end
|
24
|
+
|
25
|
+
class PDF::Instruction
|
26
|
+
using TypeConversion
|
27
|
+
|
28
|
+
attr_reader :operator
|
29
|
+
attr_accessor :operands
|
30
|
+
|
31
|
+
@insns = Hash.new(operands: [], render: lambda{})
|
32
|
+
|
33
|
+
def initialize(operator, *operands)
|
34
|
+
@operator = operator
|
35
|
+
@operands = operands.map!{|arg| arg.is_a?(Origami::Object) ? arg.value : arg}
|
36
|
+
|
37
|
+
if self.class.has_op?(operator)
|
38
|
+
opdef = self.class.get_operands(operator)
|
39
|
+
|
40
|
+
if not opdef.include?('*') and opdef.size != operands.size
|
41
|
+
raise InvalidPDFInstructionError,
|
42
|
+
"Numbers of operands mismatch for #{operator}: #{operands.inspect}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def render(canvas)
|
48
|
+
self.class.get_render_proc(@operator)[canvas, *@operands]
|
49
|
+
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
"#{operands.map{|op| op.to_o.to_s}.join(' ')}#{' ' unless operands.empty?}#{operator}\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
class << self
|
58
|
+
def insn(operator, *operands, &render_proc)
|
59
|
+
@insns[operator] = {}
|
60
|
+
@insns[operator][:operands] = operands
|
61
|
+
@insns[operator][:render] = render_proc || lambda{}
|
62
|
+
end
|
63
|
+
|
64
|
+
def has_op?(operator)
|
65
|
+
@insns.has_key? operator
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_render_proc(operator)
|
69
|
+
@insns[operator][:render]
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_operands(operator)
|
73
|
+
@insns[operator][:operands]
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse(stream)
|
77
|
+
operands = []
|
78
|
+
while type = Object.typeof(stream, true)
|
79
|
+
operands.push type.parse(stream)
|
80
|
+
end
|
81
|
+
|
82
|
+
if not stream.eos?
|
83
|
+
if stream.scan(/(?<operator>[[:graph:]&&[^\[\]<>()%\/]]+)/).nil?
|
84
|
+
raise InvalidPDFInstructionError, "Operator: #{(stream.peek(10) + '...').inspect}"
|
85
|
+
end
|
86
|
+
|
87
|
+
operator = stream['operator']
|
88
|
+
PDF::Instruction.new(operator, *operands)
|
89
|
+
else
|
90
|
+
unless operands.empty?
|
91
|
+
raise InvalidPDFInstructionError, "No operator given for operands: #{operands.map(&:to_s).join(' ')}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,182 @@
|
|
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 LineCapStyle
|
26
|
+
BUTT_CAP = 0
|
27
|
+
ROUND_CAP = 1
|
28
|
+
PROJECTING_SQUARE_CAP = 2
|
29
|
+
end
|
30
|
+
|
31
|
+
module LineJoinStyle
|
32
|
+
MITER_JOIN = 0
|
33
|
+
ROUND_JOIN = 1
|
34
|
+
BEVEL_JOIN = 2
|
35
|
+
end
|
36
|
+
|
37
|
+
class DashPattern
|
38
|
+
attr_accessor :array, :phase
|
39
|
+
|
40
|
+
def initialize(array, phase = 0)
|
41
|
+
@array = array
|
42
|
+
@phase = phase
|
43
|
+
end
|
44
|
+
|
45
|
+
def eql?(dash) #:nodoc
|
46
|
+
dash.array == @array and dash.phase == @phase
|
47
|
+
end
|
48
|
+
|
49
|
+
def hash #:nodoc:
|
50
|
+
[ @array, @phase ].hash
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class InvalidPathError < Error #:nodoc:
|
55
|
+
end
|
56
|
+
|
57
|
+
class Path
|
58
|
+
module Segment
|
59
|
+
attr_accessor :from, :to
|
60
|
+
|
61
|
+
def initialize(from, to)
|
62
|
+
@from, @to = from, to
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Line
|
67
|
+
include Segment
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_accessor :current_point
|
71
|
+
attr_reader :segments
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
@segments = []
|
75
|
+
@current_point = nil
|
76
|
+
@closed = false
|
77
|
+
end
|
78
|
+
|
79
|
+
def is_closed?
|
80
|
+
@closed
|
81
|
+
end
|
82
|
+
|
83
|
+
def close!
|
84
|
+
from = @current_point
|
85
|
+
to = @segments.first.from
|
86
|
+
|
87
|
+
@segments << Line.new(from, to)
|
88
|
+
@segments.freeze
|
89
|
+
@closed = true
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_segment(seg)
|
93
|
+
raise GraphicsStateError, "Cannot modify closed subpath" if is_closed?
|
94
|
+
|
95
|
+
@segments << seg
|
96
|
+
@current_point = seg.to
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class PDF::Instruction
|
102
|
+
insn 'm', Real, Real do |canvas, x,y|
|
103
|
+
canvas.gs.current_path << (subpath = Graphics::Path.new)
|
104
|
+
subpath.current_point = [x,y]
|
105
|
+
end
|
106
|
+
|
107
|
+
insn 'l', Real, Real do |canvas, x,y|
|
108
|
+
if canvas.gs.current_path.empty?
|
109
|
+
raise InvalidPathError, "No current point is defined"
|
110
|
+
end
|
111
|
+
|
112
|
+
subpath = canvas.gs.current_path.last
|
113
|
+
|
114
|
+
from = subpath.current_point
|
115
|
+
to = [x,y]
|
116
|
+
subpath.add_segment(Graphics::Path::Line.new(from, to))
|
117
|
+
end
|
118
|
+
|
119
|
+
insn 'h' do |canvas|
|
120
|
+
unless canvas.gs.current_path.empty?
|
121
|
+
subpath = canvas.gs.current_path.last
|
122
|
+
subpath.close! unless subpath.is_closed?
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
insn 're', Real, Real, Real, Real do |canvas, x,y,width,height|
|
127
|
+
tx = x + width
|
128
|
+
ty = y + height
|
129
|
+
canvas.gs.current_path << (subpath = Graphics::Path.new)
|
130
|
+
subpath.segments << Graphics::Path::Line.new([x,y], [tx,y])
|
131
|
+
subpath.segments << Graphics::Path::Line.new([tx,y], [tx, ty])
|
132
|
+
subpath.segments << Graphics::Path::Line.new([tx, ty], [x, ty])
|
133
|
+
subpath.close!
|
134
|
+
end
|
135
|
+
|
136
|
+
insn 'S' do |canvas|
|
137
|
+
canvas.stroke_path
|
138
|
+
end
|
139
|
+
|
140
|
+
insn 's' do |canvas|
|
141
|
+
canvas.gs.current_path.last.close!
|
142
|
+
canvas.stroke_path
|
143
|
+
end
|
144
|
+
|
145
|
+
insn 'f' do |canvas|
|
146
|
+
canvas.fill_path
|
147
|
+
end
|
148
|
+
|
149
|
+
insn 'F' do |canvas|
|
150
|
+
canvas.fill_path
|
151
|
+
end
|
152
|
+
|
153
|
+
insn 'f*' do |canvas|
|
154
|
+
canvas.fill_path
|
155
|
+
end
|
156
|
+
|
157
|
+
insn 'B' do |canvas|
|
158
|
+
canvas.fill_path
|
159
|
+
canvas.stroke_path
|
160
|
+
end
|
161
|
+
|
162
|
+
insn 'B*' do |canvas|
|
163
|
+
canvas.fill_path
|
164
|
+
canvas.stroke_path
|
165
|
+
end
|
166
|
+
|
167
|
+
insn 'b' do |canvas|
|
168
|
+
canvas.gs.current_path.last.close!
|
169
|
+
canvas.fill_path
|
170
|
+
canvas.stroke_path
|
171
|
+
end
|
172
|
+
|
173
|
+
insn 'b*' do |canvas|
|
174
|
+
canvas.gs.current_path.last.close!
|
175
|
+
canvas.fill_path
|
176
|
+
canvas.stroke_path
|
177
|
+
end
|
178
|
+
|
179
|
+
insn 'n'
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
@@ -0,0 +1,174 @@
|
|
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 Pattern
|
26
|
+
module Type
|
27
|
+
TILING = 1
|
28
|
+
SHADING = 2
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.included(receiver)
|
32
|
+
receiver.field :Type, :Type => Name, :Default => :Pattern
|
33
|
+
receiver.field :PatternType, :Type => Integer, :Required => true
|
34
|
+
end
|
35
|
+
|
36
|
+
class Tiling < ContentStream
|
37
|
+
include Pattern
|
38
|
+
include ResourcesHolder
|
39
|
+
|
40
|
+
module PaintType
|
41
|
+
COLOURED = 1
|
42
|
+
UNCOLOURED = 2
|
43
|
+
end
|
44
|
+
|
45
|
+
module Type
|
46
|
+
CONSTANT_SPACING = 1
|
47
|
+
NO_DISTORTION = 2
|
48
|
+
CONSTANT_SPACING_AND_FASTER_TILING = 3
|
49
|
+
end
|
50
|
+
|
51
|
+
field :PatternType, :Type => Integer, :Default => Pattern::Type::TILING, :Required => true
|
52
|
+
field :PaintType, :Type => Integer, :Required => true
|
53
|
+
field :TilingType, :Type => Integer, :Required => true
|
54
|
+
field :BBox, :Type => Rectangle, :Required => true
|
55
|
+
field :XStep, :Type => Number, :Required => true
|
56
|
+
field :YStep, :Type => Number, :Required => true
|
57
|
+
field :Resources, :Type => Resources, :Required => true
|
58
|
+
field :Matrix, :Type => Array.of(Number, length: 6), :Default => [ 1, 0, 0, 1, 0, 0 ]
|
59
|
+
end
|
60
|
+
|
61
|
+
class Shading < Dictionary
|
62
|
+
include StandardObject
|
63
|
+
include Pattern
|
64
|
+
|
65
|
+
module Type
|
66
|
+
FUNCTION_BASED = 1
|
67
|
+
AXIAL = 2
|
68
|
+
RADIAL = 3
|
69
|
+
FREEFORM_TRIANGLE_MESH = 4
|
70
|
+
LATTICEFORM_TRIANGLE_MESH = 5
|
71
|
+
COONS_PATCH_MESH = 6
|
72
|
+
TENSORPRODUCT_PATCH_MESH = 7
|
73
|
+
end
|
74
|
+
|
75
|
+
field :PatternType, :Type => Integer, :Default => Pattern::Type::SHADING, :Required => true
|
76
|
+
field :Shading, :Type => [ Dictionary, Stream ], :Required => true
|
77
|
+
field :Matrix, :Type => Array.of(Number, length: 6), :Default => [ 1, 0, 0, 1, 0, 0 ]
|
78
|
+
field :ExtGState, :Type => ExtGState
|
79
|
+
|
80
|
+
# Fields common to all shading objects.
|
81
|
+
module ShadingObject
|
82
|
+
def self.included(receiver)
|
83
|
+
receiver.field :ShadingType, :Type => Integer, :Required => true
|
84
|
+
receiver.field :ColorSpace, :Type => [ Name, Array ], :Required => true
|
85
|
+
receiver.field :Background, :Type => Array
|
86
|
+
receiver.field :BBox, :Type => Rectangle
|
87
|
+
receiver.field :AntiAlias, :Type => Boolean, :Default => false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Fields common to all Mesh shadings.
|
92
|
+
module Mesh
|
93
|
+
def self.included(receiver)
|
94
|
+
receiver.field :BitsPerCoordinate, :Type => Integer, :Required => true
|
95
|
+
receiver.field :BitsPerComponent, :Type => Integer, :Required => true
|
96
|
+
receiver.field :Decode, :Type => Array.of(Number), :Required => true
|
97
|
+
receiver.field :Function, :Type => [ Dictionary, Stream ]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class FunctionBased < Dictionary
|
102
|
+
include StandardObject
|
103
|
+
include ShadingObject
|
104
|
+
|
105
|
+
field :ShadingType, :Type => Integer, :Default => Shading::Type::FUNCTION_BASED, :Required => true
|
106
|
+
field :Domain, :Type => Array.of(Number, length: 4), :Default => [ 0.0, 1.0, 0.0, 1.0 ]
|
107
|
+
field :Matrix, :Type => Array.of(Number, length: 6), :Default => [ 1, 0, 0, 1, 0, 0 ]
|
108
|
+
field :Function, :Type => [ Dictionary, Stream ], :Required => true
|
109
|
+
end
|
110
|
+
|
111
|
+
class Axial < Dictionary
|
112
|
+
include StandardObject
|
113
|
+
include ShadingObject
|
114
|
+
|
115
|
+
field :ShadingType, :Type => Integer, :Default => Shading::Type::AXIAL, :Required => true
|
116
|
+
field :Coords, :Type => Array.of(Number, length: 4), :Required => true
|
117
|
+
field :Domain, :Type => Array.of(Number, length: 2), :Default => [ 0.0, 1.0 ]
|
118
|
+
field :Function, :Type => [ Dictionary, Stream ], :Required => true
|
119
|
+
field :Extend, :Type => Array.of(Boolean, length: 2), :Default => [ false, false ]
|
120
|
+
end
|
121
|
+
|
122
|
+
class Radial < Dictionary
|
123
|
+
include StandardObject
|
124
|
+
include ShadingObject
|
125
|
+
|
126
|
+
field :ShadingType, :Type => Integer, :Default => Shading::Type::RADIAL, :Required => true
|
127
|
+
field :Coords, :Type => Array.of(Number, length: 6), :Required => true
|
128
|
+
field :Domain, :Type => Array.of(Number, length: 2), :Default => [ 0.0, 1.0 ]
|
129
|
+
field :Function, :Type => [ Dictionary, Stream ], :Required => true
|
130
|
+
field :Extend, :Type => Array.of(Boolean, length: 2), :Default => [ false, false ]
|
131
|
+
end
|
132
|
+
|
133
|
+
class FreeFormTriangleMesh < Stream
|
134
|
+
include ShadingObject
|
135
|
+
include Mesh
|
136
|
+
|
137
|
+
field :ShadingType, :Type => Integer, :Default => Shading::Type::FREEFORM_TRIANGLE_MESH, :Required => true
|
138
|
+
field :BitsPerFlag, :Type => Integer, :Required => true
|
139
|
+
end
|
140
|
+
|
141
|
+
class LatticeFormTriangleMesh < Stream
|
142
|
+
include ShadingObject
|
143
|
+
include Mesh
|
144
|
+
|
145
|
+
field :ShadingType, :Type => Integer, :Default => Shading::Type::LATTICEFORM_TRIANGLE_MESH, :Required => true
|
146
|
+
field :VerticesPerRow, :Type => Integer, :Required => true
|
147
|
+
end
|
148
|
+
|
149
|
+
class CoonsPathMesh < Stream
|
150
|
+
include ShadingObject
|
151
|
+
include Mesh
|
152
|
+
|
153
|
+
field :ShadingType, :Type => Integer, :Default => Shading::Type::COONS_PATCH_MESH, :Required => true
|
154
|
+
field :BitsPerFlag, :Type => Integer, :Required => true
|
155
|
+
end
|
156
|
+
|
157
|
+
class TensorProductPatchMesh < Stream
|
158
|
+
include ShadingObject
|
159
|
+
|
160
|
+
field :ShadingType, :Type => Integer, :Default => Shading::Type::TENSORPRODUCT_PATCH_MESH, :Required => true
|
161
|
+
field :BitsPerFlag, :Type => Integer, :Required => true
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class PDF::Instruction
|
169
|
+
insn 'sh', Name do |canvas, shading|
|
170
|
+
canvas.paint_shading(shading)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|