qr_reader 0.0.1 → 0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +23 -7
- data/exe/qr_reader +1 -1
- data/lib/qr_reader/formats/jpeg.rb +61 -2
- data/lib/qr_reader/formats/jpeg2000/codestream.rb +447 -0
- data/lib/qr_reader/formats/jpeg2000/container.rb +156 -0
- data/lib/qr_reader/formats/jpeg2000/dwt.rb +607 -0
- data/lib/qr_reader/formats/jpeg2000/tier1.rb +1084 -0
- data/lib/qr_reader/formats/jpeg2000/tile.rb +722 -0
- data/lib/qr_reader/formats/jpeg2000.rb +764 -0
- data/lib/qr_reader/formats/pdf/font_programs.rb +1205 -0
- data/lib/qr_reader/formats/pdf/font_tables.rb +224 -0
- data/lib/qr_reader/formats/pdf/fonts.rb +412 -0
- data/lib/qr_reader/formats/pdf/text.rb +151 -0
- data/lib/qr_reader/formats/pdf/vector.rb +799 -0
- data/lib/qr_reader/formats/pdf.rb +183 -44
- data/lib/qr_reader/formats.rb +13 -4
- data/lib/qr_reader/reader.rb +36 -10
- data/lib/qr_reader/version.rb +1 -1
- data/lib/qr_reader.rb +1 -1
- metadata +15 -4
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module QrReader
|
|
4
|
+
module Formats
|
|
5
|
+
module JPEG2000
|
|
6
|
+
# Raised internally when a tile's packet data is truncated or
|
|
7
|
+
# corrupt: decoding keeps what was read before.
|
|
8
|
+
class PacketError < StandardError; end
|
|
9
|
+
|
|
10
|
+
# Reads packet header bits (B.10.1): MSB first, and after an 0xFF byte
|
|
11
|
+
# only 7 bits of the next one are used. Reading past the end yields
|
|
12
|
+
# zero bits and sets #overrun.
|
|
13
|
+
class BitReader
|
|
14
|
+
attr_reader :data, :pos, :overrun
|
|
15
|
+
|
|
16
|
+
def initialize(data, pos, stop)
|
|
17
|
+
@data = data
|
|
18
|
+
@pos = pos
|
|
19
|
+
@stop = stop
|
|
20
|
+
@buf = 0
|
|
21
|
+
@ct = 0
|
|
22
|
+
@overrun = false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Starts a new packet header at +pos+.
|
|
26
|
+
def restart(pos)
|
|
27
|
+
@pos = pos
|
|
28
|
+
@buf = 0
|
|
29
|
+
@ct = 0
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def bit
|
|
33
|
+
if @ct.zero?
|
|
34
|
+
@buf = (@buf << 8) & 0xFFFF
|
|
35
|
+
@ct = @buf == 0xFF00 ? 7 : 8
|
|
36
|
+
if @pos < @stop
|
|
37
|
+
@buf |= @data.getbyte(@pos)
|
|
38
|
+
@pos += 1
|
|
39
|
+
else
|
|
40
|
+
@overrun = true
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
@ct -= 1
|
|
44
|
+
(@buf >> @ct) & 1
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def bits(n)
|
|
48
|
+
v = 0
|
|
49
|
+
while n.positive?
|
|
50
|
+
v = (v << 1) | bit
|
|
51
|
+
n -= 1
|
|
52
|
+
end
|
|
53
|
+
v
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Skips to the next byte boundary (and over a stuffed byte after 0xFF).
|
|
57
|
+
def align
|
|
58
|
+
if @buf & 0xFF == 0xFF
|
|
59
|
+
@buf = (@buf << 8) & 0xFFFF
|
|
60
|
+
if @pos < @stop
|
|
61
|
+
@pos += 1
|
|
62
|
+
else
|
|
63
|
+
@overrun = true
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
@ct = 0
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Tag tree (B.10.2) over a +w+ x +h+ grid of code-blocks.
|
|
71
|
+
class TagTree
|
|
72
|
+
INFINITY = 1 << 40
|
|
73
|
+
|
|
74
|
+
def initialize(w, h)
|
|
75
|
+
parents = []
|
|
76
|
+
lw = w
|
|
77
|
+
lh = h
|
|
78
|
+
offset = 0
|
|
79
|
+
loop do
|
|
80
|
+
n = lw * lh
|
|
81
|
+
nw = (lw + 1) >> 1
|
|
82
|
+
nh = (lh + 1) >> 1
|
|
83
|
+
root = n == 1
|
|
84
|
+
y = 0
|
|
85
|
+
while y < lh
|
|
86
|
+
x = 0
|
|
87
|
+
while x < lw
|
|
88
|
+
parents << (root ? -1 : offset + n + (y >> 1) * nw + (x >> 1))
|
|
89
|
+
x += 1
|
|
90
|
+
end
|
|
91
|
+
y += 1
|
|
92
|
+
end
|
|
93
|
+
break if root
|
|
94
|
+
|
|
95
|
+
offset += n
|
|
96
|
+
lw = nw
|
|
97
|
+
lh = nh
|
|
98
|
+
end
|
|
99
|
+
@parent = parents
|
|
100
|
+
@value = Array.new(parents.size, INFINITY)
|
|
101
|
+
@low = Array.new(parents.size, 0)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Decodes whether leaf +leaf+'s value is below +threshold+.
|
|
105
|
+
def decode(bits, leaf, threshold)
|
|
106
|
+
stack = []
|
|
107
|
+
node = leaf
|
|
108
|
+
while (p = @parent[node]) >= 0
|
|
109
|
+
stack << node
|
|
110
|
+
node = p
|
|
111
|
+
end
|
|
112
|
+
low = 0
|
|
113
|
+
loop do
|
|
114
|
+
if low > @low[node]
|
|
115
|
+
@low[node] = low
|
|
116
|
+
else
|
|
117
|
+
low = @low[node]
|
|
118
|
+
end
|
|
119
|
+
while low < threshold && low < @value[node]
|
|
120
|
+
if bits.bit == 1
|
|
121
|
+
@value[node] = low
|
|
122
|
+
else
|
|
123
|
+
low += 1
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
@low[node] = low
|
|
127
|
+
break if stack.empty?
|
|
128
|
+
|
|
129
|
+
node = stack.pop
|
|
130
|
+
end
|
|
131
|
+
@value[node] < threshold
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Decoding state of one code-block: its rectangle in subband
|
|
136
|
+
# coordinates, bit-planes, Lblock, and the codeword segments
|
|
137
|
+
# received so far ([bytes, passes]).
|
|
138
|
+
class CodeBlock
|
|
139
|
+
attr_reader :x0, :y0, :x1, :y1, :segments
|
|
140
|
+
attr_accessor :numbps, :lblock, :included, :seg_max, :seg_passes, :seg_count
|
|
141
|
+
|
|
142
|
+
def initialize(x0, y0, x1, y1)
|
|
143
|
+
@x0 = x0
|
|
144
|
+
@y0 = y0
|
|
145
|
+
@x1 = x1
|
|
146
|
+
@y1 = y1
|
|
147
|
+
@included = false
|
|
148
|
+
@segments = []
|
|
149
|
+
@seg_max = 0
|
|
150
|
+
@seg_passes = 0
|
|
151
|
+
@seg_count = 0
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# The code-blocks of one subband inside a precinct.
|
|
156
|
+
PrecinctBand = Struct.new(:cblks, :inclusion, :zero_planes)
|
|
157
|
+
|
|
158
|
+
# Subband of a tile-component resolution: orientation (0 LL, 1 HL,
|
|
159
|
+
# 2 LH, 3 HH), rectangle, magnitude bit-planes Mb, step (nil when
|
|
160
|
+
# reversible) and, while decoding, its coefficient rows.
|
|
161
|
+
class Band
|
|
162
|
+
attr_reader :orient, :x0, :y0, :x1, :y1
|
|
163
|
+
attr_accessor :mb, :step, :rows
|
|
164
|
+
|
|
165
|
+
def initialize(orient, x0, y0, x1, y1)
|
|
166
|
+
@orient = orient
|
|
167
|
+
@x0 = x0
|
|
168
|
+
@y0 = y0
|
|
169
|
+
@x1 = x1
|
|
170
|
+
@y1 = y1
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def width
|
|
174
|
+
@x1 - @x0
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def height
|
|
178
|
+
@y1 - @y0
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# One resolution level of a tile-component.
|
|
183
|
+
class Resolution
|
|
184
|
+
attr_reader :r, :x0, :y0, :x1, :y1, :ppx, :ppy, :npx, :npy, :px0, :py0, :xcb, :ycb, :bands, :precincts
|
|
185
|
+
|
|
186
|
+
def initialize(r, rect, ppx, ppy, xcb, ycb, bands)
|
|
187
|
+
@r = r
|
|
188
|
+
@x0, @y0, @x1, @y1 = rect
|
|
189
|
+
@ppx = ppx
|
|
190
|
+
@ppy = ppy
|
|
191
|
+
@xcb = xcb
|
|
192
|
+
@ycb = ycb
|
|
193
|
+
@bands = bands
|
|
194
|
+
if @x0 < @x1 && @y0 < @y1
|
|
195
|
+
@px0 = @x0 >> ppx
|
|
196
|
+
@py0 = @y0 >> ppy
|
|
197
|
+
@npx = ((@x1 + (1 << ppx) - 1) >> ppx) - @px0
|
|
198
|
+
@npy = ((@y1 + (1 << ppy) - 1) >> ppy) - @py0
|
|
199
|
+
else
|
|
200
|
+
@px0 = @py0 = @npx = @npy = 0
|
|
201
|
+
end
|
|
202
|
+
@precincts = []
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def width
|
|
206
|
+
@x1 - @x0
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def height
|
|
210
|
+
@y1 - @y0
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def precinct_count
|
|
214
|
+
@npx * @npy
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def release
|
|
218
|
+
@precincts = []
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# One component of a tile: geometry and coding parameters.
|
|
223
|
+
class TileComponent
|
|
224
|
+
attr_reader :index, :x0, :y0, :x1, :y1, :style, :roi, :resolutions, :levels, :decoded_levels
|
|
225
|
+
|
|
226
|
+
def initialize(index, rect, style, roi, resolutions, decoded_levels)
|
|
227
|
+
@index = index
|
|
228
|
+
@x0, @y0, @x1, @y1 = rect
|
|
229
|
+
@style = style
|
|
230
|
+
@roi = roi
|
|
231
|
+
@resolutions = resolutions
|
|
232
|
+
@levels = style.levels
|
|
233
|
+
@decoded_levels = decoded_levels
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def reversible?
|
|
237
|
+
@style.reversible
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Size of the decoded (possibly reduced) tile-component.
|
|
241
|
+
def output_rect
|
|
242
|
+
res = @resolutions[@decoded_levels]
|
|
243
|
+
[res.x0, res.y0, res.x1, res.y1]
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Decodes one tile: geometry (B.5-B.7), packets (tier-2, B.9-B.12),
|
|
248
|
+
# code-blocks (tier-1, via Tier1) and the inverse wavelet transform.
|
|
249
|
+
class TileDecoder
|
|
250
|
+
# Limits for corrupt or hostile headers (per tile).
|
|
251
|
+
MAX_PRECINCTS = 1 << 20
|
|
252
|
+
MAX_CODEBLOCKS = 1 << 21
|
|
253
|
+
# Bit-planes beyond any valid codestream (Mb <= 37 plus ROI shift).
|
|
254
|
+
MAX_BITPLANES = 74
|
|
255
|
+
# Largest tile-component decoded at once (samples at the decoded
|
|
256
|
+
# resolution): the wavelet planes take 8 bytes per sample. Larger
|
|
257
|
+
# ones need a +reduce+ factor (or tiles).
|
|
258
|
+
MAX_DECODE_SAMPLES = 1 << 25
|
|
259
|
+
|
|
260
|
+
attr_reader :components, :rect, :mct
|
|
261
|
+
|
|
262
|
+
def initialize(codestream, info, reduce, tier1)
|
|
263
|
+
@cs = codestream
|
|
264
|
+
@info = info
|
|
265
|
+
@reduce = reduce
|
|
266
|
+
@t1 = tier1
|
|
267
|
+
@rect = codestream.tile_rect(info.index)
|
|
268
|
+
@layers = codestream.tile_param(info, :layers)
|
|
269
|
+
@sop = codestream.tile_param(info, :sop)
|
|
270
|
+
@eph = codestream.tile_param(info, :eph)
|
|
271
|
+
@mct = codestream.tile_param(info, :mct)
|
|
272
|
+
@codeblocks = 0
|
|
273
|
+
@components = codestream.components.each_with_index.map { |comp, c| build_component(comp, c) }
|
|
274
|
+
@components.each do |tc|
|
|
275
|
+
x0, y0, x1, y1 = tc.output_rect
|
|
276
|
+
next if (x1 - x0) * (y1 - y0) <= MAX_DECODE_SAMPLES
|
|
277
|
+
|
|
278
|
+
raise UnsupportedImageError, "JPEG 2000 tile too large to decode at full resolution " \
|
|
279
|
+
"(#{x1 - x0}x#{y1 - y0}); decode with reduce: 1 or more"
|
|
280
|
+
end
|
|
281
|
+
precincts = @components.sum { |tc| tc.resolutions.sum(&:precinct_count) }
|
|
282
|
+
return if precincts <= MAX_PRECINCTS
|
|
283
|
+
|
|
284
|
+
raise UnsupportedImageError, "too many JPEG 2000 precincts in a tile (#{precincts})"
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Reads all packets of the tile (tier-2). Truncated or damaged
|
|
288
|
+
# packet data ends the tile's packets early.
|
|
289
|
+
def read_packets
|
|
290
|
+
data = @info.ranges.map { |a, b| @cs.data.byteslice(a, b - a) }.join.b
|
|
291
|
+
@data = data
|
|
292
|
+
@pos = 0
|
|
293
|
+
@stop = data.bytesize
|
|
294
|
+
headers = @info.ppm || @info.params.ppt
|
|
295
|
+
if headers
|
|
296
|
+
@hbits = BitReader.new(headers, 0, headers.bytesize)
|
|
297
|
+
@separate = true
|
|
298
|
+
else
|
|
299
|
+
@hbits = BitReader.new(data, 0, @stop)
|
|
300
|
+
@separate = false
|
|
301
|
+
end
|
|
302
|
+
each_packet { |layer, res, c, p| read_packet(layer, res, c, p) }
|
|
303
|
+
rescue PacketError
|
|
304
|
+
nil
|
|
305
|
+
ensure
|
|
306
|
+
@data = nil
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# Tier-1 decodes component +c+ and runs the inverse DWT: the rows
|
|
310
|
+
# (Arrays of Integers or Floats) of the decoded tile-component, or
|
|
311
|
+
# nil when all its coefficients are zero (no DWT needed: every
|
|
312
|
+
# sample is 0).
|
|
313
|
+
def component_rows(c)
|
|
314
|
+
tc = @components[c]
|
|
315
|
+
top = tc.decoded_levels
|
|
316
|
+
zero = tc.reversible? ? 0 : 0.0
|
|
317
|
+
style = tc.style.cblk_style
|
|
318
|
+
r = 0
|
|
319
|
+
while r <= top
|
|
320
|
+
res = tc.resolutions[r]
|
|
321
|
+
res.bands.each do |band|
|
|
322
|
+
band.rows = Array.new(band.height) # rows are allocated by Tier1#store
|
|
323
|
+
end
|
|
324
|
+
res.precincts.each do |prec|
|
|
325
|
+
next unless prec
|
|
326
|
+
|
|
327
|
+
prec.each_with_index do |pb, bi|
|
|
328
|
+
next unless pb
|
|
329
|
+
|
|
330
|
+
band = res.bands[bi]
|
|
331
|
+
pb.cblks.each { |cb| decode_codeblock(cb, band, tc.roi, style) }
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
res.release
|
|
335
|
+
r += 1
|
|
336
|
+
end
|
|
337
|
+
if tc.resolutions[0..top].all? { |rr| rr.bands.all? { |b| b.rows.none? } }
|
|
338
|
+
tc.resolutions.each { |rr| rr.bands.each { |b| b.rows = nil } }
|
|
339
|
+
return nil
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
rows = tc.resolutions[0].bands[0].rows
|
|
343
|
+
r = 1
|
|
344
|
+
while r <= top
|
|
345
|
+
res = tc.resolutions[r]
|
|
346
|
+
prev = tc.resolutions[r - 1]
|
|
347
|
+
hl, lh, hh = res.bands
|
|
348
|
+
rows = DWT.synthesize(rows, hl.rows, lh.rows, hh.rows, res.width, res.height, prev.width, prev.height,
|
|
349
|
+
res.x0 & 1, res.y0 & 1, tc.reversible?)
|
|
350
|
+
r += 1
|
|
351
|
+
end
|
|
352
|
+
tc.resolutions.each { |rr| rr.bands.each { |b| b.rows = nil } }
|
|
353
|
+
width = tc.resolutions[top].width
|
|
354
|
+
rows.map! { |row| row || Array.new(width, zero) } if top.zero?
|
|
355
|
+
rows
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
private
|
|
359
|
+
|
|
360
|
+
def ceil_div(a, b)
|
|
361
|
+
-(-a / b)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def ceil_shift(a, k)
|
|
365
|
+
-((-a) >> k)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def build_component(comp, c)
|
|
369
|
+
style, quant, roi = @cs.component_params(@info, c)
|
|
370
|
+
tx0, ty0, tx1, ty1 = @rect
|
|
371
|
+
rect = [ceil_div(tx0, comp.dx), ceil_div(ty0, comp.dy), ceil_div(tx1, comp.dx), ceil_div(ty1, comp.dy)]
|
|
372
|
+
levels = style.levels
|
|
373
|
+
if levels < @reduce
|
|
374
|
+
raise UnsupportedImageError, "cannot reduce a JPEG 2000 tile with #{levels} levels by #{@reduce}"
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
top = levels - @reduce
|
|
378
|
+
resolutions = Array.new(levels + 1) do |r|
|
|
379
|
+
lev = levels - r
|
|
380
|
+
rrect = rect.map { |v| ceil_shift(v, lev) }
|
|
381
|
+
ppx, ppy = style.precincts[r] || [15, 15]
|
|
382
|
+
xcb = [style.xcb, r.zero? ? ppx : ppx - 1].min
|
|
383
|
+
ycb = [style.ycb, r.zero? ? ppy : ppy - 1].min
|
|
384
|
+
bands = if r.zero?
|
|
385
|
+
[Band.new(0, *rrect)]
|
|
386
|
+
else
|
|
387
|
+
[1, 2, 3].map do |o|
|
|
388
|
+
xo = o & 1
|
|
389
|
+
yo = o >> 1
|
|
390
|
+
Band.new(o, ceil_shift(rect[0] - (xo << lev), lev + 1),
|
|
391
|
+
ceil_shift(rect[1] - (yo << lev), lev + 1),
|
|
392
|
+
ceil_shift(rect[2] - (xo << lev), lev + 1),
|
|
393
|
+
ceil_shift(rect[3] - (yo << lev), lev + 1))
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
Resolution.new(r, rrect, ppx, ppy, xcb, ycb, bands)
|
|
397
|
+
end
|
|
398
|
+
setup_quantization(comp, style, quant, resolutions, top)
|
|
399
|
+
TileComponent.new(c, rect, style, roi, resolutions, top)
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Mb and step size of every subband (E.1).
|
|
403
|
+
def setup_quantization(comp, style, quant, resolutions, top)
|
|
404
|
+
steps = quant.steps
|
|
405
|
+
resolutions.each do |res|
|
|
406
|
+
r = res.r
|
|
407
|
+
res.bands.each do |band|
|
|
408
|
+
if quant.style == 1
|
|
409
|
+
exp, mant = steps[0]
|
|
410
|
+
exp -= r - 1 if r > 1
|
|
411
|
+
exp = 0 if exp.negative?
|
|
412
|
+
else
|
|
413
|
+
idx = r.zero? ? 0 : 3 * (r - 1) + band.orient
|
|
414
|
+
exp, mant = steps[idx] || steps[-1]
|
|
415
|
+
end
|
|
416
|
+
band.mb = quant.guard_bits + exp - 1
|
|
417
|
+
next if style.reversible || r > top
|
|
418
|
+
|
|
419
|
+
factor = band_scale(resolutions, res, band, top)
|
|
420
|
+
# OpenJPEG keeps the step size in single precision.
|
|
421
|
+
base = [(1.0 + mant / 2048.0) * (2.0**(comp.precision - exp))].pack("e").unpack1("e")
|
|
422
|
+
band.step = base * 0.5 * factor
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# The 9/7 normalization factors of +band+ folded into its step.
|
|
428
|
+
def band_scale(resolutions, res, band, top)
|
|
429
|
+
widths = (res.r..top).map { |r| resolutions[r].width }
|
|
430
|
+
heights = (res.r..top).map { |r| resolutions[r].height }
|
|
431
|
+
if res.r.zero?
|
|
432
|
+
widths.shift
|
|
433
|
+
heights.shift
|
|
434
|
+
end
|
|
435
|
+
DWT.scale_factor(band.orient & 1 == 1, widths) * DWT.scale_factor(band.orient & 2 == 2, heights)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
# Enumerates the packets of the tile in progression order (B.12),
|
|
439
|
+
# honouring POC progression changes (each packet at most once).
|
|
440
|
+
def each_packet(&)
|
|
441
|
+
seen = @info.params.pocs || @cs.main.pocs ? {} : nil
|
|
442
|
+
ncomp = @components.size
|
|
443
|
+
@cs.progressions(@info).each do |prog|
|
|
444
|
+
layers = [prog.layer_end, @layers].min
|
|
445
|
+
c0 = prog.comp_start
|
|
446
|
+
c1 = [prog.comp_end, ncomp].min
|
|
447
|
+
r0 = prog.res_start
|
|
448
|
+
r1 = [prog.res_end, 33].min
|
|
449
|
+
next if layers <= 0 || c0 >= c1 || r0 >= r1
|
|
450
|
+
|
|
451
|
+
case prog.order
|
|
452
|
+
when 0 then lrcp(layers, r0, r1, c0, c1, seen, &)
|
|
453
|
+
when 1 then rlcp(layers, r0, r1, c0, c1, seen, &)
|
|
454
|
+
else positional(prog.order, layers, r0, r1, c0, c1, seen, &)
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def emit(layer, r, c, p, seen)
|
|
460
|
+
if seen
|
|
461
|
+
key = [layer, r, c, p]
|
|
462
|
+
return if seen[key]
|
|
463
|
+
|
|
464
|
+
seen[key] = true
|
|
465
|
+
end
|
|
466
|
+
yield layer, @components[c].resolutions[r], c, p
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def lrcp(layers, r0, r1, c0, c1, seen, &)
|
|
470
|
+
layers.times do |l|
|
|
471
|
+
(r0...r1).each do |r|
|
|
472
|
+
(c0...c1).each do |c|
|
|
473
|
+
res = @components[c].resolutions[r] or next
|
|
474
|
+
res.precinct_count.times { |p| emit(l, r, c, p, seen, &) }
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def rlcp(layers, r0, r1, c0, c1, seen, &)
|
|
481
|
+
(r0...r1).each do |r|
|
|
482
|
+
layers.times do |l|
|
|
483
|
+
(c0...c1).each do |c|
|
|
484
|
+
res = @components[c].resolutions[r] or next
|
|
485
|
+
res.precinct_count.times { |p| emit(l, r, c, p, seen, &) }
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# RPCL (2), PCRL (3) and CPRL (4): precincts ordered by the
|
|
492
|
+
# reference-grid position at which B.12.1.3-5 visit them.
|
|
493
|
+
def positional(order, layers, r0, r1, c0, c1, seen, &)
|
|
494
|
+
entries = []
|
|
495
|
+
(c0...c1).each do |c|
|
|
496
|
+
tc = @components[c]
|
|
497
|
+
(r0...r1).each do |r|
|
|
498
|
+
res = tc.resolutions[r] or next
|
|
499
|
+
precinct_positions(tc, res) do |y, x, p|
|
|
500
|
+
entries << case order
|
|
501
|
+
when 2 then [r, y, x, c, p]
|
|
502
|
+
when 3 then [y, x, c, r, p]
|
|
503
|
+
else [c, y, x, r, p]
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
entries.sort!
|
|
509
|
+
entries.each do |e|
|
|
510
|
+
r, c, p = case order
|
|
511
|
+
when 2 then [e[0], e[3], e[4]]
|
|
512
|
+
when 3 then [e[3], e[2], e[4]]
|
|
513
|
+
else [e[3], e[0], e[4]]
|
|
514
|
+
end
|
|
515
|
+
layers.times { |l| emit(l, r, c, p, seen, &) }
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# Yields [y, x, precinct] for each precinct of +res+: the first
|
|
520
|
+
# tile position (on the reference grid) where the progression loops
|
|
521
|
+
# of B.12.1.3 reach it.
|
|
522
|
+
def precinct_positions(tc, res)
|
|
523
|
+
return if res.precinct_count.zero?
|
|
524
|
+
|
|
525
|
+
comp = @cs.components[tc.index]
|
|
526
|
+
lev = tc.levels - res.r
|
|
527
|
+
tx0, ty0, = @rect
|
|
528
|
+
ystep = comp.dy << (res.ppy + lev)
|
|
529
|
+
xstep = comp.dx << (res.ppx + lev)
|
|
530
|
+
y_misaligned = res.y0 % (1 << res.ppy) != 0
|
|
531
|
+
x_misaligned = res.x0 % (1 << res.ppx) != 0
|
|
532
|
+
res.npy.times do |j|
|
|
533
|
+
y = j.zero? && y_misaligned ? ty0 : (res.py0 + j) * ystep
|
|
534
|
+
res.npx.times do |i|
|
|
535
|
+
x = i.zero? && x_misaligned ? tx0 : (res.px0 + i) * xstep
|
|
536
|
+
yield y, x, j * res.npx + i
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# The precinct +p+ of +res+ (created on first use): per subband its
|
|
542
|
+
# code-blocks and tag trees.
|
|
543
|
+
def precinct(res, p)
|
|
544
|
+
prec = res.precincts[p]
|
|
545
|
+
return prec if prec
|
|
546
|
+
|
|
547
|
+
i = p % res.npx
|
|
548
|
+
j = p / res.npx
|
|
549
|
+
shift_x = res.r.zero? ? res.ppx : res.ppx - 1
|
|
550
|
+
shift_y = res.r.zero? ? res.ppy : res.ppy - 1
|
|
551
|
+
px = (res.px0 + i) << shift_x
|
|
552
|
+
py = (res.py0 + j) << shift_y
|
|
553
|
+
prec = res.bands.map do |band|
|
|
554
|
+
x0 = [px, band.x0].max
|
|
555
|
+
y0 = [py, band.y0].max
|
|
556
|
+
x1 = [px + (1 << shift_x), band.x1].min
|
|
557
|
+
y1 = [py + (1 << shift_y), band.y1].min
|
|
558
|
+
next nil if x0 >= x1 || y0 >= y1
|
|
559
|
+
|
|
560
|
+
xcb = res.xcb
|
|
561
|
+
ycb = res.ycb
|
|
562
|
+
cx0 = x0 >> xcb
|
|
563
|
+
cy0 = y0 >> ycb
|
|
564
|
+
ncx = ((x1 + (1 << xcb) - 1) >> xcb) - cx0
|
|
565
|
+
ncy = ((y1 + (1 << ycb) - 1) >> ycb) - cy0
|
|
566
|
+
@codeblocks += ncx * ncy
|
|
567
|
+
raise UnsupportedImageError, "too many JPEG 2000 code-blocks in a tile" if @codeblocks > MAX_CODEBLOCKS
|
|
568
|
+
|
|
569
|
+
cblks = Array.new(ncx * ncy) do |k|
|
|
570
|
+
bx = cx0 + k % ncx
|
|
571
|
+
by = cy0 + k / ncx
|
|
572
|
+
CodeBlock.new([bx << xcb, x0].max, [by << ycb, y0].max,
|
|
573
|
+
[(bx + 1) << xcb, x1].min, [(by + 1) << ycb, y1].min)
|
|
574
|
+
end
|
|
575
|
+
PrecinctBand.new(cblks, TagTree.new(ncx, ncy), TagTree.new(ncx, ncy))
|
|
576
|
+
end
|
|
577
|
+
res.precincts[p] = prec
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
# Reads one packet (B.9, B.10): header, then the code-block data.
|
|
581
|
+
def read_packet(layer, res, c, p)
|
|
582
|
+
raise PacketError if @pos >= @stop && !@separate
|
|
583
|
+
|
|
584
|
+
tc = @components[c]
|
|
585
|
+
keep = res.r <= tc.decoded_levels
|
|
586
|
+
cblk_style = tc.style.cblk_style
|
|
587
|
+
prec = precinct(res, p)
|
|
588
|
+
data = @data
|
|
589
|
+
if @sop && @pos + 6 <= @stop && data.getbyte(@pos) == 0xFF && data.getbyte(@pos + 1) == 0x91
|
|
590
|
+
@pos += 6
|
|
591
|
+
end
|
|
592
|
+
bits = @hbits
|
|
593
|
+
bits.restart(@separate ? bits.pos : @pos)
|
|
594
|
+
contributions = []
|
|
595
|
+
if bits.bit == 1
|
|
596
|
+
res.bands.each_with_index do |band, bi|
|
|
597
|
+
pb = prec[bi] or next
|
|
598
|
+
pb.cblks.each_with_index do |cb, k|
|
|
599
|
+
if cb.included
|
|
600
|
+
next if bits.bit.zero?
|
|
601
|
+
else
|
|
602
|
+
next unless pb.inclusion.decode(bits, k, layer + 1)
|
|
603
|
+
|
|
604
|
+
planes = 0
|
|
605
|
+
planes += 1 until pb.zero_planes.decode(bits, k, planes + 1) || planes > MAX_BITPLANES
|
|
606
|
+
raise PacketError if planes > MAX_BITPLANES || bits.overrun
|
|
607
|
+
|
|
608
|
+
cb.numbps = band.mb - planes
|
|
609
|
+
cb.lblock = 3
|
|
610
|
+
cb.included = true
|
|
611
|
+
end
|
|
612
|
+
passes = coding_passes(bits)
|
|
613
|
+
while bits.bit == 1
|
|
614
|
+
cb.lblock += 1
|
|
615
|
+
raise PacketError if cb.lblock > 32
|
|
616
|
+
end
|
|
617
|
+
segment_lengths(bits, cb, passes, cblk_style, keep, contributions)
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
bits.align
|
|
622
|
+
raise PacketError if bits.overrun
|
|
623
|
+
|
|
624
|
+
hpos = bits.pos
|
|
625
|
+
hdata = bits.data
|
|
626
|
+
if @eph && hdata.getbyte(hpos) == 0xFF && hdata.getbyte(hpos + 1) == 0x92
|
|
627
|
+
hpos += 2
|
|
628
|
+
end
|
|
629
|
+
if @separate
|
|
630
|
+
bits.restart(hpos)
|
|
631
|
+
else
|
|
632
|
+
@pos = hpos
|
|
633
|
+
end
|
|
634
|
+
read_body(contributions)
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# Number of coding passes (Table B.4).
|
|
638
|
+
def coding_passes(bits)
|
|
639
|
+
return 1 if bits.bit.zero?
|
|
640
|
+
return 2 if bits.bit.zero?
|
|
641
|
+
|
|
642
|
+
n = bits.bits(2)
|
|
643
|
+
return 3 + n if n != 3
|
|
644
|
+
|
|
645
|
+
n = bits.bits(5)
|
|
646
|
+
return 6 + n if n != 31
|
|
647
|
+
|
|
648
|
+
37 + bits.bits(7)
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
# Reads the codeword segment lengths of a code-block's new passes
|
|
652
|
+
# (B.10.7), splitting them into segments where the code-block style
|
|
653
|
+
# terminates the arithmetic coder.
|
|
654
|
+
def segment_lengths(bits, cb, passes, style, keep, contributions)
|
|
655
|
+
new_seg = cb.seg_count.zero? || cb.seg_passes == cb.seg_max
|
|
656
|
+
seg = keep ? cb.segments[-1] : nil
|
|
657
|
+
while passes.positive?
|
|
658
|
+
if new_seg
|
|
659
|
+
cb.seg_max = segment_max_passes(cb, style)
|
|
660
|
+
cb.seg_passes = 0
|
|
661
|
+
cb.seg_count += 1
|
|
662
|
+
if keep
|
|
663
|
+
seg = ["".b, 0]
|
|
664
|
+
cb.segments << seg
|
|
665
|
+
end
|
|
666
|
+
end
|
|
667
|
+
n = cb.seg_max - cb.seg_passes
|
|
668
|
+
n = passes if passes < n
|
|
669
|
+
nbits = cb.lblock + (n.bit_length - 1)
|
|
670
|
+
raise PacketError if nbits > 32
|
|
671
|
+
|
|
672
|
+
contributions << [seg, n, bits.bits(nbits)]
|
|
673
|
+
cb.seg_passes += n
|
|
674
|
+
passes -= n
|
|
675
|
+
new_seg = true
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
# Passes of the next segment (OpenJPEG's opj_t2_init_seg).
|
|
680
|
+
def segment_max_passes(cb, style)
|
|
681
|
+
return 1 if style & 4 != 0 # termination on each pass
|
|
682
|
+
return 109 if style & 1 == 0 # no bypass: one segment
|
|
683
|
+
return 10 if cb.seg_count.zero?
|
|
684
|
+
|
|
685
|
+
prev = cb.seg_max
|
|
686
|
+
prev == 1 || prev == 10 ? 2 : 1
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
def read_body(contributions)
|
|
690
|
+
data = @data
|
|
691
|
+
truncated = false
|
|
692
|
+
contributions.each do |seg, passes, length|
|
|
693
|
+
avail = @stop - @pos
|
|
694
|
+
if length > avail
|
|
695
|
+
length = avail
|
|
696
|
+
truncated = true
|
|
697
|
+
end
|
|
698
|
+
if seg
|
|
699
|
+
seg[0] << data.byteslice(@pos, length) if length.positive?
|
|
700
|
+
seg[1] += passes
|
|
701
|
+
end
|
|
702
|
+
@pos += length
|
|
703
|
+
end
|
|
704
|
+
raise PacketError if truncated
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
def decode_codeblock(cb, band, roi, style)
|
|
708
|
+
segments = cb.segments
|
|
709
|
+
return if segments.empty?
|
|
710
|
+
|
|
711
|
+
w = cb.x1 - cb.x0
|
|
712
|
+
h = cb.y1 - cb.y0
|
|
713
|
+
numbps = cb.numbps
|
|
714
|
+
return if numbps + roi > MAX_BITPLANES
|
|
715
|
+
|
|
716
|
+
@t1.decode(w, h, segments, numbps, roi, band.orient, style)
|
|
717
|
+
@t1.store(band.rows, cb.x0 - band.x0, cb.y0 - band.y0, w, h, roi, band.step, band.width)
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
end
|
|
722
|
+
end
|