origami 2.0.0 → 2.0.1
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/README.md +1 -0
- data/bin/gui/config.rb +2 -1
- data/bin/gui/file.rb +118 -240
- data/bin/gui/gtkhex.rb +5 -5
- data/bin/gui/hexview.rb +20 -16
- data/bin/gui/imgview.rb +1 -1
- data/bin/gui/menu.rb +138 -158
- data/bin/gui/properties.rb +46 -48
- data/bin/gui/signing.rb +183 -214
- data/bin/gui/textview.rb +1 -1
- data/bin/gui/treeview.rb +13 -7
- data/bin/gui/walker.rb +102 -71
- data/bin/gui/xrefs.rb +1 -1
- data/bin/pdf2ruby +3 -3
- data/bin/pdfcop +18 -11
- data/bin/pdfextract +14 -5
- data/bin/pdfmetadata +3 -3
- data/bin/shell/console.rb +8 -8
- data/bin/shell/hexdump.rb +4 -4
- data/examples/attachments/nested_document.rb +1 -1
- data/examples/javascript/hello_world.rb +3 -3
- data/lib/origami.rb +0 -1
- data/lib/origami/acroform.rb +3 -3
- data/lib/origami/array.rb +1 -3
- data/lib/origami/boolean.rb +1 -3
- data/lib/origami/catalog.rb +3 -9
- data/lib/origami/destinations.rb +2 -2
- data/lib/origami/dictionary.rb +15 -29
- data/lib/origami/encryption.rb +334 -692
- data/lib/origami/extensions/fdf.rb +3 -2
- data/lib/origami/extensions/ppklite.rb +5 -9
- data/lib/origami/filespec.rb +2 -2
- data/lib/origami/filters.rb +54 -36
- data/lib/origami/filters/ascii.rb +67 -49
- data/lib/origami/filters/ccitt.rb +4 -236
- data/lib/origami/filters/ccitt/tables.rb +267 -0
- data/lib/origami/filters/crypt.rb +1 -1
- data/lib/origami/filters/dct.rb +0 -1
- data/lib/origami/filters/flate.rb +3 -43
- data/lib/origami/filters/lzw.rb +62 -99
- data/lib/origami/filters/predictors.rb +135 -105
- data/lib/origami/filters/runlength.rb +34 -22
- data/lib/origami/graphics.rb +2 -2
- data/lib/origami/graphics/colors.rb +89 -63
- data/lib/origami/graphics/path.rb +14 -14
- data/lib/origami/graphics/patterns.rb +31 -33
- data/lib/origami/graphics/render.rb +0 -1
- data/lib/origami/graphics/state.rb +9 -9
- data/lib/origami/graphics/text.rb +17 -17
- data/lib/origami/graphics/xobject.rb +102 -92
- data/lib/origami/javascript.rb +91 -68
- data/lib/origami/linearization.rb +22 -20
- data/lib/origami/metadata.rb +1 -1
- data/lib/origami/name.rb +1 -3
- data/lib/origami/null.rb +1 -3
- data/lib/origami/numeric.rb +3 -13
- data/lib/origami/object.rb +100 -72
- data/lib/origami/page.rb +24 -28
- data/lib/origami/parser.rb +34 -51
- data/lib/origami/parsers/fdf.rb +2 -2
- data/lib/origami/parsers/pdf.rb +41 -18
- data/lib/origami/parsers/pdf/lazy.rb +83 -46
- data/lib/origami/parsers/pdf/linear.rb +19 -10
- data/lib/origami/parsers/ppklite.rb +1 -1
- data/lib/origami/pdf.rb +150 -206
- data/lib/origami/reference.rb +4 -6
- data/lib/origami/signature.rb +76 -48
- data/lib/origami/stream.rb +69 -63
- data/lib/origami/string.rb +2 -19
- data/lib/origami/trailer.rb +25 -22
- data/lib/origami/version.rb +1 -1
- data/lib/origami/xfa.rb +6 -4
- data/lib/origami/xreftable.rb +29 -29
- data/test/test_annotations.rb +16 -38
- data/test/test_pdf_attachment.rb +1 -1
- data/test/test_pdf_parse.rb +1 -1
- data/test/test_xrefs.rb +2 -2
- metadata +4 -4
- data/lib/origami/export.rb +0 -247
@@ -26,6 +26,7 @@ module Origami
|
|
26
26
|
end
|
27
27
|
|
28
28
|
module Predictor
|
29
|
+
|
29
30
|
NONE = 1
|
30
31
|
TIFF = 2
|
31
32
|
PNG_NONE = 10
|
@@ -35,42 +36,88 @@ module Origami
|
|
35
36
|
PNG_PAETH = 14
|
36
37
|
PNG_OPTIMUM = 15
|
37
38
|
|
38
|
-
|
39
|
-
|
39
|
+
class DecodeParms < Dictionary
|
40
|
+
include StandardObject
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
field :Predictor, :Type => Integer, :Default => 1
|
43
|
+
field :Colors, :Type => Integer, :Default => 1
|
44
|
+
field :BitsPerComponent, :Type => Integer, :Default => 8
|
45
|
+
field :Columns, :Type => Integer, :Default => 1
|
46
|
+
end
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
+
def self.included(receiver)
|
49
|
+
raise TypeError, "Predictors only applies to Filters" unless receiver.include?(Filter)
|
50
|
+
end
|
48
51
|
|
49
|
-
|
50
|
-
|
52
|
+
#
|
53
|
+
# Create a new predictive Filter.
|
54
|
+
# _parameters_:: A hash of filter options.
|
55
|
+
#
|
56
|
+
def initialize(parameters = {})
|
57
|
+
super(DecodeParms.new(parameters))
|
58
|
+
end
|
51
59
|
|
52
|
-
|
53
|
-
bpp = (colors * bpc + 7) >> 3
|
60
|
+
private
|
54
61
|
|
55
|
-
|
56
|
-
|
62
|
+
def pre_prediction(data)
|
63
|
+
return data unless @params.Predictor.is_a?(Integer)
|
64
|
+
|
65
|
+
apply_pre_prediction(data, prediction_parameters)
|
66
|
+
end
|
67
|
+
|
68
|
+
def post_prediction(data)
|
69
|
+
return data unless @params.Predictor.is_a?(Integer)
|
70
|
+
|
71
|
+
apply_post_prediction(data, prediction_parameters)
|
72
|
+
end
|
73
|
+
|
74
|
+
def prediction_parameters
|
75
|
+
{
|
76
|
+
predictor: @params.Predictor.to_i,
|
77
|
+
colors: @params.Colors.is_a?(Integer) ? @params.Colors.to_i : 1,
|
78
|
+
bpc: @params.BitsPerComponent.is_a?(Integer) ? @params.BitsPerComponent.to_i : 8,
|
79
|
+
columns: @params.Columns.is_a?(Integer) ? @params.Columns.to_i : 1,
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def apply_pre_prediction(data, predictor: NONE, colors: 1, bpc: 8, columns: 1)
|
84
|
+
return data if predictor == NONE
|
85
|
+
|
86
|
+
bpp, bpr = compute_bpp_bpr(data, columns, colors, bpc)
|
57
87
|
|
58
88
|
unless data.size % bpr == 0
|
59
|
-
raise PredictorError.new("Invalid data size #{data.size}, should be multiple of bpr=#{bpr}",
|
89
|
+
raise PredictorError.new("Invalid data size #{data.size}, should be multiple of bpr=#{bpr}",
|
90
|
+
input_data: data)
|
60
91
|
end
|
61
92
|
|
62
93
|
if predictor == TIFF
|
63
|
-
|
94
|
+
tiff_pre_prediction(data, colors, bpc, columns)
|
64
95
|
elsif predictor >= 10 # PNG
|
65
|
-
|
96
|
+
png_pre_prediction(data, predictor, bpp, bpr)
|
66
97
|
else
|
67
98
|
raise PredictorError.new("Unknown predictor : #{predictor}", input_data: data)
|
68
99
|
end
|
69
100
|
end
|
70
101
|
|
71
|
-
def
|
102
|
+
def apply_post_prediction(data, predictor: NONE, colors: 1, bpc: 8, columns: 1)
|
72
103
|
return data if predictor == NONE
|
73
104
|
|
105
|
+
bpp, bpr = compute_bpp_bpr(data, columns, colors, bpc)
|
106
|
+
|
107
|
+
if predictor == TIFF
|
108
|
+
tiff_post_prediction(data, colors, bpc, columns)
|
109
|
+
elsif predictor >= 10 # PNG
|
110
|
+
# Each line has an extra predictor byte.
|
111
|
+
png_post_prediction(data, bpp, bpr + 1)
|
112
|
+
else
|
113
|
+
raise PredictorError.new("Unknown predictor : #{predictor}", input_data: data)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# Computes the number of bytes per pixel and number of bytes per row.
|
119
|
+
#
|
120
|
+
def compute_bpp_bpr(data, columns, colors, bpc)
|
74
121
|
unless (1..4) === colors
|
75
122
|
raise PredictorError.new("Colors must be between 1 and 4", input_data: data)
|
76
123
|
end
|
@@ -86,18 +133,16 @@ module Origami
|
|
86
133
|
bpp = (colors * bpc + 7) >> 3
|
87
134
|
|
88
135
|
# bytes per row
|
89
|
-
bpr = (
|
136
|
+
bpr = (nvals * bpc + 7) >> 3
|
90
137
|
|
91
|
-
|
92
|
-
do_tiff_post_prediction(data, colors, bpc, columns)
|
93
|
-
elsif predictor >= 10 # PNG
|
94
|
-
do_png_post_prediction(data, bpp, bpr)
|
95
|
-
else
|
96
|
-
raise PredictorError.new("Unknown predictor : #{predictor}", input_data: data)
|
97
|
-
end
|
138
|
+
[ bpp, bpr ]
|
98
139
|
end
|
99
140
|
|
100
|
-
|
141
|
+
#
|
142
|
+
# Decodes the PNG input data.
|
143
|
+
# Each line should be prepended by a byte identifying a PNG predictor.
|
144
|
+
#
|
145
|
+
def png_post_prediction(data, bpp, bpr)
|
101
146
|
result = ""
|
102
147
|
uprow = "\0" * bpr
|
103
148
|
thisrow = "\0" * bpr
|
@@ -114,37 +159,18 @@ module Origami
|
|
114
159
|
if bpp > i
|
115
160
|
left = upleft = 0
|
116
161
|
else
|
117
|
-
left = line[i-bpp].ord
|
118
|
-
upleft = uprow[i-bpp].ord
|
162
|
+
left = line[i - bpp].ord
|
163
|
+
upleft = uprow[i - bpp].ord
|
119
164
|
end
|
120
165
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
thisrow[i] = ((line[i].ord + left) & 0xFF).chr
|
126
|
-
when PNG_UP
|
127
|
-
thisrow[i] = ((line[i].ord + up) & 0xFF).chr
|
128
|
-
when PNG_AVERAGE
|
129
|
-
thisrow[i] = ((line[i].ord + ((left + up) / 2)) & 0xFF).chr
|
130
|
-
when PNG_PAETH
|
131
|
-
p = left + up - upleft
|
132
|
-
pa, pb, pc = (p - left).abs, (p - up).abs, (p - upleft).abs
|
133
|
-
|
134
|
-
thisrow[i] = ((line[i].ord +
|
135
|
-
case [ pa, pb, pc ].min
|
136
|
-
when pa then left
|
137
|
-
when pb then up
|
138
|
-
when pc then upleft
|
139
|
-
end
|
140
|
-
) & 0xFF).chr
|
141
|
-
else
|
142
|
-
unless Origami::OPTIONS[:ignore_png_errors]
|
143
|
-
raise PredictorError.new("Unknown PNG predictor : #{predictor}", input_data: data, decoded_data: result)
|
144
|
-
end
|
166
|
+
begin
|
167
|
+
thisrow[i] = png_apply_prediction(predictor, line[i].ord, up, left, upleft, &:+)
|
168
|
+
rescue PredictorError => error
|
169
|
+
thisrow[i] = line[i] if Origami::OPTIONS[:ignore_png_errors]
|
145
170
|
|
146
|
-
|
147
|
-
|
171
|
+
error.input_data = data
|
172
|
+
error.decoded_data = result
|
173
|
+
raise(error)
|
148
174
|
end
|
149
175
|
end
|
150
176
|
|
@@ -155,47 +181,29 @@ module Origami
|
|
155
181
|
result
|
156
182
|
end
|
157
183
|
|
158
|
-
|
184
|
+
#
|
185
|
+
# Encodes the input data given a PNG predictor.
|
186
|
+
#
|
187
|
+
def png_pre_prediction(data, predictor, bpp, bpr)
|
159
188
|
result = ""
|
160
189
|
nrows = data.size / bpr
|
161
190
|
|
162
191
|
line = "\0" + data[-bpr, bpr]
|
163
192
|
|
164
|
-
(nrows-1).downto(0) do |irow|
|
193
|
+
(nrows - 1).downto(0) do |irow|
|
165
194
|
uprow =
|
166
195
|
if irow == 0
|
167
|
-
"\0" * (bpr+1)
|
196
|
+
"\0" * (bpr + 1)
|
168
197
|
else
|
169
|
-
"\0" + data[(irow-1)*bpr,bpr]
|
198
|
+
"\0" + data[(irow - 1) * bpr, bpr]
|
170
199
|
end
|
171
200
|
|
172
201
|
bpr.downto(1) do |i|
|
173
202
|
up = uprow[i].ord
|
174
|
-
left = line[i-bpp].ord
|
175
|
-
upleft = uprow[i-bpp].ord
|
176
|
-
|
177
|
-
|
178
|
-
when PNG_SUB
|
179
|
-
line[i] = ((line[i].ord - left) & 0xFF).chr
|
180
|
-
when PNG_UP
|
181
|
-
line[i] = ((line[i].ord - up) & 0xFF).chr
|
182
|
-
when PNG_AVERAGE
|
183
|
-
line[i] = ((line[i].ord - ((left + up) / 2)) & 0xFF).chr
|
184
|
-
when PNG_PAETH
|
185
|
-
p = left + up - upleft
|
186
|
-
pa, pb, pc = (p - left).abs, (p - up).abs, (p - upleft).abs
|
187
|
-
|
188
|
-
line[i] = ((line[i].ord -
|
189
|
-
case [ pa, pb, pc ].min
|
190
|
-
when pa then left
|
191
|
-
when pb then up
|
192
|
-
when pc then upleft
|
193
|
-
end
|
194
|
-
) & 0xFF).chr
|
195
|
-
when PNG_NONE
|
196
|
-
else
|
197
|
-
raise PredictorError.new("Unsupported PNG predictor : #{predictor}", input_data: data)
|
198
|
-
end
|
203
|
+
left = line[i - bpp].ord
|
204
|
+
upleft = uprow[i - bpp].ord
|
205
|
+
|
206
|
+
line[i] = png_apply_prediction(predictor, line[i].ord, up, left, upleft, &:-)
|
199
207
|
end
|
200
208
|
|
201
209
|
line[0] = (predictor - 10).chr
|
@@ -207,32 +215,54 @@ module Origami
|
|
207
215
|
result
|
208
216
|
end
|
209
217
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
218
|
+
#
|
219
|
+
# Computes the next component value given a predictor and adjacent components.
|
220
|
+
# A block must be passed to apply the operation.
|
221
|
+
#
|
222
|
+
def png_apply_prediction(predictor, value, up, left, upleft)
|
223
|
+
|
224
|
+
result =
|
225
|
+
case predictor
|
226
|
+
when PNG_NONE
|
227
|
+
value
|
228
|
+
when PNG_SUB
|
229
|
+
yield(value, left)
|
230
|
+
when PNG_UP
|
231
|
+
yield(value, up)
|
232
|
+
when PNG_AVERAGE
|
233
|
+
yield(value, (left + up) / 2)
|
234
|
+
when PNG_PAETH
|
235
|
+
yield(value, png_paeth_choose(up, left, upleft))
|
236
|
+
else
|
237
|
+
raise PredictorError, "Unsupported PNG predictor : #{predictor}"
|
227
238
|
end
|
228
239
|
|
229
|
-
|
240
|
+
(result & 0xFF).chr
|
241
|
+
end
|
242
|
+
|
243
|
+
#
|
244
|
+
# Choose the preferred value in a PNG paeth predictor given the left, up and up left samples.
|
245
|
+
#
|
246
|
+
def png_paeth_choose(left, up, upleft)
|
247
|
+
p = left + up - upleft
|
248
|
+
pa, pb, pc = (p - left).abs, (p - up).abs, (p - upleft).abs
|
249
|
+
|
250
|
+
case [pa, pb, pc].min
|
251
|
+
when pa then left
|
252
|
+
when pb then up
|
253
|
+
when pc then upleft
|
230
254
|
end
|
255
|
+
end
|
231
256
|
|
232
|
-
|
257
|
+
def tiff_post_prediction(data, colors, bpc, columns) #:nodoc:
|
258
|
+
tiff_apply_prediction(data, colors, bpc, columns, &:+)
|
259
|
+
end
|
260
|
+
|
261
|
+
def tiff_pre_prediction(data, colors, bpc, columns) #:nodoc:
|
262
|
+
tiff_apply_prediction(data, colors, bpc, columns, &:-)
|
233
263
|
end
|
234
264
|
|
235
|
-
def
|
265
|
+
def tiff_apply_prediction(data, colors, bpc, columns) #:nodoc:
|
236
266
|
bpr = (colors * bpc * columns + 7) >> 3
|
237
267
|
nrows = data.size / bpr
|
238
268
|
bitmask = (1 << bpc) - 1
|
@@ -244,7 +274,7 @@ module Origami
|
|
244
274
|
diffpixel = ::Array.new(colors, 0)
|
245
275
|
columns.times do
|
246
276
|
pixel = ::Array.new(colors) { line.read(bpc) }
|
247
|
-
diffpixel = diffpixel.zip(pixel).map!{|diff, c| (c
|
277
|
+
diffpixel = diffpixel.zip(pixel).map!{|diff, c| yield(c, diff) & bitmask}
|
248
278
|
|
249
279
|
diffpixel.each do |c|
|
250
280
|
result.write(c, bpc)
|
@@ -42,36 +42,24 @@ module Origami
|
|
42
42
|
i = 0
|
43
43
|
|
44
44
|
while i < stream.size
|
45
|
-
|
45
|
+
|
46
46
|
# How many identical bytes coming?
|
47
|
-
|
48
|
-
length = 1
|
49
|
-
while i+1 < stream.size and length < EOD and stream[i] == stream[i+1]
|
50
|
-
length = length + 1
|
51
|
-
i = i + 1
|
52
|
-
end
|
47
|
+
length = compute_run_length(stream, i)
|
53
48
|
|
54
|
-
#
|
55
49
|
# If more than 1, then compress them.
|
56
|
-
#
|
57
50
|
if length > 1
|
58
51
|
result << (257 - length).chr << stream[i]
|
59
|
-
|
52
|
+
i += length
|
53
|
+
|
60
54
|
# Otherwise how many different bytes to copy?
|
61
|
-
#
|
62
55
|
else
|
63
|
-
|
64
|
-
|
65
|
-
j = j + 1
|
66
|
-
end
|
56
|
+
next_pos = find_next_run(stream, i)
|
57
|
+
length = next_pos - i
|
67
58
|
|
68
|
-
|
69
|
-
result << length.chr << stream[i, length+1]
|
59
|
+
result << (length - 1).chr << stream[i, length]
|
70
60
|
|
71
|
-
i
|
61
|
+
i += length
|
72
62
|
end
|
73
|
-
|
74
|
-
i = i + 1
|
75
63
|
end
|
76
64
|
|
77
65
|
result << EOD.chr
|
@@ -83,7 +71,6 @@ module Origami
|
|
83
71
|
#
|
84
72
|
def decode(stream)
|
85
73
|
result = "".b
|
86
|
-
return result if stream.empty?
|
87
74
|
|
88
75
|
i = 0
|
89
76
|
until i >= stream.length or stream[i].ord == EOD do
|
@@ -104,12 +91,37 @@ module Origami
|
|
104
91
|
end
|
105
92
|
|
106
93
|
# Check if offset is beyond the end of data.
|
107
|
-
if i
|
94
|
+
if i > stream.length
|
108
95
|
raise InvalidRunLengthDataError.new("Truncated run-length data", input_data: stream, decoded_data: result)
|
109
96
|
end
|
110
97
|
|
111
98
|
result
|
112
99
|
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
#
|
104
|
+
# Find the position of the next byte at which a new run starts.
|
105
|
+
#
|
106
|
+
def find_next_run(input, pos)
|
107
|
+
start = pos
|
108
|
+
pos += 1 while pos + 1 < input.size and (pos - start + 1) < EOD and input[pos] != input[pos + 1]
|
109
|
+
|
110
|
+
pos + 1
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Computes the length of the run at the given position.
|
115
|
+
#
|
116
|
+
def compute_run_length(input, pos)
|
117
|
+
run_length = 1
|
118
|
+
while pos + 1 < input.size and run_length < EOD and input[pos] == input[pos + 1]
|
119
|
+
run_length += 1
|
120
|
+
pos += 1
|
121
|
+
end
|
122
|
+
|
123
|
+
run_length
|
124
|
+
end
|
113
125
|
end
|
114
126
|
RL = RunLength
|
115
127
|
|
data/lib/origami/graphics.rb
CHANGED
@@ -29,10 +29,10 @@ module Origami
|
|
29
29
|
end
|
30
30
|
|
31
31
|
require 'origami/graphics/instruction'
|
32
|
+
require 'origami/graphics/state'
|
32
33
|
require 'origami/graphics/colors'
|
33
34
|
require 'origami/graphics/path'
|
34
35
|
require 'origami/graphics/xobject'
|
35
|
-
require 'origami/graphics/patterns'
|
36
36
|
require 'origami/graphics/text'
|
37
|
-
require 'origami/graphics/
|
37
|
+
require 'origami/graphics/patterns'
|
38
38
|
require 'origami/graphics/render'
|
@@ -105,99 +105,125 @@ module Origami
|
|
105
105
|
def Color.to_a(color)
|
106
106
|
return color if color.is_a?(::Array)
|
107
107
|
|
108
|
-
if (
|
109
|
-
r =
|
110
|
-
g =
|
111
|
-
b =
|
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
112
|
return [r, g, b]
|
113
113
|
|
114
|
-
elsif (
|
115
|
-
c =
|
116
|
-
m =
|
117
|
-
y =
|
118
|
-
k =
|
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
119
|
return [c,m,y,k]
|
120
120
|
|
121
|
-
elsif color.respond_to
|
122
|
-
g = color.
|
123
|
-
return [
|
121
|
+
elsif color.respond_to?(:g)
|
122
|
+
g = color.g
|
123
|
+
return [g]
|
124
124
|
|
125
125
|
else
|
126
126
|
raise TypeError, "Invalid color : #{color}"
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
130
|
-
end
|
131
130
|
|
132
|
-
|
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
|
133
138
|
|
134
|
-
|
135
|
-
|
136
|
-
insn 'SC', '*' do |canvas, *c| canvas.gs.stroking_color = c end
|
137
|
-
insn 'sc', '*' do |canvas, *c| canvas.gs.nonstroking_color = c end
|
139
|
+
def set_nonstroking_color(color, space = @nonstroking_colorspace)
|
140
|
+
check_color(space, color)
|
138
141
|
|
139
|
-
|
140
|
-
|
141
|
-
raise Graphics::InvalidColorError,
|
142
|
-
"Not a valid color for DeviceGray: #{c}"
|
142
|
+
@nonstroking_colorspace = space
|
143
|
+
@nonstroking_color = color
|
143
144
|
end
|
144
145
|
|
145
|
-
|
146
|
-
|
147
|
-
end
|
146
|
+
def set_stroking_colorspace(space)
|
147
|
+
check_color_space(space, @stroking_color)
|
148
148
|
|
149
|
-
|
150
|
-
unless (0..1).include? c
|
151
|
-
raise Graphics::InvalidColorError,
|
152
|
-
"Not a valid color for DeviceGray: #{c}"
|
149
|
+
@stroking_color_space = space
|
153
150
|
end
|
154
151
|
|
155
|
-
|
156
|
-
|
157
|
-
end
|
152
|
+
def set_nonstroking_colorspace(space)
|
153
|
+
check_color_space(space, @nonstroking_color)
|
158
154
|
|
159
|
-
|
160
|
-
color = [ r, g, b ]
|
161
|
-
unless color.all? {|comp| (0..1).include? comp}
|
162
|
-
raise Graphics::InvalidColorError,
|
163
|
-
"Not a valid color for DeviceRGB: #{color.inspect}"
|
155
|
+
@nonstroking_color_space = space
|
164
156
|
end
|
165
157
|
|
166
|
-
|
167
|
-
canvas.gs.stroking_color = color
|
168
|
-
end
|
158
|
+
private
|
169
159
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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
|
175
166
|
end
|
176
167
|
|
177
|
-
|
178
|
-
|
179
|
-
|
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
180
|
|
181
|
-
|
182
|
-
color = [ c, m, y, k ]
|
183
|
-
unless color.all? {|comp| (0..1).include? comp}
|
184
|
-
raise Graphics::InvalidColorError,
|
185
|
-
"Not a valid color for DeviceCMYK: #{color.inspect}"
|
181
|
+
raise InvalidColorError, "Invalid color #{color.inspect} for #{space}" unless valid_color
|
186
182
|
end
|
187
183
|
|
188
|
-
|
189
|
-
|
190
|
-
|
184
|
+
def check_gray_color(color)
|
185
|
+
color.is_a?(::Array) and color.length == 1 and (0..1).include?(color[0])
|
186
|
+
end
|
191
187
|
|
192
|
-
|
193
|
-
|
194
|
-
unless color.all? {|comp| (0..1).include? comp}
|
195
|
-
raise Graphics::InvalidColorError,
|
196
|
-
"Not a valid color for DeviceCMYK: #{color.inspect}"
|
188
|
+
def check_rgb_color(color)
|
189
|
+
color.is_a?(::Array) and color.length == 3 and color.all? {|c| (0..1).include?(c) }
|
197
190
|
end
|
198
191
|
|
199
|
-
|
200
|
-
|
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)
|
201
227
|
end
|
202
228
|
end
|
203
229
|
|