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.
@@ -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