origami-docspring 2.2.0 → 2.3.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 +4 -4
- data/CHANGELOG.md +18 -0
- data/examples/attachments/attachment.rb +7 -8
- data/examples/attachments/nested_document.rb +6 -5
- data/examples/encryption/encryption.rb +5 -4
- data/examples/events/events.rb +7 -6
- data/examples/flash/flash.rb +10 -9
- data/examples/forms/javascript.rb +14 -13
- data/examples/forms/xfa.rb +67 -66
- data/examples/javascript/hello_world.rb +6 -5
- data/examples/javascript/js_emulation.rb +26 -26
- data/examples/loop/goto.rb +12 -11
- data/examples/loop/named.rb +17 -16
- data/examples/signature/signature.rb +11 -11
- data/examples/uri/javascript.rb +25 -24
- data/examples/uri/open-uri.rb +5 -4
- data/examples/uri/submitform.rb +11 -10
- data/lib/origami/3d.rb +330 -334
- data/lib/origami/acroform.rb +267 -268
- data/lib/origami/actions.rb +266 -278
- data/lib/origami/annotations.rb +659 -670
- data/lib/origami/array.rb +192 -196
- data/lib/origami/boolean.rb +66 -70
- data/lib/origami/catalog.rb +360 -363
- data/lib/origami/collections.rb +132 -133
- data/lib/origami/compound.rb +125 -129
- data/lib/origami/destinations.rb +226 -237
- data/lib/origami/dictionary.rb +155 -154
- data/lib/origami/encryption.rb +967 -923
- data/lib/origami/extensions/fdf.rb +270 -275
- data/lib/origami/extensions/ppklite.rb +323 -328
- data/lib/origami/filespec.rb +170 -173
- data/lib/origami/filters/ascii.rb +162 -167
- data/lib/origami/filters/ccitt/tables.rb +248 -252
- data/lib/origami/filters/ccitt.rb +309 -312
- data/lib/origami/filters/crypt.rb +31 -34
- data/lib/origami/filters/dct.rb +47 -50
- data/lib/origami/filters/flate.rb +57 -60
- data/lib/origami/filters/jbig2.rb +50 -53
- data/lib/origami/filters/jpx.rb +40 -43
- data/lib/origami/filters/lzw.rb +151 -155
- data/lib/origami/filters/predictors.rb +250 -255
- data/lib/origami/filters/runlength.rb +111 -115
- data/lib/origami/filters.rb +319 -325
- data/lib/origami/font.rb +173 -177
- data/lib/origami/functions.rb +62 -66
- data/lib/origami/graphics/colors.rb +203 -208
- data/lib/origami/graphics/instruction.rb +79 -81
- data/lib/origami/graphics/path.rb +141 -144
- data/lib/origami/graphics/patterns.rb +156 -160
- data/lib/origami/graphics/render.rb +51 -47
- data/lib/origami/graphics/state.rb +144 -142
- data/lib/origami/graphics/text.rb +185 -188
- data/lib/origami/graphics/xobject.rb +818 -804
- data/lib/origami/graphics.rb +25 -26
- data/lib/origami/header.rb +63 -65
- data/lib/origami/javascript.rb +718 -651
- data/lib/origami/linearization.rb +284 -285
- data/lib/origami/metadata.rb +156 -135
- data/lib/origami/name.rb +98 -100
- data/lib/origami/null.rb +49 -51
- data/lib/origami/numeric.rb +133 -135
- data/lib/origami/obfuscation.rb +180 -182
- data/lib/origami/object.rb +634 -631
- data/lib/origami/optionalcontent.rb +147 -149
- data/lib/origami/outline.rb +46 -48
- data/lib/origami/outputintents.rb +76 -77
- data/lib/origami/page.rb +637 -596
- data/lib/origami/parser.rb +214 -221
- data/lib/origami/parsers/fdf.rb +44 -45
- data/lib/origami/parsers/pdf/lazy.rb +147 -154
- data/lib/origami/parsers/pdf/linear.rb +104 -109
- data/lib/origami/parsers/pdf.rb +109 -107
- data/lib/origami/parsers/ppklite.rb +44 -46
- data/lib/origami/pdf.rb +886 -896
- data/lib/origami/reference.rb +116 -120
- data/lib/origami/signature.rb +617 -625
- data/lib/origami/stream.rb +560 -558
- data/lib/origami/string.rb +366 -368
- data/lib/origami/template/patterns.rb +50 -52
- data/lib/origami/template/widgets.rb +111 -114
- data/lib/origami/trailer.rb +153 -157
- data/lib/origami/tree.rb +55 -57
- data/lib/origami/version.rb +19 -19
- data/lib/origami/webcapture.rb +87 -90
- data/lib/origami/xfa/config.rb +409 -414
- data/lib/origami/xfa/connectionset.rb +113 -117
- data/lib/origami/xfa/datasets.rb +38 -42
- data/lib/origami/xfa/localeset.rb +33 -37
- data/lib/origami/xfa/package.rb +49 -52
- data/lib/origami/xfa/pdf.rb +54 -59
- data/lib/origami/xfa/signature.rb +33 -37
- data/lib/origami/xfa/sourceset.rb +34 -38
- data/lib/origami/xfa/stylesheet.rb +35 -39
- data/lib/origami/xfa/template.rb +1630 -1634
- data/lib/origami/xfa/xdc.rb +33 -37
- data/lib/origami/xfa/xfa.rb +132 -123
- data/lib/origami/xfa/xfdf.rb +34 -38
- data/lib/origami/xfa/xmpmeta.rb +34 -38
- data/lib/origami/xfa.rb +50 -53
- data/lib/origami/xreftable.rb +462 -462
- data/lib/origami.rb +37 -38
- data/test/test_actions.rb +22 -20
- data/test/test_annotations.rb +54 -52
- data/test/test_forms.rb +23 -21
- data/test/test_native_types.rb +82 -78
- data/test/test_object_tree.rb +25 -24
- data/test/test_pages.rb +43 -41
- data/test/test_pdf.rb +2 -0
- data/test/test_pdf_attachment.rb +23 -21
- data/test/test_pdf_create.rb +16 -15
- data/test/test_pdf_encrypt.rb +69 -66
- data/test/test_pdf_parse.rb +131 -129
- data/test/test_pdf_parse_lazy.rb +53 -53
- data/test/test_pdf_sign.rb +67 -67
- data/test/test_streams.rb +145 -143
- data/test/test_xrefs.rb +46 -45
- metadata +64 -8
@@ -1,230 +1,225 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# This file is part of Origami, PDF manipulation framework for Ruby
|
5
|
+
# Copyright (C) 2016 Guillaume Delugré.
|
6
|
+
#
|
7
|
+
# Origami is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# Origami is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#
|
2
20
|
|
3
|
-
|
4
|
-
|
21
|
+
module Origami
|
22
|
+
module Graphics
|
23
|
+
class InvalidColorError < Error # :nodoc:
|
24
|
+
end
|
5
25
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
26
|
+
module Color
|
27
|
+
module Intent
|
28
|
+
ABSOLUTE = :AbsoluteColorimetric
|
29
|
+
RELATIVE = :RelativeColorimetric
|
30
|
+
SATURATION = :Saturation
|
31
|
+
PERCEPTUAL = :Perceptual
|
32
|
+
end
|
33
|
+
|
34
|
+
module BlendMode
|
35
|
+
NORMAL = :Normal
|
36
|
+
COMPATIBLE = :Compatible
|
37
|
+
MULTIPLY = :Multiply
|
38
|
+
SCREEN = :Screen
|
39
|
+
OVERLAY = :Overlay
|
40
|
+
DARKEN = :Darken
|
41
|
+
LIGHTEN = :Lighten
|
42
|
+
COLORDODGE = :ColorDodge
|
43
|
+
COLORBURN = :ColorBurn
|
44
|
+
HARDLIGHT = :HardLight
|
45
|
+
SOFTLIGHT = :SoftLight
|
46
|
+
DIFFERENCE = :Difference
|
47
|
+
EXCLUSION = :Exclusion
|
48
|
+
end
|
49
|
+
|
50
|
+
module Space
|
51
|
+
DEVICE_GRAY = :DeviceGray
|
52
|
+
DEVICE_RGB = :DeviceRGB
|
53
|
+
DEVICE_CMYK = :DeviceCMYK
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.cmyk_to_rgb(c, m, y, k)
|
57
|
+
r = 1 - ((c * (1 - k) + k))
|
58
|
+
g = 1 - ((m * (1 - k) + k))
|
59
|
+
b = 1 - ((y * (1 - k) + k))
|
60
|
+
|
61
|
+
[r, g, b]
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.gray_to_rgb(g)
|
65
|
+
[g, g, g]
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Class representing an embedded ICC Profile stream.
|
70
|
+
#
|
71
|
+
class ICCProfile < Stream
|
72
|
+
field :N, Type: Integer, Required: true, Version: '1.3'
|
73
|
+
field :Alternate, Type: [Name, Array]
|
74
|
+
field :Range, Type: Array
|
75
|
+
field :Metadata, Type: Stream, Version: '1.4'
|
76
|
+
end
|
77
|
+
|
78
|
+
class GrayScale
|
79
|
+
attr_accessor :g
|
80
|
+
|
81
|
+
def initialize(g)
|
82
|
+
@g = g
|
83
|
+
end
|
84
|
+
end
|
10
85
|
|
11
|
-
|
12
|
-
|
13
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
GNU Lesser General Public License for more details.
|
86
|
+
class RGB
|
87
|
+
attr_accessor :r, :g, :b
|
15
88
|
|
16
|
-
|
17
|
-
|
89
|
+
def initialize(r, g, b)
|
90
|
+
@r, @g, @b = r, g, b
|
91
|
+
end
|
92
|
+
end
|
18
93
|
|
19
|
-
|
94
|
+
class CMYK
|
95
|
+
attr_accessor :c, :m, :y, :k
|
20
96
|
|
21
|
-
|
97
|
+
def initialize(c, m, y, k)
|
98
|
+
@c, @m, @y, @k = c, m, y, k
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.to_a(color)
|
103
|
+
return color if color.is_a?(::Array)
|
104
|
+
|
105
|
+
if %i[r g b].all? { |c| color.respond_to?(c) }
|
106
|
+
r = color.r.to_f / 255
|
107
|
+
g = color.g.to_f / 255
|
108
|
+
b = color.b.to_f / 255
|
109
|
+
[r, g, b]
|
110
|
+
|
111
|
+
elsif %i[c m y k].all? { |c| color.respond_to?(c) }
|
112
|
+
c = color.c
|
113
|
+
m = color.m
|
114
|
+
y = color.y
|
115
|
+
k = color.k
|
116
|
+
[c, m, y, k]
|
117
|
+
|
118
|
+
elsif color.respond_to?(:g)
|
119
|
+
g = color.g
|
120
|
+
[g]
|
121
|
+
|
122
|
+
else
|
123
|
+
raise TypeError, "Invalid color : #{color}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
22
127
|
|
23
|
-
|
128
|
+
class State
|
129
|
+
def set_stroking_color(color, space = @stroking_color_space)
|
130
|
+
check_color(space, color)
|
24
131
|
|
25
|
-
|
26
|
-
|
132
|
+
@stroking_colorspace = space
|
133
|
+
@stroking_color = color
|
134
|
+
end
|
27
135
|
|
28
|
-
|
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
|
136
|
+
def set_nonstroking_color(color, space = @nonstroking_colorspace)
|
137
|
+
check_color(space, color)
|
130
138
|
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
139
|
+
@nonstroking_colorspace = space
|
140
|
+
@nonstroking_color = color
|
141
|
+
end
|
197
142
|
|
198
|
-
|
143
|
+
def set_stroking_colorspace(space)
|
144
|
+
check_color_space(space, @stroking_color)
|
199
145
|
|
200
|
-
|
201
|
-
|
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
|
146
|
+
@stroking_color_space = space
|
147
|
+
end
|
204
148
|
|
205
|
-
|
206
|
-
|
207
|
-
end
|
149
|
+
def set_nonstroking_colorspace(space)
|
150
|
+
check_color_space(space, @nonstroking_color)
|
208
151
|
|
209
|
-
|
210
|
-
|
211
|
-
end
|
152
|
+
@nonstroking_color_space = space
|
153
|
+
end
|
212
154
|
|
213
|
-
|
214
|
-
canvas.gs.set_stroking_color([r, g, b], Graphics::Color::Space::DEVICE_RGB)
|
215
|
-
end
|
155
|
+
private
|
216
156
|
|
217
|
-
|
218
|
-
|
157
|
+
def check_color_space(space)
|
158
|
+
case space
|
159
|
+
when Color::Space::DEVICE_GRAY, Color::Space::DEVICE_RGB, Color::Space::DEVICE_CMYK
|
160
|
+
else
|
161
|
+
raise InvalidColorError, "Unknown color space #{space}"
|
219
162
|
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def check_color(space, color)
|
166
|
+
valid_color =
|
167
|
+
case space
|
168
|
+
when Color::Space::DEVICE_GRAY
|
169
|
+
check_gray_color(color)
|
170
|
+
when Color::Space::DEVICE_RGB
|
171
|
+
check_rgb_color(color)
|
172
|
+
when Color::Space::DEVICE_CMYK
|
173
|
+
check_cmyk_color(color)
|
174
|
+
else
|
175
|
+
raise InvalidColorError, "Unknown color space #{space}"
|
176
|
+
end
|
177
|
+
|
178
|
+
raise InvalidColorError, "Invalid color #{color.inspect} for #{space}" unless valid_color
|
179
|
+
end
|
180
|
+
|
181
|
+
def check_gray_color(color)
|
182
|
+
color.is_a?(::Array) and color.length == 1 and (0..1).include?(color[0])
|
183
|
+
end
|
184
|
+
|
185
|
+
def check_rgb_color(color)
|
186
|
+
color.is_a?(::Array) and color.length == 3 and color.all? { |c| (0..1).include?(c) }
|
187
|
+
end
|
188
|
+
|
189
|
+
def check_cmyk_color(color)
|
190
|
+
color.is_a?(::Array) and color.length == 4 and color.all? { |c| (0..1).include?(c) }
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
220
194
|
|
221
|
-
|
222
|
-
|
223
|
-
|
195
|
+
class PDF::Instruction
|
196
|
+
insn 'CS', Name do |canvas, cs| canvas.gs.set_stroking_colorspace(cs) end
|
197
|
+
insn 'cs', Name do |canvas, cs| canvas.gs.set_nonstroking_colorspace(cs) end
|
198
|
+
insn 'SC', '*' do |canvas, *c| canvas.gs.set_stroking_color(c) end
|
199
|
+
insn 'sc', '*' do |canvas, *c| canvas.gs.set_nonstroking_color(c) end
|
224
200
|
|
225
|
-
|
226
|
-
|
227
|
-
end
|
201
|
+
insn 'G', Real do |canvas, c|
|
202
|
+
canvas.gs.set_stroking_color([c], Graphics::Color::Space::DEVICE_GRAY)
|
228
203
|
end
|
229
204
|
|
205
|
+
insn 'g', Real do |canvas, c|
|
206
|
+
canvas.gs.set_nonstroking_color([c], Graphics::Color::Space::DEVICE_GRAY)
|
207
|
+
end
|
208
|
+
|
209
|
+
insn 'RG', Real, Real, Real do |canvas, r, g, b|
|
210
|
+
canvas.gs.set_stroking_color([r, g, b], Graphics::Color::Space::DEVICE_RGB)
|
211
|
+
end
|
212
|
+
|
213
|
+
insn 'rg', Real, Real, Real do |canvas, r, g, b|
|
214
|
+
canvas.gs.set_nonstroking_color([r, g, b], Graphics::Color::Space::DEVICE_RGB)
|
215
|
+
end
|
216
|
+
|
217
|
+
insn 'K', Real, Real, Real, Real do |canvas, c, m, y, k|
|
218
|
+
canvas.gs.set_stroking_color([c, m, y, k], Graphics::Color::Space::DEVICE_CMYK)
|
219
|
+
end
|
220
|
+
|
221
|
+
insn 'k', Real, Real, Real, Real do |canvas, c, m, y, k|
|
222
|
+
canvas.gs.set_nonstroking_color([c, m, y, k], Graphics::Color::Space::DEVICE_CMYK)
|
223
|
+
end
|
224
|
+
end
|
230
225
|
end
|
@@ -1,98 +1,96 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# This file is part of Origami, PDF manipulation framework for Ruby
|
5
|
+
# Copyright (C) 2016 Guillaume Delugré.
|
6
|
+
#
|
7
|
+
# Origami is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# Origami is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
20
|
|
21
21
|
module Origami
|
22
|
+
class InvalidPDFInstructionError < Error; end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
class PDF::Instruction
|
26
|
-
using TypeConversion
|
24
|
+
class PDF::Instruction
|
25
|
+
using TypeConversion
|
27
26
|
|
28
|
-
|
29
|
-
|
27
|
+
attr_reader :operator
|
28
|
+
attr_accessor :operands
|
30
29
|
|
31
|
-
|
30
|
+
@insns = Hash.new { |h, k| h[k] = {operands: [], render: lambda {}} }
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def initialize(operator, *operands)
|
33
|
+
@operator = operator
|
34
|
+
@operands = operands.map! { |arg| arg.is_a?(Origami::Object) ? arg.value : arg }
|
36
35
|
|
37
|
-
|
38
|
-
|
36
|
+
if self.class.has_op?(operator)
|
37
|
+
opdef = self.class.get_operands(operator)
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
39
|
+
if !opdef.include?('*') && (opdef.size != operands.size)
|
40
|
+
raise InvalidPDFInstructionError,
|
41
|
+
"Numbers of operands mismatch for #{operator}: #{operands.inspect}"
|
45
42
|
end
|
43
|
+
end
|
44
|
+
end
|
46
45
|
|
47
|
-
|
48
|
-
|
46
|
+
def render(canvas)
|
47
|
+
self.class.get_render_proc(@operator)[canvas, *@operands]
|
49
48
|
|
50
|
-
|
51
|
-
|
49
|
+
self
|
50
|
+
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
def to_s
|
53
|
+
"#{operands.map { |op| op.to_o.to_s }.join(" ")}#{" " unless operands.empty?}#{operator}\n"
|
54
|
+
end
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
56
|
+
class << self
|
57
|
+
def insn(operator, *operands, &render_proc)
|
58
|
+
@insns[operator] = {}
|
59
|
+
@insns[operator][:operands] = operands
|
60
|
+
@insns[operator][:render] = render_proc || lambda {}
|
61
|
+
end
|
62
|
+
|
63
|
+
def has_op?(operator)
|
64
|
+
@insns.has_key? operator
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_render_proc(operator)
|
68
|
+
@insns[operator][:render]
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_operands(operator)
|
72
|
+
@insns[operator][:operands]
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse(stream)
|
76
|
+
operands = []
|
77
|
+
while type = Object.typeof(stream, true)
|
78
|
+
operands.push type.parse(stream)
|
95
79
|
end
|
96
80
|
|
81
|
+
if !stream.eos?
|
82
|
+
if stream.scan(/(?<operator>[[:graph:]&&[^\[\]<>()%\/]]+)/).nil?
|
83
|
+
raise InvalidPDFInstructionError, "Operator: #{(stream.peek(10) + "...").inspect}"
|
84
|
+
end
|
85
|
+
|
86
|
+
operator = stream['operator']
|
87
|
+
PDF::Instruction.new(operator, *operands)
|
88
|
+
else
|
89
|
+
unless operands.empty?
|
90
|
+
raise InvalidPDFInstructionError, "No operator given for operands: #{operands.map(&:to_s).join(" ")}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
97
94
|
end
|
95
|
+
end
|
98
96
|
end
|