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,607 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QrReader
4
+ module Formats
5
+ module JPEG2000
6
+ # Inverse discrete wavelet transform (ITU-T T.800 Annex F): one
7
+ # synthesis level at a time from the four subbands, by lifting with
8
+ # periodic symmetric extension. The parity of the resolution's first
9
+ # coordinate (+cas+) says whether its first sample is low-pass (0) or
10
+ # high-pass (1), as in the standard's 1D_SR procedure. Rows are
11
+ # transformed first, then columns (like OpenJPEG).
12
+ #
13
+ # Planes are Arrays of row Arrays. Columns are lifted as whole rows
14
+ # (no gathering), and the subbands' rows are reused for the output.
15
+ # The lifting steps are pipelined: step k runs a fixed lag behind
16
+ # step k-1, so one loop applies all of them (2 for 5/3, 4 for 9/7)
17
+ # while the operands are in local variables; only the first and last
18
+ # few samples, where the symmetric extension mirrors, take the
19
+ # generic path.
20
+ #
21
+ # The 9/7 synthesis omits the K / (2/K) scaling of the lifting
22
+ # scheme: the decoder folds those factors into the dequantization
23
+ # step sizes (see DWT.scale_factor), saving a multiplication per
24
+ # sample and level.
25
+ module DWT
26
+ f32 = ->(v) { [v].pack("e").unpack1("e") }
27
+ # 9/7 lifting constants (Table F.4) as the single-precision values
28
+ # OpenJPEG uses, whose output is the reference; OpenJPEG scales
29
+ # high-pass samples by 1.625732422 instead of 2/K and compensates in
30
+ # the step sizes.
31
+ ALPHA = f32.call(-1.586134342)
32
+ BETA = f32.call(-0.052980118)
33
+ GAMMA = f32.call(0.882911075)
34
+ DELTA = f32.call(0.443506852)
35
+ K = f32.call(1.230174105)
36
+ TWO_INV_K = f32.call(1.625732422)
37
+
38
+ # The four 9/7 synthesis steps: t += c * (s[i + o] + s[i + o + 1]).
39
+ COEFFS97 = [-DELTA, -GAMMA, -BETA, -ALPHA].freeze
40
+
41
+ module_function
42
+
43
+ # The factor by which the 9/7 synthesis would scale a subband in
44
+ # one direction: +high+ is whether the band is high-pass in this
45
+ # direction at its own level, +sizes+ the sizes (width or height) of
46
+ # the resolutions from the band's own level up to the decoded one.
47
+ # Levels of size 1 are not scaled (like OpenJPEG).
48
+ def scale_factor(high, sizes)
49
+ factor = 1.0
50
+ sizes.each_with_index do |n, i|
51
+ next if n <= 1
52
+
53
+ factor *= i.zero? && high ? TWO_INV_K : K
54
+ end
55
+ factor
56
+ end
57
+
58
+ # One synthesis level: +ll+ (sn_y rows of sn_x), +hl+ (sn_y x
59
+ # dn_x), +lh+ (dn_y x sn_x) and +hh+ (dn_y x dn_x) become the next
60
+ # resolution's +rw+ x +rh+ rows. +cas_x+ / +cas_y+ are the parities
61
+ # of its x0 / y0. Subband rows may be nil: all zero (never written by
62
+ # tier-1). Rows with zero high-pass input take shortcuts (exact: the
63
+ # skipped terms are zero). Consumed subband rows are released.
64
+ def synthesize(ll, hl, lh, hh, rw, rh, sn_x, sn_y, cas_x, cas_y, reversible)
65
+ dn_x = rw - sn_x
66
+ dn_y = rh - sn_y
67
+ zero = reversible ? 0 : 0.0
68
+ perm = interleave_order(sn_x, dn_x, cas_x)
69
+ lows = Array.new(sn_y)
70
+ i = 0
71
+ while i < sn_y
72
+ high = hl[i]
73
+ lows[i] = horizontal(ll[i] || Array.new(sn_x, zero), high || Array.new(dn_x, zero), sn_x, dn_x, cas_x,
74
+ reversible, perm, !high.nil?)
75
+ ll[i] = hl[i] = nil
76
+ i += 1
77
+ end
78
+ highs = Array.new(dn_y)
79
+ zero_rows = Array.new(dn_y, false)
80
+ i = 0
81
+ while i < dn_y
82
+ low = lh[i]
83
+ high = hh[i]
84
+ if low.nil? && high.nil?
85
+ zero_rows[i] = true # stays nil: an all-zero row
86
+ else
87
+ highs[i] = horizontal(low || Array.new(sn_x, zero), high || Array.new(dn_x, zero), sn_x, dn_x, cas_x,
88
+ reversible, perm, !high.nil?)
89
+ lh[i] = hh[i] = nil
90
+ end
91
+ i += 1
92
+ end
93
+ vertical(lows, highs, sn_y, dn_y, rw, cas_y, reversible, zero_rows)
94
+ end
95
+
96
+ # Indices into low + high that give the interleaved row.
97
+ def interleave_order(sn, dn, cas)
98
+ Array.new(sn + dn) do |k|
99
+ if (k + cas).even?
100
+ (k - cas) >> 1
101
+ else
102
+ sn + ((k - 1 + cas) >> 1)
103
+ end
104
+ end
105
+ end
106
+
107
+ # Horizontal synthesis of one row: +low+ (sn samples) and +high+
108
+ # (dn samples) are lifted in place and returned interleaved.
109
+ # +high_nonzero+ false says that +high+ is all zero.
110
+ def horizontal(low, high, sn, dn, cas, reversible, perm, high_nonzero = true)
111
+ n = sn + dn
112
+ if n <= 1
113
+ if cas == 1 && dn == 1
114
+ v = high[0]
115
+ v = v.negative? ? -(-v / 2) : v / 2 if reversible
116
+ return [v]
117
+ end
118
+ return low
119
+ end
120
+ if reversible
121
+ high_nonzero ? lift53(low, high, sn, dn, cas) : predict53_only(low, high, sn, dn, cas)
122
+ else
123
+ lift97(low, high, sn, dn, cas, high_nonzero)
124
+ end
125
+ # Interleaved in place (the row keeps its storage; high is dropped).
126
+ low.replace(low.concat(high).values_at(*perm))
127
+ high.clear # frees its storage now (it would wait for a major GC)
128
+ low
129
+ end
130
+
131
+ # Lags of the pipelined steps behind step 1 (see the module notes).
132
+ def lags(cas, reversible)
133
+ if reversible
134
+ cas.zero? ? [0, 1] : [0, 0]
135
+ else
136
+ cas.zero? ? [0, 1, 1, 2] : [0, 0, 1, 1]
137
+ end
138
+ end
139
+
140
+ # First wavefront after the pipelined interior.
141
+ def interior_end(sn, dn, cas)
142
+ cas.zero? ? [sn, dn].min : [sn, dn - 1].min
143
+ end
144
+
145
+ # 9/7 lifting of one row (low and high samples separately). With
146
+ # all-zero high samples step 1 changes nothing and is skipped.
147
+ def lift97(l, h, sn, dn, cas, high_nonzero = true)
148
+ lag = lags(cas, false)
149
+ last = [sn - 1 + lag[2], dn - 1 + lag[3]].max
150
+ ge = interior_end(sn, dn, cas)
151
+ lo = cas.zero? ? -1 : 0
152
+ ho = cas.zero? ? 0 : -1
153
+ g = 0
154
+ while g <= last
155
+ if g >= 2 && g < ge
156
+ if high_nonzero
157
+ cas.zero? ? fused97_cas0(l, h, g, ge) : fused97_cas1(l, h, g, ge)
158
+ else
159
+ cas.zero? ? fused97z_cas0(l, h, g, ge) : fused97z_cas1(l, h, g, ge)
160
+ end
161
+ g = ge
162
+ next
163
+ end
164
+ k = high_nonzero ? 0 : 1
165
+ while k < 4
166
+ i = g - lag[k]
167
+ if k.even?
168
+ step_at(l, h, dn, i, lo, COEFFS97[k]) if i >= 0 && i < sn
169
+ elsif i >= 0 && i < dn
170
+ step_at(h, l, sn, i, ho, COEFFS97[k])
171
+ end
172
+ k += 1
173
+ end
174
+ g += 1
175
+ end
176
+ end
177
+
178
+ # t[i] += c * (s[i + o] + s[i + o + 1]), indices mirrored into s.
179
+ def step_at(t, s, ns, i, o, c)
180
+ j = i + o
181
+ j1 = j + 1
182
+ last = ns - 1
183
+ j = 0 if j.negative?
184
+ j = last if j > last
185
+ j1 = last if j1 > last
186
+ t[i] += c * (s[j] + s[j1])
187
+ end
188
+
189
+ # Wavefronts g...ge of the 9/7 steps for cas 0, operands carried in
190
+ # locals (see the module notes).
191
+ def fused97_cas0(l, h, g, ge)
192
+ c1 = -DELTA
193
+ c2 = -GAMMA
194
+ c3 = -BETA
195
+ c4 = -ALPHA
196
+ hm1 = h[g - 1]
197
+ lm1 = l[g - 1]
198
+ hm2 = h[g - 2]
199
+ lm2 = l[g - 2]
200
+ while g < ge
201
+ hg = h[g]
202
+ a = l[g] + c1 * (hm1 + hg)
203
+ b = hm1 + c2 * (lm1 + a)
204
+ d = lm1 + c3 * (hm2 + b)
205
+ h[g - 2] = hm2 + c4 * (lm2 + d)
206
+ l[g - 1] = d
207
+ lm2 = d
208
+ hm2 = b
209
+ lm1 = a
210
+ hm1 = hg
211
+ g += 1
212
+ end
213
+ l[ge - 1] = lm1
214
+ h[ge - 2] = hm2
215
+ end
216
+
217
+ def fused97_cas1(l, h, g, ge)
218
+ c1 = -DELTA
219
+ c2 = -GAMMA
220
+ c3 = -BETA
221
+ c4 = -ALPHA
222
+ hc = h[g]
223
+ lm1 = l[g - 1]
224
+ hm1 = h[g - 1]
225
+ lm2 = l[g - 2]
226
+ while g < ge
227
+ hn = h[g + 1]
228
+ a = l[g] + c1 * (hc + hn)
229
+ b = hc + c2 * (lm1 + a)
230
+ d = lm1 + c3 * (hm1 + b)
231
+ h[g - 1] = hm1 + c4 * (lm2 + d)
232
+ l[g - 1] = d
233
+ lm2 = d
234
+ hm1 = b
235
+ lm1 = a
236
+ hc = hn
237
+ g += 1
238
+ end
239
+ l[ge - 1] = lm1
240
+ h[ge - 1] = hm1
241
+ end
242
+
243
+ # fused97_cas0 for all-zero high input (step 1 is the identity).
244
+ def fused97z_cas0(l, h, g, ge)
245
+ c2 = -GAMMA
246
+ c3 = -BETA
247
+ c4 = -ALPHA
248
+ lm1 = l[g - 1]
249
+ hm2 = h[g - 2]
250
+ lm2 = l[g - 2]
251
+ while g < ge
252
+ a = l[g]
253
+ b = c2 * (lm1 + a)
254
+ d = lm1 + c3 * (hm2 + b)
255
+ h[g - 2] = hm2 + c4 * (lm2 + d)
256
+ l[g - 1] = d
257
+ lm2 = d
258
+ hm2 = b
259
+ lm1 = a
260
+ g += 1
261
+ end
262
+ h[ge - 2] = hm2
263
+ end
264
+
265
+ def fused97z_cas1(l, h, g, ge)
266
+ c2 = -GAMMA
267
+ c3 = -BETA
268
+ c4 = -ALPHA
269
+ lm1 = l[g - 1]
270
+ hm1 = h[g - 1]
271
+ lm2 = l[g - 2]
272
+ while g < ge
273
+ a = l[g]
274
+ b = c2 * (lm1 + a)
275
+ d = lm1 + c3 * (hm1 + b)
276
+ h[g - 1] = hm1 + c4 * (lm2 + d)
277
+ l[g - 1] = d
278
+ lm2 = d
279
+ hm1 = b
280
+ lm1 = a
281
+ g += 1
282
+ end
283
+ h[ge - 1] = hm1
284
+ end
285
+
286
+ # 5/3 synthesis of a row whose high samples are all zero: the update
287
+ # step is the identity, the predict step reads low samples only.
288
+ def predict53_only(l, h, sn, dn, cas)
289
+ last = sn - 1
290
+ i = 0
291
+ if cas.zero?
292
+ while i < dn
293
+ j1 = i + 1
294
+ j1 = last if j1 > last
295
+ h[i] = (l[i] + l[j1]) >> 1
296
+ i += 1
297
+ end
298
+ else
299
+ while i < dn
300
+ j = i - 1
301
+ j = 0 if j.negative?
302
+ j1 = i
303
+ j1 = last if j1 > last
304
+ h[i] = (l[j] + l[j1]) >> 1
305
+ i += 1
306
+ end
307
+ end
308
+ end
309
+
310
+ # 5/3 lifting of one row.
311
+ def lift53(l, h, sn, dn, cas)
312
+ lag = lags(cas, true)
313
+ last = [sn - 1, dn - 1 + lag[1]].max
314
+ ge = interior_end(sn, dn, cas)
315
+ lo = cas.zero? ? -1 : 0
316
+ ho = cas.zero? ? 0 : -1
317
+ g = 0
318
+ while g <= last
319
+ if g >= 1 && g < ge
320
+ cas.zero? ? fused53_cas0(l, h, g, ge) : fused53_cas1(l, h, g, ge)
321
+ g = ge
322
+ next
323
+ end
324
+ update53_at(l, h, dn, g, lo) if g < sn
325
+ i = g - lag[1]
326
+ predict53_at(h, l, sn, i, ho) if i >= 0 && i < dn
327
+ g += 1
328
+ end
329
+ end
330
+
331
+ def update53_at(t, s, ns, i, o)
332
+ j = i + o
333
+ j1 = j + 1
334
+ last = ns - 1
335
+ j = 0 if j.negative?
336
+ j = last if j > last
337
+ j1 = last if j1 > last
338
+ t[i] -= (s[j] + s[j1] + 2) >> 2
339
+ end
340
+
341
+ def predict53_at(t, s, ns, i, o)
342
+ j = i + o
343
+ j1 = j + 1
344
+ last = ns - 1
345
+ j = 0 if j.negative?
346
+ j = last if j > last
347
+ j1 = last if j1 > last
348
+ t[i] += (s[j] + s[j1]) >> 1
349
+ end
350
+
351
+ def fused53_cas0(l, h, g, ge)
352
+ hm1 = h[g - 1]
353
+ lm1 = l[g - 1]
354
+ while g < ge
355
+ hg = h[g]
356
+ a = l[g] - ((hm1 + hg + 2) >> 2)
357
+ h[g - 1] = hm1 + ((lm1 + a) >> 1)
358
+ l[g] = a
359
+ lm1 = a
360
+ hm1 = hg
361
+ g += 1
362
+ end
363
+ end
364
+
365
+ def fused53_cas1(l, h, g, ge)
366
+ hc = h[g]
367
+ lm1 = l[g - 1]
368
+ while g < ge
369
+ hn = h[g + 1]
370
+ a = l[g] - ((hc + hn + 2) >> 2)
371
+ h[g] = hc + ((lm1 + a) >> 1)
372
+ l[g] = a
373
+ lm1 = a
374
+ hc = hn
375
+ g += 1
376
+ end
377
+ end
378
+
379
+ # Vertical synthesis of whole rows; returns the interleaved rows.
380
+ # +zero_rows+ flags high rows that are all zero (given as nil).
381
+ def vertical(lows, highs, sn, dn, width, cas, reversible, zero_rows = nil)
382
+ n = sn + dn
383
+ if zero_rows
384
+ zero = reversible ? 0 : 0.0
385
+ i = 0
386
+ while i < dn
387
+ highs[i] ||= Array.new(width, zero)
388
+ i += 1
389
+ end
390
+ end
391
+ if n <= 1
392
+ if cas == 1 && dn == 1
393
+ row = highs[0]
394
+ halve_row(row, width) if reversible
395
+ return [row]
396
+ end
397
+ return lows
398
+ end
399
+ if reversible
400
+ rows53(lows, highs, sn, dn, cas, width, zero_rows)
401
+ else
402
+ rows97(lows, highs, sn, dn, cas, width, zero_rows)
403
+ end
404
+ out = Array.new(n)
405
+ i = 0
406
+ while i < sn
407
+ out[2 * i + cas] = lows[i]
408
+ i += 1
409
+ end
410
+ i = 0
411
+ while i < dn
412
+ out[2 * i + 1 - cas] = highs[i]
413
+ i += 1
414
+ end
415
+ out
416
+ end
417
+
418
+ # The 9/7 steps on rows, pipelined like lift97.
419
+ def rows97(l, h, sn, dn, cas, width, zero_rows = nil)
420
+ lag = lags(cas, false)
421
+ last = [sn - 1 + lag[2], dn - 1 + lag[3]].max
422
+ ge = interior_end(sn, dn, cas)
423
+ lo = cas.zero? ? -1 : 0
424
+ ho = cas.zero? ? 0 : -1
425
+ g = 0
426
+ while g <= last
427
+ if g >= 2 && g < ge
428
+ if cas.zero?
429
+ if zero_rows && zero_rows[g - 1] && zero_rows[g]
430
+ row_fused97z(l[g], h[g - 1], l[g - 1], h[g - 2], l[g - 2], width)
431
+ else
432
+ row_fused97(l[g], h[g - 1], h[g], l[g - 1], h[g - 2], l[g - 2], width)
433
+ end
434
+ elsif zero_rows && zero_rows[g] && zero_rows[g + 1]
435
+ row_fused97z(l[g], h[g], l[g - 1], h[g - 1], l[g - 2], width)
436
+ else
437
+ row_fused97(l[g], h[g], h[g + 1], l[g - 1], h[g - 1], l[g - 2], width)
438
+ end
439
+ else
440
+ k = 0
441
+ while k < 4
442
+ i = g - lag[k]
443
+ if k.even?
444
+ row_step(l, h, dn, i, lo, COEFFS97[k], width) if i >= 0 && i < sn
445
+ elsif i >= 0 && i < dn
446
+ row_step(h, l, sn, i, ho, COEFFS97[k], width)
447
+ end
448
+ k += 1
449
+ end
450
+ end
451
+ g += 1
452
+ end
453
+ end
454
+
455
+ def row_step(t, s, ns, i, o, c, width)
456
+ j = i + o
457
+ j1 = j + 1
458
+ last = ns - 1
459
+ j = 0 if j.negative?
460
+ j = last if j > last
461
+ j1 = last if j1 > last
462
+ row_axpy(t[i], s[j], s[j1], c, width)
463
+ end
464
+
465
+ # All four 9/7 steps of one wavefront on rows: a += c1 (b + c);
466
+ # b += c2 (d + a); d += c3 (e + b); e += c4 (f + d).
467
+ def row_fused97(ra, rb, rc, rd, re, rf, width)
468
+ c1 = -DELTA
469
+ c2 = -GAMMA
470
+ c3 = -BETA
471
+ c4 = -ALPHA
472
+ x = 0
473
+ while x < width
474
+ b = rb[x]
475
+ a = ra[x] + c1 * (b + rc[x])
476
+ ra[x] = a
477
+ d = rd[x]
478
+ b += c2 * (d + a)
479
+ rb[x] = b
480
+ e = re[x]
481
+ d += c3 * (e + b)
482
+ rd[x] = d
483
+ re[x] = e + c4 * (rf[x] + d)
484
+ x += 1
485
+ end
486
+ end
487
+
488
+ # row_fused97 when rows b and c are all zero (a is unchanged).
489
+ def row_fused97z(ra, rb, rd, re, rf, width)
490
+ c2 = -GAMMA
491
+ c3 = -BETA
492
+ c4 = -ALPHA
493
+ x = 0
494
+ while x < width
495
+ d = rd[x]
496
+ b = c2 * (d + ra[x])
497
+ rb[x] = b
498
+ e = re[x]
499
+ d += c3 * (e + b)
500
+ rd[x] = d
501
+ re[x] = e + c4 * (rf[x] + d)
502
+ x += 1
503
+ end
504
+ end
505
+
506
+ def rows53(l, h, sn, dn, cas, width, zero_rows = nil)
507
+ lag = lags(cas, true)
508
+ last = [sn - 1, dn - 1 + lag[1]].max
509
+ ge = interior_end(sn, dn, cas)
510
+ lo = cas.zero? ? -1 : 0
511
+ ho = cas.zero? ? 0 : -1
512
+ g = 0
513
+ while g <= last
514
+ if g >= 1 && g < ge
515
+ if cas.zero?
516
+ if zero_rows && zero_rows[g - 1] && zero_rows[g]
517
+ row_average(h[g - 1], l[g - 1], l[g], width)
518
+ else
519
+ row_fused53(l[g], h[g - 1], h[g], l[g - 1], width)
520
+ end
521
+ elsif zero_rows && zero_rows[g] && zero_rows[g + 1]
522
+ row_average(h[g], l[g - 1], l[g], width)
523
+ else
524
+ row_fused53(l[g], h[g], h[g + 1], l[g - 1], width)
525
+ end
526
+ else
527
+ row_step53(l, h, dn, g, lo, width, true) if g < sn
528
+ i = g - lag[1]
529
+ row_step53(h, l, sn, i, ho, width, false) if i >= 0 && i < dn
530
+ end
531
+ g += 1
532
+ end
533
+ end
534
+
535
+ def row_step53(t, s, ns, i, o, width, update)
536
+ j = i + o
537
+ j1 = j + 1
538
+ last = ns - 1
539
+ j = 0 if j.negative?
540
+ j = last if j > last
541
+ j1 = last if j1 > last
542
+ if update
543
+ row_update53(t[i], s[j], s[j1], width)
544
+ else
545
+ row_predict53(t[i], s[j], s[j1], width)
546
+ end
547
+ end
548
+
549
+ # Both 5/3 steps of one wavefront: a -= (b + c + 2) >> 2;
550
+ # b += (d + a) >> 1.
551
+ def row_fused53(ra, rb, rc, rd, width)
552
+ x = 0
553
+ while x < width
554
+ b = rb[x]
555
+ a = ra[x] - ((b + rc[x] + 2) >> 2)
556
+ ra[x] = a
557
+ rb[x] = b + ((rd[x] + a) >> 1)
558
+ x += 1
559
+ end
560
+ end
561
+
562
+ # t = (a + b) >> 1: the 5/3 wavefront when t and its neighbour
563
+ # high row are zero (the update step is then the identity).
564
+ def row_average(t, a, b, width)
565
+ x = 0
566
+ while x < width
567
+ t[x] = (a[x] + b[x]) >> 1
568
+ x += 1
569
+ end
570
+ end
571
+
572
+ def row_axpy(t, a, b, c, width)
573
+ x = 0
574
+ while x < width
575
+ t[x] += c * (a[x] + b[x])
576
+ x += 1
577
+ end
578
+ end
579
+
580
+ def row_update53(t, a, b, width)
581
+ x = 0
582
+ while x < width
583
+ t[x] -= (a[x] + b[x] + 2) >> 2
584
+ x += 1
585
+ end
586
+ end
587
+
588
+ def row_predict53(t, a, b, width)
589
+ x = 0
590
+ while x < width
591
+ t[x] += (a[x] + b[x]) >> 1
592
+ x += 1
593
+ end
594
+ end
595
+
596
+ def halve_row(row, width)
597
+ x = 0
598
+ while x < width
599
+ v = row[x]
600
+ row[x] = v.negative? ? -(-v / 2) : v / 2
601
+ x += 1
602
+ end
603
+ end
604
+ end
605
+ end
606
+ end
607
+ end