qr_reader 0.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 +7 -0
- data/CHANGELOG.md +16 -0
- data/LICENSE.txt +21 -0
- data/NOTICE +14 -0
- data/README.md +222 -0
- data/exe/qr_reader +66 -0
- data/lib/qr_reader/binarizer.rb +170 -0
- data/lib/qr_reader/bit_matrix.rb +120 -0
- data/lib/qr_reader/decoder/bitstream_parser.rb +307 -0
- data/lib/qr_reader/decoder/character_set.rb +163 -0
- data/lib/qr_reader/decoder/codewords.rb +164 -0
- data/lib/qr_reader/decoder/data_mask.rb +57 -0
- data/lib/qr_reader/decoder/format_reader.rb +204 -0
- data/lib/qr_reader/decoder/function_patterns.rb +62 -0
- data/lib/qr_reader/decoder/galois_field.rb +69 -0
- data/lib/qr_reader/decoder/reed_solomon.rb +312 -0
- data/lib/qr_reader/decoder.rb +241 -0
- data/lib/qr_reader/detector/alignment_grid.rb +127 -0
- data/lib/qr_reader/detector/alignment_pattern_finder.rb +191 -0
- data/lib/qr_reader/detector/candidate/dimension.rb +237 -0
- data/lib/qr_reader/detector/candidate/strokes.rb +126 -0
- data/lib/qr_reader/detector/candidate.rb +436 -0
- data/lib/qr_reader/detector/finder_pattern.rb +63 -0
- data/lib/qr_reader/detector/finder_pattern_finder.rb +199 -0
- data/lib/qr_reader/detector/geometry.rb +118 -0
- data/lib/qr_reader/detector/grid_sampler.rb +350 -0
- data/lib/qr_reader/detector/pattern_sets.rb +235 -0
- data/lib/qr_reader/detector/perspective_transform.rb +117 -0
- data/lib/qr_reader/detector/pure_detector.rb +197 -0
- data/lib/qr_reader/detector.rb +215 -0
- data/lib/qr_reader/errors.rb +14 -0
- data/lib/qr_reader/format_information.rb +79 -0
- data/lib/qr_reader/formats/bmp.rb +434 -0
- data/lib/qr_reader/formats/ccitt.rb +81 -0
- data/lib/qr_reader/formats/gif.rb +272 -0
- data/lib/qr_reader/formats/jpeg.rb +152 -0
- data/lib/qr_reader/formats/pdf.rb +2935 -0
- data/lib/qr_reader/formats/png.rb +311 -0
- data/lib/qr_reader/formats/pnm.rb +286 -0
- data/lib/qr_reader/formats/tiff.rb +1345 -0
- data/lib/qr_reader/formats.rb +279 -0
- data/lib/qr_reader/image.rb +231 -0
- data/lib/qr_reader/kernels/binarizer.rb +475 -0
- data/lib/qr_reader/kernels/ccitt.rb +554 -0
- data/lib/qr_reader/kernels/detector.rb +587 -0
- data/lib/qr_reader/kernels/image.rb +65 -0
- data/lib/qr_reader/kernels/jpeg.rb +3421 -0
- data/lib/qr_reader/kernels/lzw.rb +173 -0
- data/lib/qr_reader/kernels/pixels.rb +116 -0
- data/lib/qr_reader/kernels/png.rb +1138 -0
- data/lib/qr_reader/kernels.rb +14 -0
- data/lib/qr_reader/native_kernels.rb +130 -0
- data/lib/qr_reader/reader.rb +348 -0
- data/lib/qr_reader/result.rb +49 -0
- data/lib/qr_reader/symbol_version.rb +173 -0
- data/lib/qr_reader/version.rb +5 -0
- data/lib/qr_reader.rb +77 -0
- metadata +103 -0
|
@@ -0,0 +1,3421 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../errors"
|
|
4
|
+
|
|
5
|
+
# JPEG kernels: a luminance-only JPEG decoder in the Ruby subset that Spinel
|
|
6
|
+
# compiles (see DESIGN.md, "Kernels"); QrReader::Formats::JPEG wraps it.
|
|
7
|
+
#
|
|
8
|
+
# Supported: baseline (SOF0), extended sequential Huffman (SOF1) and
|
|
9
|
+
# progressive (SOF2) 8-bit JPEGs with any sampling factors, restart
|
|
10
|
+
# intervals, 8/16-bit quantisation tables, 1 component (gray), 3 components
|
|
11
|
+
# (YCbCr, or RGB via Adobe APP14 / component ids "RGB") and 4 components
|
|
12
|
+
# (Adobe CMYK and YCCK). Arithmetic coding, lossless, hierarchical, 12-bit
|
|
13
|
+
# and JPEG-LS files raise UnsupportedImageError. The output matches
|
|
14
|
+
# libjpeg-turbo's default "islow" IDCT exactly (as built with SIMD, which
|
|
15
|
+
# saturates out-of-range samples), including the reduced IDCTs,
|
|
16
|
+
# per-component DCT scaling and upsampling used for scale 2, 4 and 8.
|
|
17
|
+
# Truncated scan data decodes what is present (missing blocks stay
|
|
18
|
+
# mid-gray); damaged restart intervals are resynchronised by their marker
|
|
19
|
+
# numbers; other corruption raises ImageError.
|
|
20
|
+
#
|
|
21
|
+
# How it stays fast in pure Ruby:
|
|
22
|
+
# * For YCbCr only Y is reconstructed (Y is the luminance). Chroma blocks
|
|
23
|
+
# are entropy-decoded and dropped; chroma-only progressive scans (and
|
|
24
|
+
# AC scans at scale 8) are skipped without decoding.
|
|
25
|
+
# * Byte stuffing and restart markers are removed per scan at C speed, so
|
|
26
|
+
# the bit reader (32 bits per refill) never checks for markers.
|
|
27
|
+
# * Huffman lookahead tables also carry the run length and sign-extended
|
|
28
|
+
# coefficient, so most coefficients cost a single table lookup.
|
|
29
|
+
# * Coefficients are decoded into one Array per block row (65 entries per
|
|
30
|
+
# block: 64 dequantised coefficients in natural order, then the zigzag
|
|
31
|
+
# index of the last nonzero one), which selects a DC-only fill or an IDCT
|
|
32
|
+
# specialised for the inputs that can be nonzero (derived from libjpeg's
|
|
33
|
+
# formulas). Rows are IDCT'd, packed and cleared once per MCU row.
|
|
34
|
+
# * Hot loops live in methods called per MCU, block row or block, so YJIT
|
|
35
|
+
# (which compiles a method once it has been called 30 times) kicks in
|
|
36
|
+
# during the first decode.
|
|
37
|
+
# * Samples are collected four to an Array element (32-bit words) per MCU
|
|
38
|
+
# row and packed to bytes at C speed.
|
|
39
|
+
#
|
|
40
|
+
# Memory stays proportional to the output: sequential scans keep one MCU
|
|
41
|
+
# row of coefficients; progressive scans keep every coefficient of the
|
|
42
|
+
# needed components as packed 16-bit Strings (one per block row, allocated
|
|
43
|
+
# only where data arrives); nothing is allocated per pixel or coefficient
|
|
44
|
+
# for a whole image.
|
|
45
|
+
#
|
|
46
|
+
# Two resolutions for about the price of one decode: jpeg_luma_keep also
|
|
47
|
+
# returns a compact store of the luminance (see JpegDecoder#store), from
|
|
48
|
+
# which jpeg_render produces any other scale. For sequential JPEGs it holds
|
|
49
|
+
# the scan data and, per luminance block, where its AC coefficients start
|
|
50
|
+
# and its DC (8 bytes per block), so rendering skips the chroma blocks and
|
|
51
|
+
# all DC decoding; for progressive JPEGs the coefficients themselves.
|
|
52
|
+
module QrReaderKernels
|
|
53
|
+
# [width, height] from the frame header (the height from a DNL marker
|
|
54
|
+
# when the header gives 0), without decoding.
|
|
55
|
+
# spinel-sample: QrReaderKernels.jpeg_info("\xFF\xD8".b)
|
|
56
|
+
def self.jpeg_info(bytes)
|
|
57
|
+
JpegDecoder.new(bytes, 1, false).info
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Luminance at 1/+scale+ (1, 2, 4 or 8) of the size, ceil(width / scale)
|
|
61
|
+
# x ceil(height / scale) bytes, row-major.
|
|
62
|
+
# spinel-sample: QrReaderKernels.jpeg_luma("\xFF\xD8".b, 1)
|
|
63
|
+
def self.jpeg_luma(bytes, scale)
|
|
64
|
+
JpegDecoder.new(bytes, scale, false).decode
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Like jpeg_luma, but also returns a store of the luminance component
|
|
68
|
+
# for jpeg_render: [luma, store]. The store is empty when the luminance
|
|
69
|
+
# is not a single component (RGB, CMYK) or too large for scale 1.
|
|
70
|
+
# spinel-sample: QrReaderKernels.jpeg_luma_keep("\xFF\xD8".b, 4)
|
|
71
|
+
def self.jpeg_luma_keep(bytes, scale)
|
|
72
|
+
decoder = JpegDecoder.new(bytes, scale, true)
|
|
73
|
+
luma = decoder.decode
|
|
74
|
+
[luma, decoder.store]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Luminance at 1/+scale+ from a store made by jpeg_luma_keep: the same
|
|
78
|
+
# bytes as jpeg_luma at that scale, without decoding chroma or DCs.
|
|
79
|
+
# spinel-sample: QrReaderKernels.jpeg_render("\x00".b, 1)
|
|
80
|
+
def self.jpeg_render(store, scale)
|
|
81
|
+
JpegDecoder.new(store, scale, false).render_store
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Unsigned little-endian 32-bit Integer at data[off, 4], or -1 if the
|
|
85
|
+
# data ends before.
|
|
86
|
+
def self.jpeg_u32(data, off)
|
|
87
|
+
return -1 if off < 0 || off + 4 > data.bytesize
|
|
88
|
+
|
|
89
|
+
data.getbyte(off) | (data.getbyte(off + 1) << 8) | (data.getbyte(off + 2) << 16) | (data.getbyte(off + 3) << 24)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# --- Tables -------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
# Lookahead bits of the Huffman fast tables.
|
|
95
|
+
JPEG_FAST_BITS = 10
|
|
96
|
+
JPEG_FAST_MASK = (1 << JPEG_FAST_BITS) - 1
|
|
97
|
+
|
|
98
|
+
# Run used for end-of-block in the AC fast tables: it pushes the
|
|
99
|
+
# coefficient index past 63, ending the block loop without a branch.
|
|
100
|
+
# A block loop that ended at k > JPEG_EOB_RUN had its EOB at k - EOB_RUN - 1.
|
|
101
|
+
JPEG_EOB_RUN = 100
|
|
102
|
+
|
|
103
|
+
# Zigzag index -> natural (row-major) index.
|
|
104
|
+
JPEG_ZIGZAG = [
|
|
105
|
+
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
|
|
106
|
+
12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
|
|
107
|
+
35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
|
|
108
|
+
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
|
|
109
|
+
].freeze
|
|
110
|
+
|
|
111
|
+
# JPEG_ZIGZAG extended for corrupt runs past 63 (clamped to 63 like
|
|
112
|
+
# libjpeg) and for the end-of-block pseudo run (slot 64 of the block,
|
|
113
|
+
# which is overwritten with the block's last nonzero index afterwards).
|
|
114
|
+
JPEG_ZIGZAG_EXT = (JPEG_ZIGZAG + Array.new(16, 63) + Array.new(JPEG_EOB_RUN + 4 - 16, 64)).freeze
|
|
115
|
+
|
|
116
|
+
# Entries per block of a coefficient row: 64 coefficients in natural
|
|
117
|
+
# order and, at index 64, the zigzag index of the last nonzero one.
|
|
118
|
+
JPEG_BLOCK_STRIDE = 65
|
|
119
|
+
|
|
120
|
+
# Decoded samples are buffered as packed little-endian words (first
|
|
121
|
+
# sample in the low byte: "V*" packs faster than "N*"). By output block
|
|
122
|
+
# size (8 / scale): samples per word, words per block row, the factor
|
|
123
|
+
# that repeats a sample over a word, and the pack directive.
|
|
124
|
+
JPEG_SAMPLES_PER_WORD = [0, 1, 2, 0, 4, 0, 0, 0, 4].freeze
|
|
125
|
+
JPEG_WORDS = [0, 1, 1, 0, 1, 0, 0, 0, 2].freeze
|
|
126
|
+
JPEG_SPREAD = [0, 1, 0x0101, 0, 0x01010101, 0, 0, 0, 0x01010101].freeze
|
|
127
|
+
JPEG_PACK = ["", "C*", "v*", "", "V*", "", "", "", "V*"].freeze
|
|
128
|
+
|
|
129
|
+
# Largest supported output (64 Mi pixels, e.g. 8192 x 8192); bigger
|
|
130
|
+
# images need a larger scale. Guards against absurd header sizes.
|
|
131
|
+
JPEG_MAX_PIXELS = 1 << 26
|
|
132
|
+
|
|
133
|
+
# Most bytes the coefficients of a progressive JPEG may take (2 per
|
|
134
|
+
# coefficient): enough for one needed component of a MAX_PIXELS image,
|
|
135
|
+
# and for all four of a CMYK image of a quarter of that size.
|
|
136
|
+
JPEG_MAX_COEFFICIENT_BYTES = 160 << 20
|
|
137
|
+
|
|
138
|
+
# Block visits (blocks covered by decoded scans) per block of the needed
|
|
139
|
+
# components after which the rest of a file is ignored: real progressive
|
|
140
|
+
# files make about 3 to 10, but crafted ones could repeat cheap scans
|
|
141
|
+
# (e.g. end-of-band runs over the whole image).
|
|
142
|
+
JPEG_MAX_VISITS = 64
|
|
143
|
+
|
|
144
|
+
# Decoded scans after which the rest of a file is ignored: crafted files
|
|
145
|
+
# with endless refinement scans could otherwise take very long (real
|
|
146
|
+
# progressive files have about 6 to 20 scans).
|
|
147
|
+
JPEG_MAX_SCANS = 256
|
|
148
|
+
|
|
149
|
+
# Colour spaces of the stored components.
|
|
150
|
+
JPEG_GRAY = 0
|
|
151
|
+
JPEG_YCBCR = 1
|
|
152
|
+
JPEG_RGB = 2
|
|
153
|
+
JPEG_CMYK = 3
|
|
154
|
+
JPEG_YCCK = 4
|
|
155
|
+
JPEG_OTHER = 5
|
|
156
|
+
|
|
157
|
+
# Standard Huffman tables (ITU T.81 Annex K.3), used when a scan refers
|
|
158
|
+
# to an undefined table 0 or 1 (Motion-JPEG frames omit them), like
|
|
159
|
+
# libjpeg-turbo does: code counts per length and symbols.
|
|
160
|
+
JPEG_STD_DC_COUNTS = [
|
|
161
|
+
[0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
|
|
162
|
+
].freeze
|
|
163
|
+
JPEG_STD_DC_SYMBOLS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].freeze
|
|
164
|
+
JPEG_STD_AC_COUNTS = [
|
|
165
|
+
[0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d], [0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77]
|
|
166
|
+
].freeze
|
|
167
|
+
JPEG_STD_AC_SYMBOLS = [
|
|
168
|
+
[
|
|
169
|
+
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
|
|
170
|
+
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
|
|
171
|
+
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
|
|
172
|
+
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
|
|
173
|
+
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
|
|
174
|
+
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
|
|
175
|
+
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
|
176
|
+
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
|
|
177
|
+
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
|
|
178
|
+
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
|
179
|
+
0xf9, 0xfa
|
|
180
|
+
],
|
|
181
|
+
[
|
|
182
|
+
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
|
|
183
|
+
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
|
|
184
|
+
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
|
|
185
|
+
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
|
|
186
|
+
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
|
187
|
+
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
|
188
|
+
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
|
|
189
|
+
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
|
|
190
|
+
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
|
|
191
|
+
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
|
192
|
+
0xf9, 0xfa
|
|
193
|
+
]
|
|
194
|
+
].freeze
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# Post-IDCT range limiting of libjpeg-turbo's 8x8, 4x4 and 2x2 IDCTs,
|
|
198
|
+
# whose SIMD versions (used on x86 and ARM) saturate: indexed by
|
|
199
|
+
# (sample + 128) & 0xFFFF, clamps samples within +-32767 to 0..255.
|
|
200
|
+
def self.jpeg_clamp_table
|
|
201
|
+
t = Array.new(65_536, 0)
|
|
202
|
+
i = 0
|
|
203
|
+
while i < 32_896
|
|
204
|
+
t[i] = i < 256 ? i : 255
|
|
205
|
+
i += 1
|
|
206
|
+
end
|
|
207
|
+
t
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# libjpeg's C range-limit table (used by its 1x1 IDCT at scale 8),
|
|
211
|
+
# indexed by (sample + 128) & 1023: clamps to 0..255 near the valid range
|
|
212
|
+
# but wraps far out-of-range samples around.
|
|
213
|
+
def self.jpeg_range_limit_table
|
|
214
|
+
t = Array.new(1024, 0)
|
|
215
|
+
i = 0
|
|
216
|
+
while i < 1024
|
|
217
|
+
c = (i - 128) & 1023
|
|
218
|
+
t[i] = if c < 128 then c + 128
|
|
219
|
+
elsif c < 512 then 255
|
|
220
|
+
elsif c < 896 then 0
|
|
221
|
+
else c - 896
|
|
222
|
+
end
|
|
223
|
+
i += 1
|
|
224
|
+
end
|
|
225
|
+
t
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# libjpeg's YCbCr -> RGB tables (jdcolor.c, 16-bit fixed point), indexed
|
|
229
|
+
# by the Cb/Cr sample: Cr -> R, Cb -> B, Cr -> G and Cb -> G (+ rounding).
|
|
230
|
+
def self.jpeg_color_table(kind)
|
|
231
|
+
t = Array.new(256, 0)
|
|
232
|
+
i = 0
|
|
233
|
+
while i < 256
|
|
234
|
+
x = i - 128
|
|
235
|
+
t[i] = if kind == 0 then (91_881 * x + 32_768) >> 16
|
|
236
|
+
elsif kind == 1 then (116_130 * x + 32_768) >> 16
|
|
237
|
+
elsif kind == 2 then -46_802 * x
|
|
238
|
+
else -22_554 * x + 32_768
|
|
239
|
+
end
|
|
240
|
+
i += 1
|
|
241
|
+
end
|
|
242
|
+
t
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
JPEG_CLAMP = jpeg_clamp_table.freeze
|
|
246
|
+
JPEG_RANGE_LIMIT = jpeg_range_limit_table.freeze
|
|
247
|
+
JPEG_CR_R = jpeg_color_table(0).freeze
|
|
248
|
+
JPEG_CB_B = jpeg_color_table(1).freeze
|
|
249
|
+
JPEG_CR_G = jpeg_color_table(2).freeze
|
|
250
|
+
JPEG_CB_G = jpeg_color_table(3).freeze
|
|
251
|
+
|
|
252
|
+
# A shared empty Integer Array: "not defined" tables, unused slots.
|
|
253
|
+
JPEG_NONE = Array.new(0, 0).freeze
|
|
254
|
+
# Huffman code counts of an undefined table.
|
|
255
|
+
JPEG_NO_COUNTS = Array.new(16, 0).freeze
|
|
256
|
+
|
|
257
|
+
JPEG_FF = "\xFF".b.freeze
|
|
258
|
+
JPEG_DNL_MARKER = "\xFF\xDC\x00\x04".b.freeze
|
|
259
|
+
# Zero bytes appended to a scan: more than one MCU can consume, so a
|
|
260
|
+
# truncated MCU never reads past the end of the data.
|
|
261
|
+
JPEG_TAIL_PADDING = ("\0" * 4096).b.freeze
|
|
262
|
+
|
|
263
|
+
# First Integer of a store made by jpeg_luma_keep ("JPK3"), and its kinds.
|
|
264
|
+
JPEG_STORE_MAGIC = 0x334B_504A
|
|
265
|
+
JPEG_STORE_SEQUENTIAL = 1
|
|
266
|
+
JPEG_STORE_PROGRESSIVE = 2
|
|
267
|
+
# Integers in a store header (before the kind's own data).
|
|
268
|
+
JPEG_STORE_HEAD = 77
|
|
269
|
+
# Bytes per block of a raw progressive coefficient row, and the offset of
|
|
270
|
+
# the block's last nonzero zigzag index in it.
|
|
271
|
+
JPEG_RAW_BLOCK = JPEG_BLOCK_STRIDE * 2
|
|
272
|
+
JPEG_RAW_KM = 128
|
|
273
|
+
|
|
274
|
+
# Name of an unsupported frame type (SOF marker code).
|
|
275
|
+
def self.jpeg_sof_name(code)
|
|
276
|
+
if code == 0xC3 then "lossless"
|
|
277
|
+
elsif code == 0xC5 then "hierarchical"
|
|
278
|
+
elsif code == 0xC6 then "hierarchical progressive"
|
|
279
|
+
elsif code == 0xC7 then "hierarchical lossless"
|
|
280
|
+
elsif code == 0xC9 then "arithmetic-coded"
|
|
281
|
+
elsif code == 0xCA then "arithmetic-coded progressive"
|
|
282
|
+
elsif code == 0xCB then "arithmetic-coded lossless"
|
|
283
|
+
elsif code == 0xCD then "arithmetic-coded hierarchical"
|
|
284
|
+
elsif code == 0xCE then "arithmetic-coded hierarchical progressive"
|
|
285
|
+
elsif code == 0xCF then "arithmetic-coded hierarchical lossless"
|
|
286
|
+
else "JPEG-LS"
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Raised internally when the data ends early; decoding then finishes with
|
|
291
|
+
# what was decoded so far.
|
|
292
|
+
class JpegTruncated < QrReader::ImageError; end
|
|
293
|
+
|
|
294
|
+
# A Huffman table with FAST_BITS lookahead tables.
|
|
295
|
+
#
|
|
296
|
+
# +look+ maps the next FAST_BITS bits to (code length << 8 | symbol), or 0
|
|
297
|
+
# for longer codes (see #decode_long). +fast+ also folds in the extra
|
|
298
|
+
# bits: (value << 16) | (run << 8) | (total bit length), or 0 when code
|
|
299
|
+
# and extra bits do not fit in FAST_BITS. Zero-valued AC entries are the
|
|
300
|
+
# end-of-block (run JPEG_EOB_RUN) and ZRL (run 15) symbols.
|
|
301
|
+
class JpegHuffman
|
|
302
|
+
attr_reader :fast, :look, :counts, :symbols
|
|
303
|
+
|
|
304
|
+
# +counts+: number of codes of each length 1..16; +symbols+ in code order.
|
|
305
|
+
def initialize(counts, symbols, ac)
|
|
306
|
+
@fast = Array.new(1 << JPEG_FAST_BITS, 0)
|
|
307
|
+
@look = Array.new(1 << JPEG_FAST_BITS, 0)
|
|
308
|
+
@maxcode = Array.new(18, 0)
|
|
309
|
+
@valoff = Array.new(17, 0)
|
|
310
|
+
@counts = counts
|
|
311
|
+
@symbols = symbols
|
|
312
|
+
code = 0
|
|
313
|
+
index = 0
|
|
314
|
+
len = 1
|
|
315
|
+
while len <= 16
|
|
316
|
+
n = counts[len - 1]
|
|
317
|
+
@valoff[len] = index - code
|
|
318
|
+
i = 0
|
|
319
|
+
while i < n
|
|
320
|
+
sym = symbols[index]
|
|
321
|
+
raise QrReader::ImageError, "corrupt JPEG: bad DC Huffman symbol #{sym}" if !ac && sym > 15
|
|
322
|
+
|
|
323
|
+
add_entries(code, len, sym, ac) if len <= JPEG_FAST_BITS
|
|
324
|
+
code += 1
|
|
325
|
+
index += 1
|
|
326
|
+
i += 1
|
|
327
|
+
end
|
|
328
|
+
# Codes must fit in len bits and may not be all ones (like libjpeg).
|
|
329
|
+
raise QrReader::ImageError, "corrupt JPEG: bad Huffman table" if n > 0 && code >= (1 << len)
|
|
330
|
+
|
|
331
|
+
@maxcode[len] = code << (16 - len)
|
|
332
|
+
code <<= 1
|
|
333
|
+
len += 1
|
|
334
|
+
end
|
|
335
|
+
@maxcode[17] = 1 << 17
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Decodes a code longer than FAST_BITS from the next 16 bits. Returns
|
|
339
|
+
# (length << 8) | symbol; an invalid code yields symbol 0 and length 16
|
|
340
|
+
# ("fake a zero", like libjpeg).
|
|
341
|
+
def decode_long(window)
|
|
342
|
+
len = JPEG_FAST_BITS + 1
|
|
343
|
+
len += 1 while window >= @maxcode[len]
|
|
344
|
+
return 16 << 8 if len > 16
|
|
345
|
+
|
|
346
|
+
(len << 8) | @symbols[(window >> (16 - len)) + @valoff[len]]
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
private
|
|
350
|
+
|
|
351
|
+
def add_entries(code, len, sym, ac)
|
|
352
|
+
shift = JPEG_FAST_BITS - len
|
|
353
|
+
base = code << shift
|
|
354
|
+
@look.fill((len << 8) | sym, base, 1 << shift)
|
|
355
|
+
run = 0
|
|
356
|
+
size = sym
|
|
357
|
+
if ac
|
|
358
|
+
run = sym >> 4
|
|
359
|
+
size = sym & 15
|
|
360
|
+
end
|
|
361
|
+
if size == 0
|
|
362
|
+
# DC: difference 0. AC: ZRL, or end of block (libjpeg treats every
|
|
363
|
+
# other zero-size symbol in sequential scans as EOB).
|
|
364
|
+
run = JPEG_EOB_RUN if ac && run != 15
|
|
365
|
+
@fast.fill((run << 8) | len, base, 1 << shift)
|
|
366
|
+
elsif size <= shift
|
|
367
|
+
rest = shift - size
|
|
368
|
+
count = 1 << rest
|
|
369
|
+
head = (run << 8) | (len + size)
|
|
370
|
+
half = 1 << (size - 1)
|
|
371
|
+
offset = (1 << size) - 1
|
|
372
|
+
v = 0
|
|
373
|
+
while v <= offset
|
|
374
|
+
value = v < half ? v - offset : v
|
|
375
|
+
@fast.fill((value << 16) | head, base | (v << rest), count)
|
|
376
|
+
v += 1
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
nil
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# A placeholder table (no codes).
|
|
384
|
+
JPEG_EMPTY_HUFFMAN = JpegHuffman.new(JPEG_NO_COUNTS, JPEG_NONE, false)
|
|
385
|
+
|
|
386
|
+
# Frame component state.
|
|
387
|
+
class JpegComponent
|
|
388
|
+
attr_reader :index, :id, :h, :v, :tq, :plane, :raw, :marks, :sdata
|
|
389
|
+
# Sample size at full scale, blocks covered by a non-interleaved scan,
|
|
390
|
+
# allocated block grid (padded to whole MCUs) and plane size in samples.
|
|
391
|
+
attr_accessor :cw, :ch, :bw, :bh, :abw, :abh, :pw, :ph
|
|
392
|
+
# Whether the component contributes to the luminance output.
|
|
393
|
+
attr_accessor :needed
|
|
394
|
+
# Output size of its blocks (libjpeg's DCT_scaled_size: 8, 4, 2 or 1)
|
|
395
|
+
# and the IDCT producing them.
|
|
396
|
+
attr_accessor :bs, :idct
|
|
397
|
+
# Progressive JPEGs: Integers per block of the raw coefficient rows
|
|
398
|
+
# (JPEG_BLOCK_STRIDE, or 1 when only DCs are needed).
|
|
399
|
+
attr_accessor :stride
|
|
400
|
+
# Latched dequantisation table, indexed by (extended) zigzag position.
|
|
401
|
+
attr_accessor :qz
|
|
402
|
+
|
|
403
|
+
def initialize(index, id, h, v, tq)
|
|
404
|
+
@index = index
|
|
405
|
+
@id = id
|
|
406
|
+
@h = h
|
|
407
|
+
@v = v
|
|
408
|
+
@tq = tq
|
|
409
|
+
@cw = 0
|
|
410
|
+
@ch = 0
|
|
411
|
+
@bw = 0
|
|
412
|
+
@bh = 0
|
|
413
|
+
@abw = 0
|
|
414
|
+
@abh = 0
|
|
415
|
+
@pw = 0
|
|
416
|
+
@ph = 0
|
|
417
|
+
@needed = false
|
|
418
|
+
@bs = 8
|
|
419
|
+
@idct = JpegIDCT.new(8)
|
|
420
|
+
# Output plane (binary String, pw x ph, filled row by row).
|
|
421
|
+
@plane = "".b
|
|
422
|
+
# Progressive JPEGs: raw coefficients (not dequantised) as packed
|
|
423
|
+
# signed 16-bit Strings, one per block row ("" until data arrives).
|
|
424
|
+
@raw = []
|
|
425
|
+
@stride = JPEG_BLOCK_STRIDE
|
|
426
|
+
@qz = JPEG_NONE
|
|
427
|
+
# Store (see JpegDecoder#store) of a sequential decode: per block of
|
|
428
|
+
# the allocated grid, the bit position of its AC data in the scan and
|
|
429
|
+
# its DC, as (position << 16) | (DC & 0xFFFF), or -1 without data.
|
|
430
|
+
@marks = JPEG_NONE
|
|
431
|
+
# Store of a progressive decode: the raw coefficient rows.
|
|
432
|
+
@sdata = "".b
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# Starts an empty output plane for pw x ph samples.
|
|
436
|
+
def start_plane
|
|
437
|
+
@plane = String.new(capacity: @pw * @ph, encoding: Encoding::BINARY)
|
|
438
|
+
nil
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# Appends sample rows to the plane (nothing beyond its size).
|
|
442
|
+
def append_plane(rows)
|
|
443
|
+
@plane << rows if @plane.bytesize + rows.bytesize <= @pw * @ph
|
|
444
|
+
nil
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
# Pads the plane with mid-gray rows up to its full size.
|
|
448
|
+
def finish_plane
|
|
449
|
+
gray = @pw * @ph - @plane.bytesize
|
|
450
|
+
@plane << ("\x80".b * gray) if gray > 0
|
|
451
|
+
nil
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Starts the progressive coefficient rows (all empty).
|
|
455
|
+
def start_raw
|
|
456
|
+
@raw = Array.new(@abh, "".b)
|
|
457
|
+
nil
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
# Raw coefficient row +r+, allocated (all zero) on first use.
|
|
461
|
+
def raw_row(r)
|
|
462
|
+
row = @raw[r]
|
|
463
|
+
if row.empty?
|
|
464
|
+
row = "\0".b * (@abw * @stride * 2)
|
|
465
|
+
@raw[r] = row
|
|
466
|
+
end
|
|
467
|
+
row
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# Frees raw coefficient row +r+.
|
|
471
|
+
def release_raw(r)
|
|
472
|
+
@raw[r] = "".b
|
|
473
|
+
nil
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
# Starts the block marks of a sequential decode with a store.
|
|
477
|
+
def start_marks
|
|
478
|
+
@marks = Array.new(@abw * @abh, -1)
|
|
479
|
+
nil
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# Appends raw coefficient row +raw+ ("" for an all-zero row) to the
|
|
483
|
+
# store of a progressive decode.
|
|
484
|
+
def store_raw(raw)
|
|
485
|
+
if raw.empty?
|
|
486
|
+
@sdata << ("\0".b * (@abw * JPEG_RAW_BLOCK))
|
|
487
|
+
else
|
|
488
|
+
@sdata << raw
|
|
489
|
+
end
|
|
490
|
+
nil
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
# Inverse DCTs, bit-exact with libjpeg's jidctint.c ("islow", 8x8 output)
|
|
495
|
+
# and jidctred.c (4x4 and 2x2 output for scaled decoding).
|
|
496
|
+
#
|
|
497
|
+
# The idct<size>_<n> methods are libjpeg's 1-D kernels specialised for
|
|
498
|
+
# blocks whose nonzero coefficients lie in the top-left n x n corner
|
|
499
|
+
# (dropping zero terms changes nothing in integer arithmetic). Rounding
|
|
500
|
+
# and the +128 level shift are folded into the DC term of each pass.
|
|
501
|
+
#
|
|
502
|
+
# Input: dequantised coefficients in natural order at c[base, 64].
|
|
503
|
+
# Output: a bs x bs block written to the Array +out+ as packed
|
|
504
|
+
# little-endian words (JPEG_WORDS[bs] per block row) at word offset
|
|
505
|
+
# +off+ with row stride +stride+ (in words). Writing four samples per
|
|
506
|
+
# Array element instead of one is markedly faster under YJIT.
|
|
507
|
+
#
|
|
508
|
+
# One instance (with a fixed set of instance variables, which keeps
|
|
509
|
+
# YJIT's code monomorphic) serves a whole decode.
|
|
510
|
+
class JpegIDCT
|
|
511
|
+
attr_reader :bs
|
|
512
|
+
|
|
513
|
+
# +bs+: output block size 8, 4, 2 or 1 (1 needs no IDCT, only #fill).
|
|
514
|
+
def initialize(bs)
|
|
515
|
+
@bs = bs
|
|
516
|
+
@ws = Array.new(64, 0)
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# IDCT of the block at c[base, 64] whose last nonzero coefficient has
|
|
520
|
+
# zigzag index +km+ (> 0; DC-only blocks are filled by callers).
|
|
521
|
+
def transform(c, base, km, out, off, stride)
|
|
522
|
+
bs = @bs
|
|
523
|
+
if bs == 8
|
|
524
|
+
if km <= 2 then idct8_2(c, base, out, off, stride)
|
|
525
|
+
elsif km <= 9 then idct8_4(c, base, out, off, stride)
|
|
526
|
+
elsif km <= 20 then idct8_6(c, base, out, off, stride)
|
|
527
|
+
else idct8_8(c, base, out, off, stride)
|
|
528
|
+
end
|
|
529
|
+
elsif bs == 4
|
|
530
|
+
if km <= 2 then idct4_2(c, base, out, off, stride)
|
|
531
|
+
elsif km <= 9 then idct4_4(c, base, out, off, stride)
|
|
532
|
+
else idct4_8(c, base, out, off, stride)
|
|
533
|
+
end
|
|
534
|
+
elsif km <= 2
|
|
535
|
+
idct2_2(c, base, out, off, stride)
|
|
536
|
+
else
|
|
537
|
+
idct2_8(c, base, out, off, stride)
|
|
538
|
+
end
|
|
539
|
+
nil
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
# Sample of a DC-only block (the same for every IDCT size, except that
|
|
543
|
+
# libjpeg-turbo's 1x1 IDCT wraps instead of saturating).
|
|
544
|
+
def dc_sample(dequantised_dc)
|
|
545
|
+
if @bs == 1
|
|
546
|
+
JPEG_RANGE_LIMIT[((dequantised_dc + 1028) >> 3) & 1023]
|
|
547
|
+
else
|
|
548
|
+
JPEG_CLAMP[((dequantised_dc + 1028) >> 3) & 0xFFFF]
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
# Fills a bs x bs block of +out+ (packed words) with sample +value+.
|
|
553
|
+
def fill(out, off, stride, value)
|
|
554
|
+
bs = @bs
|
|
555
|
+
v = value * JPEG_SPREAD[bs]
|
|
556
|
+
r = 0
|
|
557
|
+
if bs == 8
|
|
558
|
+
while r < 8
|
|
559
|
+
out[off] = v
|
|
560
|
+
out[off + 1] = v
|
|
561
|
+
off += stride
|
|
562
|
+
r += 1
|
|
563
|
+
end
|
|
564
|
+
else
|
|
565
|
+
while r < bs
|
|
566
|
+
out[off] = v
|
|
567
|
+
off += stride
|
|
568
|
+
r += 1
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
nil
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# IDCTs the +n+ blocks of a coefficient row (JPEG_BLOCK_STRIDE entries
|
|
575
|
+
# per block: dequantised coefficients in natural order, then the zigzag
|
|
576
|
+
# index of the last nonzero one) into +out+ at word offset +off+.
|
|
577
|
+
def render_row(row, n, out, off, stride)
|
|
578
|
+
step = JPEG_WORDS[@bs]
|
|
579
|
+
dc_only = @bs == 1
|
|
580
|
+
base = 0
|
|
581
|
+
x = 0
|
|
582
|
+
while x < n
|
|
583
|
+
km = row[base + 64]
|
|
584
|
+
if km == 0 || dc_only
|
|
585
|
+
fill(out, off, stride, dc_sample(row[base]))
|
|
586
|
+
else
|
|
587
|
+
transform(row, base, km, out, off, stride)
|
|
588
|
+
end
|
|
589
|
+
base += JPEG_BLOCK_STRIDE
|
|
590
|
+
off += step
|
|
591
|
+
x += 1
|
|
592
|
+
end
|
|
593
|
+
nil
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
def idct8_2(c, base, out, off, stride)
|
|
597
|
+
rl = JPEG_CLAMP
|
|
598
|
+
ws = @ws
|
|
599
|
+
i = 0
|
|
600
|
+
ci = base
|
|
601
|
+
while i <= 1
|
|
602
|
+
d0 = c[ci]
|
|
603
|
+
d1 = c[ci + 8]
|
|
604
|
+
if d1 == 0
|
|
605
|
+
ws[i] = ws[i + 8] = ws[i + 16] = ws[i + 24] = ws[i + 32] = ws[i + 40] = ws[i + 48] = ws[i + 56] = d0 << 2
|
|
606
|
+
else
|
|
607
|
+
t0 = (d0 << 13) + 1024
|
|
608
|
+
o3 = d1 * 11_363
|
|
609
|
+
o2 = d1 * 9633
|
|
610
|
+
o1 = d1 * 6437
|
|
611
|
+
o0 = d1 * 2260
|
|
612
|
+
ws[i] = (t0 + o3) >> 11
|
|
613
|
+
ws[i + 8] = (t0 + o2) >> 11
|
|
614
|
+
ws[i + 16] = (t0 + o1) >> 11
|
|
615
|
+
ws[i + 24] = (t0 + o0) >> 11
|
|
616
|
+
ws[i + 32] = (t0 - o0) >> 11
|
|
617
|
+
ws[i + 40] = (t0 - o1) >> 11
|
|
618
|
+
ws[i + 48] = (t0 - o2) >> 11
|
|
619
|
+
ws[i + 56] = (t0 - o3) >> 11
|
|
620
|
+
end
|
|
621
|
+
i += 1
|
|
622
|
+
ci = base + i
|
|
623
|
+
end
|
|
624
|
+
i = 0
|
|
625
|
+
while i < 64
|
|
626
|
+
d0 = ws[i]
|
|
627
|
+
d1 = ws[i + 1]
|
|
628
|
+
if d1 == 0
|
|
629
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x1010101
|
|
630
|
+
out[off] = v
|
|
631
|
+
out[off + 1] = v
|
|
632
|
+
else
|
|
633
|
+
t0 = (d0 + 4112) << 13
|
|
634
|
+
o3 = d1 * 11_363
|
|
635
|
+
o2 = d1 * 9633
|
|
636
|
+
o1 = d1 * 6437
|
|
637
|
+
o0 = d1 * 2260
|
|
638
|
+
out[off] = rl[((t0 + o3) >> 18) & 0xFFFF] | (rl[((t0 + o2) >> 18) & 0xFFFF] << 8) | (rl[((t0 + o1) >> 18) & 0xFFFF] << 16) | (rl[((t0 + o0) >> 18) & 0xFFFF] << 24)
|
|
639
|
+
out[off + 1] = rl[((t0 - o0) >> 18) & 0xFFFF] | (rl[((t0 - o1) >> 18) & 0xFFFF] << 8) | (rl[((t0 - o2) >> 18) & 0xFFFF] << 16) | (rl[((t0 - o3) >> 18) & 0xFFFF] << 24)
|
|
640
|
+
end
|
|
641
|
+
off += stride
|
|
642
|
+
i += 8
|
|
643
|
+
end
|
|
644
|
+
nil
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
def idct8_4(c, base, out, off, stride)
|
|
648
|
+
rl = JPEG_CLAMP
|
|
649
|
+
ws = @ws
|
|
650
|
+
i = 0
|
|
651
|
+
ci = base
|
|
652
|
+
while i <= 3
|
|
653
|
+
d0 = c[ci]
|
|
654
|
+
d1 = c[ci + 8]
|
|
655
|
+
d2 = c[ci + 16]
|
|
656
|
+
d3 = c[ci + 24]
|
|
657
|
+
if d1 == 0 && d2 == 0 && d3 == 0
|
|
658
|
+
ws[i] = ws[i + 8] = ws[i + 16] = ws[i + 24] = ws[i + 32] = ws[i + 40] = ws[i + 48] = ws[i + 56] = d0 << 2
|
|
659
|
+
else
|
|
660
|
+
t0 = (d0 << 13) + 1024
|
|
661
|
+
t2 = d2 * 4433
|
|
662
|
+
t3 = d2 * 10_703
|
|
663
|
+
t10 = t0 + t3
|
|
664
|
+
t13 = t0 - t3
|
|
665
|
+
t11 = t0 + t2
|
|
666
|
+
t12 = t0 - t2
|
|
667
|
+
o0 = d1 * 2260 - d3 * 6436
|
|
668
|
+
o1 = d1 * 6437 - d3 * 11_362
|
|
669
|
+
o2 = d1 * 9633 - d3 * 2259
|
|
670
|
+
o3 = d1 * 11_363 + d3 * 9633
|
|
671
|
+
ws[i] = (t10 + o3) >> 11
|
|
672
|
+
ws[i + 8] = (t11 + o2) >> 11
|
|
673
|
+
ws[i + 16] = (t12 + o1) >> 11
|
|
674
|
+
ws[i + 24] = (t13 + o0) >> 11
|
|
675
|
+
ws[i + 32] = (t13 - o0) >> 11
|
|
676
|
+
ws[i + 40] = (t12 - o1) >> 11
|
|
677
|
+
ws[i + 48] = (t11 - o2) >> 11
|
|
678
|
+
ws[i + 56] = (t10 - o3) >> 11
|
|
679
|
+
end
|
|
680
|
+
i += 1
|
|
681
|
+
ci = base + i
|
|
682
|
+
end
|
|
683
|
+
i = 0
|
|
684
|
+
while i < 64
|
|
685
|
+
d0 = ws[i]
|
|
686
|
+
d1 = ws[i + 1]
|
|
687
|
+
d2 = ws[i + 2]
|
|
688
|
+
d3 = ws[i + 3]
|
|
689
|
+
if d1 == 0 && d2 == 0 && d3 == 0
|
|
690
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x1010101
|
|
691
|
+
out[off] = v
|
|
692
|
+
out[off + 1] = v
|
|
693
|
+
else
|
|
694
|
+
t0 = (d0 + 4112) << 13
|
|
695
|
+
t2 = d2 * 4433
|
|
696
|
+
t3 = d2 * 10_703
|
|
697
|
+
t10 = t0 + t3
|
|
698
|
+
t13 = t0 - t3
|
|
699
|
+
t11 = t0 + t2
|
|
700
|
+
t12 = t0 - t2
|
|
701
|
+
o0 = d1 * 2260 - d3 * 6436
|
|
702
|
+
o1 = d1 * 6437 - d3 * 11_362
|
|
703
|
+
o2 = d1 * 9633 - d3 * 2259
|
|
704
|
+
o3 = d1 * 11_363 + d3 * 9633
|
|
705
|
+
out[off] = rl[((t10 + o3) >> 18) & 0xFFFF] | (rl[((t11 + o2) >> 18) & 0xFFFF] << 8) | (rl[((t12 + o1) >> 18) & 0xFFFF] << 16) | (rl[((t13 + o0) >> 18) & 0xFFFF] << 24)
|
|
706
|
+
out[off + 1] = rl[((t13 - o0) >> 18) & 0xFFFF] | (rl[((t12 - o1) >> 18) & 0xFFFF] << 8) | (rl[((t11 - o2) >> 18) & 0xFFFF] << 16) | (rl[((t10 - o3) >> 18) & 0xFFFF] << 24)
|
|
707
|
+
end
|
|
708
|
+
off += stride
|
|
709
|
+
i += 8
|
|
710
|
+
end
|
|
711
|
+
nil
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
def idct8_6(c, base, out, off, stride)
|
|
715
|
+
rl = JPEG_CLAMP
|
|
716
|
+
ws = @ws
|
|
717
|
+
i = 0
|
|
718
|
+
ci = base
|
|
719
|
+
while i <= 5
|
|
720
|
+
d0 = c[ci]
|
|
721
|
+
d1 = c[ci + 8]
|
|
722
|
+
d2 = c[ci + 16]
|
|
723
|
+
d3 = c[ci + 24]
|
|
724
|
+
d4 = c[ci + 32]
|
|
725
|
+
d5 = c[ci + 40]
|
|
726
|
+
if d1 == 0 && d2 == 0 && d3 == 0 && d4 == 0 && d5 == 0
|
|
727
|
+
ws[i] = ws[i + 8] = ws[i + 16] = ws[i + 24] = ws[i + 32] = ws[i + 40] = ws[i + 48] = ws[i + 56] = d0 << 2
|
|
728
|
+
else
|
|
729
|
+
t0 = ((d0 + d4) << 13) + 1024
|
|
730
|
+
t1 = ((d0 - d4) << 13) + 1024
|
|
731
|
+
t2 = d2 * 4433
|
|
732
|
+
t3 = d2 * 10_703
|
|
733
|
+
t10 = t0 + t3
|
|
734
|
+
t13 = t0 - t3
|
|
735
|
+
t11 = t1 + t2
|
|
736
|
+
t12 = t1 - t2
|
|
737
|
+
s2 = d5 + d3
|
|
738
|
+
s4 = d5 + d1
|
|
739
|
+
z5 = (s4 + d3) * 9633
|
|
740
|
+
z1 = d1 * -7373
|
|
741
|
+
z2 = s2 * -20_995
|
|
742
|
+
z3 = d3 * -16_069 + z5
|
|
743
|
+
z4 = s4 * -3196 + z5
|
|
744
|
+
o0 = z1 + z3
|
|
745
|
+
o1 = d5 * 16_819 + z2 + z4
|
|
746
|
+
o2 = d3 * 25_172 + z2 + z3
|
|
747
|
+
o3 = d1 * 12_299 + z1 + z4
|
|
748
|
+
ws[i] = (t10 + o3) >> 11
|
|
749
|
+
ws[i + 8] = (t11 + o2) >> 11
|
|
750
|
+
ws[i + 16] = (t12 + o1) >> 11
|
|
751
|
+
ws[i + 24] = (t13 + o0) >> 11
|
|
752
|
+
ws[i + 32] = (t13 - o0) >> 11
|
|
753
|
+
ws[i + 40] = (t12 - o1) >> 11
|
|
754
|
+
ws[i + 48] = (t11 - o2) >> 11
|
|
755
|
+
ws[i + 56] = (t10 - o3) >> 11
|
|
756
|
+
end
|
|
757
|
+
i += 1
|
|
758
|
+
ci = base + i
|
|
759
|
+
end
|
|
760
|
+
i = 0
|
|
761
|
+
while i < 64
|
|
762
|
+
d0 = ws[i]
|
|
763
|
+
d1 = ws[i + 1]
|
|
764
|
+
d2 = ws[i + 2]
|
|
765
|
+
d3 = ws[i + 3]
|
|
766
|
+
d4 = ws[i + 4]
|
|
767
|
+
d5 = ws[i + 5]
|
|
768
|
+
if d1 == 0 && d2 == 0 && d3 == 0 && d4 == 0 && d5 == 0
|
|
769
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x1010101
|
|
770
|
+
out[off] = v
|
|
771
|
+
out[off + 1] = v
|
|
772
|
+
else
|
|
773
|
+
t0 = ((d0 + d4) + 4112) << 13
|
|
774
|
+
t1 = ((d0 - d4) + 4112) << 13
|
|
775
|
+
t2 = d2 * 4433
|
|
776
|
+
t3 = d2 * 10_703
|
|
777
|
+
t10 = t0 + t3
|
|
778
|
+
t13 = t0 - t3
|
|
779
|
+
t11 = t1 + t2
|
|
780
|
+
t12 = t1 - t2
|
|
781
|
+
s2 = d5 + d3
|
|
782
|
+
s4 = d5 + d1
|
|
783
|
+
z5 = (s4 + d3) * 9633
|
|
784
|
+
z1 = d1 * -7373
|
|
785
|
+
z2 = s2 * -20_995
|
|
786
|
+
z3 = d3 * -16_069 + z5
|
|
787
|
+
z4 = s4 * -3196 + z5
|
|
788
|
+
o0 = z1 + z3
|
|
789
|
+
o1 = d5 * 16_819 + z2 + z4
|
|
790
|
+
o2 = d3 * 25_172 + z2 + z3
|
|
791
|
+
o3 = d1 * 12_299 + z1 + z4
|
|
792
|
+
out[off] = rl[((t10 + o3) >> 18) & 0xFFFF] | (rl[((t11 + o2) >> 18) & 0xFFFF] << 8) | (rl[((t12 + o1) >> 18) & 0xFFFF] << 16) | (rl[((t13 + o0) >> 18) & 0xFFFF] << 24)
|
|
793
|
+
out[off + 1] = rl[((t13 - o0) >> 18) & 0xFFFF] | (rl[((t12 - o1) >> 18) & 0xFFFF] << 8) | (rl[((t11 - o2) >> 18) & 0xFFFF] << 16) | (rl[((t10 - o3) >> 18) & 0xFFFF] << 24)
|
|
794
|
+
end
|
|
795
|
+
off += stride
|
|
796
|
+
i += 8
|
|
797
|
+
end
|
|
798
|
+
nil
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
def idct8_8(c, base, out, off, stride)
|
|
802
|
+
rl = JPEG_CLAMP
|
|
803
|
+
ws = @ws
|
|
804
|
+
i = 0
|
|
805
|
+
ci = base
|
|
806
|
+
while i <= 7
|
|
807
|
+
d0 = c[ci]
|
|
808
|
+
d1 = c[ci + 8]
|
|
809
|
+
d2 = c[ci + 16]
|
|
810
|
+
d3 = c[ci + 24]
|
|
811
|
+
d4 = c[ci + 32]
|
|
812
|
+
d5 = c[ci + 40]
|
|
813
|
+
d6 = c[ci + 48]
|
|
814
|
+
d7 = c[ci + 56]
|
|
815
|
+
if d1 == 0 && d2 == 0 && d3 == 0 && d4 == 0 && d5 == 0 && d6 == 0 && d7 == 0
|
|
816
|
+
ws[i] = ws[i + 8] = ws[i + 16] = ws[i + 24] = ws[i + 32] = ws[i + 40] = ws[i + 48] = ws[i + 56] = d0 << 2
|
|
817
|
+
else
|
|
818
|
+
z1 = (d2 + d6) * 4433
|
|
819
|
+
t2 = z1 - d6 * 15_137
|
|
820
|
+
t3 = z1 + d2 * 6270
|
|
821
|
+
t0 = ((d0 + d4) << 13) + 1024
|
|
822
|
+
t1 = ((d0 - d4) << 13) + 1024
|
|
823
|
+
t10 = t0 + t3
|
|
824
|
+
t13 = t0 - t3
|
|
825
|
+
t11 = t1 + t2
|
|
826
|
+
t12 = t1 - t2
|
|
827
|
+
s1 = d7 + d1
|
|
828
|
+
s2 = d5 + d3
|
|
829
|
+
s3 = d7 + d3
|
|
830
|
+
s4 = d5 + d1
|
|
831
|
+
z5 = (s3 + s4) * 9633
|
|
832
|
+
z1 = s1 * -7373
|
|
833
|
+
z2 = s2 * -20_995
|
|
834
|
+
z3 = s3 * -16_069 + z5
|
|
835
|
+
z4 = s4 * -3196 + z5
|
|
836
|
+
o0 = d7 * 2446 + z1 + z3
|
|
837
|
+
o1 = d5 * 16_819 + z2 + z4
|
|
838
|
+
o2 = d3 * 25_172 + z2 + z3
|
|
839
|
+
o3 = d1 * 12_299 + z1 + z4
|
|
840
|
+
ws[i] = (t10 + o3) >> 11
|
|
841
|
+
ws[i + 8] = (t11 + o2) >> 11
|
|
842
|
+
ws[i + 16] = (t12 + o1) >> 11
|
|
843
|
+
ws[i + 24] = (t13 + o0) >> 11
|
|
844
|
+
ws[i + 32] = (t13 - o0) >> 11
|
|
845
|
+
ws[i + 40] = (t12 - o1) >> 11
|
|
846
|
+
ws[i + 48] = (t11 - o2) >> 11
|
|
847
|
+
ws[i + 56] = (t10 - o3) >> 11
|
|
848
|
+
end
|
|
849
|
+
i += 1
|
|
850
|
+
ci = base + i
|
|
851
|
+
end
|
|
852
|
+
i = 0
|
|
853
|
+
while i < 64
|
|
854
|
+
d0 = ws[i]
|
|
855
|
+
d1 = ws[i + 1]
|
|
856
|
+
d2 = ws[i + 2]
|
|
857
|
+
d3 = ws[i + 3]
|
|
858
|
+
d4 = ws[i + 4]
|
|
859
|
+
d5 = ws[i + 5]
|
|
860
|
+
d6 = ws[i + 6]
|
|
861
|
+
d7 = ws[i + 7]
|
|
862
|
+
if d1 == 0 && d2 == 0 && d3 == 0 && d4 == 0 && d5 == 0 && d6 == 0 && d7 == 0
|
|
863
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x1010101
|
|
864
|
+
out[off] = v
|
|
865
|
+
out[off + 1] = v
|
|
866
|
+
else
|
|
867
|
+
z1 = (d2 + d6) * 4433
|
|
868
|
+
t2 = z1 - d6 * 15_137
|
|
869
|
+
t3 = z1 + d2 * 6270
|
|
870
|
+
t0 = ((d0 + d4) + 4112) << 13
|
|
871
|
+
t1 = ((d0 - d4) + 4112) << 13
|
|
872
|
+
t10 = t0 + t3
|
|
873
|
+
t13 = t0 - t3
|
|
874
|
+
t11 = t1 + t2
|
|
875
|
+
t12 = t1 - t2
|
|
876
|
+
s1 = d7 + d1
|
|
877
|
+
s2 = d5 + d3
|
|
878
|
+
s3 = d7 + d3
|
|
879
|
+
s4 = d5 + d1
|
|
880
|
+
z5 = (s3 + s4) * 9633
|
|
881
|
+
z1 = s1 * -7373
|
|
882
|
+
z2 = s2 * -20_995
|
|
883
|
+
z3 = s3 * -16_069 + z5
|
|
884
|
+
z4 = s4 * -3196 + z5
|
|
885
|
+
o0 = d7 * 2446 + z1 + z3
|
|
886
|
+
o1 = d5 * 16_819 + z2 + z4
|
|
887
|
+
o2 = d3 * 25_172 + z2 + z3
|
|
888
|
+
o3 = d1 * 12_299 + z1 + z4
|
|
889
|
+
out[off] = rl[((t10 + o3) >> 18) & 0xFFFF] | (rl[((t11 + o2) >> 18) & 0xFFFF] << 8) | (rl[((t12 + o1) >> 18) & 0xFFFF] << 16) | (rl[((t13 + o0) >> 18) & 0xFFFF] << 24)
|
|
890
|
+
out[off + 1] = rl[((t13 - o0) >> 18) & 0xFFFF] | (rl[((t12 - o1) >> 18) & 0xFFFF] << 8) | (rl[((t11 - o2) >> 18) & 0xFFFF] << 16) | (rl[((t10 - o3) >> 18) & 0xFFFF] << 24)
|
|
891
|
+
end
|
|
892
|
+
off += stride
|
|
893
|
+
i += 8
|
|
894
|
+
end
|
|
895
|
+
nil
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
def idct4_2(c, base, out, off, stride)
|
|
899
|
+
rl = JPEG_CLAMP
|
|
900
|
+
ws = @ws
|
|
901
|
+
i = 0
|
|
902
|
+
ci = base
|
|
903
|
+
while i <= 1
|
|
904
|
+
d0 = c[ci]
|
|
905
|
+
d1 = c[ci + 8]
|
|
906
|
+
if d1 == 0
|
|
907
|
+
ws[i] = ws[i + 8] = ws[i + 16] = ws[i + 24] = d0 << 2
|
|
908
|
+
else
|
|
909
|
+
t0 = (d0 << 14) + 2048
|
|
910
|
+
t2 = 0
|
|
911
|
+
t10 = t0 + t2
|
|
912
|
+
t12 = t0 - t2
|
|
913
|
+
o0 = d1 * 8697
|
|
914
|
+
o2 = d1 * 20_995
|
|
915
|
+
ws[i] = (t10 + o2) >> 12
|
|
916
|
+
ws[i + 8] = (t12 + o0) >> 12
|
|
917
|
+
ws[i + 16] = (t12 - o0) >> 12
|
|
918
|
+
ws[i + 24] = (t10 - o2) >> 12
|
|
919
|
+
end
|
|
920
|
+
i += 1
|
|
921
|
+
ci = base + i
|
|
922
|
+
end
|
|
923
|
+
i = 0
|
|
924
|
+
while i < 32
|
|
925
|
+
d0 = ws[i]
|
|
926
|
+
d1 = ws[i + 1]
|
|
927
|
+
if d1 == 0
|
|
928
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x1010101
|
|
929
|
+
out[off] = v
|
|
930
|
+
else
|
|
931
|
+
t0 = (d0 + 4112) << 14
|
|
932
|
+
t2 = 0
|
|
933
|
+
t10 = t0 + t2
|
|
934
|
+
t12 = t0 - t2
|
|
935
|
+
o0 = d1 * 8697
|
|
936
|
+
o2 = d1 * 20_995
|
|
937
|
+
out[off] = rl[((t10 + o2) >> 19) & 0xFFFF] | (rl[((t12 + o0) >> 19) & 0xFFFF] << 8) | (rl[((t12 - o0) >> 19) & 0xFFFF] << 16) | (rl[((t10 - o2) >> 19) & 0xFFFF] << 24)
|
|
938
|
+
end
|
|
939
|
+
off += stride
|
|
940
|
+
i += 8
|
|
941
|
+
end
|
|
942
|
+
nil
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
def idct4_4(c, base, out, off, stride)
|
|
946
|
+
rl = JPEG_CLAMP
|
|
947
|
+
ws = @ws
|
|
948
|
+
i = 0
|
|
949
|
+
ci = base
|
|
950
|
+
while i <= 3
|
|
951
|
+
d0 = c[ci]
|
|
952
|
+
d1 = c[ci + 8]
|
|
953
|
+
d2 = c[ci + 16]
|
|
954
|
+
d3 = c[ci + 24]
|
|
955
|
+
if d1 == 0 && d2 == 0 && d3 == 0
|
|
956
|
+
ws[i] = ws[i + 8] = ws[i + 16] = ws[i + 24] = d0 << 2
|
|
957
|
+
else
|
|
958
|
+
t0 = (d0 << 14) + 2048
|
|
959
|
+
t2 = d2 * 15_137
|
|
960
|
+
t10 = t0 + t2
|
|
961
|
+
t12 = t0 - t2
|
|
962
|
+
o0 = d3 * -17_799 + d1 * 8697
|
|
963
|
+
o2 = d3 * 7373 + d1 * 20_995
|
|
964
|
+
ws[i] = (t10 + o2) >> 12
|
|
965
|
+
ws[i + 8] = (t12 + o0) >> 12
|
|
966
|
+
ws[i + 16] = (t12 - o0) >> 12
|
|
967
|
+
ws[i + 24] = (t10 - o2) >> 12
|
|
968
|
+
end
|
|
969
|
+
i += 1
|
|
970
|
+
ci = base + i
|
|
971
|
+
end
|
|
972
|
+
i = 0
|
|
973
|
+
while i < 32
|
|
974
|
+
d0 = ws[i]
|
|
975
|
+
d1 = ws[i + 1]
|
|
976
|
+
d2 = ws[i + 2]
|
|
977
|
+
d3 = ws[i + 3]
|
|
978
|
+
if d1 == 0 && d2 == 0 && d3 == 0
|
|
979
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x1010101
|
|
980
|
+
out[off] = v
|
|
981
|
+
else
|
|
982
|
+
t0 = (d0 + 4112) << 14
|
|
983
|
+
t2 = d2 * 15_137
|
|
984
|
+
t10 = t0 + t2
|
|
985
|
+
t12 = t0 - t2
|
|
986
|
+
o0 = d3 * -17_799 + d1 * 8697
|
|
987
|
+
o2 = d3 * 7373 + d1 * 20_995
|
|
988
|
+
out[off] = rl[((t10 + o2) >> 19) & 0xFFFF] | (rl[((t12 + o0) >> 19) & 0xFFFF] << 8) | (rl[((t12 - o0) >> 19) & 0xFFFF] << 16) | (rl[((t10 - o2) >> 19) & 0xFFFF] << 24)
|
|
989
|
+
end
|
|
990
|
+
off += stride
|
|
991
|
+
i += 8
|
|
992
|
+
end
|
|
993
|
+
nil
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
def idct4_8(c, base, out, off, stride)
|
|
997
|
+
rl = JPEG_CLAMP
|
|
998
|
+
ws = @ws
|
|
999
|
+
i = 0
|
|
1000
|
+
ci = base
|
|
1001
|
+
while i <= 7
|
|
1002
|
+
d0 = c[ci]
|
|
1003
|
+
d1 = c[ci + 8]
|
|
1004
|
+
d2 = c[ci + 16]
|
|
1005
|
+
d3 = c[ci + 24]
|
|
1006
|
+
d5 = c[ci + 40]
|
|
1007
|
+
d6 = c[ci + 48]
|
|
1008
|
+
d7 = c[ci + 56]
|
|
1009
|
+
if d1 == 0 && d2 == 0 && d3 == 0 && d5 == 0 && d6 == 0 && d7 == 0
|
|
1010
|
+
ws[i] = ws[i + 8] = ws[i + 16] = ws[i + 24] = d0 << 2
|
|
1011
|
+
else
|
|
1012
|
+
t0 = (d0 << 14) + 2048
|
|
1013
|
+
t2 = d2 * 15_137 + d6 * -6270
|
|
1014
|
+
t10 = t0 + t2
|
|
1015
|
+
t12 = t0 - t2
|
|
1016
|
+
o0 = d7 * -1730 + d5 * 11_893 + d3 * -17_799 + d1 * 8697
|
|
1017
|
+
o2 = d7 * -4176 + d5 * -4926 + d3 * 7373 + d1 * 20_995
|
|
1018
|
+
ws[i] = (t10 + o2) >> 12
|
|
1019
|
+
ws[i + 8] = (t12 + o0) >> 12
|
|
1020
|
+
ws[i + 16] = (t12 - o0) >> 12
|
|
1021
|
+
ws[i + 24] = (t10 - o2) >> 12
|
|
1022
|
+
end
|
|
1023
|
+
i += (i == 3 ? 2 : 1)
|
|
1024
|
+
ci = base + i
|
|
1025
|
+
end
|
|
1026
|
+
i = 0
|
|
1027
|
+
while i < 32
|
|
1028
|
+
d0 = ws[i]
|
|
1029
|
+
d1 = ws[i + 1]
|
|
1030
|
+
d2 = ws[i + 2]
|
|
1031
|
+
d3 = ws[i + 3]
|
|
1032
|
+
d5 = ws[i + 5]
|
|
1033
|
+
d6 = ws[i + 6]
|
|
1034
|
+
d7 = ws[i + 7]
|
|
1035
|
+
if d1 == 0 && d2 == 0 && d3 == 0 && d5 == 0 && d6 == 0 && d7 == 0
|
|
1036
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x1010101
|
|
1037
|
+
out[off] = v
|
|
1038
|
+
else
|
|
1039
|
+
t0 = (d0 + 4112) << 14
|
|
1040
|
+
t2 = d2 * 15_137 + d6 * -6270
|
|
1041
|
+
t10 = t0 + t2
|
|
1042
|
+
t12 = t0 - t2
|
|
1043
|
+
o0 = d7 * -1730 + d5 * 11_893 + d3 * -17_799 + d1 * 8697
|
|
1044
|
+
o2 = d7 * -4176 + d5 * -4926 + d3 * 7373 + d1 * 20_995
|
|
1045
|
+
out[off] = rl[((t10 + o2) >> 19) & 0xFFFF] | (rl[((t12 + o0) >> 19) & 0xFFFF] << 8) | (rl[((t12 - o0) >> 19) & 0xFFFF] << 16) | (rl[((t10 - o2) >> 19) & 0xFFFF] << 24)
|
|
1046
|
+
end
|
|
1047
|
+
off += stride
|
|
1048
|
+
i += 8
|
|
1049
|
+
end
|
|
1050
|
+
nil
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
def idct2_2(c, base, out, off, stride)
|
|
1054
|
+
rl = JPEG_CLAMP
|
|
1055
|
+
ws = @ws
|
|
1056
|
+
i = 0
|
|
1057
|
+
ci = base
|
|
1058
|
+
while i <= 1
|
|
1059
|
+
d0 = c[ci]
|
|
1060
|
+
d1 = c[ci + 8]
|
|
1061
|
+
if d1 == 0
|
|
1062
|
+
ws[i] = ws[i + 8] = d0 << 2
|
|
1063
|
+
else
|
|
1064
|
+
t10 = (d0 << 15) + 4096
|
|
1065
|
+
t0 = d1 * 29_692
|
|
1066
|
+
ws[i] = (t10 + t0) >> 13
|
|
1067
|
+
ws[i + 8] = (t10 - t0) >> 13
|
|
1068
|
+
end
|
|
1069
|
+
i += 1
|
|
1070
|
+
ci = base + i
|
|
1071
|
+
end
|
|
1072
|
+
i = 0
|
|
1073
|
+
while i < 16
|
|
1074
|
+
d0 = ws[i]
|
|
1075
|
+
d1 = ws[i + 1]
|
|
1076
|
+
if d1 == 0
|
|
1077
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x101
|
|
1078
|
+
out[off] = v
|
|
1079
|
+
else
|
|
1080
|
+
t10 = (d0 + 4112) << 15
|
|
1081
|
+
t0 = d1 * 29_692
|
|
1082
|
+
out[off] = rl[((t10 + t0) >> 20) & 0xFFFF] | (rl[((t10 - t0) >> 20) & 0xFFFF] << 8)
|
|
1083
|
+
end
|
|
1084
|
+
off += stride
|
|
1085
|
+
i += 8
|
|
1086
|
+
end
|
|
1087
|
+
nil
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
def idct2_8(c, base, out, off, stride)
|
|
1091
|
+
rl = JPEG_CLAMP
|
|
1092
|
+
ws = @ws
|
|
1093
|
+
i = 0
|
|
1094
|
+
ci = base
|
|
1095
|
+
while i <= 7
|
|
1096
|
+
d0 = c[ci]
|
|
1097
|
+
d1 = c[ci + 8]
|
|
1098
|
+
d3 = c[ci + 24]
|
|
1099
|
+
d5 = c[ci + 40]
|
|
1100
|
+
d7 = c[ci + 56]
|
|
1101
|
+
if d1 == 0 && d3 == 0 && d5 == 0 && d7 == 0
|
|
1102
|
+
ws[i] = ws[i + 8] = d0 << 2
|
|
1103
|
+
else
|
|
1104
|
+
t10 = (d0 << 15) + 4096
|
|
1105
|
+
t0 = d7 * -5906 + d5 * 6967 + d3 * -10_426 + d1 * 29_692
|
|
1106
|
+
ws[i] = (t10 + t0) >> 13
|
|
1107
|
+
ws[i + 8] = (t10 - t0) >> 13
|
|
1108
|
+
end
|
|
1109
|
+
i += (i == 1 || i == 3 || i == 5 ? 2 : 1)
|
|
1110
|
+
ci = base + i
|
|
1111
|
+
end
|
|
1112
|
+
i = 0
|
|
1113
|
+
while i < 16
|
|
1114
|
+
d0 = ws[i]
|
|
1115
|
+
d1 = ws[i + 1]
|
|
1116
|
+
d3 = ws[i + 3]
|
|
1117
|
+
d5 = ws[i + 5]
|
|
1118
|
+
d7 = ws[i + 7]
|
|
1119
|
+
if d1 == 0 && d3 == 0 && d5 == 0 && d7 == 0
|
|
1120
|
+
v = rl[((d0 + 4112) >> 5) & 0xFFFF] * 0x101
|
|
1121
|
+
out[off] = v
|
|
1122
|
+
else
|
|
1123
|
+
t10 = (d0 + 4112) << 15
|
|
1124
|
+
t0 = d7 * -5906 + d5 * 6967 + d3 * -10_426 + d1 * 29_692
|
|
1125
|
+
out[off] = rl[((t10 + t0) >> 20) & 0xFFFF] | (rl[((t10 - t0) >> 20) & 0xFFFF] << 8)
|
|
1126
|
+
end
|
|
1127
|
+
off += stride
|
|
1128
|
+
i += 8
|
|
1129
|
+
end
|
|
1130
|
+
nil
|
|
1131
|
+
end
|
|
1132
|
+
end
|
|
1133
|
+
|
|
1134
|
+
# Decoder state for one JPEG stream, or for rendering a coefficient store.
|
|
1135
|
+
class JpegDecoder
|
|
1136
|
+
# Restart interval, MCU grid and whether to keep a coefficient store.
|
|
1137
|
+
attr_reader :restart_interval, :mcux, :mcuy, :keep
|
|
1138
|
+
|
|
1139
|
+
# +bytes+: the JPEG (or a coefficient store for #render_store).
|
|
1140
|
+
def initialize(bytes, scale, keep)
|
|
1141
|
+
@data = bytes
|
|
1142
|
+
@scale = scale
|
|
1143
|
+
@bs = 8 / scale
|
|
1144
|
+
@keep = keep
|
|
1145
|
+
@qt = [JPEG_NONE, JPEG_NONE, JPEG_NONE, JPEG_NONE]
|
|
1146
|
+
# Huffman table definitions and built tables: DC 0..3, AC 4..7.
|
|
1147
|
+
@hcounts = [JPEG_NO_COUNTS, JPEG_NO_COUNTS, JPEG_NO_COUNTS, JPEG_NO_COUNTS,
|
|
1148
|
+
JPEG_NO_COUNTS, JPEG_NO_COUNTS, JPEG_NO_COUNTS, JPEG_NO_COUNTS]
|
|
1149
|
+
@hsymbols = [JPEG_NONE, JPEG_NONE, JPEG_NONE, JPEG_NONE, JPEG_NONE, JPEG_NONE, JPEG_NONE, JPEG_NONE]
|
|
1150
|
+
@hdefined = [0, 0, 0, 0, 0, 0, 0, 0]
|
|
1151
|
+
empty = JPEG_EMPTY_HUFFMAN
|
|
1152
|
+
@htables = [empty, empty, empty, empty, empty, empty, empty, empty]
|
|
1153
|
+
@hbuilt = [0, 0, 0, 0, 0, 0, 0, 0]
|
|
1154
|
+
@restart_interval = 0
|
|
1155
|
+
@jfif = false
|
|
1156
|
+
@adobe_transform = -1
|
|
1157
|
+
# (Object lists are built from a literal with their first element,
|
|
1158
|
+
# which lets Spinel compile them as typed object arrays.)
|
|
1159
|
+
@components = []
|
|
1160
|
+
@scans_decoded = 0
|
|
1161
|
+
@marker_end = 0
|
|
1162
|
+
@precision = 0
|
|
1163
|
+
@width = 0
|
|
1164
|
+
@height = 0
|
|
1165
|
+
@progressive = false
|
|
1166
|
+
@frame_end = 0
|
|
1167
|
+
@hmax = 0
|
|
1168
|
+
@vmax = 0
|
|
1169
|
+
@mcux = 0
|
|
1170
|
+
@mcuy = 0
|
|
1171
|
+
@out_w = 0
|
|
1172
|
+
@out_h = 0
|
|
1173
|
+
@color = JPEG_GRAY
|
|
1174
|
+
@scanned = [0]
|
|
1175
|
+
@visits = 0
|
|
1176
|
+
@max_visits = 0
|
|
1177
|
+
# The current scan's entropy-coded data (see #entropy_data).
|
|
1178
|
+
@scan = "".b
|
|
1179
|
+
@starts = JPEG_NONE
|
|
1180
|
+
@ends = JPEG_NONE
|
|
1181
|
+
# Store of a sequential decode: the scan with the luminance blocks
|
|
1182
|
+
# and their AC Huffman table.
|
|
1183
|
+
@keep_scan = "".b
|
|
1184
|
+
@keep_table = empty
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
def info
|
|
1188
|
+
begin
|
|
1189
|
+
parse(true)
|
|
1190
|
+
rescue JpegTruncated
|
|
1191
|
+
raise QrReader::ImageError, "truncated JPEG header"
|
|
1192
|
+
end
|
|
1193
|
+
raise QrReader::ImageError, "JPEG has no frame header" if @components.empty?
|
|
1194
|
+
|
|
1195
|
+
begin
|
|
1196
|
+
resolve_height
|
|
1197
|
+
rescue JpegTruncated
|
|
1198
|
+
raise QrReader::ImageError, "truncated JPEG header"
|
|
1199
|
+
end
|
|
1200
|
+
[@width, @height]
|
|
1201
|
+
end
|
|
1202
|
+
|
|
1203
|
+
def decode
|
|
1204
|
+
begin
|
|
1205
|
+
parse(false)
|
|
1206
|
+
rescue QrReader::UnsupportedImageError => e
|
|
1207
|
+
raise e
|
|
1208
|
+
rescue JpegTruncated
|
|
1209
|
+
# Truncation after complete scans: keep what was decoded.
|
|
1210
|
+
raise QrReader::ImageError, "truncated JPEG" if @scans_decoded == 0
|
|
1211
|
+
rescue QrReader::ImageError => e
|
|
1212
|
+
# Corruption after complete scans: keep what was decoded.
|
|
1213
|
+
raise e if @scans_decoded == 0
|
|
1214
|
+
end
|
|
1215
|
+
raise QrReader::ImageError, "JPEG has no image data" if @scans_decoded == 0
|
|
1216
|
+
|
|
1217
|
+
finish
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
def huffman_table(ac, id)
|
|
1221
|
+
slot = ac ? id + 4 : id
|
|
1222
|
+
return @htables[slot] if @hbuilt[slot] == 1
|
|
1223
|
+
|
|
1224
|
+
counts = @hcounts[slot]
|
|
1225
|
+
symbols = @hsymbols[slot]
|
|
1226
|
+
if @hdefined[slot] == 0
|
|
1227
|
+
raise QrReader::ImageError, "corrupt JPEG: missing Huffman table" if id > 1
|
|
1228
|
+
|
|
1229
|
+
counts = ac ? JPEG_STD_AC_COUNTS[id] : JPEG_STD_DC_COUNTS[id]
|
|
1230
|
+
symbols = ac ? JPEG_STD_AC_SYMBOLS[id] : JPEG_STD_DC_SYMBOLS
|
|
1231
|
+
end
|
|
1232
|
+
table = JpegHuffman.new(counts, symbols, ac)
|
|
1233
|
+
@htables[slot] = table
|
|
1234
|
+
@hbuilt[slot] = 1
|
|
1235
|
+
table
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
# Latches the component's quantisation table (as libjpeg does at the
|
|
1239
|
+
# component's first scan), indexed by extended zigzag position.
|
|
1240
|
+
def latch_quant(comp)
|
|
1241
|
+
return nil unless comp.qz.empty?
|
|
1242
|
+
|
|
1243
|
+
q = @qt[comp.tq]
|
|
1244
|
+
raise QrReader::ImageError, "corrupt JPEG: missing quantisation table #{comp.tq}" if q.empty?
|
|
1245
|
+
|
|
1246
|
+
comp.qz = q + Array.new(16, q[63]) + Array.new(JPEG_ZIGZAG_EXT.size - 80, 0)
|
|
1247
|
+
nil
|
|
1248
|
+
end
|
|
1249
|
+
|
|
1250
|
+
# The store of a decode with +keep+ (a binary String; empty when nothing
|
|
1251
|
+
# was kept), from which #render_store renders the luminance at any
|
|
1252
|
+
# scale.
|
|
1253
|
+
#
|
|
1254
|
+
# Layout: little-endian unsigned 32-bit Integers - magic, kind
|
|
1255
|
+
# (JPEG_STORE_SEQUENTIAL or JPEG_STORE_PROGRESSIVE), width, height,
|
|
1256
|
+
# colour space, hmax, vmax, component count, the stored (luminance)
|
|
1257
|
+
# component's index, h, v, abw and abh, and its 64 quantisation values
|
|
1258
|
+
# (zigzag order) - followed by the kind's data:
|
|
1259
|
+
# * sequential: the luminance blocks' AC Huffman table (16 code counts,
|
|
1260
|
+
# the symbol count and the symbols, as Integers), the scan data size;
|
|
1261
|
+
# per block of the abw x abh grid two Integers, the bit position of its
|
|
1262
|
+
# AC coefficients in the scan data (0xFFFFFFFF: no data, mid-gray) and
|
|
1263
|
+
# its DC (raw, 16-bit); then the scan data (see #entropy_data).
|
|
1264
|
+
# * progressive: abh raw coefficient rows (JpegComponent#raw_row).
|
|
1265
|
+
def store
|
|
1266
|
+
return "".b unless @keep
|
|
1267
|
+
|
|
1268
|
+
c = @components[0]
|
|
1269
|
+
i = 0
|
|
1270
|
+
while i < @components.size
|
|
1271
|
+
c = @components[i] if @components[i].needed
|
|
1272
|
+
i += 1
|
|
1273
|
+
end
|
|
1274
|
+
head = [JPEG_STORE_MAGIC, @progressive ? JPEG_STORE_PROGRESSIVE : JPEG_STORE_SEQUENTIAL, @width, @height,
|
|
1275
|
+
@color, @hmax, @vmax, @components.size, c.index, c.h, c.v, c.abw, c.abh]
|
|
1276
|
+
k = 0
|
|
1277
|
+
while k < 64
|
|
1278
|
+
head << (c.qz.empty? ? 0 : c.qz[k])
|
|
1279
|
+
k += 1
|
|
1280
|
+
end
|
|
1281
|
+
unless @progressive
|
|
1282
|
+
table = @keep_table
|
|
1283
|
+
k = 0
|
|
1284
|
+
while k < 16
|
|
1285
|
+
head << table.counts[k]
|
|
1286
|
+
k += 1
|
|
1287
|
+
end
|
|
1288
|
+
head << table.symbols.size
|
|
1289
|
+
k = 0
|
|
1290
|
+
while k < table.symbols.size
|
|
1291
|
+
head << table.symbols[k]
|
|
1292
|
+
k += 1
|
|
1293
|
+
end
|
|
1294
|
+
head << @keep_scan.bytesize
|
|
1295
|
+
end
|
|
1296
|
+
out = String.new(capacity: head.size * 4 + c.abw * c.abh * 8 + @keep_scan.bytesize + c.sdata.bytesize,
|
|
1297
|
+
encoding: Encoding::BINARY)
|
|
1298
|
+
i = 0
|
|
1299
|
+
while i < head.size
|
|
1300
|
+
v = head[i]
|
|
1301
|
+
out << (v & 255) << ((v >> 8) & 255) << ((v >> 16) & 255) << ((v >> 24) & 255)
|
|
1302
|
+
i += 1
|
|
1303
|
+
end
|
|
1304
|
+
if @progressive
|
|
1305
|
+
out << c.sdata
|
|
1306
|
+
else
|
|
1307
|
+
marks = c.marks
|
|
1308
|
+
n = c.abw
|
|
1309
|
+
r = 0
|
|
1310
|
+
while r < c.abh
|
|
1311
|
+
out << mark_bytes(marks, r * n, n)
|
|
1312
|
+
r += 1
|
|
1313
|
+
end
|
|
1314
|
+
out << @keep_scan
|
|
1315
|
+
end
|
|
1316
|
+
out
|
|
1317
|
+
end
|
|
1318
|
+
|
|
1319
|
+
# Luminance at this decoder's scale from the store in @data.
|
|
1320
|
+
def render_store
|
|
1321
|
+
data = @data
|
|
1322
|
+
size = data.bytesize
|
|
1323
|
+
kind = QrReaderKernels.jpeg_u32(data, 4)
|
|
1324
|
+
if QrReaderKernels.jpeg_u32(data, 0) != JPEG_STORE_MAGIC || size < JPEG_STORE_HEAD * 4 ||
|
|
1325
|
+
(kind != JPEG_STORE_SEQUENTIAL && kind != JPEG_STORE_PROGRESSIVE)
|
|
1326
|
+
raise QrReader::ImageError, "not a JPEG store"
|
|
1327
|
+
end
|
|
1328
|
+
|
|
1329
|
+
@progressive = kind == JPEG_STORE_PROGRESSIVE
|
|
1330
|
+
@width = QrReaderKernels.jpeg_u32(data, 8)
|
|
1331
|
+
@height = QrReaderKernels.jpeg_u32(data, 12)
|
|
1332
|
+
@color = QrReaderKernels.jpeg_u32(data, 16)
|
|
1333
|
+
@hmax = QrReaderKernels.jpeg_u32(data, 20)
|
|
1334
|
+
@vmax = QrReaderKernels.jpeg_u32(data, 24)
|
|
1335
|
+
ncomp = QrReaderKernels.jpeg_u32(data, 28)
|
|
1336
|
+
index = QrReaderKernels.jpeg_u32(data, 32)
|
|
1337
|
+
c = JpegComponent.new(index, index, QrReaderKernels.jpeg_u32(data, 36), QrReaderKernels.jpeg_u32(data, 40), 0)
|
|
1338
|
+
c.abw = QrReaderKernels.jpeg_u32(data, 44)
|
|
1339
|
+
c.abh = QrReaderKernels.jpeg_u32(data, 48)
|
|
1340
|
+
if @width < 1 || @width > 65_535 || @height < 1 || @height > 65_535 || @hmax < 1 || @hmax > 4 ||
|
|
1341
|
+
@vmax < 1 || @vmax > 4 || ncomp < 1 || ncomp > 10 || index >= ncomp || @color > JPEG_OTHER ||
|
|
1342
|
+
c.h < 1 || c.h > @hmax || c.v < 1 || c.v > @vmax
|
|
1343
|
+
raise QrReader::ImageError, "corrupt JPEG store"
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
mcux = (@width + 8 * @hmax - 1) / (8 * @hmax)
|
|
1347
|
+
mcuy = (@height + 8 * @vmax - 1) / (8 * @vmax)
|
|
1348
|
+
raise QrReader::ImageError, "corrupt JPEG store" if c.abw < 1 || c.abw > mcux * c.h || c.abh < 1 || c.abh > mcuy * c.v
|
|
1349
|
+
|
|
1350
|
+
comps = [index == 0 ? c : JpegComponent.new(0, 0, 1, 1, 0)]
|
|
1351
|
+
i = 1
|
|
1352
|
+
while i < ncomp
|
|
1353
|
+
comps << (i == index ? c : JpegComponent.new(i, i, 1, 1, 0))
|
|
1354
|
+
i += 1
|
|
1355
|
+
end
|
|
1356
|
+
@components = comps
|
|
1357
|
+
setup_output
|
|
1358
|
+
q = Array.new(64, 0)
|
|
1359
|
+
k = 0
|
|
1360
|
+
while k < 64
|
|
1361
|
+
q[k] = QrReaderKernels.jpeg_u32(data, 52 + 4 * k)
|
|
1362
|
+
k += 1
|
|
1363
|
+
end
|
|
1364
|
+
c.qz = q + Array.new(16, q[63]) + Array.new(JPEG_ZIGZAG_EXT.size - 80, 0)
|
|
1365
|
+
c.needed = true
|
|
1366
|
+
c.bs = scaled_block_size(c)
|
|
1367
|
+
c.idct = JpegIDCT.new(c.bs)
|
|
1368
|
+
c.pw = c.abw * c.bs
|
|
1369
|
+
c.ph = c.abh * c.bs
|
|
1370
|
+
p = JPEG_STORE_HEAD * 4
|
|
1371
|
+
if @progressive
|
|
1372
|
+
raise QrReader::ImageError, "corrupt JPEG store" if p + c.abh * c.abw * JPEG_RAW_BLOCK > size
|
|
1373
|
+
|
|
1374
|
+
render_stored_raw(c, p)
|
|
1375
|
+
else
|
|
1376
|
+
counts = Array.new(16, 0)
|
|
1377
|
+
total = 0
|
|
1378
|
+
k = 0
|
|
1379
|
+
while k < 16
|
|
1380
|
+
counts[k] = QrReaderKernels.jpeg_u32(data, p + 4 * k)
|
|
1381
|
+
total += counts[k]
|
|
1382
|
+
k += 1
|
|
1383
|
+
end
|
|
1384
|
+
nsym = QrReaderKernels.jpeg_u32(data, p + 64)
|
|
1385
|
+
raise QrReader::ImageError, "corrupt JPEG store" if nsym != total || nsym > 256
|
|
1386
|
+
|
|
1387
|
+
symbols = Array.new(nsym, 0)
|
|
1388
|
+
k = 0
|
|
1389
|
+
while k < nsym
|
|
1390
|
+
symbols[k] = QrReaderKernels.jpeg_u32(data, p + 68 + 4 * k)
|
|
1391
|
+
k += 1
|
|
1392
|
+
end
|
|
1393
|
+
p += 68 + 4 * nsym
|
|
1394
|
+
scan_size = QrReaderKernels.jpeg_u32(data, p)
|
|
1395
|
+
marks = p + 4
|
|
1396
|
+
scan = marks + c.abw * c.abh * 8
|
|
1397
|
+
# (No scan data if the luminance scan could not be decoded.)
|
|
1398
|
+
raise QrReader::ImageError, "corrupt JPEG store" if scan + scan_size != size
|
|
1399
|
+
|
|
1400
|
+
render_marked(c, marks, scan, scan_size, JpegHuffman.new(counts, symbols, true))
|
|
1401
|
+
end
|
|
1402
|
+
output
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
private
|
|
1406
|
+
|
|
1407
|
+
# ---------------------------------------------------------------
|
|
1408
|
+
# Marker parsing
|
|
1409
|
+
|
|
1410
|
+
def parse(header_only)
|
|
1411
|
+
data = @data
|
|
1412
|
+
raise QrReader::ImageError, "not a JPEG file" unless data.getbyte(0) == 0xFF && data.getbyte(1) == 0xD8
|
|
1413
|
+
|
|
1414
|
+
pos = 2
|
|
1415
|
+
while (code = next_marker(pos)) >= 0
|
|
1416
|
+
pos = @marker_end
|
|
1417
|
+
if code >= 0xC0 && code <= 0xC2
|
|
1418
|
+
pos = read_frame(pos, code)
|
|
1419
|
+
return nil if header_only
|
|
1420
|
+
elsif code == 0xC3 || (code >= 0xC5 && code <= 0xC7) || (code >= 0xC9 && code <= 0xCB) ||
|
|
1421
|
+
(code >= 0xCD && code <= 0xCF) || code == 0xF7
|
|
1422
|
+
raise QrReader::UnsupportedImageError, "#{QrReaderKernels.jpeg_sof_name(code)} JPEG is not supported" unless header_only
|
|
1423
|
+
|
|
1424
|
+
read_frame(pos, code)
|
|
1425
|
+
return nil
|
|
1426
|
+
elsif code == 0xC4
|
|
1427
|
+
pos = read_dht(pos)
|
|
1428
|
+
elsif code == 0xDB
|
|
1429
|
+
pos = read_dqt(pos)
|
|
1430
|
+
elsif code == 0xDD
|
|
1431
|
+
pos = read_dri(pos)
|
|
1432
|
+
elsif code == 0xDA
|
|
1433
|
+
raise QrReader::ImageError, "corrupt JPEG: scan before frame header" if header_only
|
|
1434
|
+
|
|
1435
|
+
pos = read_scan(pos)
|
|
1436
|
+
elsif code == 0xD9
|
|
1437
|
+
return nil
|
|
1438
|
+
elsif code == 0xE0
|
|
1439
|
+
pos = read_app0(pos)
|
|
1440
|
+
elsif code == 0xEE
|
|
1441
|
+
pos = read_app14(pos)
|
|
1442
|
+
elsif (code >= 0xD0 && code <= 0xD8) || code == 0x01
|
|
1443
|
+
# markers without payload
|
|
1444
|
+
elsif code == 0xDE || code == 0xDF
|
|
1445
|
+
raise QrReader::UnsupportedImageError, "hierarchical JPEG is not supported"
|
|
1446
|
+
elsif code >= 0x02 && code <= 0xBF
|
|
1447
|
+
raise QrReader::ImageError, "corrupt JPEG: unknown marker 0x#{code.to_s(16).upcase}"
|
|
1448
|
+
else
|
|
1449
|
+
pos = segment_end(pos)
|
|
1450
|
+
end
|
|
1451
|
+
end
|
|
1452
|
+
nil
|
|
1453
|
+
end
|
|
1454
|
+
|
|
1455
|
+
# Finds the next marker at or after +pos+, skipping junk and fill bytes.
|
|
1456
|
+
# Returns its code (and sets @marker_end to the position after it), or
|
|
1457
|
+
# -1 at the end of the data.
|
|
1458
|
+
def next_marker(pos)
|
|
1459
|
+
data = @data
|
|
1460
|
+
size = data.bytesize
|
|
1461
|
+
while pos < size
|
|
1462
|
+
f = data.byteindex(JPEG_FF, pos)
|
|
1463
|
+
return -1 unless f
|
|
1464
|
+
|
|
1465
|
+
pos = f + 1
|
|
1466
|
+
pos += 1 while pos < size && data.getbyte(pos) == 0xFF
|
|
1467
|
+
return -1 if pos >= size
|
|
1468
|
+
|
|
1469
|
+
code = data.getbyte(pos)
|
|
1470
|
+
if code != 0
|
|
1471
|
+
@marker_end = pos + 1
|
|
1472
|
+
return code
|
|
1473
|
+
end
|
|
1474
|
+
end
|
|
1475
|
+
-1
|
|
1476
|
+
end
|
|
1477
|
+
|
|
1478
|
+
def u16(pos)
|
|
1479
|
+
raise JpegTruncated, "truncated JPEG" if pos < 0 || pos + 2 > @data.bytesize
|
|
1480
|
+
|
|
1481
|
+
(@data.getbyte(pos) << 8) | @data.getbyte(pos + 1)
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1484
|
+
def byte(pos)
|
|
1485
|
+
raise JpegTruncated, "truncated JPEG" if pos < 0 || pos >= @data.bytesize
|
|
1486
|
+
|
|
1487
|
+
@data.getbyte(pos)
|
|
1488
|
+
end
|
|
1489
|
+
|
|
1490
|
+
# Position after the marker segment whose length field is at +pos+.
|
|
1491
|
+
def segment_end(pos)
|
|
1492
|
+
len = u16(pos)
|
|
1493
|
+
raise QrReader::ImageError, "corrupt JPEG: bad marker length" if len < 2
|
|
1494
|
+
raise JpegTruncated, "truncated JPEG" if pos + len > @data.bytesize
|
|
1495
|
+
|
|
1496
|
+
pos + len
|
|
1497
|
+
end
|
|
1498
|
+
|
|
1499
|
+
def read_frame(pos, code)
|
|
1500
|
+
stop = segment_end(pos)
|
|
1501
|
+
raise QrReader::ImageError, "corrupt JPEG: duplicate frame header" unless @components.empty?
|
|
1502
|
+
|
|
1503
|
+
@precision = byte(pos + 2)
|
|
1504
|
+
@height = u16(pos + 3)
|
|
1505
|
+
@width = u16(pos + 5)
|
|
1506
|
+
count = byte(pos + 7)
|
|
1507
|
+
raise QrReader::ImageError, "corrupt JPEG: bad image width" if @width == 0
|
|
1508
|
+
raise QrReader::ImageError, "corrupt JPEG: bad component count" if count < 1 || count > 10
|
|
1509
|
+
raise QrReader::ImageError, "corrupt JPEG: bad frame header length" if stop - pos != 8 + 3 * count
|
|
1510
|
+
|
|
1511
|
+
@progressive = code == 0xC2
|
|
1512
|
+
comps = [frame_component(pos, 0)]
|
|
1513
|
+
i = 1
|
|
1514
|
+
while i < count
|
|
1515
|
+
comps << frame_component(pos, i)
|
|
1516
|
+
i += 1
|
|
1517
|
+
end
|
|
1518
|
+
@components = comps
|
|
1519
|
+
@frame_end = stop
|
|
1520
|
+
stop
|
|
1521
|
+
end
|
|
1522
|
+
|
|
1523
|
+
# Component +i+ of the frame header whose length field is at +pos+.
|
|
1524
|
+
def frame_component(pos, i)
|
|
1525
|
+
p = pos + 8 + 3 * i
|
|
1526
|
+
hv = byte(p + 1)
|
|
1527
|
+
h = hv >> 4
|
|
1528
|
+
v = hv & 15
|
|
1529
|
+
tq = byte(p + 2)
|
|
1530
|
+
raise QrReader::ImageError, "corrupt JPEG: bad sampling factors" if h < 1 || h > 4 || v < 1 || v > 4
|
|
1531
|
+
raise QrReader::ImageError, "corrupt JPEG: bad quantisation table id" if tq > 3
|
|
1532
|
+
|
|
1533
|
+
JpegComponent.new(i, byte(p), h, v, tq)
|
|
1534
|
+
end
|
|
1535
|
+
|
|
1536
|
+
def read_dht(pos)
|
|
1537
|
+
stop = segment_end(pos)
|
|
1538
|
+
p = pos + 2
|
|
1539
|
+
while p < stop
|
|
1540
|
+
info = byte(p)
|
|
1541
|
+
klass = info >> 4
|
|
1542
|
+
id = info & 15
|
|
1543
|
+
raise QrReader::ImageError, "corrupt JPEG: bad Huffman table id" if klass > 1 || id > 3
|
|
1544
|
+
|
|
1545
|
+
counts = Array.new(16, 0)
|
|
1546
|
+
total = 0
|
|
1547
|
+
i = 0
|
|
1548
|
+
while i < 16
|
|
1549
|
+
n = byte(p + 1 + i)
|
|
1550
|
+
counts[i] = n
|
|
1551
|
+
total += n
|
|
1552
|
+
i += 1
|
|
1553
|
+
end
|
|
1554
|
+
raise QrReader::ImageError, "corrupt JPEG: bad Huffman table" if total > 256 || p + 17 + total > stop
|
|
1555
|
+
|
|
1556
|
+
symbols = Array.new(total, 0)
|
|
1557
|
+
i = 0
|
|
1558
|
+
while i < total
|
|
1559
|
+
symbols[i] = @data.getbyte(p + 17 + i)
|
|
1560
|
+
i += 1
|
|
1561
|
+
end
|
|
1562
|
+
slot = klass == 0 ? id : id + 4
|
|
1563
|
+
@hcounts[slot] = counts
|
|
1564
|
+
@hsymbols[slot] = symbols
|
|
1565
|
+
@hdefined[slot] = 1
|
|
1566
|
+
@hbuilt[slot] = 0
|
|
1567
|
+
p += 17 + total
|
|
1568
|
+
end
|
|
1569
|
+
stop
|
|
1570
|
+
end
|
|
1571
|
+
|
|
1572
|
+
def read_dqt(pos)
|
|
1573
|
+
stop = segment_end(pos)
|
|
1574
|
+
p = pos + 2
|
|
1575
|
+
while p < stop
|
|
1576
|
+
info = byte(p)
|
|
1577
|
+
precision = info >> 4
|
|
1578
|
+
id = info & 15
|
|
1579
|
+
size = precision == 0 ? 64 : 128
|
|
1580
|
+
raise QrReader::ImageError, "corrupt JPEG: bad quantisation table" if precision > 1 || id > 3 || p + 1 + size > stop
|
|
1581
|
+
|
|
1582
|
+
q = Array.new(64, 0)
|
|
1583
|
+
i = 0
|
|
1584
|
+
while i < 64
|
|
1585
|
+
q[i] = precision == 0 ? @data.getbyte(p + 1 + i) : (@data.getbyte(p + 1 + 2 * i) << 8) | @data.getbyte(p + 2 + 2 * i)
|
|
1586
|
+
i += 1
|
|
1587
|
+
end
|
|
1588
|
+
@qt[id] = q
|
|
1589
|
+
p += 1 + size
|
|
1590
|
+
end
|
|
1591
|
+
stop
|
|
1592
|
+
end
|
|
1593
|
+
|
|
1594
|
+
def read_dri(pos)
|
|
1595
|
+
stop = segment_end(pos)
|
|
1596
|
+
raise QrReader::ImageError, "corrupt JPEG: bad DRI marker" if stop - pos != 4
|
|
1597
|
+
|
|
1598
|
+
@restart_interval = u16(pos + 2)
|
|
1599
|
+
stop
|
|
1600
|
+
end
|
|
1601
|
+
|
|
1602
|
+
def read_app0(pos)
|
|
1603
|
+
stop = segment_end(pos)
|
|
1604
|
+
@jfif = true if stop - pos >= 16 && @data.byteslice(pos + 2, 5) == "JFIF\0"
|
|
1605
|
+
stop
|
|
1606
|
+
end
|
|
1607
|
+
|
|
1608
|
+
def read_app14(pos)
|
|
1609
|
+
stop = segment_end(pos)
|
|
1610
|
+
@adobe_transform = byte(pos + 13) if stop - pos >= 14 && @data.byteslice(pos + 2, 5) == "Adobe"
|
|
1611
|
+
stop
|
|
1612
|
+
end
|
|
1613
|
+
|
|
1614
|
+
# Height 0 in the frame header means it is given by a DNL marker after
|
|
1615
|
+
# the first scan (0xFF 0xDC cannot occur inside scan data).
|
|
1616
|
+
def resolve_height
|
|
1617
|
+
return nil if @height != 0
|
|
1618
|
+
|
|
1619
|
+
at = @data.byteindex(JPEG_DNL_MARKER, @frame_end)
|
|
1620
|
+
raise QrReader::ImageError, "corrupt JPEG: zero image height" unless at
|
|
1621
|
+
|
|
1622
|
+
@height = u16(at + 4)
|
|
1623
|
+
raise QrReader::ImageError, "corrupt JPEG: zero image height" if @height == 0
|
|
1624
|
+
|
|
1625
|
+
nil
|
|
1626
|
+
end
|
|
1627
|
+
|
|
1628
|
+
# ---------------------------------------------------------------
|
|
1629
|
+
# Frame setup (at the first scan, when all header markers are known)
|
|
1630
|
+
|
|
1631
|
+
def setup_frame
|
|
1632
|
+
return nil if @hmax > 0
|
|
1633
|
+
|
|
1634
|
+
if @precision != 8
|
|
1635
|
+
if @precision == 12 || @precision == 16
|
|
1636
|
+
raise QrReader::UnsupportedImageError, "#{@precision}-bit JPEG is not supported"
|
|
1637
|
+
end
|
|
1638
|
+
|
|
1639
|
+
raise QrReader::ImageError, "corrupt JPEG: bad sample precision #{@precision}"
|
|
1640
|
+
end
|
|
1641
|
+
resolve_height
|
|
1642
|
+
comps = @components
|
|
1643
|
+
@color = color_space
|
|
1644
|
+
nneeded = 1
|
|
1645
|
+
nneeded = 3 if @color == JPEG_RGB
|
|
1646
|
+
nneeded = 4 if @color == JPEG_CMYK || @color == JPEG_YCCK
|
|
1647
|
+
# A coefficient store only for single-component luminance that can be
|
|
1648
|
+
# rendered at full size.
|
|
1649
|
+
@keep = false if nneeded > 1 || @width * @height > JPEG_MAX_PIXELS
|
|
1650
|
+
hmax = 0
|
|
1651
|
+
vmax = 0
|
|
1652
|
+
i = 0
|
|
1653
|
+
while i < comps.size
|
|
1654
|
+
c = comps[i]
|
|
1655
|
+
hmax = c.h if c.h > hmax
|
|
1656
|
+
vmax = c.v if c.v > vmax
|
|
1657
|
+
i += 1
|
|
1658
|
+
end
|
|
1659
|
+
@hmax = hmax
|
|
1660
|
+
@vmax = vmax
|
|
1661
|
+
setup_output
|
|
1662
|
+
@mcux = (@width + 8 * hmax - 1) / (8 * hmax)
|
|
1663
|
+
@mcuy = (@height + 8 * vmax - 1) / (8 * vmax)
|
|
1664
|
+
idcts = [JpegIDCT.new(1), JpegIDCT.new(1), JpegIDCT.new(2), JpegIDCT.new(1), JpegIDCT.new(4),
|
|
1665
|
+
JpegIDCT.new(1), JpegIDCT.new(1), JpegIDCT.new(1), JpegIDCT.new(8)]
|
|
1666
|
+
single = comps.size == 1
|
|
1667
|
+
blocks = 0
|
|
1668
|
+
i = 0
|
|
1669
|
+
while i < comps.size
|
|
1670
|
+
c = comps[i]
|
|
1671
|
+
c.bs = scaled_block_size(c)
|
|
1672
|
+
c.idct = idcts[c.bs]
|
|
1673
|
+
setup_component(c, i < nneeded, single)
|
|
1674
|
+
blocks += c.abw * c.abh if c.needed
|
|
1675
|
+
i += 1
|
|
1676
|
+
end
|
|
1677
|
+
check_coefficient_memory if @progressive
|
|
1678
|
+
@scanned = Array.new(comps.size, 0)
|
|
1679
|
+
@visits = 0
|
|
1680
|
+
@max_visits = JPEG_MAX_VISITS * blocks + 65_536
|
|
1681
|
+
nil
|
|
1682
|
+
end
|
|
1683
|
+
|
|
1684
|
+
# Output size at this decoder's scale (checked against MAX_PIXELS).
|
|
1685
|
+
def setup_output
|
|
1686
|
+
w = @width
|
|
1687
|
+
h = @height
|
|
1688
|
+
@out_w = (w + @scale - 1) / @scale
|
|
1689
|
+
@out_h = (h + @scale - 1) / @scale
|
|
1690
|
+
raise QrReader::UnsupportedImageError, "JPEG too large (#{w}x#{h})" if @out_w * @out_h > JPEG_MAX_PIXELS
|
|
1691
|
+
|
|
1692
|
+
nil
|
|
1693
|
+
end
|
|
1694
|
+
|
|
1695
|
+
# libjpeg's per-component DCT scaling: at reduced scales a subsampled
|
|
1696
|
+
# component gets a larger IDCT where that replaces upsampling.
|
|
1697
|
+
def scaled_block_size(c)
|
|
1698
|
+
size = @bs
|
|
1699
|
+
while size < 8 && ((@hmax * @bs) % (c.h * size * 2)) == 0 && ((@vmax * @bs) % (c.v * size * 2)) == 0
|
|
1700
|
+
size += size
|
|
1701
|
+
end
|
|
1702
|
+
size
|
|
1703
|
+
end
|
|
1704
|
+
|
|
1705
|
+
# Progressive JPEGs keep all coefficients of the needed components (2
|
|
1706
|
+
# bytes each): refuse sizes whose storage would be excessive.
|
|
1707
|
+
def check_coefficient_memory
|
|
1708
|
+
bytes = 0
|
|
1709
|
+
i = 0
|
|
1710
|
+
while i < @components.size
|
|
1711
|
+
c = @components[i]
|
|
1712
|
+
bytes += c.abw * c.abh * c.stride * 2 if c.needed
|
|
1713
|
+
i += 1
|
|
1714
|
+
end
|
|
1715
|
+
return nil if bytes <= JPEG_MAX_COEFFICIENT_BYTES
|
|
1716
|
+
|
|
1717
|
+
raise QrReader::UnsupportedImageError, "progressive JPEG too large to decode at scale #{@scale} " \
|
|
1718
|
+
"(#{@width}x#{@height}, #{@components.size} components)"
|
|
1719
|
+
end
|
|
1720
|
+
|
|
1721
|
+
def setup_component(c, needed, single)
|
|
1722
|
+
c.cw = (@width * c.h + @hmax - 1) / @hmax
|
|
1723
|
+
c.ch = (@height * c.v + @vmax - 1) / @vmax
|
|
1724
|
+
c.bw = (c.cw + 7) / 8
|
|
1725
|
+
c.bh = (c.ch + 7) / 8
|
|
1726
|
+
c.abw = single ? c.bw : @mcux * c.h
|
|
1727
|
+
c.abh = single ? c.bh : @mcuy * c.v
|
|
1728
|
+
c.pw = c.abw * c.bs
|
|
1729
|
+
c.ph = c.abh * c.bs
|
|
1730
|
+
c.needed = needed
|
|
1731
|
+
return nil unless needed
|
|
1732
|
+
|
|
1733
|
+
if @progressive
|
|
1734
|
+
# Only the DC is kept when it is all that is rendered.
|
|
1735
|
+
c.stride = c.bs == 1 && !@keep ? 1 : JPEG_BLOCK_STRIDE
|
|
1736
|
+
c.start_raw
|
|
1737
|
+
else
|
|
1738
|
+
c.start_plane
|
|
1739
|
+
c.start_marks if @keep
|
|
1740
|
+
end
|
|
1741
|
+
nil
|
|
1742
|
+
end
|
|
1743
|
+
|
|
1744
|
+
# Colour space of the stored components, following libjpeg's rules.
|
|
1745
|
+
def color_space
|
|
1746
|
+
comps = @components
|
|
1747
|
+
n = comps.size
|
|
1748
|
+
if n == 1
|
|
1749
|
+
JPEG_GRAY
|
|
1750
|
+
elsif n == 3
|
|
1751
|
+
if @jfif then JPEG_YCBCR
|
|
1752
|
+
elsif @adobe_transform >= 0 then @adobe_transform == 0 ? JPEG_RGB : JPEG_YCBCR
|
|
1753
|
+
elsif comps[0].id == 82 && comps[1].id == 71 && comps[2].id == 66 then JPEG_RGB # "RGB"
|
|
1754
|
+
else JPEG_YCBCR
|
|
1755
|
+
end
|
|
1756
|
+
elsif n == 4
|
|
1757
|
+
@adobe_transform <= 0 ? JPEG_CMYK : JPEG_YCCK
|
|
1758
|
+
else
|
|
1759
|
+
JPEG_OTHER
|
|
1760
|
+
end
|
|
1761
|
+
end
|
|
1762
|
+
|
|
1763
|
+
# ---------------------------------------------------------------
|
|
1764
|
+
# Scans
|
|
1765
|
+
|
|
1766
|
+
def read_scan(pos)
|
|
1767
|
+
raise QrReader::ImageError, "corrupt JPEG: scan before frame header" if @components.empty?
|
|
1768
|
+
|
|
1769
|
+
stop = segment_end(pos)
|
|
1770
|
+
count = byte(pos + 2)
|
|
1771
|
+
raise QrReader::ImageError, "corrupt JPEG: bad scan header" if count < 1 || count > 4 || stop - pos != 6 + 2 * count
|
|
1772
|
+
|
|
1773
|
+
taken = []
|
|
1774
|
+
dcs = []
|
|
1775
|
+
acs = []
|
|
1776
|
+
i = 0
|
|
1777
|
+
while i < count
|
|
1778
|
+
id = byte(pos + 3 + 2 * i)
|
|
1779
|
+
tables = byte(pos + 4 + 2 * i)
|
|
1780
|
+
comp = scan_component(id, taken)
|
|
1781
|
+
raise QrReader::ImageError, "corrupt JPEG: bad scan component" if comp < 0
|
|
1782
|
+
raise QrReader::ImageError, "corrupt JPEG: bad Huffman table id" if (tables >> 4) > 3 || (tables & 15) > 3
|
|
1783
|
+
|
|
1784
|
+
taken << comp
|
|
1785
|
+
dcs << (tables >> 4)
|
|
1786
|
+
acs << (tables & 15)
|
|
1787
|
+
i += 1
|
|
1788
|
+
end
|
|
1789
|
+
comps = [@components[taken[0]]]
|
|
1790
|
+
i = 1
|
|
1791
|
+
while i < count
|
|
1792
|
+
comps << @components[taken[i]]
|
|
1793
|
+
i += 1
|
|
1794
|
+
end
|
|
1795
|
+
ss = byte(stop - 3)
|
|
1796
|
+
se = byte(stop - 2)
|
|
1797
|
+
ah = byte(stop - 1) >> 4
|
|
1798
|
+
al = byte(stop - 1) & 15
|
|
1799
|
+
|
|
1800
|
+
setup_frame
|
|
1801
|
+
raise QrReader::ImageError, "corrupt JPEG: too many blocks per MCU" if count > 1 && mcu_blocks(comps) > 10
|
|
1802
|
+
|
|
1803
|
+
validate_progression(count, ss, se, ah, al) if @progressive
|
|
1804
|
+
seg_end = scan_extent(stop)
|
|
1805
|
+
if decode_scan?(comps, ss)
|
|
1806
|
+
# Crafted files could repeat cheap scans that each visit every block.
|
|
1807
|
+
@visits += count == 1 ? comps[0].bw * comps[0].bh : @mcux * @mcuy * mcu_blocks(comps)
|
|
1808
|
+
raise QrReader::ImageError, "corrupt JPEG: too many scans" if @scans_decoded >= JPEG_MAX_SCANS || @visits > @max_visits
|
|
1809
|
+
|
|
1810
|
+
entropy_data(stop, seg_end)
|
|
1811
|
+
@scans_decoded += 1
|
|
1812
|
+
if @progressive
|
|
1813
|
+
JpegProgressive.new(self, comps, dcs, ss, se, ah, al, acs[0], @scan, @starts, @ends).run
|
|
1814
|
+
else
|
|
1815
|
+
JpegSequential.new(self, comps, dcs, acs, @scan, @starts, @ends).run
|
|
1816
|
+
keep_scan(comps, acs) if @keep
|
|
1817
|
+
end
|
|
1818
|
+
@scan = "".b
|
|
1819
|
+
end
|
|
1820
|
+
seg_end
|
|
1821
|
+
end
|
|
1822
|
+
|
|
1823
|
+
# Keeps the scan data and AC table of the needed component's (only)
|
|
1824
|
+
# sequential scan for the store.
|
|
1825
|
+
def keep_scan(comps, acs)
|
|
1826
|
+
# (Bit positions in the store are 32-bit.)
|
|
1827
|
+
@keep = false if @scan.bytesize >= (1 << 28)
|
|
1828
|
+
i = 0
|
|
1829
|
+
while i < comps.size
|
|
1830
|
+
if comps[i].needed
|
|
1831
|
+
@keep_scan = @scan
|
|
1832
|
+
@keep_table = huffman_table(true, acs[i])
|
|
1833
|
+
end
|
|
1834
|
+
i += 1
|
|
1835
|
+
end
|
|
1836
|
+
nil
|
|
1837
|
+
end
|
|
1838
|
+
|
|
1839
|
+
# Index of the first component with this id not yet in the scan (whose
|
|
1840
|
+
# indices are +taken+; some encoders write duplicate ids, libjpeg-turbo
|
|
1841
|
+
# matches them so), or -1.
|
|
1842
|
+
def scan_component(id, taken)
|
|
1843
|
+
i = 0
|
|
1844
|
+
while i < @components.size
|
|
1845
|
+
if @components[i].id == id
|
|
1846
|
+
free = true
|
|
1847
|
+
j = 0
|
|
1848
|
+
while j < taken.size
|
|
1849
|
+
free = false if taken[j] == i
|
|
1850
|
+
j += 1
|
|
1851
|
+
end
|
|
1852
|
+
return i if free
|
|
1853
|
+
end
|
|
1854
|
+
i += 1
|
|
1855
|
+
end
|
|
1856
|
+
-1
|
|
1857
|
+
end
|
|
1858
|
+
|
|
1859
|
+
# Blocks per MCU of an interleaved scan.
|
|
1860
|
+
def mcu_blocks(comps)
|
|
1861
|
+
n = 0
|
|
1862
|
+
i = 0
|
|
1863
|
+
while i < comps.size
|
|
1864
|
+
n += comps[i].h * comps[i].v
|
|
1865
|
+
i += 1
|
|
1866
|
+
end
|
|
1867
|
+
n
|
|
1868
|
+
end
|
|
1869
|
+
|
|
1870
|
+
def validate_progression(count, ss, se, ah, al)
|
|
1871
|
+
bad = ss == 0 ? se != 0 : ss > se || se > 63 || count != 1
|
|
1872
|
+
bad ||= ah != 0 && al != ah - 1
|
|
1873
|
+
bad ||= al > 13
|
|
1874
|
+
raise QrReader::ImageError, "corrupt JPEG: bad progressive scan parameters" if bad
|
|
1875
|
+
|
|
1876
|
+
nil
|
|
1877
|
+
end
|
|
1878
|
+
|
|
1879
|
+
# Whether a scan contributes to the output: scans without needed
|
|
1880
|
+
# components, progressive AC scans of components decoded DC-only (block
|
|
1881
|
+
# size 1, without a coefficient store) and repeated sequential scans
|
|
1882
|
+
# are skipped.
|
|
1883
|
+
def decode_scan?(comps, ss)
|
|
1884
|
+
unless @progressive
|
|
1885
|
+
# A component has a single sequential scan: repeats are ignored,
|
|
1886
|
+
# and so are scans of components the output does not need.
|
|
1887
|
+
fresh = false
|
|
1888
|
+
i = 0
|
|
1889
|
+
while i < comps.size
|
|
1890
|
+
c = comps[i]
|
|
1891
|
+
fresh = true if c.needed && @scanned[c.index] == 0
|
|
1892
|
+
@scanned[c.index] = 1
|
|
1893
|
+
i += 1
|
|
1894
|
+
end
|
|
1895
|
+
return fresh
|
|
1896
|
+
end
|
|
1897
|
+
if ss == 0
|
|
1898
|
+
i = 0
|
|
1899
|
+
while i < comps.size
|
|
1900
|
+
return true if comps[i].needed
|
|
1901
|
+
|
|
1902
|
+
i += 1
|
|
1903
|
+
end
|
|
1904
|
+
return false
|
|
1905
|
+
end
|
|
1906
|
+
c = comps[0]
|
|
1907
|
+
c.needed && c.stride > 1
|
|
1908
|
+
end
|
|
1909
|
+
|
|
1910
|
+
# End of the entropy-coded data starting at +pos+: the first 0xFF that
|
|
1911
|
+
# is neither stuffing nor a restart marker. Fill bytes (0xFF runs)
|
|
1912
|
+
# before stuffing or RST are allowed. With restart intervals, reserved
|
|
1913
|
+
# marker codes (corrupt data) do not end the scan either: like libjpeg,
|
|
1914
|
+
# decoding resumes at the next RST.
|
|
1915
|
+
def scan_extent(pos)
|
|
1916
|
+
data = @data
|
|
1917
|
+
size = data.bytesize
|
|
1918
|
+
resync = @restart_interval > 0
|
|
1919
|
+
while pos < size
|
|
1920
|
+
e = data.byteindex(JPEG_FF, pos)
|
|
1921
|
+
return size unless e
|
|
1922
|
+
|
|
1923
|
+
r = e + 1
|
|
1924
|
+
return size if r >= size
|
|
1925
|
+
|
|
1926
|
+
c = data.getbyte(r)
|
|
1927
|
+
if c == 0xFF
|
|
1928
|
+
r += 1 while r < size && data.getbyte(r) == 0xFF
|
|
1929
|
+
return e if r >= size
|
|
1930
|
+
|
|
1931
|
+
c = data.getbyte(r)
|
|
1932
|
+
return e unless c == 0 || (c >= 0xD0 && c <= 0xD7) || (resync && c < 0xC0)
|
|
1933
|
+
elsif c != 0 && (c < 0xD0 || c > 0xD7)
|
|
1934
|
+
return e if !resync || c >= 0xC0
|
|
1935
|
+
end
|
|
1936
|
+
pos = r + 1
|
|
1937
|
+
end
|
|
1938
|
+
size
|
|
1939
|
+
end
|
|
1940
|
+
|
|
1941
|
+
# The entropy-coded segment [pos, stop) without byte stuffing, its
|
|
1942
|
+
# restart intervals concatenated, as @scan (followed by zero padding).
|
|
1943
|
+
# @starts[i] is the byte offset of interval i, @ends[i] the bit
|
|
1944
|
+
# position just after its data.
|
|
1945
|
+
def entropy_data(pos, stop)
|
|
1946
|
+
data = @data
|
|
1947
|
+
stop -= 1 if stop > pos && data.getbyte(stop - 1) == 0xFF # dangling half of a stuffed byte
|
|
1948
|
+
resync = @restart_interval > 0
|
|
1949
|
+
buf = String.new(capacity: stop - pos + JPEG_TAIL_PADDING.bytesize, encoding: Encoding::BINARY)
|
|
1950
|
+
piece_start = []
|
|
1951
|
+
piece_end = []
|
|
1952
|
+
marks = []
|
|
1953
|
+
cur = 0
|
|
1954
|
+
cut = false # the interval's data ended at a reserved marker (corrupt data)
|
|
1955
|
+
p = pos
|
|
1956
|
+
while p < stop
|
|
1957
|
+
f = data.byteindex(JPEG_FF, p)
|
|
1958
|
+
if f.nil? || f >= stop
|
|
1959
|
+
buf << data.byteslice(p, stop - p) unless cut
|
|
1960
|
+
break
|
|
1961
|
+
end
|
|
1962
|
+
buf << data.byteslice(p, f - p) if !cut && f > p
|
|
1963
|
+
q = f + 1
|
|
1964
|
+
q += 1 while q < stop && data.getbyte(q) == 0xFF # fill bytes
|
|
1965
|
+
if q >= stop
|
|
1966
|
+
buf << data.byteslice(f, stop - f) unless cut
|
|
1967
|
+
break
|
|
1968
|
+
end
|
|
1969
|
+
c = data.getbyte(q)
|
|
1970
|
+
if c == 0
|
|
1971
|
+
buf << JPEG_FF unless cut
|
|
1972
|
+
elsif c >= 0xD0 && c <= 0xD7
|
|
1973
|
+
break unless resync # a stray RST ends the data, like in libjpeg
|
|
1974
|
+
|
|
1975
|
+
piece_start << cur
|
|
1976
|
+
piece_end << buf.bytesize
|
|
1977
|
+
marks << c
|
|
1978
|
+
cur = buf.bytesize
|
|
1979
|
+
cut = false
|
|
1980
|
+
else
|
|
1981
|
+
# Reserved marker: fill bytes before it stay, the interval ends.
|
|
1982
|
+
buf << data.byteslice(f, q - 1 - f) if !cut && q - 1 > f
|
|
1983
|
+
cut = true
|
|
1984
|
+
end
|
|
1985
|
+
p = q + 1
|
|
1986
|
+
end
|
|
1987
|
+
if marks.empty?
|
|
1988
|
+
@starts = [0]
|
|
1989
|
+
@ends = [buf.bytesize << 3]
|
|
1990
|
+
buf << JPEG_TAIL_PADDING
|
|
1991
|
+
@scan = buf
|
|
1992
|
+
return nil
|
|
1993
|
+
end
|
|
1994
|
+
|
|
1995
|
+
piece_start << cur
|
|
1996
|
+
piece_end << buf.bytesize
|
|
1997
|
+
# The intervals in order, each starting on a 4-byte boundary (an empty
|
|
1998
|
+
# one where the next begins).
|
|
1999
|
+
order = restart_intervals(marks)
|
|
2000
|
+
out = String.new(capacity: buf.bytesize + 4 * order.size + JPEG_TAIL_PADDING.bytesize, encoding: Encoding::BINARY)
|
|
2001
|
+
starts = []
|
|
2002
|
+
ends = []
|
|
2003
|
+
i = 0
|
|
2004
|
+
while i < order.size
|
|
2005
|
+
j = order[i]
|
|
2006
|
+
start = out.bytesize
|
|
2007
|
+
len = j < 0 ? 0 : piece_end[j] - piece_start[j]
|
|
2008
|
+
out << buf.byteslice(piece_start[j], len) << JPEG_TAIL_PADDING.byteslice(0, -len & 3) if len > 0
|
|
2009
|
+
starts << start
|
|
2010
|
+
ends << ((start + len) << 3)
|
|
2011
|
+
i += 1
|
|
2012
|
+
end
|
|
2013
|
+
out << JPEG_TAIL_PADDING
|
|
2014
|
+
@scan = out
|
|
2015
|
+
@starts = starts
|
|
2016
|
+
@ends = ends
|
|
2017
|
+
nil
|
|
2018
|
+
end
|
|
2019
|
+
|
|
2020
|
+
# The data pieces of a scan split at restart markers (piece 0 before
|
|
2021
|
+
# the first marker, piece j + 1 after marks[j]) in restart interval
|
|
2022
|
+
# order, assigned by the markers' numbers (modulo 8), -1 for an empty
|
|
2023
|
+
# interval. A marker without the
|
|
2024
|
+
# expected number is judged by the next one: if that one continues from
|
|
2025
|
+
# the expected number, this marker is corrupt and counts as expected; if
|
|
2026
|
+
# it continues from this marker, intervals were lost (up to five; they
|
|
2027
|
+
# stay empty, i.e. gray) or, for a marker one or two behind, the data is
|
|
2028
|
+
# stale and dropped. Otherwise libjpeg's resync rules apply: one or two
|
|
2029
|
+
# ahead means lost intervals, one or two behind stale data, else resume.
|
|
2030
|
+
def restart_intervals(marks)
|
|
2031
|
+
order = [0]
|
|
2032
|
+
expected = 0
|
|
2033
|
+
n = marks.size
|
|
2034
|
+
j = 0
|
|
2035
|
+
while j < n
|
|
2036
|
+
m = marks[j] & 7
|
|
2037
|
+
ahead = (m - expected) & 7
|
|
2038
|
+
if ahead != 0
|
|
2039
|
+
nxt = j + 1 < n ? marks[j + 1] & 7 : -1
|
|
2040
|
+
if nxt == ((expected + 1) & 7)
|
|
2041
|
+
ahead = 0
|
|
2042
|
+
elsif nxt != ((m + 1) & 7) && ahead >= 3 && ahead <= 5
|
|
2043
|
+
ahead = 0
|
|
2044
|
+
end
|
|
2045
|
+
end
|
|
2046
|
+
if ahead < 6
|
|
2047
|
+
a = 0
|
|
2048
|
+
while a < ahead
|
|
2049
|
+
order << -1 # a lost (empty) interval
|
|
2050
|
+
a += 1
|
|
2051
|
+
end
|
|
2052
|
+
order << j + 1
|
|
2053
|
+
expected += ahead + 1
|
|
2054
|
+
end
|
|
2055
|
+
j += 1
|
|
2056
|
+
end
|
|
2057
|
+
order
|
|
2058
|
+
end
|
|
2059
|
+
|
|
2060
|
+
# ---------------------------------------------------------------
|
|
2061
|
+
# Output
|
|
2062
|
+
|
|
2063
|
+
def finish
|
|
2064
|
+
comps = @components
|
|
2065
|
+
i = 0
|
|
2066
|
+
while i < comps.size
|
|
2067
|
+
c = comps[i]
|
|
2068
|
+
if c.needed
|
|
2069
|
+
if @progressive
|
|
2070
|
+
render_raw(c)
|
|
2071
|
+
else
|
|
2072
|
+
c.finish_plane
|
|
2073
|
+
end
|
|
2074
|
+
end
|
|
2075
|
+
i += 1
|
|
2076
|
+
end
|
|
2077
|
+
output
|
|
2078
|
+
end
|
|
2079
|
+
|
|
2080
|
+
# Luminance from the component planes.
|
|
2081
|
+
def output
|
|
2082
|
+
comps = @components
|
|
2083
|
+
color = @color
|
|
2084
|
+
if color == JPEG_RGB
|
|
2085
|
+
convert_rgb(component_samples(comps[0]), component_samples(comps[1]), component_samples(comps[2]))
|
|
2086
|
+
elsif color == JPEG_CMYK || color == JPEG_YCCK
|
|
2087
|
+
convert_cmyk(component_samples(comps[0]), component_samples(comps[1]), component_samples(comps[2]),
|
|
2088
|
+
component_samples(comps[3]), color == JPEG_YCCK)
|
|
2089
|
+
else
|
|
2090
|
+
component_samples(comps[0])
|
|
2091
|
+
end
|
|
2092
|
+
end
|
|
2093
|
+
|
|
2094
|
+
# IDCTs the raw progressive coefficients of +c+ into its plane, row by
|
|
2095
|
+
# row (freeing them, or moving them to the store with +keep+).
|
|
2096
|
+
def render_raw(c)
|
|
2097
|
+
latch_quant(c)
|
|
2098
|
+
c.start_plane
|
|
2099
|
+
bs = c.bs
|
|
2100
|
+
stride = c.pw / JPEG_SAMPLES_PER_WORD[bs]
|
|
2101
|
+
buf = Array.new(stride * bs, 0)
|
|
2102
|
+
pack = JPEG_PACK[bs]
|
|
2103
|
+
dc_only = c.stride == 1
|
|
2104
|
+
row = dc_only ? JPEG_NONE : Array.new(c.abw * JPEG_BLOCK_STRIDE, 0)
|
|
2105
|
+
by = 0
|
|
2106
|
+
while by < c.abh
|
|
2107
|
+
raw = c.raw[by]
|
|
2108
|
+
if raw.empty?
|
|
2109
|
+
# No data: all coefficients 0.
|
|
2110
|
+
buf.fill(128 * JPEG_SPREAD[bs])
|
|
2111
|
+
elsif dc_only
|
|
2112
|
+
render_dc_row(c, raw, c.qz[0], buf)
|
|
2113
|
+
else
|
|
2114
|
+
raw_to_row(raw, 0, c.abw, c.qz, row)
|
|
2115
|
+
c.idct.render_row(row, c.abw, buf, 0, stride)
|
|
2116
|
+
row.fill(0)
|
|
2117
|
+
end
|
|
2118
|
+
c.store_raw(raw) if @keep
|
|
2119
|
+
c.release_raw(by)
|
|
2120
|
+
c.append_plane(buf.pack(pack))
|
|
2121
|
+
by += 1
|
|
2122
|
+
end
|
|
2123
|
+
nil
|
|
2124
|
+
end
|
|
2125
|
+
|
|
2126
|
+
# Dequantises the +n+ blocks of the raw coefficient row at raw[off, ...]
|
|
2127
|
+
# into the (all zero) coefficient row +row+.
|
|
2128
|
+
def raw_to_row(raw, off, n, qz, row)
|
|
2129
|
+
zz = JPEG_ZIGZAG
|
|
2130
|
+
q0 = qz[0]
|
|
2131
|
+
base = 0
|
|
2132
|
+
p = off
|
|
2133
|
+
x = 0
|
|
2134
|
+
while x < n
|
|
2135
|
+
v = raw.getbyte(p) | (raw.getbyte(p + 1) << 8)
|
|
2136
|
+
row[base] = (v < 32_768 ? v : v - 65_536) * q0
|
|
2137
|
+
km = raw.getbyte(p + JPEG_RAW_KM)
|
|
2138
|
+
km = 63 if km > 63
|
|
2139
|
+
k = 1
|
|
2140
|
+
while k <= km
|
|
2141
|
+
i = zz[k]
|
|
2142
|
+
v = raw.getbyte(p + 2 * i) | (raw.getbyte(p + 2 * i + 1) << 8)
|
|
2143
|
+
row[base + i] = (v < 32_768 ? v : v - 65_536) * qz[k] if v != 0
|
|
2144
|
+
k += 1
|
|
2145
|
+
end
|
|
2146
|
+
row[base + 64] = km
|
|
2147
|
+
base += JPEG_BLOCK_STRIDE
|
|
2148
|
+
p += JPEG_RAW_BLOCK
|
|
2149
|
+
x += 1
|
|
2150
|
+
end
|
|
2151
|
+
nil
|
|
2152
|
+
end
|
|
2153
|
+
|
|
2154
|
+
# DC-only samples (block size 1) of a raw row of DCs of +c+.
|
|
2155
|
+
def render_dc_row(c, raw, q0, buf)
|
|
2156
|
+
idct = c.idct
|
|
2157
|
+
n = c.abw
|
|
2158
|
+
x = 0
|
|
2159
|
+
while x < n
|
|
2160
|
+
v = raw.getbyte(2 * x) | (raw.getbyte(2 * x + 1) << 8)
|
|
2161
|
+
buf[x] = idct.dc_sample((v < 32_768 ? v : v - 65_536) * q0)
|
|
2162
|
+
x += 1
|
|
2163
|
+
end
|
|
2164
|
+
nil
|
|
2165
|
+
end
|
|
2166
|
+
|
|
2167
|
+
# Renders the plane of +c+ from the raw coefficient rows of a store
|
|
2168
|
+
# starting at @data[pos].
|
|
2169
|
+
def render_stored_raw(c, pos)
|
|
2170
|
+
c.start_plane
|
|
2171
|
+
bs = c.bs
|
|
2172
|
+
stride = c.pw / JPEG_SAMPLES_PER_WORD[bs]
|
|
2173
|
+
buf = Array.new(stride * bs, 0)
|
|
2174
|
+
pack = JPEG_PACK[bs]
|
|
2175
|
+
row = Array.new(c.abw * JPEG_BLOCK_STRIDE, 0)
|
|
2176
|
+
by = 0
|
|
2177
|
+
while by < c.abh
|
|
2178
|
+
raw_to_row(@data, pos, c.abw, c.qz, row)
|
|
2179
|
+
c.idct.render_row(row, c.abw, buf, 0, stride)
|
|
2180
|
+
row.fill(0)
|
|
2181
|
+
c.append_plane(buf.pack(pack))
|
|
2182
|
+
pos += c.abw * JPEG_RAW_BLOCK
|
|
2183
|
+
by += 1
|
|
2184
|
+
end
|
|
2185
|
+
nil
|
|
2186
|
+
end
|
|
2187
|
+
|
|
2188
|
+
# The marks (see JpegComponent#marks) marks[start, n] as store bytes.
|
|
2189
|
+
def mark_bytes(marks, start, n)
|
|
2190
|
+
out = String.new(capacity: n * 8, encoding: Encoding::BINARY)
|
|
2191
|
+
i = start
|
|
2192
|
+
stop = start + n
|
|
2193
|
+
while i < stop
|
|
2194
|
+
m = marks[i]
|
|
2195
|
+
if m < 0
|
|
2196
|
+
out << 255 << 255 << 255 << 255 << 0 << 0 << 0 << 0
|
|
2197
|
+
else
|
|
2198
|
+
v = m >> 16
|
|
2199
|
+
out << (v & 255) << ((v >> 8) & 255) << ((v >> 16) & 255) << ((v >> 24) & 255)
|
|
2200
|
+
out << (m & 255) << ((m >> 8) & 255) << 0 << 0
|
|
2201
|
+
end
|
|
2202
|
+
i += 1
|
|
2203
|
+
end
|
|
2204
|
+
out
|
|
2205
|
+
end
|
|
2206
|
+
|
|
2207
|
+
# Renders the plane of +c+ from a sequential store: block marks at
|
|
2208
|
+
# @data[marks], scan data at @data[scan, size], AC Huffman +table+.
|
|
2209
|
+
def render_marked(c, marks, scan, size, table)
|
|
2210
|
+
c.start_plane
|
|
2211
|
+
bs = c.bs
|
|
2212
|
+
stride = c.pw / JPEG_SAMPLES_PER_WORD[bs]
|
|
2213
|
+
buf = Array.new(stride * bs, 0)
|
|
2214
|
+
pack = JPEG_PACK[bs]
|
|
2215
|
+
row = Array.new(c.abw * JPEG_BLOCK_STRIDE, 0)
|
|
2216
|
+
# Blocks start at least one MCU's worth of padding before the end.
|
|
2217
|
+
limit = (size - JPEG_TAIL_PADDING.bytesize) << 3
|
|
2218
|
+
by = 0
|
|
2219
|
+
while by < c.abh
|
|
2220
|
+
if bs == 1
|
|
2221
|
+
marked_dc_row(row, marks + by * c.abw * 8, c.abw, limit, c.qz)
|
|
2222
|
+
else
|
|
2223
|
+
marked_row(row, marks + by * c.abw * 8, c.abw, scan, limit, table, c.qz)
|
|
2224
|
+
end
|
|
2225
|
+
c.idct.render_row(row, c.abw, buf, 0, stride)
|
|
2226
|
+
row.fill(0)
|
|
2227
|
+
c.append_plane(buf.pack(pack))
|
|
2228
|
+
by += 1
|
|
2229
|
+
end
|
|
2230
|
+
nil
|
|
2231
|
+
end
|
|
2232
|
+
|
|
2233
|
+
# The DCs of the +n+ blocks whose marks start at @data[mp] into +row+.
|
|
2234
|
+
def marked_dc_row(row, mp, n, limit, qz)
|
|
2235
|
+
data = @data
|
|
2236
|
+
q0 = qz[0]
|
|
2237
|
+
base = 0
|
|
2238
|
+
x = 0
|
|
2239
|
+
while x < n
|
|
2240
|
+
bitpos = data.getbyte(mp) | (data.getbyte(mp + 1) << 8) | (data.getbyte(mp + 2) << 16) | (data.getbyte(mp + 3) << 24)
|
|
2241
|
+
if bitpos < limit
|
|
2242
|
+
v = data.getbyte(mp + 4) | (data.getbyte(mp + 5) << 8)
|
|
2243
|
+
row[base] = (v < 32_768 ? v : v - 65_536) * q0
|
|
2244
|
+
end
|
|
2245
|
+
base += JPEG_BLOCK_STRIDE
|
|
2246
|
+
mp += 8
|
|
2247
|
+
x += 1
|
|
2248
|
+
end
|
|
2249
|
+
nil
|
|
2250
|
+
end
|
|
2251
|
+
|
|
2252
|
+
# Decodes the +n+ blocks whose marks start at @data[mp] into +row+: DC
|
|
2253
|
+
# from the mark, AC coefficients from the scan data at @data[scan] with
|
|
2254
|
+
# +table+ (like JpegSequential#decode_mcu).
|
|
2255
|
+
def marked_row(row, mp, n, scan, limit, table, qz)
|
|
2256
|
+
data = @data
|
|
2257
|
+
fast = table.fast
|
|
2258
|
+
look = table.look
|
|
2259
|
+
zz = JPEG_ZIGZAG_EXT
|
|
2260
|
+
q0 = qz[0]
|
|
2261
|
+
base = 0
|
|
2262
|
+
x = 0
|
|
2263
|
+
while x < n
|
|
2264
|
+
bitpos = data.getbyte(mp) | (data.getbyte(mp + 1) << 8) | (data.getbyte(mp + 2) << 16) | (data.getbyte(mp + 3) << 24)
|
|
2265
|
+
if bitpos < limit
|
|
2266
|
+
v = data.getbyte(mp + 4) | (data.getbyte(mp + 5) << 8)
|
|
2267
|
+
row[base] = (v < 32_768 ? v : v - 65_536) * q0
|
|
2268
|
+
pos = scan + (bitpos >> 3)
|
|
2269
|
+
acc = (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) | (data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
2270
|
+
pos += 4
|
|
2271
|
+
bits = 32 - (bitpos & 7)
|
|
2272
|
+
k = 1
|
|
2273
|
+
while k < 64
|
|
2274
|
+
if bits < 31
|
|
2275
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
2276
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
2277
|
+
pos += 4
|
|
2278
|
+
bits += 32
|
|
2279
|
+
end
|
|
2280
|
+
e = fast[(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2281
|
+
if e != 0
|
|
2282
|
+
bits -= e & 255
|
|
2283
|
+
k += (e >> 8) & 255
|
|
2284
|
+
row[base + zz[k]] = (e >> 16) * qz[k]
|
|
2285
|
+
k += 1
|
|
2286
|
+
else
|
|
2287
|
+
e = look[(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2288
|
+
e = table.decode_long((acc >> (bits - 16)) & 0xFFFF) if e == 0
|
|
2289
|
+
bits -= e >> 8
|
|
2290
|
+
s = e & 15
|
|
2291
|
+
if s != 0
|
|
2292
|
+
k += (e >> 4) & 15
|
|
2293
|
+
v = (acc >> (bits - s)) & ((1 << s) - 1)
|
|
2294
|
+
bits -= s
|
|
2295
|
+
v -= (1 << s) - 1 if v < (1 << (s - 1))
|
|
2296
|
+
row[base + zz[k]] = v * qz[k]
|
|
2297
|
+
k += 1
|
|
2298
|
+
elsif (e & 0xF0) == 0xF0
|
|
2299
|
+
k += 16
|
|
2300
|
+
else
|
|
2301
|
+
k += JPEG_EOB_RUN + 1
|
|
2302
|
+
end
|
|
2303
|
+
end
|
|
2304
|
+
end
|
|
2305
|
+
row[base + 64] = k > JPEG_EOB_RUN ? k - JPEG_EOB_RUN - 2 : 63
|
|
2306
|
+
end
|
|
2307
|
+
base += JPEG_BLOCK_STRIDE
|
|
2308
|
+
mp += 8
|
|
2309
|
+
x += 1
|
|
2310
|
+
end
|
|
2311
|
+
nil
|
|
2312
|
+
end
|
|
2313
|
+
|
|
2314
|
+
# Samples of component +c+ at output size (cropped, or upsampled when
|
|
2315
|
+
# the component is subsampled relative to the frame).
|
|
2316
|
+
def component_samples(c)
|
|
2317
|
+
ow = @out_w
|
|
2318
|
+
oh = @out_h
|
|
2319
|
+
# Samples per MCU after scaling (libjpeg's input group), which the
|
|
2320
|
+
# upsampler expands to hmax x vmax output pixels.
|
|
2321
|
+
h = c.h * c.bs / @bs
|
|
2322
|
+
v = c.v * c.bs / @bs
|
|
2323
|
+
return crop(c.plane, c.pw, ow, oh) if h == @hmax && v == @vmax
|
|
2324
|
+
|
|
2325
|
+
# Component size at this scale (libjpeg's downsampled size).
|
|
2326
|
+
cw = (@width * c.h * c.bs + @hmax * 8 - 1) / (@hmax * 8)
|
|
2327
|
+
ch = (@height * c.v * c.bs + @vmax * 8 - 1) / (@vmax * 8)
|
|
2328
|
+
# libjpeg's "fancy" upsampling needs DCT_scaled_size > 1.
|
|
2329
|
+
JpegUpsampler.new(c.plane, c.pw, cw, ch, @hmax, @vmax, h, v, @bs > 1).run(ow, oh)
|
|
2330
|
+
end
|
|
2331
|
+
|
|
2332
|
+
def crop(plane, pw, w, h)
|
|
2333
|
+
return plane.byteslice(0, w * h) if pw == w
|
|
2334
|
+
|
|
2335
|
+
out = String.new(capacity: w * h, encoding: Encoding::BINARY)
|
|
2336
|
+
y = 0
|
|
2337
|
+
while y < h
|
|
2338
|
+
out << plane.byteslice(y * pw, w)
|
|
2339
|
+
y += 1
|
|
2340
|
+
end
|
|
2341
|
+
out
|
|
2342
|
+
end
|
|
2343
|
+
|
|
2344
|
+
def convert_rgb(r, g, b)
|
|
2345
|
+
w = @out_w
|
|
2346
|
+
out = String.new(capacity: w * @out_h, encoding: Encoding::BINARY)
|
|
2347
|
+
y = 0
|
|
2348
|
+
while y < @out_h
|
|
2349
|
+
out << rgb_row(r, g, b, y * w, w)
|
|
2350
|
+
y += 1
|
|
2351
|
+
end
|
|
2352
|
+
out
|
|
2353
|
+
end
|
|
2354
|
+
|
|
2355
|
+
def rgb_row(r, g, b, i, n)
|
|
2356
|
+
row = String.new(capacity: n, encoding: Encoding::BINARY)
|
|
2357
|
+
stop = i + n
|
|
2358
|
+
while i < stop
|
|
2359
|
+
row << ((306 * r.getbyte(i) + 601 * g.getbyte(i) + 117 * b.getbyte(i) + 0x200) >> 10)
|
|
2360
|
+
i += 1
|
|
2361
|
+
end
|
|
2362
|
+
row
|
|
2363
|
+
end
|
|
2364
|
+
|
|
2365
|
+
def convert_cmyk(c, m, y, k, ycck)
|
|
2366
|
+
w = @out_w
|
|
2367
|
+
out = String.new(capacity: w * @out_h, encoding: Encoding::BINARY)
|
|
2368
|
+
row = 0
|
|
2369
|
+
while row < @out_h
|
|
2370
|
+
out << (ycck ? ycck_row(c, m, y, k, row * w, w) : cmyk_row(c, m, y, k, row * w, w))
|
|
2371
|
+
row += 1
|
|
2372
|
+
end
|
|
2373
|
+
out
|
|
2374
|
+
end
|
|
2375
|
+
|
|
2376
|
+
# Adobe CMYK JPEGs store inverted ink (255 = no ink), so the stored
|
|
2377
|
+
# values are 255 - ink: R = C' * K' / 255 (rounded) and so on.
|
|
2378
|
+
def cmyk_row(c, m, y, k, i, n)
|
|
2379
|
+
row = String.new(capacity: n, encoding: Encoding::BINARY)
|
|
2380
|
+
stop = i + n
|
|
2381
|
+
while i < stop
|
|
2382
|
+
kk = k.getbyte(i)
|
|
2383
|
+
r = (c.getbyte(i) * kk + 127) / 255
|
|
2384
|
+
g = (m.getbyte(i) * kk + 127) / 255
|
|
2385
|
+
b = (y.getbyte(i) * kk + 127) / 255
|
|
2386
|
+
row << ((306 * r + 601 * g + 117 * b + 0x200) >> 10)
|
|
2387
|
+
i += 1
|
|
2388
|
+
end
|
|
2389
|
+
row
|
|
2390
|
+
end
|
|
2391
|
+
|
|
2392
|
+
# YCCK stores YCbCr-encoded CMY plus K; libjpeg converts it to CMYK with
|
|
2393
|
+
# its fixed-point YCbCr->RGB tables (C = 255 - R, ...), which then goes
|
|
2394
|
+
# through #cmyk_row's formula.
|
|
2395
|
+
def ycck_row(y, cb, cr, k, i, n)
|
|
2396
|
+
row = String.new(capacity: n, encoding: Encoding::BINARY)
|
|
2397
|
+
cr_r = JPEG_CR_R
|
|
2398
|
+
cb_b = JPEG_CB_B
|
|
2399
|
+
cr_g = JPEG_CR_G
|
|
2400
|
+
cb_g = JPEG_CB_G
|
|
2401
|
+
stop = i + n
|
|
2402
|
+
while i < stop
|
|
2403
|
+
yy = 255 - y.getbyte(i)
|
|
2404
|
+
u = cb.getbyte(i)
|
|
2405
|
+
v = cr.getbyte(i)
|
|
2406
|
+
kk = k.getbyte(i)
|
|
2407
|
+
c = yy - cr_r[v]
|
|
2408
|
+
m = yy - ((cb_g[u] + cr_g[v]) >> 16)
|
|
2409
|
+
ye = yy - cb_b[u]
|
|
2410
|
+
c = c < 0 ? 0 : (c > 255 ? 255 : c)
|
|
2411
|
+
m = m < 0 ? 0 : (m > 255 ? 255 : m)
|
|
2412
|
+
ye = ye < 0 ? 0 : (ye > 255 ? 255 : ye)
|
|
2413
|
+
r = (c * kk + 127) / 255
|
|
2414
|
+
g = (m * kk + 127) / 255
|
|
2415
|
+
b = (ye * kk + 127) / 255
|
|
2416
|
+
row << ((306 * r + 601 * g + 117 * b + 0x200) >> 10)
|
|
2417
|
+
i += 1
|
|
2418
|
+
end
|
|
2419
|
+
row
|
|
2420
|
+
end
|
|
2421
|
+
end
|
|
2422
|
+
|
|
2423
|
+
|
|
2424
|
+
# Decodes one sequential (baseline or extended) scan into the component
|
|
2425
|
+
# planes. The needed blocks of an MCU row are decoded into coefficient
|
|
2426
|
+
# rows, which are IDCT'd into the planes (and kept in the coefficient
|
|
2427
|
+
# store) when the row is complete; blocks of components that do not
|
|
2428
|
+
# contribute to the luminance are entropy-decoded and dropped.
|
|
2429
|
+
class JpegSequential
|
|
2430
|
+
# Per block: skip it, decode only its DC, or its DC and AC coefficients.
|
|
2431
|
+
SKIP = 0
|
|
2432
|
+
DC_ONLY = 1
|
|
2433
|
+
FULL = 2
|
|
2434
|
+
|
|
2435
|
+
def initialize(decoder, comps, dcs, acs, data, starts, ends)
|
|
2436
|
+
@ri = decoder.restart_interval
|
|
2437
|
+
@keep = decoder.keep
|
|
2438
|
+
@data = data
|
|
2439
|
+
@starts = starts
|
|
2440
|
+
@ends = ends
|
|
2441
|
+
@acc = 0
|
|
2442
|
+
@bits = 0
|
|
2443
|
+
@pos = 0
|
|
2444
|
+
@endbit = 0
|
|
2445
|
+
interleaved = comps.size > 1
|
|
2446
|
+
if interleaved
|
|
2447
|
+
@mcux = decoder.mcux
|
|
2448
|
+
@mcuy = decoder.mcuy
|
|
2449
|
+
else
|
|
2450
|
+
@mcux = comps[0].bw
|
|
2451
|
+
@mcuy = comps[0].bh
|
|
2452
|
+
end
|
|
2453
|
+
@preds = Array.new(comps.size, 0)
|
|
2454
|
+
# Per block of the MCU.
|
|
2455
|
+
# (Object lists start from a literal and grow by index, which lets
|
|
2456
|
+
# Spinel compile them as typed object arrays.)
|
|
2457
|
+
@pred_idx = []
|
|
2458
|
+
@dc_fast = []
|
|
2459
|
+
@dc_look = []
|
|
2460
|
+
@dc_table = [JPEG_EMPTY_HUFFMAN]
|
|
2461
|
+
@ac_fast = []
|
|
2462
|
+
@ac_look = []
|
|
2463
|
+
@ac_table = [JPEG_EMPTY_HUFFMAN]
|
|
2464
|
+
@mode = []
|
|
2465
|
+
@q = []
|
|
2466
|
+
@coef = [] # its coefficient row
|
|
2467
|
+
@col = [] # its block column in the MCU
|
|
2468
|
+
@cols = [] # block columns per MCU of its component
|
|
2469
|
+
# With a store: its component's marks (JpegComponent#marks), its block
|
|
2470
|
+
# row in the MCU, block rows per MCU and blocks per block row.
|
|
2471
|
+
@marks = []
|
|
2472
|
+
@row = []
|
|
2473
|
+
@rowstep = []
|
|
2474
|
+
@width = []
|
|
2475
|
+
# Per needed component: its coefficient rows (one per block row of an
|
|
2476
|
+
# MCU row, in @rows from @first), sample buffer and words per row.
|
|
2477
|
+
@ncomp = 0
|
|
2478
|
+
@comp = [comps[0]]
|
|
2479
|
+
@rows = []
|
|
2480
|
+
@first = []
|
|
2481
|
+
@nrows = []
|
|
2482
|
+
@buf = []
|
|
2483
|
+
@stride = []
|
|
2484
|
+
setup_blocks(decoder, comps, dcs, acs, interleaved)
|
|
2485
|
+
@nb = @pred_idx.size
|
|
2486
|
+
# Per block of the last MCU: bit position of its AC data, and its DC.
|
|
2487
|
+
@ac_start = Array.new(@nb, 0)
|
|
2488
|
+
@dc = Array.new(@nb, 0)
|
|
2489
|
+
end
|
|
2490
|
+
|
|
2491
|
+
def run
|
|
2492
|
+
total = @mcux * @mcuy
|
|
2493
|
+
ri = @ri
|
|
2494
|
+
mcu = 0
|
|
2495
|
+
interval = 0
|
|
2496
|
+
mx = 0
|
|
2497
|
+
my = 0
|
|
2498
|
+
while mcu < total
|
|
2499
|
+
if interval >= @starts.size
|
|
2500
|
+
flush if mx > 0 # no data left: the rest stays gray
|
|
2501
|
+
return nil
|
|
2502
|
+
end
|
|
2503
|
+
n = total - mcu
|
|
2504
|
+
n = ri if ri > 0 && ri < n
|
|
2505
|
+
start_interval(interval)
|
|
2506
|
+
interval += 1
|
|
2507
|
+
dead = false
|
|
2508
|
+
while n > 0
|
|
2509
|
+
n -= 1
|
|
2510
|
+
mcu += 1
|
|
2511
|
+
if !dead && !decode_mcu(mx, my)
|
|
2512
|
+
# Ran past the end of the data: drop this MCU and the rest of
|
|
2513
|
+
# the interval (or of the image); they stay gray.
|
|
2514
|
+
dead = true
|
|
2515
|
+
if ri == 0 || interval >= @starts.size
|
|
2516
|
+
flush
|
|
2517
|
+
return nil
|
|
2518
|
+
end
|
|
2519
|
+
end
|
|
2520
|
+
mx += 1
|
|
2521
|
+
next unless mx == @mcux
|
|
2522
|
+
|
|
2523
|
+
flush
|
|
2524
|
+
mx = 0
|
|
2525
|
+
my += 1
|
|
2526
|
+
end
|
|
2527
|
+
end
|
|
2528
|
+
nil
|
|
2529
|
+
end
|
|
2530
|
+
|
|
2531
|
+
private
|
|
2532
|
+
|
|
2533
|
+
def setup_blocks(decoder, comps, dcs, acs, interleaved)
|
|
2534
|
+
si = 0
|
|
2535
|
+
while si < comps.size
|
|
2536
|
+
c = comps[si]
|
|
2537
|
+
dc = decoder.huffman_table(false, dcs[si])
|
|
2538
|
+
ac = decoder.huffman_table(true, acs[si])
|
|
2539
|
+
hn = interleaved ? c.h : 1
|
|
2540
|
+
vn = interleaved ? c.v : 1
|
|
2541
|
+
first = @rows.size
|
|
2542
|
+
if c.needed
|
|
2543
|
+
decoder.latch_quant(c)
|
|
2544
|
+
stride = c.pw / JPEG_SAMPLES_PER_WORD[c.bs]
|
|
2545
|
+
@comp[@ncomp] = c
|
|
2546
|
+
@ncomp += 1
|
|
2547
|
+
@first << first
|
|
2548
|
+
@nrows << vn
|
|
2549
|
+
@buf << Array.new(stride * vn * c.bs, 0)
|
|
2550
|
+
@stride << stride
|
|
2551
|
+
r = 0
|
|
2552
|
+
while r < vn
|
|
2553
|
+
@rows << Array.new(c.abw * JPEG_BLOCK_STRIDE, 0)
|
|
2554
|
+
r += 1
|
|
2555
|
+
end
|
|
2556
|
+
end
|
|
2557
|
+
by = 0
|
|
2558
|
+
while by < vn
|
|
2559
|
+
bx = 0
|
|
2560
|
+
while bx < hn
|
|
2561
|
+
@dc_table[@pred_idx.size] = dc
|
|
2562
|
+
@ac_table[@pred_idx.size] = ac
|
|
2563
|
+
@pred_idx << si
|
|
2564
|
+
@dc_fast << dc.fast
|
|
2565
|
+
@dc_look << dc.look
|
|
2566
|
+
@ac_fast << ac.fast
|
|
2567
|
+
@ac_look << ac.look
|
|
2568
|
+
if c.needed
|
|
2569
|
+
@mode << (c.bs > 1 ? FULL : DC_ONLY)
|
|
2570
|
+
@q << c.qz
|
|
2571
|
+
@coef << @rows[first + by]
|
|
2572
|
+
@col << bx
|
|
2573
|
+
@cols << hn
|
|
2574
|
+
@marks << c.marks
|
|
2575
|
+
else
|
|
2576
|
+
@mode << SKIP
|
|
2577
|
+
@q << JPEG_NONE
|
|
2578
|
+
@coef << JPEG_NONE
|
|
2579
|
+
@col << 0
|
|
2580
|
+
@cols << 0
|
|
2581
|
+
@marks << JPEG_NONE
|
|
2582
|
+
end
|
|
2583
|
+
@row << by
|
|
2584
|
+
@rowstep << vn
|
|
2585
|
+
@width << c.abw
|
|
2586
|
+
bx += 1
|
|
2587
|
+
end
|
|
2588
|
+
by += 1
|
|
2589
|
+
end
|
|
2590
|
+
si += 1
|
|
2591
|
+
end
|
|
2592
|
+
nil
|
|
2593
|
+
end
|
|
2594
|
+
|
|
2595
|
+
def start_interval(index)
|
|
2596
|
+
@pos = @starts[index]
|
|
2597
|
+
@endbit = @ends[index]
|
|
2598
|
+
@acc = 0
|
|
2599
|
+
@bits = 0
|
|
2600
|
+
@preds.fill(0)
|
|
2601
|
+
nil
|
|
2602
|
+
end
|
|
2603
|
+
|
|
2604
|
+
# Decodes the MCU at column +mx+ of MCU row +my+ into the coefficient
|
|
2605
|
+
# rows (and marks its blocks for the store). Returns false (leaving its
|
|
2606
|
+
# blocks zero) if the MCU ran past the end of the interval's data.
|
|
2607
|
+
def decode_mcu(mx, my)
|
|
2608
|
+
data = @data
|
|
2609
|
+
starts = @ac_start
|
|
2610
|
+
dcs = @dc
|
|
2611
|
+
acc = @acc
|
|
2612
|
+
bits = @bits
|
|
2613
|
+
pos = @pos
|
|
2614
|
+
preds = @preds
|
|
2615
|
+
zz = JPEG_ZIGZAG_EXT
|
|
2616
|
+
nb = @nb
|
|
2617
|
+
b = 0
|
|
2618
|
+
while b < nb
|
|
2619
|
+
# DC coefficient (bits >= 31 after a refill covers any code + extra bits)
|
|
2620
|
+
if bits < 31
|
|
2621
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
2622
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
2623
|
+
pos += 4
|
|
2624
|
+
bits += 32
|
|
2625
|
+
end
|
|
2626
|
+
e = @dc_fast[b][(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2627
|
+
diff = 0
|
|
2628
|
+
if e != 0
|
|
2629
|
+
bits -= e & 255
|
|
2630
|
+
diff = e >> 16
|
|
2631
|
+
else
|
|
2632
|
+
e = @dc_look[b][(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2633
|
+
e = @dc_table[b].decode_long((acc >> (bits - 16)) & 0xFFFF) if e == 0
|
|
2634
|
+
bits -= e >> 8
|
|
2635
|
+
s = e & 255
|
|
2636
|
+
if s != 0
|
|
2637
|
+
diff = (acc >> (bits - s)) & ((1 << s) - 1)
|
|
2638
|
+
bits -= s
|
|
2639
|
+
diff -= (1 << s) - 1 if diff < (1 << (s - 1))
|
|
2640
|
+
end
|
|
2641
|
+
end
|
|
2642
|
+
ci = @pred_idx[b]
|
|
2643
|
+
pred = ((preds[ci] + diff + 32_768) & 0xFFFF) - 32_768 # JCOEF wraps to 16 bits
|
|
2644
|
+
preds[ci] = pred
|
|
2645
|
+
|
|
2646
|
+
# AC coefficients
|
|
2647
|
+
fast = @ac_fast[b]
|
|
2648
|
+
mode = @mode[b]
|
|
2649
|
+
starts[b] = pos * 8 - bits
|
|
2650
|
+
dcs[b] = pred
|
|
2651
|
+
k = 1
|
|
2652
|
+
if mode == FULL
|
|
2653
|
+
q = @q[b]
|
|
2654
|
+
coef = @coef[b]
|
|
2655
|
+
base = (mx * @cols[b] + @col[b]) * JPEG_BLOCK_STRIDE
|
|
2656
|
+
coef[base] = pred * q[0]
|
|
2657
|
+
while k < 64
|
|
2658
|
+
if bits < 31
|
|
2659
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
2660
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
2661
|
+
pos += 4
|
|
2662
|
+
bits += 32
|
|
2663
|
+
end
|
|
2664
|
+
e = fast[(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2665
|
+
if e != 0
|
|
2666
|
+
# (end of block writes 0 to slot 64, which is set below)
|
|
2667
|
+
bits -= e & 255
|
|
2668
|
+
k += (e >> 8) & 255
|
|
2669
|
+
coef[base + zz[k]] = (e >> 16) * q[k]
|
|
2670
|
+
k += 1
|
|
2671
|
+
else
|
|
2672
|
+
e = @ac_look[b][(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2673
|
+
e = @ac_table[b].decode_long((acc >> (bits - 16)) & 0xFFFF) if e == 0
|
|
2674
|
+
bits -= e >> 8
|
|
2675
|
+
s = e & 15
|
|
2676
|
+
if s != 0
|
|
2677
|
+
k += (e >> 4) & 15
|
|
2678
|
+
v = (acc >> (bits - s)) & ((1 << s) - 1)
|
|
2679
|
+
bits -= s
|
|
2680
|
+
v -= (1 << s) - 1 if v < (1 << (s - 1))
|
|
2681
|
+
coef[base + zz[k]] = v * q[k]
|
|
2682
|
+
k += 1
|
|
2683
|
+
elsif (e & 0xF0) == 0xF0
|
|
2684
|
+
k += 16
|
|
2685
|
+
else
|
|
2686
|
+
k += JPEG_EOB_RUN + 1
|
|
2687
|
+
end
|
|
2688
|
+
end
|
|
2689
|
+
end
|
|
2690
|
+
coef[base + 64] = k > JPEG_EOB_RUN ? k - JPEG_EOB_RUN - 2 : 63
|
|
2691
|
+
else
|
|
2692
|
+
if mode == DC_ONLY
|
|
2693
|
+
@coef[b][(mx * @cols[b] + @col[b]) * JPEG_BLOCK_STRIDE] = pred * @q[b][0]
|
|
2694
|
+
end
|
|
2695
|
+
# Skip the AC coefficients.
|
|
2696
|
+
while k < 64
|
|
2697
|
+
if bits < 31
|
|
2698
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
2699
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
2700
|
+
pos += 4
|
|
2701
|
+
bits += 32
|
|
2702
|
+
end
|
|
2703
|
+
e = fast[(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2704
|
+
if e != 0
|
|
2705
|
+
bits -= e & 255
|
|
2706
|
+
k += ((e >> 8) & 255) + 1
|
|
2707
|
+
else
|
|
2708
|
+
e = @ac_look[b][(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2709
|
+
e = @ac_table[b].decode_long((acc >> (bits - 16)) & 0xFFFF) if e == 0
|
|
2710
|
+
bits -= (e >> 8) + (e & 15)
|
|
2711
|
+
if (e & 15) != 0
|
|
2712
|
+
k += ((e >> 4) & 15) + 1
|
|
2713
|
+
elsif (e & 0xF0) == 0xF0
|
|
2714
|
+
k += 16
|
|
2715
|
+
else
|
|
2716
|
+
k = 64
|
|
2717
|
+
end
|
|
2718
|
+
end
|
|
2719
|
+
end
|
|
2720
|
+
end
|
|
2721
|
+
b += 1
|
|
2722
|
+
end
|
|
2723
|
+
|
|
2724
|
+
if pos * 8 - bits > @endbit
|
|
2725
|
+
clear_mcu(mx)
|
|
2726
|
+
return false
|
|
2727
|
+
end
|
|
2728
|
+
|
|
2729
|
+
@acc = acc
|
|
2730
|
+
@bits = bits
|
|
2731
|
+
@pos = pos
|
|
2732
|
+
mark_mcu(mx, my) if @keep
|
|
2733
|
+
true
|
|
2734
|
+
end
|
|
2735
|
+
|
|
2736
|
+
# Marks the blocks of the MCU at column +mx+ of MCU row +my+ for the
|
|
2737
|
+
# store: where their AC coefficients start, and their DCs.
|
|
2738
|
+
def mark_mcu(mx, my)
|
|
2739
|
+
b = 0
|
|
2740
|
+
while b < @nb
|
|
2741
|
+
if @mode[b] != SKIP
|
|
2742
|
+
@marks[b][(my * @rowstep[b] + @row[b]) * @width[b] + mx * @cols[b] + @col[b]] =
|
|
2743
|
+
(@ac_start[b] << 16) | (@dc[b] & 0xFFFF)
|
|
2744
|
+
end
|
|
2745
|
+
b += 1
|
|
2746
|
+
end
|
|
2747
|
+
nil
|
|
2748
|
+
end
|
|
2749
|
+
|
|
2750
|
+
# Zeroes the blocks of the MCU at column +mx+ (mid-gray).
|
|
2751
|
+
def clear_mcu(mx)
|
|
2752
|
+
b = 0
|
|
2753
|
+
while b < @nb
|
|
2754
|
+
if @mode[b] != SKIP
|
|
2755
|
+
@coef[b].fill(0, (mx * @cols[b] + @col[b]) * JPEG_BLOCK_STRIDE, JPEG_BLOCK_STRIDE)
|
|
2756
|
+
end
|
|
2757
|
+
b += 1
|
|
2758
|
+
end
|
|
2759
|
+
nil
|
|
2760
|
+
end
|
|
2761
|
+
|
|
2762
|
+
# IDCTs the coefficient rows of the MCU row into the planes and clears
|
|
2763
|
+
# them.
|
|
2764
|
+
def flush
|
|
2765
|
+
i = 0
|
|
2766
|
+
while i < @ncomp
|
|
2767
|
+
c = @comp[i]
|
|
2768
|
+
buf = @buf[i]
|
|
2769
|
+
stride = @stride[i]
|
|
2770
|
+
idct = c.idct
|
|
2771
|
+
first = @first[i]
|
|
2772
|
+
r = 0
|
|
2773
|
+
while r < @nrows[i]
|
|
2774
|
+
row = @rows[first + r]
|
|
2775
|
+
idct.render_row(row, c.abw, buf, r * c.bs * stride, stride)
|
|
2776
|
+
row.fill(0)
|
|
2777
|
+
r += 1
|
|
2778
|
+
end
|
|
2779
|
+
c.append_plane(buf.pack(JPEG_PACK[c.bs]))
|
|
2780
|
+
i += 1
|
|
2781
|
+
end
|
|
2782
|
+
nil
|
|
2783
|
+
end
|
|
2784
|
+
end
|
|
2785
|
+
|
|
2786
|
+
# Decodes one progressive scan into the raw coefficient rows of its
|
|
2787
|
+
# components (packed signed 16-bit Strings, JpegComponent#raw_row): DC
|
|
2788
|
+
# first or refinement (possibly interleaved), or AC first or refinement
|
|
2789
|
+
# of one spectral band of one component. Coefficients wrap to 16 bits
|
|
2790
|
+
# like libjpeg's JCOEF.
|
|
2791
|
+
class JpegProgressive
|
|
2792
|
+
DC_FIRST = 0
|
|
2793
|
+
DC_REFINE = 1
|
|
2794
|
+
AC_FIRST = 2
|
|
2795
|
+
AC_REFINE = 3
|
|
2796
|
+
# Bytes per block of a raw coefficient row, and the offset of the last
|
|
2797
|
+
# nonzero zigzag index in a block.
|
|
2798
|
+
BLOCK_BYTES = JPEG_BLOCK_STRIDE * 2
|
|
2799
|
+
KM = 128
|
|
2800
|
+
|
|
2801
|
+
def initialize(decoder, comps, dcs, ss, se, ah, al, ac, data, starts, ends)
|
|
2802
|
+
@ri = decoder.restart_interval
|
|
2803
|
+
@data = data
|
|
2804
|
+
@starts = starts
|
|
2805
|
+
@ends = ends
|
|
2806
|
+
@ss = ss
|
|
2807
|
+
@se = se
|
|
2808
|
+
@al = al
|
|
2809
|
+
@acc = 0
|
|
2810
|
+
@bits = 0
|
|
2811
|
+
@pos = 0
|
|
2812
|
+
@endbit = 0
|
|
2813
|
+
@eobrun = 0
|
|
2814
|
+
@preds = Array.new(comps.size, 0)
|
|
2815
|
+
@newnz = Array.new(64, 0)
|
|
2816
|
+
@kind = ss == 0 ? (ah == 0 ? DC_FIRST : DC_REFINE) : (ah == 0 ? AC_FIRST : AC_REFINE)
|
|
2817
|
+
if comps.size == 1
|
|
2818
|
+
@units_x = comps[0].bw
|
|
2819
|
+
@units_y = comps[0].bh
|
|
2820
|
+
else
|
|
2821
|
+
@units_x = decoder.mcux
|
|
2822
|
+
@units_y = decoder.mcuy
|
|
2823
|
+
end
|
|
2824
|
+
# AC scans: the component and its Huffman table.
|
|
2825
|
+
@comp = comps[0]
|
|
2826
|
+
@table = JPEG_EMPTY_HUFFMAN
|
|
2827
|
+
@table = decoder.huffman_table(true, ac) if ss != 0
|
|
2828
|
+
# DC scans, per block of the MCU: component, whether needed, block
|
|
2829
|
+
# row in the MCU row, block column at MCU column 0 and per MCU
|
|
2830
|
+
# column (in coefficients), block rows per MCU row, predictor, table.
|
|
2831
|
+
@b_comp = [comps[0]]
|
|
2832
|
+
@b_need = []
|
|
2833
|
+
@b_row = []
|
|
2834
|
+
@b_col = []
|
|
2835
|
+
@b_colstep = []
|
|
2836
|
+
@b_rowstep = []
|
|
2837
|
+
@b_pred = []
|
|
2838
|
+
@b_fast = []
|
|
2839
|
+
@b_look = []
|
|
2840
|
+
@b_table = [JPEG_EMPTY_HUFFMAN]
|
|
2841
|
+
@nb = 0
|
|
2842
|
+
if ss == 0
|
|
2843
|
+
setup_dc(decoder, comps, dcs)
|
|
2844
|
+
else
|
|
2845
|
+
decoder.latch_quant(@comp)
|
|
2846
|
+
end
|
|
2847
|
+
end
|
|
2848
|
+
|
|
2849
|
+
def run
|
|
2850
|
+
ux = @units_x
|
|
2851
|
+
total = ux * @units_y
|
|
2852
|
+
ri = @ri
|
|
2853
|
+
u = 0
|
|
2854
|
+
interval = 0
|
|
2855
|
+
while u < total && interval < @starts.size
|
|
2856
|
+
n = total - u
|
|
2857
|
+
n = ri if ri > 0 && ri < n
|
|
2858
|
+
@pos = @starts[interval]
|
|
2859
|
+
@endbit = @ends[interval]
|
|
2860
|
+
@acc = 0
|
|
2861
|
+
@bits = 0
|
|
2862
|
+
@eobrun = 0
|
|
2863
|
+
@preds.fill(0)
|
|
2864
|
+
interval += 1
|
|
2865
|
+
stop = u + n
|
|
2866
|
+
while u < stop
|
|
2867
|
+
y = u / ux
|
|
2868
|
+
x0 = u - y * ux
|
|
2869
|
+
x1 = x0 + stop - u
|
|
2870
|
+
x1 = ux if x1 > ux
|
|
2871
|
+
kind = @kind
|
|
2872
|
+
ok = if kind <= DC_REFINE then dc_row(y, x0, x1)
|
|
2873
|
+
elsif kind == AC_FIRST then ac_first_row(y, x0, x1)
|
|
2874
|
+
else ac_refine_row(y, x0, x1)
|
|
2875
|
+
end
|
|
2876
|
+
# On running out of data, skip the rest of the interval.
|
|
2877
|
+
u = ok ? u + x1 - x0 : stop
|
|
2878
|
+
end
|
|
2879
|
+
end
|
|
2880
|
+
nil
|
|
2881
|
+
end
|
|
2882
|
+
|
|
2883
|
+
private
|
|
2884
|
+
|
|
2885
|
+
def setup_dc(decoder, comps, dcs)
|
|
2886
|
+
interleaved = comps.size > 1
|
|
2887
|
+
si = 0
|
|
2888
|
+
while si < comps.size
|
|
2889
|
+
c = comps[si]
|
|
2890
|
+
decoder.latch_quant(c) if c.needed
|
|
2891
|
+
t = decoder.huffman_table(false, dcs[si]) if @kind == DC_FIRST
|
|
2892
|
+
hn = interleaved ? c.h : 1
|
|
2893
|
+
vn = interleaved ? c.v : 1
|
|
2894
|
+
stride = c.stride
|
|
2895
|
+
by = 0
|
|
2896
|
+
while by < vn
|
|
2897
|
+
bx = 0
|
|
2898
|
+
while bx < hn
|
|
2899
|
+
@b_comp[@b_need.size] = c
|
|
2900
|
+
@b_table[@b_need.size] = t if t
|
|
2901
|
+
@b_need << (c.needed ? 1 : 0)
|
|
2902
|
+
@b_row << by
|
|
2903
|
+
@b_col << bx * stride
|
|
2904
|
+
@b_colstep << hn * stride
|
|
2905
|
+
@b_rowstep << vn
|
|
2906
|
+
@b_pred << si
|
|
2907
|
+
if t
|
|
2908
|
+
@b_fast << t.fast
|
|
2909
|
+
@b_look << t.look
|
|
2910
|
+
end
|
|
2911
|
+
bx += 1
|
|
2912
|
+
end
|
|
2913
|
+
by += 1
|
|
2914
|
+
end
|
|
2915
|
+
si += 1
|
|
2916
|
+
end
|
|
2917
|
+
@nb = @b_need.size
|
|
2918
|
+
nil
|
|
2919
|
+
end
|
|
2920
|
+
|
|
2921
|
+
# DC first / refinement scan, MCUs mx0...mx1 of MCU row my.
|
|
2922
|
+
def dc_row(my, mx0, mx1)
|
|
2923
|
+
data = @data
|
|
2924
|
+
acc = @acc
|
|
2925
|
+
bits = @bits
|
|
2926
|
+
pos = @pos
|
|
2927
|
+
preds = @preds
|
|
2928
|
+
refine = @kind == DC_REFINE
|
|
2929
|
+
al = @al
|
|
2930
|
+
bit = 1 << al
|
|
2931
|
+
nb = @nb
|
|
2932
|
+
mx = mx0
|
|
2933
|
+
while mx < mx1
|
|
2934
|
+
b = 0
|
|
2935
|
+
while b < nb
|
|
2936
|
+
if bits < 31
|
|
2937
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
2938
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
2939
|
+
pos += 4
|
|
2940
|
+
bits += 32
|
|
2941
|
+
end
|
|
2942
|
+
need = @b_need[b] == 1
|
|
2943
|
+
coefs = ""
|
|
2944
|
+
p = 0
|
|
2945
|
+
if need
|
|
2946
|
+
coefs = @b_comp[b].raw_row(@b_row[b] + my * @b_rowstep[b])
|
|
2947
|
+
p = (@b_col[b] + mx * @b_colstep[b]) * 2
|
|
2948
|
+
end
|
|
2949
|
+
if refine
|
|
2950
|
+
bits -= 1
|
|
2951
|
+
if need && ((acc >> bits) & 1) == 1
|
|
2952
|
+
u = coefs.getbyte(p) | (coefs.getbyte(p + 1) << 8) | bit
|
|
2953
|
+
coefs.setbyte(p, u & 255)
|
|
2954
|
+
coefs.setbyte(p + 1, (u >> 8) & 255)
|
|
2955
|
+
end
|
|
2956
|
+
else
|
|
2957
|
+
e = @b_fast[b][(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2958
|
+
diff = 0
|
|
2959
|
+
if e != 0
|
|
2960
|
+
bits -= e & 255
|
|
2961
|
+
diff = e >> 16
|
|
2962
|
+
else
|
|
2963
|
+
e = @b_look[b][(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
2964
|
+
e = @b_table[b].decode_long((acc >> (bits - 16)) & 0xFFFF) if e == 0
|
|
2965
|
+
bits -= e >> 8
|
|
2966
|
+
s = e & 255
|
|
2967
|
+
if s != 0
|
|
2968
|
+
diff = (acc >> (bits - s)) & ((1 << s) - 1)
|
|
2969
|
+
bits -= s
|
|
2970
|
+
diff -= (1 << s) - 1 if diff < (1 << (s - 1))
|
|
2971
|
+
end
|
|
2972
|
+
end
|
|
2973
|
+
ci = @b_pred[b]
|
|
2974
|
+
pred = ((preds[ci] + diff + 32_768) & 0xFFFF) - 32_768
|
|
2975
|
+
preds[ci] = pred
|
|
2976
|
+
if need
|
|
2977
|
+
u = (pred << al) & 0xFFFF
|
|
2978
|
+
coefs.setbyte(p, u & 255)
|
|
2979
|
+
coefs.setbyte(p + 1, u >> 8)
|
|
2980
|
+
end
|
|
2981
|
+
end
|
|
2982
|
+
b += 1
|
|
2983
|
+
end
|
|
2984
|
+
if pos * 8 - bits > @endbit
|
|
2985
|
+
# Out of data: undo this MCU of a first scan.
|
|
2986
|
+
undo_dc(my, mx) unless refine
|
|
2987
|
+
return false
|
|
2988
|
+
end
|
|
2989
|
+
mx += 1
|
|
2990
|
+
end
|
|
2991
|
+
@acc = acc
|
|
2992
|
+
@bits = bits
|
|
2993
|
+
@pos = pos
|
|
2994
|
+
true
|
|
2995
|
+
end
|
|
2996
|
+
|
|
2997
|
+
def undo_dc(my, mx)
|
|
2998
|
+
b = 0
|
|
2999
|
+
while b < @nb
|
|
3000
|
+
if @b_need[b] == 1
|
|
3001
|
+
coefs = @b_comp[b].raw_row(@b_row[b] + my * @b_rowstep[b])
|
|
3002
|
+
p = (@b_col[b] + mx * @b_colstep[b]) * 2
|
|
3003
|
+
coefs.setbyte(p, 0)
|
|
3004
|
+
coefs.setbyte(p + 1, 0)
|
|
3005
|
+
end
|
|
3006
|
+
b += 1
|
|
3007
|
+
end
|
|
3008
|
+
nil
|
|
3009
|
+
end
|
|
3010
|
+
|
|
3011
|
+
# First scan of AC band ss..se, blocks bx0...bx1 of block row by.
|
|
3012
|
+
def ac_first_row(by, bx0, bx1)
|
|
3013
|
+
data = @data
|
|
3014
|
+
acc = @acc
|
|
3015
|
+
bits = @bits
|
|
3016
|
+
pos = @pos
|
|
3017
|
+
eobrun = @eobrun
|
|
3018
|
+
table = @table
|
|
3019
|
+
fast = table.fast
|
|
3020
|
+
look = table.look
|
|
3021
|
+
coefs = @comp.raw_row(by)
|
|
3022
|
+
ss = @ss
|
|
3023
|
+
se = @se
|
|
3024
|
+
al = @al
|
|
3025
|
+
zz = JPEG_ZIGZAG_EXT
|
|
3026
|
+
bx = bx0
|
|
3027
|
+
while bx < bx1
|
|
3028
|
+
if eobrun > 0
|
|
3029
|
+
# Blocks inside an end-of-band run have nothing in this band.
|
|
3030
|
+
skip = bx1 - bx
|
|
3031
|
+
skip = eobrun if eobrun < skip
|
|
3032
|
+
eobrun -= skip
|
|
3033
|
+
bx += skip
|
|
3034
|
+
next
|
|
3035
|
+
end
|
|
3036
|
+
base = bx * BLOCK_BYTES
|
|
3037
|
+
k = ss
|
|
3038
|
+
last = 0
|
|
3039
|
+
while k <= se
|
|
3040
|
+
if bits < 31
|
|
3041
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
3042
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
3043
|
+
pos += 4
|
|
3044
|
+
bits += 32
|
|
3045
|
+
end
|
|
3046
|
+
peek = (acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK
|
|
3047
|
+
e = fast[peek]
|
|
3048
|
+
v = e >> 16
|
|
3049
|
+
if e != 0 && v != 0
|
|
3050
|
+
bits -= e & 255
|
|
3051
|
+
k += (e >> 8) & 255
|
|
3052
|
+
u = (v << al) & 0xFFFF
|
|
3053
|
+
p = base + 2 * zz[k]
|
|
3054
|
+
coefs.setbyte(p, u & 255)
|
|
3055
|
+
coefs.setbyte(p + 1, u >> 8)
|
|
3056
|
+
last = k
|
|
3057
|
+
k += 1
|
|
3058
|
+
else
|
|
3059
|
+
e = look[peek]
|
|
3060
|
+
e = table.decode_long((acc >> (bits - 16)) & 0xFFFF) if e == 0
|
|
3061
|
+
bits -= e >> 8
|
|
3062
|
+
s = e & 15
|
|
3063
|
+
r = (e >> 4) & 15
|
|
3064
|
+
if s != 0
|
|
3065
|
+
k += r
|
|
3066
|
+
v = (acc >> (bits - s)) & ((1 << s) - 1)
|
|
3067
|
+
bits -= s
|
|
3068
|
+
v -= (1 << s) - 1 if v < (1 << (s - 1))
|
|
3069
|
+
u = (v << al) & 0xFFFF
|
|
3070
|
+
p = base + 2 * zz[k]
|
|
3071
|
+
coefs.setbyte(p, u & 255)
|
|
3072
|
+
coefs.setbyte(p + 1, u >> 8)
|
|
3073
|
+
last = k
|
|
3074
|
+
k += 1
|
|
3075
|
+
elsif r == 15
|
|
3076
|
+
k += 16
|
|
3077
|
+
else
|
|
3078
|
+
# End of band: this block and 2^r - 1 + (r extra bits) more.
|
|
3079
|
+
eobrun = (1 << r) - 1
|
|
3080
|
+
if r > 0
|
|
3081
|
+
eobrun += (acc >> (bits - r)) & ((1 << r) - 1)
|
|
3082
|
+
bits -= r
|
|
3083
|
+
end
|
|
3084
|
+
break
|
|
3085
|
+
end
|
|
3086
|
+
end
|
|
3087
|
+
end
|
|
3088
|
+
if pos * 8 - bits > @endbit
|
|
3089
|
+
# Out of data: undo this block (the band was empty before).
|
|
3090
|
+
k = ss
|
|
3091
|
+
while k <= se
|
|
3092
|
+
p = base + 2 * zz[k]
|
|
3093
|
+
coefs.setbyte(p, 0)
|
|
3094
|
+
coefs.setbyte(p + 1, 0)
|
|
3095
|
+
k += 1
|
|
3096
|
+
end
|
|
3097
|
+
return false
|
|
3098
|
+
end
|
|
3099
|
+
last = 63 if last > 63
|
|
3100
|
+
coefs.setbyte(base + KM, last) if last > coefs.getbyte(base + KM)
|
|
3101
|
+
bx += 1
|
|
3102
|
+
end
|
|
3103
|
+
@acc = acc
|
|
3104
|
+
@bits = bits
|
|
3105
|
+
@pos = pos
|
|
3106
|
+
@eobrun = eobrun
|
|
3107
|
+
true
|
|
3108
|
+
end
|
|
3109
|
+
|
|
3110
|
+
# Successive approximation refinement of AC band ss..se (libjpeg's
|
|
3111
|
+
# decode_mcu_AC_refine), blocks bx0...bx1 of block row by.
|
|
3112
|
+
def ac_refine_row(by, bx0, bx1)
|
|
3113
|
+
data = @data
|
|
3114
|
+
acc = @acc
|
|
3115
|
+
bits = @bits
|
|
3116
|
+
pos = @pos
|
|
3117
|
+
eobrun = @eobrun
|
|
3118
|
+
table = @table
|
|
3119
|
+
look = table.look
|
|
3120
|
+
coefs = @comp.raw_row(by)
|
|
3121
|
+
ss = @ss
|
|
3122
|
+
se = @se
|
|
3123
|
+
p1 = 1 << @al
|
|
3124
|
+
m1 = -1 << @al
|
|
3125
|
+
zz = JPEG_ZIGZAG_EXT
|
|
3126
|
+
newnz = @newnz
|
|
3127
|
+
bx = bx0
|
|
3128
|
+
while bx < bx1
|
|
3129
|
+
base = bx * BLOCK_BYTES
|
|
3130
|
+
last = coefs.getbyte(base + KM)
|
|
3131
|
+
nnz = 0
|
|
3132
|
+
if eobrun > 0 && last < ss
|
|
3133
|
+
# Inside an end-of-band run with nothing to refine in this band
|
|
3134
|
+
# (and likewise the following blocks).
|
|
3135
|
+
eobrun -= 1
|
|
3136
|
+
bx += 1
|
|
3137
|
+
while eobrun > 0 && bx < bx1 && coefs.getbyte(bx * BLOCK_BYTES + KM) < ss
|
|
3138
|
+
eobrun -= 1
|
|
3139
|
+
bx += 1
|
|
3140
|
+
end
|
|
3141
|
+
next
|
|
3142
|
+
end
|
|
3143
|
+
k = ss
|
|
3144
|
+
if eobrun == 0
|
|
3145
|
+
while k <= se
|
|
3146
|
+
if bits < 31
|
|
3147
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
3148
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
3149
|
+
pos += 4
|
|
3150
|
+
bits += 32
|
|
3151
|
+
end
|
|
3152
|
+
e = look[(acc >> (bits - JPEG_FAST_BITS)) & JPEG_FAST_MASK]
|
|
3153
|
+
e = table.decode_long((acc >> (bits - 16)) & 0xFFFF) if e == 0
|
|
3154
|
+
bits -= e >> 8
|
|
3155
|
+
s = e & 15
|
|
3156
|
+
r = (e >> 4) & 15
|
|
3157
|
+
if s != 0
|
|
3158
|
+
# A new coefficient of magnitude 1 (its size should be 1).
|
|
3159
|
+
bits -= 1
|
|
3160
|
+
s = ((acc >> bits) & 1) == 1 ? p1 : m1
|
|
3161
|
+
elsif r != 15
|
|
3162
|
+
eobrun = 1 << r
|
|
3163
|
+
if r > 0
|
|
3164
|
+
eobrun += (acc >> (bits - r)) & ((1 << r) - 1)
|
|
3165
|
+
bits -= r
|
|
3166
|
+
end
|
|
3167
|
+
break
|
|
3168
|
+
end
|
|
3169
|
+
# Skip r zero coefficients, refining the nonzero ones passed.
|
|
3170
|
+
while k <= se
|
|
3171
|
+
p = base + 2 * zz[k]
|
|
3172
|
+
u = coefs.getbyte(p) | (coefs.getbyte(p + 1) << 8)
|
|
3173
|
+
if u != 0
|
|
3174
|
+
if bits < 31
|
|
3175
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
3176
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
3177
|
+
pos += 4
|
|
3178
|
+
bits += 32
|
|
3179
|
+
end
|
|
3180
|
+
bits -= 1
|
|
3181
|
+
if ((acc >> bits) & 1) == 1 && (u & p1) == 0
|
|
3182
|
+
u = (u < 32_768 ? u + p1 : u + m1) & 0xFFFF
|
|
3183
|
+
coefs.setbyte(p, u & 255)
|
|
3184
|
+
coefs.setbyte(p + 1, u >> 8)
|
|
3185
|
+
end
|
|
3186
|
+
else
|
|
3187
|
+
r -= 1
|
|
3188
|
+
break if r < 0
|
|
3189
|
+
end
|
|
3190
|
+
k += 1
|
|
3191
|
+
end
|
|
3192
|
+
if s != 0
|
|
3193
|
+
p = base + 2 * zz[k]
|
|
3194
|
+
u = s & 0xFFFF
|
|
3195
|
+
coefs.setbyte(p, u & 255)
|
|
3196
|
+
coefs.setbyte(p + 1, u >> 8)
|
|
3197
|
+
newnz[nnz] = p
|
|
3198
|
+
nnz += 1 if nnz < 63
|
|
3199
|
+
last = k if k > last
|
|
3200
|
+
end
|
|
3201
|
+
k += 1
|
|
3202
|
+
end
|
|
3203
|
+
end
|
|
3204
|
+
if eobrun > 0
|
|
3205
|
+
# Refine the band's remaining nonzero coefficients; none lie beyond
|
|
3206
|
+
# the block's last nonzero position.
|
|
3207
|
+
limit = last < se ? last : se
|
|
3208
|
+
while k <= limit
|
|
3209
|
+
p = base + 2 * zz[k]
|
|
3210
|
+
u = coefs.getbyte(p) | (coefs.getbyte(p + 1) << 8)
|
|
3211
|
+
if u != 0
|
|
3212
|
+
if bits < 31
|
|
3213
|
+
acc = ((acc & ((1 << bits) - 1)) << 32) | (data.getbyte(pos) << 24) | (data.getbyte(pos + 1) << 16) |
|
|
3214
|
+
(data.getbyte(pos + 2) << 8) | data.getbyte(pos + 3)
|
|
3215
|
+
pos += 4
|
|
3216
|
+
bits += 32
|
|
3217
|
+
end
|
|
3218
|
+
bits -= 1
|
|
3219
|
+
if ((acc >> bits) & 1) == 1 && (u & p1) == 0
|
|
3220
|
+
u = (u < 32_768 ? u + p1 : u + m1) & 0xFFFF
|
|
3221
|
+
coefs.setbyte(p, u & 255)
|
|
3222
|
+
coefs.setbyte(p + 1, u >> 8)
|
|
3223
|
+
end
|
|
3224
|
+
end
|
|
3225
|
+
k += 1
|
|
3226
|
+
end
|
|
3227
|
+
eobrun -= 1
|
|
3228
|
+
end
|
|
3229
|
+
if pos * 8 - bits > @endbit
|
|
3230
|
+
# Out of data: re-zero the coefficients this block made nonzero
|
|
3231
|
+
# (like libjpeg), so that its last nonzero index stays valid.
|
|
3232
|
+
while nnz > 0
|
|
3233
|
+
nnz -= 1
|
|
3234
|
+
coefs.setbyte(newnz[nnz], 0)
|
|
3235
|
+
coefs.setbyte(newnz[nnz] + 1, 0)
|
|
3236
|
+
end
|
|
3237
|
+
return false
|
|
3238
|
+
end
|
|
3239
|
+
|
|
3240
|
+
coefs.setbyte(base + KM, last > 63 ? 63 : last)
|
|
3241
|
+
bx += 1
|
|
3242
|
+
end
|
|
3243
|
+
@acc = acc
|
|
3244
|
+
@bits = bits
|
|
3245
|
+
@pos = pos
|
|
3246
|
+
@eobrun = eobrun
|
|
3247
|
+
true
|
|
3248
|
+
end
|
|
3249
|
+
end
|
|
3250
|
+
|
|
3251
|
+
# Upsamples a subsampled component plane to the output size, choosing the
|
|
3252
|
+
# method like libjpeg (jdsample.c): with +fancy+ (DCT_scaled_size > 1) 2x
|
|
3253
|
+
# ratios use the "fancy" triangle filters (h2v1 and h2v2 only for
|
|
3254
|
+
# components wider than 2 samples, h1v2 always), other integer ratios
|
|
3255
|
+
# replicate samples. Fractional ratios, which libjpeg rejects, use the
|
|
3256
|
+
# nearest sample.
|
|
3257
|
+
class JpegUpsampler
|
|
3258
|
+
REPLICATE = 0
|
|
3259
|
+
H2V1 = 1
|
|
3260
|
+
H1V2 = 2
|
|
3261
|
+
H2V2 = 3
|
|
3262
|
+
|
|
3263
|
+
# +plane+ has row stride +stride+; the component's valid size is +cw+ x
|
|
3264
|
+
# +ch+ samples, and +h+ x +v+ of them cover +hmax+ x +vmax+ output pixels.
|
|
3265
|
+
def initialize(plane, stride, cw, ch, hmax, vmax, h, v, fancy)
|
|
3266
|
+
@plane = plane
|
|
3267
|
+
@stride = stride
|
|
3268
|
+
@cw = cw
|
|
3269
|
+
@ch = ch
|
|
3270
|
+
@hmax = hmax
|
|
3271
|
+
@vmax = vmax
|
|
3272
|
+
@h = h
|
|
3273
|
+
@v = v
|
|
3274
|
+
@rh = (hmax % h) == 0 ? hmax / h : 0
|
|
3275
|
+
rv = (vmax % v) == 0 ? vmax / v : 0
|
|
3276
|
+
@mode = if fancy && @rh == 2 && rv == 1 && cw > 2 then H2V1
|
|
3277
|
+
elsif fancy && @rh == 1 && rv == 2 then H1V2
|
|
3278
|
+
elsif fancy && @rh == 2 && rv == 2 && cw > 2 then H2V2
|
|
3279
|
+
else REPLICATE
|
|
3280
|
+
end
|
|
3281
|
+
end
|
|
3282
|
+
|
|
3283
|
+
def run(ow, oh)
|
|
3284
|
+
out = String.new(capacity: ow * oh, encoding: Encoding::BINARY)
|
|
3285
|
+
mode = @mode
|
|
3286
|
+
last_src = -1
|
|
3287
|
+
last = ""
|
|
3288
|
+
y = 0
|
|
3289
|
+
while y < oh
|
|
3290
|
+
row = ""
|
|
3291
|
+
if mode == H2V1
|
|
3292
|
+
row = h2v1(row_offset(y), ow)
|
|
3293
|
+
elsif mode == H1V2
|
|
3294
|
+
row = h1v2(y)
|
|
3295
|
+
elsif mode == H2V2
|
|
3296
|
+
row = h2v2(y, ow)
|
|
3297
|
+
else
|
|
3298
|
+
# Replicated rows: repeat the previous output row.
|
|
3299
|
+
src = y * @v / @vmax
|
|
3300
|
+
if src == last_src
|
|
3301
|
+
row = last
|
|
3302
|
+
else
|
|
3303
|
+
row = replicate_row(row_offset(src), ow)
|
|
3304
|
+
last = row
|
|
3305
|
+
last_src = src
|
|
3306
|
+
end
|
|
3307
|
+
end
|
|
3308
|
+
raise QrReader::ImageError, "corrupt JPEG: upsampling mismatch" unless row.bytesize == ow
|
|
3309
|
+
|
|
3310
|
+
out << row
|
|
3311
|
+
y += 1
|
|
3312
|
+
end
|
|
3313
|
+
out
|
|
3314
|
+
end
|
|
3315
|
+
|
|
3316
|
+
private
|
|
3317
|
+
|
|
3318
|
+
# Offset of component row +y+ in the plane (clamped to the valid rows,
|
|
3319
|
+
# as libjpeg repeats the first and last row for context).
|
|
3320
|
+
def row_offset(y)
|
|
3321
|
+
y = 0 if y < 0
|
|
3322
|
+
y = @ch - 1 if y >= @ch
|
|
3323
|
+
y * @stride
|
|
3324
|
+
end
|
|
3325
|
+
|
|
3326
|
+
# Samples x * h / hmax of the row at +off+ for x < ow: replication for
|
|
3327
|
+
# integer ratios, the nearest sample for fractional ones.
|
|
3328
|
+
def replicate_row(off, ow)
|
|
3329
|
+
plane = @plane
|
|
3330
|
+
out = String.new(capacity: ow, encoding: Encoding::BINARY)
|
|
3331
|
+
last = @cw - 1
|
|
3332
|
+
rh = @rh
|
|
3333
|
+
x = 0
|
|
3334
|
+
if rh > 0
|
|
3335
|
+
sx = off
|
|
3336
|
+
while x < ow
|
|
3337
|
+
v = plane.getbyte(sx)
|
|
3338
|
+
r = rh
|
|
3339
|
+
while r > 0 && x < ow
|
|
3340
|
+
out << v
|
|
3341
|
+
x += 1
|
|
3342
|
+
r -= 1
|
|
3343
|
+
end
|
|
3344
|
+
sx += 1
|
|
3345
|
+
end
|
|
3346
|
+
else
|
|
3347
|
+
h = @h
|
|
3348
|
+
hmax = @hmax
|
|
3349
|
+
while x < ow
|
|
3350
|
+
sx = x * h / hmax
|
|
3351
|
+
out << plane.getbyte(off + (sx > last ? last : sx))
|
|
3352
|
+
x += 1
|
|
3353
|
+
end
|
|
3354
|
+
end
|
|
3355
|
+
out
|
|
3356
|
+
end
|
|
3357
|
+
|
|
3358
|
+
# libjpeg h1v2_fancy_upsample: 3/4 nearer + 1/4 further row.
|
|
3359
|
+
def h1v2(y)
|
|
3360
|
+
plane = @plane
|
|
3361
|
+
lower = (y & 1) == 1
|
|
3362
|
+
near = row_offset(y >> 1)
|
|
3363
|
+
far = row_offset(lower ? (y >> 1) + 1 : (y >> 1) - 1)
|
|
3364
|
+
bias = lower ? 2 : 1
|
|
3365
|
+
n = @cw
|
|
3366
|
+
out = String.new(capacity: n, encoding: Encoding::BINARY)
|
|
3367
|
+
x = 0
|
|
3368
|
+
while x < n
|
|
3369
|
+
out << ((plane.getbyte(near + x) * 3 + plane.getbyte(far + x) + bias) >> 2)
|
|
3370
|
+
x += 1
|
|
3371
|
+
end
|
|
3372
|
+
out
|
|
3373
|
+
end
|
|
3374
|
+
|
|
3375
|
+
# libjpeg h2v1_fancy_upsample: 3/4 nearer + 1/4 further sample. The last
|
|
3376
|
+
# output exists only if the output is that wide.
|
|
3377
|
+
def h2v1(off, ow)
|
|
3378
|
+
s = @plane
|
|
3379
|
+
n = @cw
|
|
3380
|
+
out = String.new(capacity: ow, encoding: Encoding::BINARY)
|
|
3381
|
+
first = s.getbyte(off)
|
|
3382
|
+
out << first << ((first * 3 + s.getbyte(off + 1) + 2) >> 2)
|
|
3383
|
+
x = off + 1
|
|
3384
|
+
e = off + n - 1
|
|
3385
|
+
while x < e
|
|
3386
|
+
t = s.getbyte(x) * 3
|
|
3387
|
+
out << ((t + s.getbyte(x - 1) + 1) >> 2) << ((t + s.getbyte(x + 1) + 2) >> 2)
|
|
3388
|
+
x += 1
|
|
3389
|
+
end
|
|
3390
|
+
tail = s.getbyte(e)
|
|
3391
|
+
out << ((tail * 3 + s.getbyte(e - 1) + 1) >> 2)
|
|
3392
|
+
out << tail if 2 * n <= ow
|
|
3393
|
+
out
|
|
3394
|
+
end
|
|
3395
|
+
|
|
3396
|
+
# libjpeg h2v2_fancy_upsample on column sums 3 * nearer + further row.
|
|
3397
|
+
def h2v2(y, ow)
|
|
3398
|
+
s = @plane
|
|
3399
|
+
lower = (y & 1) == 1
|
|
3400
|
+
near = row_offset(y >> 1)
|
|
3401
|
+
far = row_offset(lower ? (y >> 1) + 1 : (y >> 1) - 1)
|
|
3402
|
+
n = @cw
|
|
3403
|
+
out = String.new(capacity: ow, encoding: Encoding::BINARY)
|
|
3404
|
+
this = s.getbyte(near) * 3 + s.getbyte(far)
|
|
3405
|
+
nxt = s.getbyte(near + 1) * 3 + s.getbyte(far + 1)
|
|
3406
|
+
out << ((this * 4 + 8) >> 4) << ((this * 3 + nxt + 7) >> 4)
|
|
3407
|
+
x = 1
|
|
3408
|
+
while x < n - 1
|
|
3409
|
+
last = this
|
|
3410
|
+
this = nxt
|
|
3411
|
+
nxt = s.getbyte(near + x + 1) * 3 + s.getbyte(far + x + 1)
|
|
3412
|
+
t = this * 3
|
|
3413
|
+
out << ((t + last + 8) >> 4) << ((t + nxt + 7) >> 4)
|
|
3414
|
+
x += 1
|
|
3415
|
+
end
|
|
3416
|
+
out << ((nxt * 3 + this + 8) >> 4)
|
|
3417
|
+
out << ((nxt * 4 + 7) >> 4) if 2 * n <= ow
|
|
3418
|
+
out
|
|
3419
|
+
end
|
|
3420
|
+
end
|
|
3421
|
+
end
|