/src/serenity/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2024, Nico Weber <thakis@chromium.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/Debug.h> |
8 | | #include <AK/Utf16View.h> |
9 | | #include <LibGfx/ImageFormats/CCITTDecoder.h> |
10 | | #include <LibGfx/ImageFormats/JBIG2Loader.h> |
11 | | #include <LibGfx/ImageFormats/QMArithmeticDecoder.h> |
12 | | #include <LibTextCodec/Decoder.h> |
13 | | |
14 | | // Spec: ITU-T_T_88__08_2018.pdf in the zip file here: |
15 | | // https://www.itu.int/rec/T-REC-T.88-201808-I |
16 | | // Annex H has a datastream example. |
17 | | |
18 | | // That spec was published in 2018 and contains all previous amendments. Its history is: |
19 | | // * 2002: Original spec published, describes decoding only. Has generic regions, |
20 | | // symbol regions, text regions, halftone regions, and pattern regions. |
21 | | // * 2003: Amendment 1 approved. Describes encoding. Not interesting for us. |
22 | | // * 2004: (Amendment 1 erratum 1 approved. Not interesting for us.) |
23 | | // * 2003: Amendment 2 approved. Added support for EXTTEMPLATE. |
24 | | // * 2011: Amendment 3 approved. Added support for color coding |
25 | | // (COLEXTFLAG, CPCOMPLEN, CPDEFCOLS, CPEXCOLS, CPNCOMP, CPNVALS, GBCOLS, |
26 | | // GBCOMBOP, GBFGCOLID, SBCOLS, SBCOLSECTSIZE and SBFGCOLID). |
27 | | // This history might explain why EXTTEMPLATE and colors are very rare in practice. |
28 | | |
29 | | namespace Gfx { |
30 | | |
31 | | namespace JBIG2 { |
32 | | |
33 | | // Annex A, Arithmetic integer decoding procedure |
34 | | class ArithmeticIntegerDecoder { |
35 | | public: |
36 | | ArithmeticIntegerDecoder(QMArithmeticDecoder&); |
37 | | |
38 | | // A.2 Procedure for decoding values (except IAID) |
39 | | // Returns OptionalNone for OOB. |
40 | | Optional<i32> decode(); |
41 | | |
42 | | // Returns Error for OOB. |
43 | | ErrorOr<i32> decode_non_oob(); |
44 | | |
45 | | private: |
46 | | QMArithmeticDecoder& m_decoder; |
47 | | u16 PREV { 0 }; |
48 | | Vector<QMArithmeticDecoder::Context> contexts; |
49 | | }; |
50 | | |
51 | | ArithmeticIntegerDecoder::ArithmeticIntegerDecoder(QMArithmeticDecoder& decoder) |
52 | 1.32k | : m_decoder(decoder) |
53 | 1.32k | { |
54 | 1.32k | contexts.resize(1 << 9); |
55 | 1.32k | } |
56 | | |
57 | | Optional<int> ArithmeticIntegerDecoder::decode() |
58 | 168 | { |
59 | | // A.2 Procedure for decoding values (except IAID) |
60 | | // "1) Set: |
61 | | // PREV = 1" |
62 | 168 | u16 PREV = 1; |
63 | | |
64 | | // "2) Follow the flowchart in Figure A.1. Decode each bit with CX equal to "IAx + PREV" where "IAx" represents the identifier |
65 | | // of the current arithmetic integer decoding procedure, "+" represents concatenation, and the rightmost 9 bits of PREV are used." |
66 | 6.07k | auto decode_bit = [&]() { |
67 | 6.07k | bool D = m_decoder.get_next_bit(contexts[PREV & 0x1FF]); |
68 | | // "3) After each bit is decoded: |
69 | | // If PREV < 256 set: |
70 | | // PREV = (PREV << 1) OR D |
71 | | // Otherwise set: |
72 | | // PREV = (((PREV << 1) OR D) AND 511) OR 256 |
73 | | // where D represents the value of the just-decoded bit. |
74 | 6.07k | if (PREV < 256) |
75 | 1.33k | PREV = (PREV << 1) | (u16)D; |
76 | 4.74k | else |
77 | 4.74k | PREV = (((PREV << 1) | (u16)D) & 511) | 256; |
78 | 6.07k | return D; |
79 | 6.07k | }; |
80 | | |
81 | 168 | auto decode_bits = [&](int n) { |
82 | 168 | u32 result = 0; |
83 | 5.26k | for (int i = 0; i < n; ++i) |
84 | 5.09k | result = (result << 1) | decode_bit(); |
85 | 168 | return result; |
86 | 168 | }; |
87 | | |
88 | | // Figure A.1 – Flowchart for the integer arithmetic decoding procedures (except IAID) |
89 | 168 | u8 S = decode_bit(); |
90 | 168 | u32 V; |
91 | 168 | if (!decode_bit()) |
92 | 1 | V = decode_bits(2); |
93 | 167 | else if (!decode_bit()) |
94 | 2 | V = decode_bits(4) + 4; |
95 | 165 | else if (!decode_bit()) |
96 | 3 | V = decode_bits(6) + 20; |
97 | 162 | else if (!decode_bit()) |
98 | 5 | V = decode_bits(8) + 84; |
99 | 157 | else if (!decode_bit()) |
100 | 0 | V = decode_bits(12) + 340; |
101 | 157 | else |
102 | 157 | V = decode_bits(32) + 4436; |
103 | | |
104 | | // "4) The sequence of bits decoded, interpreted according to Table A.1, gives the value that is the result of this invocation |
105 | | // of the integer arithmetic decoding procedure." |
106 | 168 | if (S == 1 && V == 0) |
107 | 0 | return {}; |
108 | 168 | return S ? -V : V; |
109 | 168 | } |
110 | | |
111 | | ErrorOr<i32> ArithmeticIntegerDecoder::decode_non_oob() |
112 | 168 | { |
113 | 168 | auto result = decode(); |
114 | 168 | if (!result.has_value()) |
115 | 0 | return Error::from_string_literal("ArithmeticIntegerDecoder: Unexpected OOB"); |
116 | 168 | return result.value(); |
117 | 168 | } |
118 | | |
119 | | class ArithmeticIntegerIDDecoder { |
120 | | public: |
121 | | ArithmeticIntegerIDDecoder(QMArithmeticDecoder&, u32 code_length); |
122 | | |
123 | | // A.3 The IAID decoding procedure |
124 | | u32 decode(); |
125 | | |
126 | | private: |
127 | | QMArithmeticDecoder& m_decoder; |
128 | | u32 m_code_length { 0 }; |
129 | | Vector<QMArithmeticDecoder::Context> contexts; |
130 | | }; |
131 | | |
132 | | ArithmeticIntegerIDDecoder::ArithmeticIntegerIDDecoder(QMArithmeticDecoder& decoder, u32 code_length) |
133 | 147 | : m_decoder(decoder) |
134 | 147 | , m_code_length(code_length) |
135 | 147 | { |
136 | 147 | contexts.resize(1 << (code_length + 1)); |
137 | 147 | } |
138 | | |
139 | | u32 ArithmeticIntegerIDDecoder::decode() |
140 | 11 | { |
141 | | // A.3 The IAID decoding procedure |
142 | 11 | u32 prev = 1; |
143 | 11 | for (u8 i = 0; i < m_code_length; ++i) { |
144 | 0 | bool bit = m_decoder.get_next_bit(contexts[prev]); |
145 | 0 | prev = (prev << 1) | bit; |
146 | 0 | } |
147 | 11 | prev = prev - (1 << m_code_length); |
148 | 11 | return prev; |
149 | 11 | } |
150 | | |
151 | | } |
152 | | |
153 | | static u8 number_of_context_bits_for_template(u8 template_) |
154 | 4.30k | { |
155 | 4.30k | if (template_ == 0) |
156 | 1.84k | return 16; |
157 | 2.45k | if (template_ == 1) |
158 | 465 | return 13; |
159 | 1.99k | VERIFY(template_ == 2 || template_ == 3); |
160 | 1.99k | return 10; |
161 | 1.99k | } |
162 | | |
163 | | // JBIG2 spec, Annex D, D.4.1 ID string |
164 | | static constexpr u8 id_string[] = { 0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A }; |
165 | | |
166 | | // 7.3 Segment types |
167 | | enum SegmentType { |
168 | | SymbolDictionary = 0, |
169 | | IntermediateTextRegion = 4, |
170 | | ImmediateTextRegion = 6, |
171 | | ImmediateLosslessTextRegion = 7, |
172 | | PatternDictionary = 16, |
173 | | IntermediateHalftoneRegion = 20, |
174 | | ImmediateHalftoneRegion = 22, |
175 | | ImmediateLosslessHalftoneRegion = 23, |
176 | | IntermediateGenericRegion = 36, |
177 | | ImmediateGenericRegion = 38, |
178 | | ImmediateLosslessGenericRegion = 39, |
179 | | IntermediateGenericRefinementRegion = 40, |
180 | | ImmediateGenericRefinementRegion = 42, |
181 | | ImmediateLosslessGenericRefinementRegion = 43, |
182 | | PageInformation = 48, |
183 | | EndOfPage = 49, |
184 | | EndOfStripe = 50, |
185 | | EndOfFile = 51, |
186 | | Profiles = 52, |
187 | | Tables = 53, |
188 | | ColorPalette = 54, |
189 | | Extension = 62, |
190 | | }; |
191 | | |
192 | | // Annex D |
193 | | enum class Organization { |
194 | | // D.1 Sequential organization |
195 | | Sequential, |
196 | | |
197 | | // D.2 Random-access organization |
198 | | RandomAccess, |
199 | | |
200 | | // D.3 Embedded organization |
201 | | Embedded, |
202 | | }; |
203 | | |
204 | | struct SegmentHeader { |
205 | | u32 segment_number { 0 }; |
206 | | SegmentType type { SegmentType::Extension }; |
207 | | Vector<u32> referred_to_segment_numbers; |
208 | | |
209 | | // 7.2.6 Segment page association |
210 | | // "The first page must be numbered "1". This field may contain a value of zero; this value indicates that this segment is not associated with any page." |
211 | | u32 page_association { 0 }; |
212 | | |
213 | | Optional<u32> data_length; |
214 | | }; |
215 | | |
216 | | class BitBuffer { |
217 | | public: |
218 | | static ErrorOr<NonnullOwnPtr<BitBuffer>> create(size_t width, size_t height); |
219 | | bool get_bit(size_t x, size_t y) const; |
220 | | void set_bit(size_t x, size_t y, bool b); |
221 | | void fill(bool b); |
222 | | |
223 | | ErrorOr<NonnullOwnPtr<BitBuffer>> subbitmap(Gfx::IntRect const& rect) const; |
224 | | |
225 | | ErrorOr<NonnullRefPtr<Gfx::Bitmap>> to_gfx_bitmap() const; |
226 | | ErrorOr<ByteBuffer> to_byte_buffer() const; |
227 | | |
228 | 1.66G | size_t width() const { return m_width; } |
229 | 19.4k | size_t height() const { return m_height; } |
230 | | |
231 | | private: |
232 | | BitBuffer(ByteBuffer, size_t width, size_t height, size_t pitch); |
233 | | |
234 | | ByteBuffer m_bits; |
235 | | size_t m_width { 0 }; |
236 | | size_t m_height { 0 }; |
237 | | size_t m_pitch { 0 }; |
238 | | }; |
239 | | |
240 | | ErrorOr<NonnullOwnPtr<BitBuffer>> BitBuffer::create(size_t width, size_t height) |
241 | 4.79k | { |
242 | 4.79k | size_t pitch = ceil_div(width, static_cast<size_t>(8)); |
243 | 4.79k | auto bits = TRY(ByteBuffer::create_uninitialized(pitch * height)); |
244 | 0 | return adopt_nonnull_own_or_enomem(new (nothrow) BitBuffer(move(bits), width, height, pitch)); |
245 | 4.79k | } |
246 | | |
247 | | bool BitBuffer::get_bit(size_t x, size_t y) const |
248 | 1.36G | { |
249 | 1.36G | VERIFY(x < m_width); |
250 | 1.36G | VERIFY(y < m_height); |
251 | 1.36G | size_t byte_offset = x / 8; |
252 | 1.36G | size_t bit_offset = x % 8; |
253 | 1.36G | u8 byte = m_bits[y * m_pitch + byte_offset]; |
254 | 1.36G | byte = (byte >> (8 - 1 - bit_offset)) & 1; |
255 | 1.36G | return byte != 0; |
256 | 1.36G | } |
257 | | |
258 | | void BitBuffer::set_bit(size_t x, size_t y, bool b) |
259 | 597M | { |
260 | 597M | VERIFY(x < m_width); |
261 | 597M | VERIFY(y < m_height); |
262 | 597M | size_t byte_offset = x / 8; |
263 | 597M | size_t bit_offset = x % 8; |
264 | 597M | u8 byte = m_bits[y * m_pitch + byte_offset]; |
265 | 597M | u8 mask = 1u << (8 - 1 - bit_offset); |
266 | 597M | if (b) |
267 | 194M | byte |= mask; |
268 | 402M | else |
269 | 402M | byte &= ~mask; |
270 | 597M | m_bits[y * m_pitch + byte_offset] = byte; |
271 | 597M | } |
272 | | |
273 | | void BitBuffer::fill(bool b) |
274 | 638 | { |
275 | 638 | u8 fill_byte = b ? 0xff : 0; |
276 | 638 | for (auto& byte : m_bits.bytes()) |
277 | 47.8G | byte = fill_byte; |
278 | 638 | } |
279 | | |
280 | | ErrorOr<NonnullOwnPtr<BitBuffer>> BitBuffer::subbitmap(Gfx::IntRect const& rect) const |
281 | 0 | { |
282 | 0 | VERIFY(rect.x() >= 0); |
283 | 0 | VERIFY(rect.width() >= 0); |
284 | 0 | VERIFY(static_cast<size_t>(rect.right()) <= width()); |
285 | | |
286 | 0 | VERIFY(rect.y() >= 0); |
287 | 0 | VERIFY(rect.height() >= 0); |
288 | 0 | VERIFY(static_cast<size_t>(rect.bottom()) <= height()); |
289 | | |
290 | 0 | auto subbitmap = TRY(create(rect.width(), rect.height())); |
291 | 0 | for (int y = 0; y < rect.height(); ++y) |
292 | 0 | for (int x = 0; x < rect.width(); ++x) |
293 | 0 | subbitmap->set_bit(x, y, get_bit(rect.x() + x, rect.y() + y)); |
294 | 0 | return subbitmap; |
295 | 0 | } |
296 | | |
297 | | ErrorOr<NonnullRefPtr<Gfx::Bitmap>> BitBuffer::to_gfx_bitmap() const |
298 | 108 | { |
299 | 108 | auto bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { m_width, m_height })); |
300 | 4.17k | for (size_t y = 0; y < m_height; ++y) { |
301 | 15.0M | for (size_t x = 0; x < m_width; ++x) { |
302 | 15.0M | auto color = get_bit(x, y) ? Color::Black : Color::White; |
303 | 15.0M | bitmap->set_pixel(x, y, color); |
304 | 15.0M | } |
305 | 4.15k | } |
306 | 24 | return bitmap; |
307 | 108 | } |
308 | | |
309 | | ErrorOr<ByteBuffer> BitBuffer::to_byte_buffer() const |
310 | 0 | { |
311 | 0 | return ByteBuffer::copy(m_bits); |
312 | 0 | } |
313 | | |
314 | | BitBuffer::BitBuffer(ByteBuffer bits, size_t width, size_t height, size_t pitch) |
315 | 4.79k | : m_bits(move(bits)) |
316 | 4.79k | , m_width(width) |
317 | 4.79k | , m_height(height) |
318 | 4.79k | , m_pitch(pitch) |
319 | 4.79k | { |
320 | 4.79k | } |
321 | | |
322 | | class Symbol : public RefCounted<Symbol> { |
323 | | public: |
324 | | static NonnullRefPtr<Symbol> create(NonnullOwnPtr<BitBuffer> bitmap) |
325 | 0 | { |
326 | 0 | return adopt_ref(*new Symbol(move(bitmap))); |
327 | 0 | } |
328 | | |
329 | 0 | BitBuffer const& bitmap() const { return *m_bitmap; } |
330 | | |
331 | | private: |
332 | | Symbol(NonnullOwnPtr<BitBuffer> bitmap) |
333 | 0 | : m_bitmap(move(bitmap)) |
334 | 0 | { |
335 | 0 | } |
336 | | |
337 | | NonnullOwnPtr<BitBuffer> m_bitmap; |
338 | | }; |
339 | | |
340 | | struct SegmentData { |
341 | | SegmentHeader header; |
342 | | ReadonlyBytes data; |
343 | | |
344 | | // Set on dictionary segments after they've been decoded. |
345 | | Optional<Vector<NonnullRefPtr<Symbol>>> symbols; |
346 | | |
347 | | // Set on pattern segments after they've been decoded. |
348 | | Optional<Vector<NonnullRefPtr<Symbol>>> patterns; |
349 | | }; |
350 | | |
351 | | // 7.4.8.5 Page segment flags |
352 | | enum class CombinationOperator { |
353 | | Or = 0, |
354 | | And = 1, |
355 | | Xor = 2, |
356 | | XNor = 3, |
357 | | Replace = 4, |
358 | | }; |
359 | | |
360 | | static void composite_bitbuffer(BitBuffer& out, BitBuffer const& bitmap, Gfx::IntPoint position, CombinationOperator operator_) |
361 | 4.23k | { |
362 | 4.23k | if (!IntRect { position, { bitmap.width(), bitmap.height() } }.intersects(IntRect { { 0, 0 }, { out.width(), out.height() } })) |
363 | 565 | return; |
364 | | |
365 | 3.66k | size_t start_x = 0, end_x = bitmap.width(); |
366 | 3.66k | size_t start_y = 0, end_y = bitmap.height(); |
367 | 3.66k | if (position.x() < 0) { |
368 | 487 | start_x = -position.x(); |
369 | 487 | position.set_x(0); |
370 | 487 | } |
371 | 3.66k | if (position.y() < 0) { |
372 | 306 | start_y = -position.y(); |
373 | 306 | position.set_y(0); |
374 | 306 | } |
375 | 3.66k | if (position.x() + bitmap.width() > out.width()) |
376 | 290 | end_x = out.width() - position.x(); |
377 | 3.66k | if (position.y() + bitmap.height() > out.height()) |
378 | 6 | end_y = out.height() - position.y(); |
379 | | |
380 | 6.75M | for (size_t y = start_y; y < end_y; ++y) { |
381 | 219M | for (size_t x = start_x; x < end_x; ++x) { |
382 | 212M | bool bit = bitmap.get_bit(x, y); |
383 | 212M | switch (operator_) { |
384 | 50.8M | case CombinationOperator::Or: |
385 | 50.8M | bit = bit || out.get_bit(position.x() + x, position.y() + y); |
386 | 50.8M | break; |
387 | 256 | case CombinationOperator::And: |
388 | 256 | bit = bit && out.get_bit(position.x() + x, position.y() + y); |
389 | 256 | break; |
390 | 123M | case CombinationOperator::Xor: |
391 | 123M | bit = bit ^ out.get_bit(position.x() + x, position.y() + y); |
392 | 123M | break; |
393 | 11.7M | case CombinationOperator::XNor: |
394 | 11.7M | bit = !(bit ^ out.get_bit(position.x() + x, position.y() + y)); |
395 | 11.7M | break; |
396 | 26.9M | case CombinationOperator::Replace: |
397 | | // Nothing to do. |
398 | 26.9M | break; |
399 | 212M | } |
400 | 212M | out.set_bit(position.x() + x, position.y() + y, bit); |
401 | 212M | } |
402 | 6.74M | } |
403 | 3.66k | } |
404 | | |
405 | | struct Page { |
406 | | IntSize size; |
407 | | |
408 | | // This is never CombinationOperator::Replace for Pages. |
409 | | CombinationOperator default_combination_operator { CombinationOperator::Or }; |
410 | | |
411 | | OwnPtr<BitBuffer> bits; |
412 | | }; |
413 | | |
414 | | struct JBIG2LoadingContext { |
415 | | enum class State { |
416 | | NotDecoded = 0, |
417 | | Error, |
418 | | Decoded, |
419 | | }; |
420 | | State state { State::NotDecoded }; |
421 | | |
422 | | Organization organization { Organization::Sequential }; |
423 | | Page page; |
424 | | |
425 | | Optional<u32> number_of_pages; |
426 | | |
427 | | Vector<SegmentData> segments; |
428 | | HashMap<u32, u32> segments_by_number; |
429 | | }; |
430 | | |
431 | | static ErrorOr<void> decode_jbig2_header(JBIG2LoadingContext& context, ReadonlyBytes data) |
432 | 502 | { |
433 | 502 | if (!JBIG2ImageDecoderPlugin::sniff(data)) |
434 | 7 | return Error::from_string_literal("JBIG2LoadingContext: Invalid JBIG2 header"); |
435 | | |
436 | 495 | FixedMemoryStream stream(data.slice(sizeof(id_string))); |
437 | | |
438 | | // D.4.2 File header flags |
439 | 495 | u8 header_flags = TRY(stream.read_value<u8>()); |
440 | 495 | if (header_flags & 0b11110000) |
441 | 0 | return Error::from_string_literal("JBIG2LoadingContext: Invalid header flags"); |
442 | 495 | context.organization = (header_flags & 1) ? Organization::Sequential : Organization::RandomAccess; |
443 | 495 | dbgln_if(JBIG2_DEBUG, "JBIG2LoadingContext: Organization: {} ({})", (int)context.organization, context.organization == Organization::Sequential ? "Sequential" : "Random-access"); |
444 | 495 | bool has_known_number_of_pages = (header_flags & 2) ? false : true; |
445 | 495 | bool uses_templates_with_12_AT_pixels = (header_flags & 4) ? true : false; |
446 | 495 | bool contains_colored_region_segments = (header_flags & 8) ? true : false; |
447 | | |
448 | | // FIXME: Do something with these? |
449 | 495 | (void)uses_templates_with_12_AT_pixels; |
450 | 495 | (void)contains_colored_region_segments; |
451 | | |
452 | | // D.4.3 Number of pages |
453 | 495 | if (has_known_number_of_pages) { |
454 | 49 | context.number_of_pages = TRY(stream.read_value<BigEndian<u32>>()); |
455 | 49 | dbgln_if(JBIG2_DEBUG, "JBIG2LoadingContext: Number of pages: {}", context.number_of_pages.value()); |
456 | 49 | } |
457 | | |
458 | 495 | return {}; |
459 | 495 | } |
460 | | |
461 | | static ErrorOr<SegmentHeader> decode_segment_header(SeekableStream& stream) |
462 | 579k | { |
463 | | // 7.2.2 Segment number |
464 | 579k | u32 segment_number = TRY(stream.read_value<BigEndian<u32>>()); |
465 | 579k | dbgln_if(JBIG2_DEBUG, "Segment number: {}", segment_number); |
466 | | |
467 | | // 7.2.3 Segment header flags |
468 | 579k | u8 flags = TRY(stream.read_value<u8>()); |
469 | 0 | SegmentType type = static_cast<SegmentType>(flags & 0b11'1111); |
470 | 579k | dbgln_if(JBIG2_DEBUG, "Segment type: {}", (int)type); |
471 | 579k | bool segment_page_association_size_is_32_bits = (flags & 0b100'0000) != 0; |
472 | 579k | bool segment_retained_only_by_itself_and_extension_segments = (flags & 0b1000'00000) != 0; |
473 | | |
474 | | // FIXME: Do something with this? |
475 | 579k | (void)segment_retained_only_by_itself_and_extension_segments; |
476 | | |
477 | | // 7.2.4 Referred-to segment count and retention flags |
478 | 579k | u8 referred_to_segment_count_and_retention_flags = TRY(stream.read_value<u8>()); |
479 | 0 | u32 count_of_referred_to_segments = referred_to_segment_count_and_retention_flags >> 5; |
480 | 579k | if (count_of_referred_to_segments == 5 || count_of_referred_to_segments == 6) |
481 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid count_of_referred_to_segments"); |
482 | 579k | u32 extra_count = 0; |
483 | 579k | if (count_of_referred_to_segments == 7) { |
484 | 457 | TRY(stream.seek(-1, SeekMode::FromCurrentPosition)); |
485 | 457 | count_of_referred_to_segments = TRY(stream.read_value<BigEndian<u32>>()) & 0x1FFF'FFFF; |
486 | 0 | extra_count = ceil_div(count_of_referred_to_segments + 1, 8); |
487 | 457 | TRY(stream.seek(extra_count, SeekMode::FromCurrentPosition)); |
488 | 448 | } |
489 | 579k | dbgln_if(JBIG2_DEBUG, "Referred-to segment count: {}", count_of_referred_to_segments); |
490 | | |
491 | | // 7.2.5 Referred-to segment numbers |
492 | 579k | Vector<u32> referred_to_segment_numbers; |
493 | 672k | for (u32 i = 0; i < count_of_referred_to_segments; ++i) { |
494 | 93.2k | u32 referred_to_segment_number; |
495 | 93.2k | if (segment_number <= 256) |
496 | 73.7k | referred_to_segment_number = TRY(stream.read_value<u8>()); |
497 | 19.5k | else if (segment_number <= 65536) |
498 | 16.8k | referred_to_segment_number = TRY(stream.read_value<BigEndian<u16>>()); |
499 | 2.65k | else |
500 | 2.65k | referred_to_segment_number = TRY(stream.read_value<BigEndian<u32>>()); |
501 | 93.2k | referred_to_segment_numbers.append(referred_to_segment_number); |
502 | 93.2k | dbgln_if(JBIG2_DEBUG, "Referred-to segment number: {}", referred_to_segment_number); |
503 | 93.2k | } |
504 | | |
505 | | // 7.2.6 Segment page association |
506 | 579k | u32 segment_page_association; |
507 | 579k | if (segment_page_association_size_is_32_bits) { |
508 | 3.87k | segment_page_association = TRY(stream.read_value<BigEndian<u32>>()); |
509 | 575k | } else { |
510 | 575k | segment_page_association = TRY(stream.read_value<u8>()); |
511 | 575k | } |
512 | 579k | dbgln_if(JBIG2_DEBUG, "Segment page association: {}", segment_page_association); |
513 | | |
514 | | // 7.2.7 Segment data length |
515 | 579k | u32 data_length = TRY(stream.read_value<BigEndian<u32>>()); |
516 | 579k | dbgln_if(JBIG2_DEBUG, "Segment data length: {}", data_length); |
517 | | |
518 | | // FIXME: Add some validity checks: |
519 | | // - check type is valid |
520 | | // - check referred_to_segment_numbers are smaller than segment_number |
521 | | // - 7.3.1 Rules for segment references |
522 | | // - 7.3.2 Rules for page associations |
523 | | |
524 | 579k | Optional<u32> opt_data_length; |
525 | 579k | if (data_length != 0xffff'ffff) |
526 | 570k | opt_data_length = data_length; |
527 | 8.96k | else if (type != ImmediateGenericRegion) |
528 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Unknown data length only allowed for ImmediateGenericRegion"); |
529 | | |
530 | 579k | return SegmentHeader { segment_number, type, move(referred_to_segment_numbers), segment_page_association, opt_data_length }; |
531 | 579k | } |
532 | | |
533 | | static ErrorOr<size_t> scan_for_immediate_generic_region_size(ReadonlyBytes data) |
534 | 8.95k | { |
535 | | // 7.2.7 Segment data length |
536 | | // "If the segment's type is "Immediate generic region", then the length field may contain the value 0xFFFFFFFF. |
537 | | // This value is intended to mean that the length of the segment's data part is unknown at the time that the segment header is written (...). |
538 | | // In this case, the true length of the segment's data part shall be determined through examination of the data: |
539 | | // if the segment uses template-based arithmetic coding, then the segment's data part ends with the two-byte sequence 0xFF 0xAC followed by a four-byte row count. |
540 | | // If the segment uses MMR coding, then the segment's data part ends with the two-byte sequence 0x00 0x00 followed by a four-byte row count. |
541 | | // The form of encoding used by the segment may be determined by examining the eighteenth byte of its segment data part, |
542 | | // and the end sequences can occur anywhere after that eighteenth byte." |
543 | | // 7.4.6.4 Decoding a generic region segment |
544 | | // "NOTE – The sequence 0x00 0x00 cannot occur within MMR-encoded data; the sequence 0xFF 0xAC can occur only at the end of arithmetically-coded data. |
545 | | // Thus, those sequences cannot occur by chance in the data that is decoded to generate the contents of the generic region." |
546 | 8.95k | dbgln_if(JBIG2_DEBUG, "(Unknown data length, computing it)"); |
547 | | |
548 | 8.95k | if (data.size() < 19 + sizeof(u32)) |
549 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Data too short to contain segment data header and end sequence"); |
550 | | |
551 | | // Per 7.4.6.1 Generic region segment data header, this starts with the 17 bytes described in |
552 | | // 7.4.1 Region segment information field, followed the byte described in 7.4.6.2 Generic region segment flags. |
553 | | // That byte's lowest bit stores if the segment uses MMR. |
554 | 8.95k | u8 flags = data[17]; |
555 | 8.95k | bool uses_mmr = (flags & 1) != 0; |
556 | 8.95k | auto end_sequence = uses_mmr ? to_array<u8>({ 0x00, 0x00 }) : to_array<u8>({ 0xFF, 0xAC }); |
557 | 8.95k | u8 const* end = static_cast<u8 const*>(memmem(data.data() + 19, data.size() - 19 - sizeof(u32), end_sequence.data(), end_sequence.size())); |
558 | 8.95k | if (!end) |
559 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Could not find end sequence in segment data"); |
560 | | |
561 | 8.95k | size_t size = end - data.data() + end_sequence.size() + sizeof(u32); |
562 | 8.95k | dbgln_if(JBIG2_DEBUG, "(Computed size is {})", size); |
563 | 8.95k | return size; |
564 | 8.95k | } |
565 | | |
566 | | static ErrorOr<void> decode_segment_headers(JBIG2LoadingContext& context, ReadonlyBytes data) |
567 | 495 | { |
568 | 495 | FixedMemoryStream stream(data); |
569 | | |
570 | 495 | Vector<ReadonlyBytes> segment_datas; |
571 | 521k | auto store_and_skip_segment_data = [&](SegmentHeader const& segment_header) -> ErrorOr<void> { |
572 | 521k | size_t start_offset = TRY(stream.tell()); |
573 | 521k | u32 data_length = TRY(segment_header.data_length.try_value_or_lazy_evaluated([&]() { |
574 | 521k | return scan_for_immediate_generic_region_size(data.slice(start_offset)); |
575 | 521k | })); |
576 | | |
577 | 521k | if (start_offset + data_length > data.size()) { |
578 | 24 | dbgln_if(JBIG2_DEBUG, "JBIG2ImageDecoderPlugin: start_offset={}, data_length={}, data.size()={}", start_offset, data_length, data.size()); |
579 | 24 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Segment data length exceeds file size"); |
580 | 24 | } |
581 | 521k | ReadonlyBytes segment_data = data.slice(start_offset, data_length); |
582 | 521k | segment_datas.append(segment_data); |
583 | | |
584 | 521k | TRY(stream.seek(data_length, SeekMode::FromCurrentPosition)); |
585 | 0 | return {}; |
586 | 521k | }; |
587 | | |
588 | 495 | Vector<SegmentHeader> segment_headers; |
589 | 580k | while (!stream.is_eof()) { |
590 | 579k | auto segment_header = TRY(decode_segment_header(stream)); |
591 | 0 | segment_headers.append(segment_header); |
592 | | |
593 | 579k | if (context.organization != Organization::RandomAccess) |
594 | 520k | TRY(store_and_skip_segment_data(segment_header)); |
595 | | |
596 | | // Required per spec for files with RandomAccess organization. |
597 | 579k | if (segment_header.type == SegmentType::EndOfFile) |
598 | 14 | break; |
599 | 579k | } |
600 | | |
601 | 439 | if (context.organization == Organization::RandomAccess) { |
602 | 26 | for (auto const& segment_header : segment_headers) |
603 | 1.35k | TRY(store_and_skip_segment_data(segment_header)); |
604 | 26 | } |
605 | | |
606 | 431 | if (segment_headers.size() != segment_datas.size()) |
607 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Segment headers and segment datas have different sizes"); |
608 | 440k | for (size_t i = 0; i < segment_headers.size(); ++i) { |
609 | 440k | context.segments.append({ segment_headers[i], segment_datas[i], {}, {} }); |
610 | 440k | context.segments_by_number.set(segment_headers[i].segment_number, context.segments.size() - 1); |
611 | 440k | } |
612 | | |
613 | 431 | return {}; |
614 | 431 | } |
615 | | |
616 | | // 7.4.1 Region segment information field |
617 | | struct [[gnu::packed]] RegionSegmentInformationField { |
618 | | BigEndian<u32> width; |
619 | | BigEndian<u32> height; |
620 | | BigEndian<u32> x_location; |
621 | | BigEndian<u32> y_location; |
622 | | u8 flags; |
623 | | |
624 | | CombinationOperator external_combination_operator() const |
625 | 4.61k | { |
626 | 4.61k | VERIFY((flags & 0x7) <= 4); |
627 | 4.61k | return static_cast<CombinationOperator>(flags & 0x7); |
628 | 4.61k | } |
629 | | |
630 | | bool is_color_bitmap() const |
631 | 4.45k | { |
632 | 4.45k | return (flags & 0x8) != 0; |
633 | 4.45k | } |
634 | | }; |
635 | | static_assert(AssertSize<RegionSegmentInformationField, 17>()); |
636 | | |
637 | | static ErrorOr<RegionSegmentInformationField> decode_region_segment_information_field(ReadonlyBytes data) |
638 | 4.46k | { |
639 | | // 7.4.8 Page information segment syntax |
640 | 4.46k | if (data.size() < sizeof(RegionSegmentInformationField)) |
641 | 4 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid region segment information field size"); |
642 | 4.46k | auto result = *(RegionSegmentInformationField const*)data.data(); |
643 | 4.46k | if ((result.flags & 0b1111'0000) != 0) |
644 | 6 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid region segment information field flags"); |
645 | 4.45k | if ((result.flags & 0x7) > 4) |
646 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid region segment information field operator"); |
647 | | |
648 | | // NOTE 3 – If the colour extension flag (COLEXTFLAG) is equal to 1, the external combination operator must be REPLACE. |
649 | 4.45k | if (result.is_color_bitmap() && result.external_combination_operator() != CombinationOperator::Replace) |
650 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid colored region segment information field operator"); |
651 | | |
652 | 4.45k | return result; |
653 | 4.45k | } |
654 | | |
655 | | // 7.4.8 Page information segment syntax |
656 | | struct [[gnu::packed]] PageInformationSegment { |
657 | | BigEndian<u32> bitmap_width; |
658 | | BigEndian<u32> bitmap_height; |
659 | | BigEndian<u32> page_x_resolution; // In pixels/meter. |
660 | | BigEndian<u32> page_y_resolution; // In pixels/meter. |
661 | | u8 flags; |
662 | | BigEndian<u16> striping_information; |
663 | | }; |
664 | | static_assert(AssertSize<PageInformationSegment, 19>()); |
665 | | |
666 | | static ErrorOr<PageInformationSegment> decode_page_information_segment(ReadonlyBytes data) |
667 | 1.48k | { |
668 | | // 7.4.8 Page information segment syntax |
669 | 1.48k | if (data.size() != sizeof(PageInformationSegment)) |
670 | 2 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid page information segment size"); |
671 | 1.47k | return *(PageInformationSegment const*)data.data(); |
672 | 1.48k | } |
673 | | |
674 | | static ErrorOr<void> scan_for_page_size(JBIG2LoadingContext& context) |
675 | 431 | { |
676 | | // We only decode the first page at the moment. |
677 | 431 | bool found_size = false; |
678 | 440k | for (auto const& segment : context.segments) { |
679 | 440k | if (segment.header.type != SegmentType::PageInformation || segment.header.page_association != 1) |
680 | 439k | continue; |
681 | 988 | auto page_information = TRY(decode_page_information_segment(segment.data)); |
682 | | |
683 | | // FIXME: We're supposed to compute this from the striping information if it's not set. |
684 | 987 | if (page_information.bitmap_height == 0xffff'ffff) |
685 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot handle unknown page height yet"); |
686 | | |
687 | 987 | context.page.size = { page_information.bitmap_width, page_information.bitmap_height }; |
688 | 987 | found_size = true; |
689 | 987 | } |
690 | 430 | if (!found_size) |
691 | 44 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: No page information segment found for page 1"); |
692 | 386 | return {}; |
693 | 430 | } |
694 | | |
695 | | static ErrorOr<void> warn_about_multiple_pages(JBIG2LoadingContext& context) |
696 | 386 | { |
697 | 386 | HashTable<u32> seen_pages; |
698 | 386 | Vector<u32> pages; |
699 | | |
700 | 308k | for (auto const& segment : context.segments) { |
701 | 308k | if (segment.header.page_association == 0) |
702 | 299k | continue; |
703 | 8.65k | if (seen_pages.contains(segment.header.page_association)) |
704 | 6.96k | continue; |
705 | 1.68k | seen_pages.set(segment.header.page_association); |
706 | 1.68k | pages.append(segment.header.page_association); |
707 | 1.68k | } |
708 | | |
709 | | // scan_for_page_size() already checked that there's a page 1. |
710 | 386 | VERIFY(seen_pages.contains(1)); |
711 | 386 | if (pages.size() == 1) |
712 | 76 | return {}; |
713 | | |
714 | 310 | StringBuilder builder; |
715 | 310 | builder.appendff("JBIG2 file contains {} pages ({}", pages.size(), pages[0]); |
716 | 310 | size_t i; |
717 | 1.39k | for (i = 1; i < min(pages.size(), 10); ++i) |
718 | 1.08k | builder.appendff(" {}", pages[i]); |
719 | 310 | if (i != pages.size()) |
720 | 34 | builder.append(" ..."sv); |
721 | 310 | builder.append("). We will only render page 1."sv); |
722 | 310 | dbgln("JBIG2ImageDecoderPlugin: {}", TRY(builder.to_string())); |
723 | | |
724 | 0 | return {}; |
725 | 310 | } |
726 | | |
727 | | struct AdaptiveTemplatePixel { |
728 | | i8 x { 0 }; |
729 | | i8 y { 0 }; |
730 | | }; |
731 | | |
732 | | // Figure 7 – Field to which AT pixel locations are restricted |
733 | | static ErrorOr<void> check_valid_adaptive_template_pixel(AdaptiveTemplatePixel const& adaptive_template_pixel) |
734 | 8.68k | { |
735 | | // Don't have to check < -127 or > 127: The offsets are stored in an i8, so they can't be out of those bounds. |
736 | 8.68k | if (adaptive_template_pixel.y > 0) |
737 | 7 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Adaptive pixel y too big"); |
738 | 8.67k | if (adaptive_template_pixel.y == 0 && adaptive_template_pixel.x > -1) |
739 | 60 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Adaptive pixel x too big"); |
740 | 8.61k | return {}; |
741 | 8.67k | } |
742 | | |
743 | | // 6.2.2 Input parameters |
744 | | // Table 2 – Parameters for the generic region decoding procedure |
745 | | struct GenericRegionDecodingInputParameters { |
746 | | bool is_modified_modified_read { false }; // "MMR" in spec. |
747 | | u32 region_width { 0 }; // "GBW" in spec. |
748 | | u32 region_height { 0 }; // "GBH" in spec. |
749 | | u8 gb_template { 0 }; |
750 | | bool is_typical_prediction_used { false }; // "TPGDON" in spec. |
751 | | bool is_extended_reference_template_used { false }; // "EXTTEMPLATE" in spec. |
752 | | Optional<BitBuffer const&> skip_pattern; // "USESKIP", "SKIP" in spec. |
753 | | |
754 | | Array<AdaptiveTemplatePixel, 12> adaptive_template_pixels; // "GBATX" / "GBATY" in spec. |
755 | | // FIXME: GBCOLS, GBCOMBOP, COLEXTFLAG |
756 | | |
757 | | // If is_modified_modified_read is false, generic_region_decoding_procedure() reads data off this decoder. |
758 | | QMArithmeticDecoder* arithmetic_decoder { nullptr }; |
759 | | }; |
760 | | |
761 | | // 6.2 Generic region decoding procedure |
762 | | static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(GenericRegionDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts) |
763 | 4.30k | { |
764 | 4.30k | if (inputs.is_modified_modified_read) { |
765 | 983 | dbgln_if(JBIG2_DEBUG, "JBIG2ImageDecoderPlugin: MMR image data"); |
766 | | |
767 | | // 6.2.6 Decoding using MMR coding |
768 | 983 | auto buffer = TRY(CCITT::decode_ccitt_group4(data, inputs.region_width, inputs.region_height)); |
769 | 900 | auto result = TRY(BitBuffer::create(inputs.region_width, inputs.region_height)); |
770 | 0 | size_t bytes_per_row = ceil_div(inputs.region_width, 8); |
771 | 900 | if (buffer.size() != bytes_per_row * inputs.region_height) |
772 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Decoded MMR data has wrong size"); |
773 | | |
774 | | // FIXME: Could probably just copy the ByteBuffer directly into the BitBuffer's internal ByteBuffer instead. |
775 | 16.8M | for (size_t y = 0; y < inputs.region_height; ++y) { |
776 | 165M | for (size_t x = 0; x < inputs.region_width; ++x) { |
777 | 149M | bool bit = buffer[y * bytes_per_row + x / 8] & (1 << (7 - x % 8)); |
778 | 149M | result->set_bit(x, y, bit); |
779 | 149M | } |
780 | 16.8M | } |
781 | 899 | return result; |
782 | 900 | } |
783 | | |
784 | | // 6.2.5 Decoding using a template and arithmetic coding |
785 | 3.32k | if (inputs.is_extended_reference_template_used) |
786 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode EXTTEMPLATE yet"); |
787 | | |
788 | 3.32k | int number_of_adaptive_template_pixels = inputs.gb_template == 0 ? 4 : 1; |
789 | 11.9k | for (int i = 0; i < number_of_adaptive_template_pixels; ++i) |
790 | 8.68k | TRY(check_valid_adaptive_template_pixel(inputs.adaptive_template_pixels[i])); |
791 | | |
792 | 3.25k | if (inputs.skip_pattern.has_value()) |
793 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode USESKIP yet"); |
794 | | |
795 | 3.25k | auto result = TRY(BitBuffer::create(inputs.region_width, inputs.region_height)); |
796 | | |
797 | 1.98G | static constexpr auto get_pixel = [](NonnullOwnPtr<BitBuffer> const& buffer, int x, int y) -> bool { |
798 | 1.98G | if (x < 0 || x >= (int)buffer->width() || y < 0) |
799 | 1.01G | return false; |
800 | 971M | return buffer->get_bit(x, y); |
801 | 1.98G | }; |
802 | | |
803 | | // Figure 3(a) – Template when GBTEMPLATE = 0 and EXTTEMPLATE = 0, |
804 | 50.9M | constexpr auto compute_context_0 = [](NonnullOwnPtr<BitBuffer> const& buffer, ReadonlySpan<AdaptiveTemplatePixel> adaptive_pixels, int x, int y) -> u16 { |
805 | 50.9M | u16 result = 0; |
806 | 254M | for (int i = 0; i < 4; ++i) |
807 | 203M | result = (result << 1) | (u16)get_pixel(buffer, x + adaptive_pixels[i].x, y + adaptive_pixels[i].y); |
808 | 203M | for (int i = 0; i < 3; ++i) |
809 | 152M | result = (result << 1) | (u16)get_pixel(buffer, x - 1 + i, y - 2); |
810 | 305M | for (int i = 0; i < 5; ++i) |
811 | 254M | result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y - 1); |
812 | 254M | for (int i = 0; i < 4; ++i) |
813 | 203M | result = (result << 1) | (u16)get_pixel(buffer, x - 4 + i, y); |
814 | 50.9M | return result; |
815 | 50.9M | }; |
816 | | |
817 | | // Figure 4 – Template when GBTEMPLATE = 1 |
818 | 2.30M | auto compute_context_1 = [](NonnullOwnPtr<BitBuffer> const& buffer, ReadonlySpan<AdaptiveTemplatePixel> adaptive_pixels, int x, int y) -> u16 { |
819 | 2.30M | u16 result = 0; |
820 | 2.30M | result = (result << 1) | (u16)get_pixel(buffer, x + adaptive_pixels[0].x, y + adaptive_pixels[0].y); |
821 | 11.5M | for (int i = 0; i < 4; ++i) |
822 | 9.23M | result = (result << 1) | (u16)get_pixel(buffer, x - 1 + i, y - 2); |
823 | 13.8M | for (int i = 0; i < 5; ++i) |
824 | 11.5M | result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y - 1); |
825 | 9.23M | for (int i = 0; i < 3; ++i) |
826 | 6.92M | result = (result << 1) | (u16)get_pixel(buffer, x - 3 + i, y); |
827 | 2.30M | return result; |
828 | 2.30M | }; |
829 | | |
830 | | // Figure 5 – Template when GBTEMPLATE = 2 |
831 | 68.1M | auto compute_context_2 = [](NonnullOwnPtr<BitBuffer> const& buffer, ReadonlySpan<AdaptiveTemplatePixel> adaptive_pixels, int x, int y) -> u16 { |
832 | 68.1M | u16 result = 0; |
833 | 68.1M | result = (result << 1) | (u16)get_pixel(buffer, x + adaptive_pixels[0].x, y + adaptive_pixels[0].y); |
834 | 272M | for (int i = 0; i < 3; ++i) |
835 | 204M | result = (result << 1) | (u16)get_pixel(buffer, x - 1 + i, y - 2); |
836 | 340M | for (int i = 0; i < 4; ++i) |
837 | 272M | result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y - 1); |
838 | 204M | for (int i = 0; i < 2; ++i) |
839 | 136M | result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y); |
840 | 68.1M | return result; |
841 | 68.1M | }; |
842 | | |
843 | | // Figure 6 – Template when GBTEMPLATE = 3 |
844 | 37.9M | auto compute_context_3 = [](NonnullOwnPtr<BitBuffer> const& buffer, ReadonlySpan<AdaptiveTemplatePixel> adaptive_pixels, int x, int y) -> u16 { |
845 | 37.9M | u16 result = 0; |
846 | 37.9M | result = (result << 1) | (u16)get_pixel(buffer, x + adaptive_pixels[0].x, y + adaptive_pixels[0].y); |
847 | 227M | for (int i = 0; i < 5; ++i) |
848 | 189M | result = (result << 1) | (u16)get_pixel(buffer, x - 3 + i, y - 1); |
849 | 189M | for (int i = 0; i < 4; ++i) |
850 | 151M | result = (result << 1) | (u16)get_pixel(buffer, x - 4 + i, y); |
851 | 37.9M | return result; |
852 | 37.9M | }; |
853 | | |
854 | 3.25k | u16 (*compute_context)(NonnullOwnPtr<BitBuffer> const&, ReadonlySpan<AdaptiveTemplatePixel>, int, int); |
855 | 3.25k | if (inputs.gb_template == 0) |
856 | 1.78k | compute_context = compute_context_0; |
857 | 1.47k | else if (inputs.gb_template == 1) |
858 | 351 | compute_context = compute_context_1; |
859 | 1.12k | else if (inputs.gb_template == 2) |
860 | 912 | compute_context = compute_context_2; |
861 | 208 | else { |
862 | 208 | VERIFY(inputs.gb_template == 3); |
863 | 208 | compute_context = compute_context_3; |
864 | 208 | } |
865 | | |
866 | | // "The values of the pixels in this neighbourhood define a context. Each context has its own adaptive probability estimate |
867 | | // used by the arithmetic coder (see Annex E)." |
868 | | // "* Decode the current pixel by invoking the arithmetic entropy decoding procedure, with CX set to the value formed by |
869 | | // concatenating the label "GB" and the 10-16 pixel values gathered in CONTEXT." |
870 | | // Implementor's note: What this is supposed to mean is that we have a bunch of independent contexts, and we pick the |
871 | | // context for the current pixel based on pixel values in the neighborhood. The "GB" part just means this context is |
872 | | // independent from other contexts in the spec. They are passed in to this function. |
873 | | |
874 | | // Figure 8 – Reused context for coding the SLTP value when GBTEMPLATE is 0 |
875 | 3.25k | constexpr u16 sltp_context_for_template_0 = 0b10011'0110010'0101; |
876 | | |
877 | | // Figure 9 – Reused context for coding the SLTP value when GBTEMPLATE is 1 |
878 | 3.25k | constexpr u16 sltp_context_for_template_1 = 0b0011'110010'101; |
879 | | |
880 | | // Figure 10 – Reused context for coding the SLTP value when GBTEMPLATE is 2 |
881 | 3.25k | constexpr u16 sltp_context_for_template_2 = 0b001'11001'01; |
882 | | |
883 | | // Figure 11 – Reused context for coding the SLTP value when GBTEMPLATE is 3 |
884 | 3.25k | constexpr u16 sltp_context_for_template_3 = 0b011001'0101; |
885 | | |
886 | 3.25k | u16 sltp_context = [](u8 gb_template) { |
887 | 3.25k | if (gb_template == 0) |
888 | 1.78k | return sltp_context_for_template_0; |
889 | 1.47k | if (gb_template == 1) |
890 | 351 | return sltp_context_for_template_1; |
891 | 1.12k | if (gb_template == 2) |
892 | 912 | return sltp_context_for_template_2; |
893 | 208 | VERIFY(gb_template == 3); |
894 | 208 | return sltp_context_for_template_3; |
895 | 208 | }(inputs.gb_template); |
896 | | |
897 | | // 6.2.5.7 Decoding the bitmap |
898 | 3.25k | QMArithmeticDecoder& decoder = *inputs.arithmetic_decoder; |
899 | 3.25k | bool ltp = false; // "LTP" in spec. "Line (uses) Typical Prediction" maybe? |
900 | 46.7M | for (size_t y = 0; y < inputs.region_height; ++y) { |
901 | 46.7M | if (inputs.is_typical_prediction_used) { |
902 | | // "SLTP" in spec. "Swap LTP" or "Switch LTP" maybe? |
903 | 16.9M | bool sltp = decoder.get_next_bit(contexts[sltp_context]); |
904 | 16.9M | ltp = ltp ^ sltp; |
905 | 16.9M | if (ltp) { |
906 | 84.2M | for (size_t x = 0; x < inputs.region_width; ++x) |
907 | 75.9M | result->set_bit(x, y, get_pixel(result, (int)x, (int)y - 1)); |
908 | 8.32M | continue; |
909 | 8.32M | } |
910 | 16.9M | } |
911 | | |
912 | 197M | for (size_t x = 0; x < inputs.region_width; ++x) { |
913 | 159M | u16 context = compute_context(result, inputs.adaptive_template_pixels, x, y); |
914 | 159M | bool bit = decoder.get_next_bit(contexts[context]); |
915 | 159M | result->set_bit(x, y, bit); |
916 | 159M | } |
917 | 38.4M | } |
918 | | |
919 | 3.25k | return result; |
920 | 3.25k | } |
921 | | |
922 | | // 6.3.2 Input parameters |
923 | | // Table 6 – Parameters for the generic refinement region decoding procedure |
924 | | struct GenericRefinementRegionDecodingInputParameters { |
925 | | u32 region_width { 0 }; // "GRW" in spec. |
926 | | u32 region_height { 0 }; // "GRH" in spec. |
927 | | u8 gr_template { 0 }; // "GRTEMPLATE" in spec. |
928 | | BitBuffer const* reference_bitmap { nullptr }; // "GRREFERENCE" in spec. |
929 | | i32 reference_x_offset { 0 }; // "GRREFERENCEDX" in spec. |
930 | | i32 reference_y_offset { 0 }; // "GRREFERENCEDY" in spec. |
931 | | bool is_typical_prediction_used { false }; // "TPGDON" in spec. |
932 | | Array<AdaptiveTemplatePixel, 2> adaptive_template_pixels; // "GRATX" / "GRATY" in spec. |
933 | | }; |
934 | | |
935 | | // 6.3 Generic Refinement Region Decoding Procedure |
936 | | static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_refinement_region_decoding_procedure(GenericRefinementRegionDecodingInputParameters& inputs, QMArithmeticDecoder& decoder, Vector<QMArithmeticDecoder::Context>& contexts) |
937 | 0 | { |
938 | 0 | VERIFY(inputs.gr_template == 0 || inputs.gr_template == 1); |
939 | | |
940 | 0 | if (inputs.is_typical_prediction_used) |
941 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode typical prediction in generic refinement regions yet"); |
942 | | |
943 | 0 | if (inputs.gr_template == 0) { |
944 | 0 | TRY(check_valid_adaptive_template_pixel(inputs.adaptive_template_pixels[0])); |
945 | | // inputs.adaptive_template_pixels[1] is allowed to contain any value. |
946 | 0 | } |
947 | | // GRTEMPLATE 1 never uses adaptive pixels. |
948 | | |
949 | | // 6.3.5.3 Fixed templates and adaptive templates |
950 | 0 | static constexpr auto get_pixel = [](BitBuffer const& buffer, int x, int y) -> bool { |
951 | 0 | if (x < 0 || x >= (int)buffer.width() || y < 0 || y >= (int)buffer.height()) |
952 | 0 | return false; |
953 | 0 | return buffer.get_bit(x, y); |
954 | 0 | }; |
955 | | |
956 | | // Figure 12 – 13-pixel refinement template showing the AT pixels at their nominal locations |
957 | 0 | constexpr auto compute_context_0 = [](ReadonlySpan<AdaptiveTemplatePixel> adaptive_pixels, BitBuffer const& reference, int reference_x, int reference_y, BitBuffer const& buffer, int x, int y) -> u16 { |
958 | 0 | u16 result = 0; |
959 | |
|
960 | 0 | for (int dy = -1; dy <= 1; ++dy) { |
961 | 0 | for (int dx = -1; dx <= 1; ++dx) { |
962 | 0 | if (dy == -1 && dx == -1) |
963 | 0 | result = (result << 1) | (u16)get_pixel(reference, reference_x + adaptive_pixels[1].x, reference_y + adaptive_pixels[1].y); |
964 | 0 | else |
965 | 0 | result = (result << 1) | (u16)get_pixel(reference, reference_x + dx, reference_y + dy); |
966 | 0 | } |
967 | 0 | } |
968 | |
|
969 | 0 | result = (result << 1) | (u16)get_pixel(buffer, x + adaptive_pixels[0].x, y + adaptive_pixels[0].y); |
970 | 0 | for (int i = 0; i < 2; ++i) |
971 | 0 | result = (result << 1) | (u16)get_pixel(buffer, x + i, y - 1); |
972 | 0 | result = (result << 1) | (u16)get_pixel(buffer, x - 1, y); |
973 | |
|
974 | 0 | return result; |
975 | 0 | }; |
976 | | |
977 | | // Figure 13 – 10-pixel refinement template |
978 | 0 | constexpr auto compute_context_1 = [](ReadonlySpan<AdaptiveTemplatePixel>, BitBuffer const& reference, int reference_x, int reference_y, BitBuffer const& buffer, int x, int y) -> u16 { |
979 | 0 | u16 result = 0; |
980 | |
|
981 | 0 | for (int dy = -1; dy <= 1; ++dy) { |
982 | 0 | for (int dx = -1; dx <= 1; ++dx) { |
983 | 0 | if ((dy == -1 && (dx == -1 || dx == 1)) || (dy == 1 && dx == -1)) |
984 | 0 | continue; |
985 | 0 | result = (result << 1) | (u16)get_pixel(reference, reference_x + dx, reference_y + dy); |
986 | 0 | } |
987 | 0 | } |
988 | |
|
989 | 0 | for (int i = 0; i < 3; ++i) |
990 | 0 | result = (result << 1) | (u16)get_pixel(buffer, x - 1 + i, y - 1); |
991 | 0 | result = (result << 1) | (u16)get_pixel(buffer, x - 1, y); |
992 | |
|
993 | 0 | return result; |
994 | 0 | }; |
995 | |
|
996 | 0 | auto compute_context = inputs.gr_template == 0 ? compute_context_0 : compute_context_1; |
997 | | |
998 | | // 6.3.5.6 Decoding the refinement bitmap |
999 | 0 | auto result = TRY(BitBuffer::create(inputs.region_width, inputs.region_height)); |
1000 | 0 | for (size_t y = 0; y < result->height(); ++y) { |
1001 | 0 | for (size_t x = 0; x < result->width(); ++x) { |
1002 | 0 | u16 context = compute_context(inputs.adaptive_template_pixels, *inputs.reference_bitmap, x - inputs.reference_x_offset, y - inputs.reference_y_offset, *result, x, y); |
1003 | 0 | bool bit = decoder.get_next_bit(contexts[context]); |
1004 | 0 | result->set_bit(x, y, bit); |
1005 | 0 | } |
1006 | 0 | } |
1007 | |
|
1008 | 0 | return result; |
1009 | 0 | } |
1010 | | |
1011 | | // 6.4.2 Input parameters |
1012 | | // Table 9 – Parameters for the text region decoding procedure |
1013 | | struct TextRegionDecodingInputParameters { |
1014 | | bool uses_huffman_encoding { false }; // "SBHUFF" in spec. |
1015 | | bool uses_refinement_coding { false }; // "SBREFINE" in spec. |
1016 | | u32 region_width { 0 }; // "SBW" in spec. |
1017 | | u32 region_height { 0 }; // "SBH" in spec. |
1018 | | u32 number_of_instances { 0 }; // "SBNUMINSTANCES" in spec. |
1019 | | u32 size_of_symbol_instance_strips { 0 }; // "SBSTRIPS" in spec. |
1020 | | // "SBNUMSYMS" is `symbols.size()` below. |
1021 | | |
1022 | | // FIXME: SBSYMCODES |
1023 | | u32 id_symbol_code_length { 0 }; // "SBSYMCODELEN" in spec. |
1024 | | Vector<NonnullRefPtr<Symbol>> symbols; // "SBNUMSYMS" / "SBSYMS" in spec. |
1025 | | u8 default_pixel { 0 }; // "SBDEFPIXEL" in spec. |
1026 | | |
1027 | | CombinationOperator operator_ { CombinationOperator::Or }; // "SBCOMBOP" in spec. |
1028 | | |
1029 | | bool is_transposed { false }; // "TRANSPOSED" in spec. |
1030 | | |
1031 | | enum class Corner { |
1032 | | BottomLeft = 0, |
1033 | | TopLeft = 1, |
1034 | | BottomRight = 2, |
1035 | | TopRight = 3, |
1036 | | }; |
1037 | | Corner reference_corner { Corner::TopLeft }; // "REFCORNER" in spec. |
1038 | | |
1039 | | i8 delta_s_offset { 0 }; // "SBDSOFFSET" in spec. |
1040 | | // FIXME: SBHUFFFS, SBHUFFFDS, SBHUFFDT, SBHUFFRDW, SBHUFFRDH, SBHUFFRDX, SBHUFFRDY, SBHUFFRSIZE |
1041 | | |
1042 | | u8 refinement_template { 0 }; // "SBRTEMPLATE" in spec. |
1043 | | Array<AdaptiveTemplatePixel, 2> refinement_adaptive_template_pixels; // "SBRATX" / "SBRATY" in spec. |
1044 | | // FIXME: COLEXTFLAG, SBCOLS |
1045 | | }; |
1046 | | |
1047 | | // 6.4 Text Region Decoding Procedure |
1048 | | static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegionDecodingInputParameters const& inputs, ReadonlyBytes data) |
1049 | 147 | { |
1050 | 147 | if (inputs.uses_huffman_encoding) |
1051 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode huffman text regions yet"); |
1052 | | |
1053 | 147 | auto decoder = TRY(QMArithmeticDecoder::initialize(data)); |
1054 | | |
1055 | | // 6.4.6 Strip delta T |
1056 | | // "If SBHUFF is 1, decode a value using the Huffman table specified by SBHUFFDT and multiply the resulting value by SBSTRIPS. |
1057 | | // If SBHUFF is 0, decode a value using the IADT integer arithmetic decoding procedure (see Annex A) and multiply the resulting value by SBSTRIPS." |
1058 | | // FIXME: Implement support for SBHUFF = 1. |
1059 | 0 | JBIG2::ArithmeticIntegerDecoder delta_t_integer_decoder(decoder); |
1060 | 157 | auto read_delta_t = [&]() -> ErrorOr<i32> { |
1061 | 157 | return TRY(delta_t_integer_decoder.decode_non_oob()) * inputs.size_of_symbol_instance_strips; |
1062 | 157 | }; |
1063 | | |
1064 | | // 6.4.7 First symbol instance S coordinate |
1065 | | // "If SBHUFF is 1, decode a value using the Huffman table specified by SBHUFFFS. |
1066 | | // If SBHUFF is 0, decode a value using the IAFS integer arithmetic decoding procedure (see Annex A)." |
1067 | | // FIXME: Implement support for SBHUFF = 1. |
1068 | 147 | JBIG2::ArithmeticIntegerDecoder first_s_integer_decoder(decoder); |
1069 | 147 | auto read_first_s = [&]() -> ErrorOr<i32> { |
1070 | 11 | return first_s_integer_decoder.decode_non_oob(); |
1071 | 11 | }; |
1072 | | |
1073 | | // 6.4.8 Subsequent symbol instance S coordinate |
1074 | | // "If SBHUFF is 1, decode a value using the Huffman table specified by SBHUFFDS. |
1075 | | // If SBHUFF is 0, decode a value using the IADS integer arithmetic decoding procedure (see Annex A). |
1076 | | // In either case it is possible that the result of this decoding is the out-of-band value OOB."" |
1077 | | // FIXME: Implement support for SBHUFF = 1. |
1078 | 147 | JBIG2::ArithmeticIntegerDecoder subsequent_s_integer_decoder(decoder); |
1079 | 147 | auto read_subsequent_s = [&]() -> Optional<i32> { |
1080 | 0 | return subsequent_s_integer_decoder.decode(); |
1081 | 0 | }; |
1082 | | |
1083 | | // 6.4.9 Symbol instance T coordinate |
1084 | | // "If SBSTRIPS == 1, then the value decoded is always zero. Otherwise: |
1085 | | // • If SBHUFF is 1, decode a value by reading ceil(log2(SBSTRIPS)) bits directly from the bitstream. |
1086 | | // • If SBHUFF is 0, decode a value using the IAIT integer arithmetic decoding procedure (see Annex A)." |
1087 | | // FIXME: Implement support for SBHUFF = 1. |
1088 | 147 | JBIG2::ArithmeticIntegerDecoder instance_t_integer_decoder(decoder); |
1089 | 147 | auto read_instance_t = [&]() -> ErrorOr<i32> { |
1090 | 11 | if (inputs.size_of_symbol_instance_strips == 1) |
1091 | 11 | return 0; |
1092 | 0 | return instance_t_integer_decoder.decode_non_oob(); |
1093 | 11 | }; |
1094 | | |
1095 | | // 6.4.10 Symbol instance symbol ID |
1096 | | // "If SBHUFF is 1, decode a value by reading one bit at a time until the resulting bit string is equal to one of the entries in |
1097 | | // SBSYMCODES. The resulting value, which is IDI, is the index of the entry in SBSYMCODES that is read. |
1098 | | // If SBHUFF is 0, decode a value using the IAID integer arithmetic decoding procedure (see Annex A). Set IDI to the |
1099 | | // resulting value."" |
1100 | | // FIXME: Implement support for SBHUFF = 1. |
1101 | 147 | JBIG2::ArithmeticIntegerIDDecoder id_decoder(decoder, inputs.id_symbol_code_length); |
1102 | | |
1103 | | // 6.4.11.1 Symbol instance refinement delta width |
1104 | | // FIXME: Implement support for SBHUFF = 1. |
1105 | 147 | JBIG2::ArithmeticIntegerDecoder refinement_delta_width_decoder(decoder); |
1106 | 147 | auto read_refinement_delta_width = [&]() -> ErrorOr<i32> { |
1107 | 0 | return refinement_delta_width_decoder.decode_non_oob(); |
1108 | 0 | }; |
1109 | | |
1110 | | // 6.4.11.2 Symbol instance refinement delta width |
1111 | | // FIXME: Implement support for SBHUFF = 1. |
1112 | 147 | JBIG2::ArithmeticIntegerDecoder refinement_delta_height_decoder(decoder); |
1113 | 147 | auto read_refinement_delta_height = [&]() -> ErrorOr<i32> { |
1114 | 0 | return refinement_delta_height_decoder.decode_non_oob(); |
1115 | 0 | }; |
1116 | | |
1117 | | // 6.4.11.3 Symbol instance refinement X offset |
1118 | | // FIXME: Implement support for SBHUFF = 1. |
1119 | 147 | JBIG2::ArithmeticIntegerDecoder refinement_x_offset_decoder(decoder); |
1120 | 147 | auto read_refinement_x_offset = [&]() -> ErrorOr<i32> { |
1121 | 0 | return refinement_x_offset_decoder.decode_non_oob(); |
1122 | 0 | }; |
1123 | | |
1124 | | // 6.4.11.4 Symbol instance refinement Y offset |
1125 | | // FIXME: Implement support for SBHUFF = 1. |
1126 | 147 | JBIG2::ArithmeticIntegerDecoder refinement_y_offset_decoder(decoder); |
1127 | 147 | auto read_refinement_y_offset = [&]() -> ErrorOr<i32> { |
1128 | 0 | return refinement_y_offset_decoder.decode_non_oob(); |
1129 | 0 | }; |
1130 | | |
1131 | | // 6.4.11 Symbol instance bitmap |
1132 | 147 | JBIG2::ArithmeticIntegerDecoder has_refinement_image_decoder(decoder); |
1133 | 147 | Vector<QMArithmeticDecoder::Context> refinement_contexts; |
1134 | 147 | if (inputs.uses_refinement_coding) |
1135 | 1 | refinement_contexts.resize(1 << (inputs.refinement_template == 0 ? 13 : 10)); |
1136 | 147 | OwnPtr<BitBuffer> refinement_result; |
1137 | 147 | auto read_bitmap = [&](u32 id) -> ErrorOr<BitBuffer const*> { |
1138 | 11 | if (id >= inputs.symbols.size()) |
1139 | 11 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Symbol ID out of range"); |
1140 | 0 | auto const& symbol = inputs.symbols[id]->bitmap(); |
1141 | |
|
1142 | 0 | bool has_refinement_image = false; // "R_I" in spec. |
1143 | 0 | if (inputs.uses_refinement_coding) { |
1144 | | // "• If SBHUFF is 1, then read one bit and set RI to the value of that bit. |
1145 | | // • If SBHUFF is 0, then decode one bit using the IARI integer arithmetic decoding procedure and set RI to the value of that bit." |
1146 | | // FIXME: Implement support for SBHUFF = 1. |
1147 | 0 | has_refinement_image = TRY(has_refinement_image_decoder.decode_non_oob()); |
1148 | 0 | } |
1149 | | |
1150 | 0 | if (!has_refinement_image) |
1151 | 0 | return &symbol; |
1152 | | |
1153 | 0 | auto refinement_delta_width = TRY(read_refinement_delta_width()); |
1154 | 0 | auto refinement_delta_height = TRY(read_refinement_delta_height()); |
1155 | 0 | auto refinement_x_offset = TRY(read_refinement_x_offset()); |
1156 | 0 | auto refinement_y_offset = TRY(read_refinement_y_offset()); |
1157 | | // FIXME: This is missing some steps needed for the SBHUFF = 1 case. |
1158 | | |
1159 | 0 | dbgln_if(JBIG2_DEBUG, "refinement delta width: {}, refinement delta height: {}, refinement x offset: {}, refinement y offset: {}", refinement_delta_width, refinement_delta_height, refinement_x_offset, refinement_y_offset); |
1160 | | |
1161 | | // Table 12 – Parameters used to decode a symbol instance's bitmap using refinement |
1162 | 0 | GenericRefinementRegionDecodingInputParameters refinement_inputs; |
1163 | 0 | refinement_inputs.region_width = symbol.width() + refinement_delta_width; |
1164 | 0 | refinement_inputs.region_height = symbol.height() + refinement_delta_height; |
1165 | 0 | refinement_inputs.gr_template = inputs.refinement_template; |
1166 | 0 | refinement_inputs.reference_bitmap = &symbol; |
1167 | 0 | refinement_inputs.reference_x_offset = refinement_delta_width / 2 + refinement_x_offset; |
1168 | 0 | refinement_inputs.reference_y_offset = refinement_delta_height / 2 + refinement_y_offset; |
1169 | 0 | refinement_inputs.is_typical_prediction_used = false; |
1170 | 0 | refinement_inputs.adaptive_template_pixels = inputs.refinement_adaptive_template_pixels; |
1171 | 0 | refinement_result = TRY(generic_refinement_region_decoding_procedure(refinement_inputs, decoder, refinement_contexts)); |
1172 | 0 | return refinement_result.ptr(); |
1173 | 0 | }; |
1174 | | |
1175 | | // 6.4.5 Decoding the text region |
1176 | | |
1177 | | // "1) Fill a bitmap SBREG, of the size given by SBW and SBH, with the SBDEFPIXEL value." |
1178 | 147 | auto result = TRY(BitBuffer::create(inputs.region_width, inputs.region_height)); |
1179 | 147 | if (inputs.default_pixel != 0) |
1180 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot handle SBDEFPIXEL not equal to 0 yet"); |
1181 | 146 | result->fill(inputs.default_pixel != 0); |
1182 | | |
1183 | | // "2) Decode the initial STRIPT value as described in 6.4.6. Negate the decoded value and assign this negated value to the variable STRIPT. |
1184 | | // Assign the value 0 to FIRSTS. Assign the value 0 to NINSTANCES." |
1185 | 146 | i32 strip_t = -TRY(read_delta_t()); |
1186 | 0 | i32 first_s = 0; |
1187 | 146 | u32 n_instances = 0; |
1188 | | |
1189 | | // "3) If COLEXTFLAG is 1, decode the colour section as described in 6.4.12." |
1190 | | // FIXME: Implement support for colors one day. |
1191 | | |
1192 | | // "4) Decode each strip as follows: |
1193 | | // a) If NINSTANCES is equal to SBNUMINSTANCES then there are no more strips to decode, |
1194 | | // and the process of decoding the text region is complete; proceed to step 4)." |
1195 | | // Implementor's note. The spec means "proceed to step 5)" at the end of 4a). |
1196 | 146 | while (n_instances < inputs.number_of_instances) { |
1197 | | // "b) Decode the strip's delta T value as described in 6.4.6. Let DT be the decoded value. Set: |
1198 | | // STRIPT = STRIPT + DT" |
1199 | 11 | i32 delta_t = TRY(read_delta_t()); |
1200 | 0 | strip_t += delta_t; |
1201 | | |
1202 | 11 | i32 cur_s; |
1203 | 11 | bool is_first_symbol = true; |
1204 | 11 | while (true) { |
1205 | | // "c) Decode each symbol instance in the strip as follows: |
1206 | | // i) If the current symbol instance is the first symbol instance in the strip, then decode the first |
1207 | | // symbol instance's S coordinate as described in 6.4.7. Let DFS be the decoded value. Set: |
1208 | | // FIRSTS = FIRSTS + DFS |
1209 | | // CURS = FIRSTS |
1210 | | // ii) Otherwise, if the current symbol instance is not the first symbol instance in the strip, decode |
1211 | | // the symbol instance's S coordinate as described in 6.4.8. If the result of this decoding is OOB |
1212 | | // then the last symbol instance of the strip has been decoded; proceed to step 3 d). Otherwise, let |
1213 | | // IDS be the decoded value. Set: |
1214 | | // CURS = CURS + IDS + SBDSOFFSET" |
1215 | | // Implementor's note: The spec means "proceed to step 4 d)" in 4c ii). |
1216 | 11 | if (is_first_symbol) { |
1217 | 11 | i32 delta_first_s = TRY(read_first_s()); |
1218 | 0 | first_s += delta_first_s; |
1219 | 11 | cur_s = first_s; |
1220 | 11 | is_first_symbol = false; |
1221 | 11 | } else { |
1222 | 0 | auto subsequent_s = read_subsequent_s(); |
1223 | 0 | if (!subsequent_s.has_value()) |
1224 | 0 | break; |
1225 | 0 | i32 instance_delta_s = subsequent_s.value(); |
1226 | 0 | cur_s += instance_delta_s + inputs.delta_s_offset; |
1227 | 0 | } |
1228 | | |
1229 | | // "iii) Decode the symbol instance's T coordinate as described in 6.4.9. Let CURT be the decoded value. Set: |
1230 | | // TI = STRIPT + CURT" |
1231 | 11 | i32 cur_t = TRY(read_instance_t()); |
1232 | 0 | i32 t_instance = strip_t + cur_t; |
1233 | | |
1234 | | // "iv) Decode the symbol instance's symbol ID as described in 6.4.10. Let IDI be the decoded value." |
1235 | 11 | u32 id = id_decoder.decode(); |
1236 | | |
1237 | | // "v) Determine the symbol instance's bitmap IBI as described in 6.4.11. The width and height of this |
1238 | | // bitmap shall be denoted as WI and HI respectively." |
1239 | 11 | auto const& symbol = *TRY(read_bitmap(id)); |
1240 | | |
1241 | | // "vi) Update CURS as follows: |
1242 | | // • If TRANSPOSED is 0, and REFCORNER is TOPRIGHT or BOTTOMRIGHT, set: |
1243 | | // CURS = CURS + WI – 1 |
1244 | | // • If TRANSPOSED is 1, and REFCORNER is BOTTOMLEFT or BOTTOMRIGHT, set: |
1245 | | // CURS = CURS + HI – 1 |
1246 | | // • Otherwise, do not change CURS in this step." |
1247 | 0 | using enum TextRegionDecodingInputParameters::Corner; |
1248 | 0 | if (!inputs.is_transposed && (inputs.reference_corner == TopRight || inputs.reference_corner == BottomRight)) |
1249 | 0 | cur_s += symbol.width() - 1; |
1250 | 0 | if (inputs.is_transposed && (inputs.reference_corner == BottomLeft || inputs.reference_corner == BottomRight)) |
1251 | 0 | cur_s += symbol.height() - 1; |
1252 | | |
1253 | | // "vii) Set: |
1254 | | // SI = CURS" |
1255 | 0 | auto s_instance = cur_s; |
1256 | | |
1257 | | // "viii) Determine the location of the symbol instance bitmap with respect to SBREG as follows: |
1258 | | // • If TRANSPOSED is 0, then: |
1259 | | // – If REFCORNER is TOPLEFT then the top left pixel of the symbol instance bitmap |
1260 | | // IBI shall be placed at SBREG[SI, TI]. |
1261 | | // – If REFCORNER is TOPRIGHT then the top right pixel of the symbol instance |
1262 | | // bitmap IBI shall be placed at SBREG[SI, TI]. |
1263 | | // – If REFCORNER is BOTTOMLEFT then the bottom left pixel of the symbol |
1264 | | // instance bitmap IBI shall be placed at SBREG[SI, TI]. |
1265 | | // – If REFCORNER is BOTTOMRIGHT then the bottom right pixel of the symbol |
1266 | | // instance bitmap IBI shall be placed at SBREG[SI, TI]. |
1267 | | // • If TRANSPOSED is 1, then: |
1268 | | // – If REFCORNER is TOPLEFT then the top left pixel of the symbol instance bitmap |
1269 | | // IBI shall be placed at SBREG[TI, SI]. |
1270 | | // – If REFCORNER is TOPRIGHT then the top right pixel of the symbol instance |
1271 | | // bitmap IBI shall be placed at SBREG[TI, SI]. |
1272 | | // – If REFCORNER is BOTTOMLEFT then the bottom left pixel of the symbol |
1273 | | // instance bitmap IBI shall be placed at SBREG[TI, SI]. |
1274 | | // – If REFCORNER is BOTTOMRIGHT then the bottom right pixel of the symbol |
1275 | | // instance bitmap IBI shall be placed at SBREG[TI, SI]. |
1276 | | // If any part of IBI, when placed at this location, lies outside the bounds of SBREG, then ignore |
1277 | | // this part of IBI in step 3 c) ix)." |
1278 | | // Implementor's note: The spec means "ignore this part of IBI in step 3 c) x)" in 3c viii)'s last sentence. |
1279 | 0 | if (inputs.is_transposed) |
1280 | 0 | swap(s_instance, t_instance); |
1281 | 0 | if (inputs.reference_corner == TopRight || inputs.reference_corner == BottomRight) |
1282 | 0 | s_instance -= symbol.width() - 1; |
1283 | 0 | if (inputs.reference_corner == BottomLeft || inputs.reference_corner == BottomRight) |
1284 | 0 | t_instance -= symbol.height() - 1; |
1285 | | |
1286 | | // "ix) If COLEXTFLAG is 1, set the colour specified by SBCOLS[SBFGCOLID[NINSTANCES]] |
1287 | | // to the foreground colour of the symbol instance bitmap IBI." |
1288 | | // FIXME: Implement support for colors one day. |
1289 | | |
1290 | | // "x) Draw IBI into SBREG. Combine each pixel of IBI with the current value of the corresponding |
1291 | | // pixel in SBREG, using the combination operator specified by SBCOMBOP. Write the results |
1292 | | // of each combination into that pixel in SBREG." |
1293 | 0 | dbgln_if(JBIG2_DEBUG, "combining symbol {} ({}x{}) at ({}, {}) with operator {}", id, symbol.width(), symbol.height(), s_instance, t_instance, (int)inputs.operator_); |
1294 | 0 | composite_bitbuffer(*result, symbol, { s_instance, t_instance }, inputs.operator_); |
1295 | | |
1296 | | // "xi) Update CURS as follows: |
1297 | | // • If TRANSPOSED is 0, and REFCORNER is TOPLEFT or BOTTOMLEFT, set: |
1298 | | // CURS = CURS + WI – 1 |
1299 | | // • If TRANSPOSED is 1, and REFCORNER is TOPLEFT or TOPRIGHT, set: |
1300 | | // CURS = CURS + HI – 1 |
1301 | | // • Otherwise, do not change CURS in this step." |
1302 | 0 | if (!inputs.is_transposed && (inputs.reference_corner == TopLeft || inputs.reference_corner == BottomLeft)) |
1303 | 0 | cur_s += symbol.width() - 1; |
1304 | 0 | if (inputs.is_transposed && (inputs.reference_corner == TopLeft || inputs.reference_corner == TopRight)) |
1305 | 0 | cur_s += symbol.height() - 1; |
1306 | | |
1307 | | // "xii) Set: |
1308 | | // NINSTANCES = NINSTANCES + 1" |
1309 | 0 | ++n_instances; |
1310 | 0 | } |
1311 | | // "d) When the strip has been completely decoded, decode the next strip." |
1312 | | // (Done in the next loop iteration.) |
1313 | 11 | } |
1314 | | |
1315 | | // "5) After all the strips have been decoded, the current contents of SBREG are the results that shall be |
1316 | | // obtained by every decoder, whether it performs this exact sequence of steps or not." |
1317 | 135 | return result; |
1318 | 146 | } |
1319 | | |
1320 | | // 6.5.2 Input parameters |
1321 | | // Table 13 – Parameters for the symbol dictionary decoding procedure |
1322 | | struct SymbolDictionaryDecodingInputParameters { |
1323 | | |
1324 | | bool uses_huffman_encoding { false }; // "SDHUFF" in spec. |
1325 | | bool uses_refinement_or_aggregate_coding { false }; // "SDREFAGG" in spec. |
1326 | | |
1327 | | Vector<NonnullRefPtr<Symbol>> input_symbols; // "SDNUMINSYMS", "SDINSYMS" in spec. |
1328 | | |
1329 | | u32 number_of_new_symbols { 0 }; // "SDNUMNEWSYMS" in spec. |
1330 | | u32 number_of_exported_symbols { 0 }; // "SDNUMEXSYMS" in spec. |
1331 | | |
1332 | | // FIXME: SDHUFFDH, SDHUFFDW, SDHUFFBMSIZE, SDHUFFAGGINST |
1333 | | |
1334 | | u8 symbol_template { 0 }; // "SDTEMPLATE" in spec. |
1335 | | Array<AdaptiveTemplatePixel, 4> adaptive_template_pixels; // "SDATX" / "SDATY" in spec. |
1336 | | |
1337 | | u8 refinement_template { 0 }; // "SDRTEMPLATE" in spec; |
1338 | | Array<AdaptiveTemplatePixel, 2> refinement_adaptive_template_pixels; // "SDRATX" / "SDRATY" in spec. |
1339 | | }; |
1340 | | |
1341 | | // 6.5 Symbol Dictionary Decoding Procedure |
1342 | | static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedure(SymbolDictionaryDecodingInputParameters const& inputs, ReadonlyBytes data) |
1343 | 0 | { |
1344 | 0 | if (inputs.uses_huffman_encoding) |
1345 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode huffman symbol dictionaries yet"); |
1346 | | |
1347 | 0 | auto decoder = TRY(QMArithmeticDecoder::initialize(data)); |
1348 | 0 | Vector<QMArithmeticDecoder::Context> contexts; |
1349 | 0 | contexts.resize(1 << number_of_context_bits_for_template(inputs.symbol_template)); |
1350 | | |
1351 | | // 6.5.6 Height class delta height |
1352 | | // "If SDHUFF is 1, decode a value using the Huffman table specified by SDHUFFDH. |
1353 | | // If SDHUFF is 0, decode a value using the IADH integer arithmetic decoding procedure (see Annex A)." |
1354 | | // FIXME: Implement support for SDHUFF = 1. |
1355 | 0 | JBIG2::ArithmeticIntegerDecoder delta_height_integer_decoder(decoder); |
1356 | 0 | auto read_delta_height = [&]() -> ErrorOr<i32> { |
1357 | 0 | return delta_height_integer_decoder.decode_non_oob(); |
1358 | 0 | }; |
1359 | | |
1360 | | // 6.5.7 Delta width |
1361 | | // "If SDHUFF is 1, decode a value using the Huffman table specified by SDHUFFDW. |
1362 | | // If SDHUFF is 0, decode a value using the IADW integer arithmetic decoding procedure (see Annex A). |
1363 | | // In either case it is possible that the result of this decoding is the out-of-band value OOB." |
1364 | | // FIXME: Implement support for SDHUFF = 1. |
1365 | 0 | JBIG2::ArithmeticIntegerDecoder delta_width_integer_decoder(decoder); |
1366 | 0 | auto read_delta_width = [&]() -> Optional<i32> { |
1367 | 0 | return delta_width_integer_decoder.decode(); |
1368 | 0 | }; |
1369 | | |
1370 | | // 6.5.8 Symbol bitmap |
1371 | | // "This field is only present if SDHUFF = 0 or SDREFAGG = 1. This field takes one of two forms; SDREFAGG |
1372 | | // determines which form is used." |
1373 | | |
1374 | | // 6.5.8.2.1 Number of symbol instances in aggregation |
1375 | | // If SDHUFF is 1, decode a value using the Huffman table specified by SDHUFFAGGINST. |
1376 | | // If SDHUFF is 0, decode a value using the IAAI integer arithmetic decoding procedure (see Annex A). |
1377 | | // FIXME: Implement support for SDHUFF = 1. |
1378 | 0 | Optional<JBIG2::ArithmeticIntegerDecoder> number_of_symbol_instances_decoder; |
1379 | 0 | auto read_number_of_symbol_instances = [&]() -> ErrorOr<i32> { |
1380 | 0 | if (!number_of_symbol_instances_decoder.has_value()) |
1381 | 0 | number_of_symbol_instances_decoder = JBIG2::ArithmeticIntegerDecoder(decoder); |
1382 | 0 | return number_of_symbol_instances_decoder->decode_non_oob(); |
1383 | 0 | }; |
1384 | | |
1385 | | // 6.5.8.1 Direct-coded symbol bitmap |
1386 | 0 | Optional<JBIG2::ArithmeticIntegerIDDecoder> id_decoder; |
1387 | 0 | Optional<JBIG2::ArithmeticIntegerDecoder> refinement_x_offset_decoder; |
1388 | 0 | Optional<JBIG2::ArithmeticIntegerDecoder> refinement_y_offset_decoder; |
1389 | | |
1390 | | // FIXME: When we implement REFAGGNINST > 1 support, do these need to be shared with |
1391 | | // text_region_decoding_procedure() then? |
1392 | 0 | Vector<QMArithmeticDecoder::Context> refinement_contexts; |
1393 | | |
1394 | | // This belongs in 6.5.5 1) below, but also needs to be captured by read_bitmap here. |
1395 | 0 | Vector<NonnullRefPtr<Symbol>> new_symbols; |
1396 | |
|
1397 | 0 | auto read_symbol_bitmap = [&](u32 width, u32 height) -> ErrorOr<NonnullOwnPtr<BitBuffer>> { |
1398 | | // "If SDREFAGG is 0, then decode the symbol's bitmap using a generic region decoding procedure as described in 6.2. |
1399 | | // Set the parameters to this decoding procedure as shown in Table 16." |
1400 | 0 | if (!inputs.uses_refinement_or_aggregate_coding) { |
1401 | | // Table 16 – Parameters used to decode a symbol's bitmap using generic bitmap decoding |
1402 | 0 | GenericRegionDecodingInputParameters generic_inputs; |
1403 | 0 | generic_inputs.is_modified_modified_read = false; |
1404 | 0 | generic_inputs.region_width = width; |
1405 | 0 | generic_inputs.region_height = height; |
1406 | 0 | generic_inputs.gb_template = inputs.symbol_template; |
1407 | 0 | generic_inputs.is_extended_reference_template_used = false; // Missing from spec in table 16. |
1408 | 0 | for (int i = 0; i < 4; ++i) |
1409 | 0 | generic_inputs.adaptive_template_pixels[i] = inputs.adaptive_template_pixels[i]; |
1410 | 0 | generic_inputs.arithmetic_decoder = &decoder; |
1411 | 0 | return generic_region_decoding_procedure(generic_inputs, {}, contexts); |
1412 | 0 | } |
1413 | | |
1414 | | // 6.5.8.2 Refinement/aggregate-coded symbol bitmap |
1415 | | // "1) Decode the number of symbol instances contained in the aggregation, as specified in 6.5.8.2.1. Let REFAGGNINST be the value decoded." |
1416 | 0 | auto number_of_symbol_instances = TRY(read_number_of_symbol_instances()); // "REFAGGNINST" in spec. |
1417 | 0 | dbgln_if(JBIG2_DEBUG, "Number of symbol instances: {}", number_of_symbol_instances); |
1418 | |
|
1419 | 0 | if (number_of_symbol_instances > 1) { |
1420 | | // "2) If REFAGGNINST is greater than one, then decode the bitmap itself using a text region decoding procedure |
1421 | | // as described in 6.4. Set the parameters to this decoding procedure as shown in Table 17." |
1422 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode symbol bitmaps with more than one symbol instance yet"); |
1423 | 0 | } |
1424 | | |
1425 | | // "3) If REFAGGNINST is equal to one, then decode the bitmap as described in 6.5.8.2.2." |
1426 | | |
1427 | | // 6.5.8.2.3 Setting SBSYMCODES and SBSYMCODELEN |
1428 | | // FIXME: Implement support for SDHUFF = 1 |
1429 | 0 | u32 code_length = ceil(log2(inputs.input_symbols.size() + inputs.number_of_new_symbols)); |
1430 | | |
1431 | | // 6.5.8.2.2 Decoding a bitmap when REFAGGNINST = 1 |
1432 | | // FIXME: This is missing some steps for the SDHUFF = 1 case. |
1433 | 0 | if (number_of_symbol_instances != 1) |
1434 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Unexpected number of symbol instances"); |
1435 | | |
1436 | 0 | if (!id_decoder.has_value()) |
1437 | 0 | id_decoder = JBIG2::ArithmeticIntegerIDDecoder(decoder, code_length); |
1438 | 0 | u32 symbol_id = id_decoder->decode(); |
1439 | |
|
1440 | 0 | if (!refinement_x_offset_decoder.has_value()) |
1441 | 0 | refinement_x_offset_decoder = JBIG2::ArithmeticIntegerDecoder(decoder); |
1442 | 0 | i32 refinement_x_offset = TRY(refinement_x_offset_decoder->decode_non_oob()); |
1443 | | |
1444 | 0 | if (!refinement_y_offset_decoder.has_value()) |
1445 | 0 | refinement_y_offset_decoder = JBIG2::ArithmeticIntegerDecoder(decoder); |
1446 | 0 | i32 refinement_y_offset = TRY(refinement_y_offset_decoder->decode_non_oob()); |
1447 | | |
1448 | 0 | if (symbol_id >= inputs.input_symbols.size() && symbol_id - inputs.input_symbols.size() >= new_symbols.size()) |
1449 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Refinement/aggregate symbol ID out of range"); |
1450 | | |
1451 | 0 | auto IBO = (symbol_id < inputs.input_symbols.size()) ? inputs.input_symbols[symbol_id] : new_symbols[symbol_id - inputs.input_symbols.size()]; |
1452 | | // Table 18 – Parameters used to decode a symbol's bitmap when REFAGGNINST = 1 |
1453 | 0 | GenericRefinementRegionDecodingInputParameters refinement_inputs; |
1454 | 0 | refinement_inputs.region_width = width; |
1455 | 0 | refinement_inputs.region_height = height; |
1456 | 0 | refinement_inputs.gr_template = inputs.refinement_template; |
1457 | 0 | refinement_inputs.reference_bitmap = &IBO->bitmap(); |
1458 | 0 | refinement_inputs.reference_x_offset = refinement_x_offset; |
1459 | 0 | refinement_inputs.reference_y_offset = refinement_y_offset; |
1460 | 0 | refinement_inputs.is_typical_prediction_used = false; |
1461 | 0 | refinement_inputs.adaptive_template_pixels = inputs.refinement_adaptive_template_pixels; |
1462 | 0 | if (refinement_contexts.is_empty()) |
1463 | 0 | refinement_contexts.resize(1 << (inputs.refinement_template == 0 ? 13 : 10)); |
1464 | 0 | return generic_refinement_region_decoding_procedure(refinement_inputs, decoder, refinement_contexts); |
1465 | 0 | }; |
1466 | | |
1467 | | // 6.5.5 Decoding the symbol dictionary |
1468 | | // "1) Create an array SDNEWSYMS of bitmaps, having SDNUMNEWSYMS entries." |
1469 | | // Done above read_symbol_bitmap's definition. |
1470 | | |
1471 | | // "2) If SDHUFF is 1 and SDREFAGG is 0, create an array SDNEWSYMWIDTHS of integers, having SDNUMNEWSYMS entries." |
1472 | | // FIXME: Implement support for SDHUFF = 1. |
1473 | | |
1474 | | // "3) Set: |
1475 | | // HCHEIGHT = 0 |
1476 | | // NSYMSDECODED = 0" |
1477 | 0 | u32 height_class_height = 0; |
1478 | 0 | u32 number_of_symbols_decoded = 0; |
1479 | | |
1480 | | // "4) Decode each height class as follows: |
1481 | | // a) If NSYMSDECODED == SDNUMNEWSYMS then all the symbols in the dictionary have been decoded; proceed to step 5)." |
1482 | 0 | while (number_of_symbols_decoded < inputs.number_of_new_symbols) { |
1483 | | // "b) Decode the height class delta height as described in 6.5.6. Let HCDH be the decoded value. Set: |
1484 | | // HCHEIGHT = HCEIGHT + HCDH |
1485 | | // SYMWIDTH = 0 |
1486 | | // TOTWIDTH = 0 |
1487 | | // HCFIRSTSYM = NSYMSDECODED" |
1488 | 0 | i32 delta_height = TRY(read_delta_height()); |
1489 | 0 | height_class_height += delta_height; |
1490 | 0 | u32 symbol_width = 0; |
1491 | 0 | u32 total_width = 0; |
1492 | 0 | u32 height_class_first_symbol = number_of_symbols_decoded; |
1493 | | // "c) Decode each symbol within the height class as follows:" |
1494 | 0 | while (true) { |
1495 | | // "i) Decode the delta width for the symbol as described in 6.5.7." |
1496 | 0 | auto opt_delta_width = read_delta_width(); |
1497 | | // " If the result of this decoding is OOB then all the symbols in this height class have been decoded; proceed to step 4 d)." |
1498 | 0 | if (!opt_delta_width.has_value()) |
1499 | 0 | break; |
1500 | | |
1501 | 0 | VERIFY(number_of_symbols_decoded < inputs.number_of_new_symbols); |
1502 | | // " Otherwise let DW be the decoded value and set:" |
1503 | | // SYMWIDTH = SYMWIDTH + DW |
1504 | | // TOTWIDTH = TOTWIDTH + SYMWIDTH" |
1505 | 0 | i32 delta_width = opt_delta_width.value(); |
1506 | 0 | symbol_width += delta_width; |
1507 | 0 | total_width += symbol_width; |
1508 | | |
1509 | | // "ii) If SDHUFF is 0 or SDREFAGG is 1, then decode the symbol's bitmap as described in 6.5.8. |
1510 | | // Let BS be the decoded bitmap (this bitmap has width SYMWIDTH and height HCHEIGHT). Set: |
1511 | | // SDNEWSYMS[NSYMSDECODED] = BS" |
1512 | | // FIXME: Implement support for SDHUFF = 1. |
1513 | | // FIXME: Doing this eagerly is pretty wasteful. Decode on demand instead? |
1514 | 0 | auto bitmap = TRY(read_symbol_bitmap(symbol_width, height_class_height)); |
1515 | 0 | new_symbols.append(Symbol::create(move(bitmap))); |
1516 | | |
1517 | | // "iii) If SDHUFF is 1 and SDREFAGG is 0, then set: |
1518 | | // SDNEWSYMWIDTHS[NSYMSDECODED] = SYMWIDTH" |
1519 | | // FIXME: Implement support for SDHUFF = 1. |
1520 | 0 | (void)total_width; |
1521 | 0 | (void)height_class_first_symbol; |
1522 | | |
1523 | | // "iv) Set: |
1524 | | // NSYMSDECODED = NSYMSDECODED + 1" |
1525 | 0 | number_of_symbols_decoded++; |
1526 | 0 | } |
1527 | | // "d) If SDHUFF is 1 and SDREFAGG is 0, [...long text elided...]" |
1528 | | // FIXME: Implement support for SDHUFF = 1. |
1529 | 0 | } |
1530 | | |
1531 | | // "5) Determine which symbol bitmaps are exported from this symbol dictionary, as described in 6.5.10. These |
1532 | | // bitmaps can be drawn from the symbols that are used as input to the symbol dictionary decoding |
1533 | | // procedure as well as the new symbols produced by the decoding procedure." |
1534 | 0 | JBIG2::ArithmeticIntegerDecoder export_integer_decoder(decoder); |
1535 | | |
1536 | | // 6.5.10 Exported symbols |
1537 | 0 | Vector<bool> export_flags; |
1538 | 0 | export_flags.resize(inputs.input_symbols.size() + inputs.number_of_new_symbols); |
1539 | | |
1540 | | // "1) Set: |
1541 | | // EXINDEX = 0 |
1542 | | // CUREXFLAG = 0" |
1543 | 0 | u32 exported_index = 0; |
1544 | 0 | bool current_export_flag = false; |
1545 | |
|
1546 | 0 | do { |
1547 | | // "2) Decode a value using Table B.1 if SDHUFF is 1, or the IAEX integer arithmetic decoding procedure if |
1548 | | // SDHUFF is 0. Let EXRUNLENGTH be the decoded value." |
1549 | | // FIXME: Implement support for SDHUFF = 1. |
1550 | 0 | i32 export_run_length = TRY(export_integer_decoder.decode_non_oob()); |
1551 | | |
1552 | | // "3) Set EXFLAGS[EXINDEX] through EXFLAGS[EXINDEX + EXRUNLENGTH – 1] to CUREXFLAG. |
1553 | | // If EXRUNLENGTH = 0, then this step does not change any values." |
1554 | 0 | for (int i = 0; i < export_run_length; ++i) |
1555 | 0 | export_flags[exported_index + i] = current_export_flag; |
1556 | | |
1557 | | // "4) Set: |
1558 | | // EXINDEX = EXINDEX + EXRUNLENGTH |
1559 | | // CUREXFLAG = NOT(CUREXFLAG)" |
1560 | 0 | exported_index += export_run_length; |
1561 | 0 | current_export_flag = !current_export_flag; |
1562 | | |
1563 | | // 5) Repeat steps 2) through 4) until EXINDEX == SDNUMINSYMS + SDNUMNEWSYMS. |
1564 | 0 | } while (exported_index < inputs.input_symbols.size() + inputs.number_of_new_symbols); |
1565 | | |
1566 | | // "6) The array EXFLAGS now contains 1 for each symbol that is exported from the dictionary, and 0 for each |
1567 | | // symbol that is not exported." |
1568 | 0 | Vector<NonnullRefPtr<Symbol>> exported_symbols; |
1569 | | |
1570 | | // "7) Set: |
1571 | | // I = 0 |
1572 | | // J = 0 |
1573 | | // 8) For each value of I from 0 to SDNUMINSYMS + SDNUMNEWSYMS – 1," |
1574 | 0 | for (size_t i = 0; i < inputs.input_symbols.size() + inputs.number_of_new_symbols; ++i) { |
1575 | | // "if EXFLAGS[I] == 1 then perform the following steps:" |
1576 | 0 | if (!export_flags[i]) |
1577 | 0 | continue; |
1578 | | // "a) If I < SDNUMINSYMS then set: |
1579 | | // SDEXSYMS[J] = SDINSYMS[I] |
1580 | | // J = J + 1" |
1581 | 0 | if (i < inputs.input_symbols.size()) |
1582 | 0 | exported_symbols.append(inputs.input_symbols[i]); |
1583 | | |
1584 | | // "b) If I >= SDNUMINSYMS then set: |
1585 | | // SDEXSYMS[J] = SDNEWSYMS[I – SDNUMINSYMS] |
1586 | | // J = J + 1" |
1587 | 0 | if (i >= inputs.input_symbols.size()) |
1588 | 0 | exported_symbols.append(move(new_symbols[i - inputs.input_symbols.size()])); |
1589 | 0 | } |
1590 | |
|
1591 | 0 | if (exported_symbols.size() != inputs.number_of_exported_symbols) |
1592 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Unexpected number of exported symbols"); |
1593 | | |
1594 | 0 | return exported_symbols; |
1595 | 0 | } |
1596 | | |
1597 | | // Annex C Gray-scale image decoding procedure |
1598 | | |
1599 | | // C.2 Input parameters |
1600 | | // Table C.1 – Parameters for the gray-scale image decoding procedure |
1601 | | struct GrayscaleInputParameters { |
1602 | | bool uses_mmr { false }; // "GSMMR" in spec. |
1603 | | |
1604 | | Optional<BitBuffer const&> skip_pattern; // "GSUSESKIP" / "GSKIP" in spec. |
1605 | | |
1606 | | u8 bpp { 0 }; // "GSBPP" in spec. |
1607 | | u32 width { 0 }; // "GSW" in spec. |
1608 | | u32 height { 0 }; // "GSH" in spec. |
1609 | | u8 template_id { 0 }; // "GSTEMPLATE" in spec. |
1610 | | |
1611 | | // If uses_mmr is false, grayscale_image_decoding_procedure() reads data off this decoder. |
1612 | | QMArithmeticDecoder* arithmetic_decoder { nullptr }; |
1613 | | }; |
1614 | | |
1615 | | static ErrorOr<Vector<u8>> grayscale_image_decoding_procedure(GrayscaleInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts) |
1616 | 0 | { |
1617 | | // FIXME: Support this. generic_region_decoding_procedure() currently doesn't tell us how much data it |
1618 | | // reads for MMR bitmaps, so we can't currently read more than one MMR bitplane here. |
1619 | 0 | if (inputs.uses_mmr) |
1620 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode MMR grayscale images yet"); |
1621 | | |
1622 | | // Table C.4 – Parameters used to decode a bitplane of the gray-scale image |
1623 | 0 | GenericRegionDecodingInputParameters generic_inputs; |
1624 | 0 | generic_inputs.is_modified_modified_read = inputs.uses_mmr; |
1625 | 0 | generic_inputs.region_width = inputs.width; |
1626 | 0 | generic_inputs.region_height = inputs.height; |
1627 | 0 | generic_inputs.gb_template = inputs.template_id; |
1628 | 0 | generic_inputs.is_typical_prediction_used = false; |
1629 | 0 | generic_inputs.is_extended_reference_template_used = false; // Missing from spec. |
1630 | 0 | generic_inputs.skip_pattern = inputs.skip_pattern; |
1631 | 0 | generic_inputs.adaptive_template_pixels[0].x = inputs.template_id <= 1 ? 3 : 2; |
1632 | 0 | generic_inputs.adaptive_template_pixels[0].y = -1; |
1633 | 0 | generic_inputs.adaptive_template_pixels[1].x = -3; |
1634 | 0 | generic_inputs.adaptive_template_pixels[1].y = -1; |
1635 | 0 | generic_inputs.adaptive_template_pixels[2].x = 2; |
1636 | 0 | generic_inputs.adaptive_template_pixels[2].y = -2; |
1637 | 0 | generic_inputs.adaptive_template_pixels[3].x = -2; |
1638 | 0 | generic_inputs.adaptive_template_pixels[3].y = -2; |
1639 | 0 | generic_inputs.arithmetic_decoder = inputs.arithmetic_decoder; |
1640 | | |
1641 | | // C.5 Decoding the gray-scale image |
1642 | | // "The gray-scale image is obtained by decoding GSBPP bitplanes. These bitplanes are denoted (from least significant to |
1643 | | // most significant) GSPLANES[0], GSPLANES[1], . . . , GSPLANES[GSBPP – 1]. The bitplanes are Gray-coded, so |
1644 | | // that each bitplane's true value is equal to its coded value XORed with the next-more-significant bitplane." |
1645 | 0 | Vector<OwnPtr<BitBuffer>> bitplanes; |
1646 | 0 | bitplanes.resize(inputs.bpp); |
1647 | | |
1648 | | // "1) Decode GSPLANES[GSBPP – 1] using the generic region decoding procedure. The parameters to the |
1649 | | // generic region decoding procedure are as shown in Table C.4." |
1650 | 0 | bitplanes[inputs.bpp - 1] = TRY(generic_region_decoding_procedure(generic_inputs, data, contexts)); |
1651 | | |
1652 | | // "2) Set J = GSBPP – 2." |
1653 | 0 | int j = inputs.bpp - 2; |
1654 | | |
1655 | | // "3) While J >= 0, perform the following steps:" |
1656 | 0 | while (j >= 0) { |
1657 | | // "a) Decode GSPLANES[J] using the generic region decoding procedure. The parameters to the generic |
1658 | | // region decoding procedure are as shown in Table C.4." |
1659 | 0 | bitplanes[j] = TRY(generic_region_decoding_procedure(generic_inputs, data, contexts)); |
1660 | | |
1661 | | // "b) For each pixel (x, y) in GSPLANES[J], set: |
1662 | | // GSPLANES[J][x, y] = GSPLANES[J + 1][x, y] XOR GSPLANES[J][x, y]" |
1663 | 0 | for (u32 y = 0; y < inputs.height; ++y) { |
1664 | 0 | for (u32 x = 0; x < inputs.width; ++x) { |
1665 | 0 | bool bit = bitplanes[j + 1]->get_bit(x, y) ^ bitplanes[j]->get_bit(x, y); |
1666 | 0 | bitplanes[j]->set_bit(x, y, bit); |
1667 | 0 | } |
1668 | 0 | } |
1669 | | |
1670 | | // "c) Set J = J – 1." |
1671 | 0 | j = j - 1; |
1672 | 0 | } |
1673 | | |
1674 | | // "4) For each (x, y), set: |
1675 | | // GSVALS [x, y] = sum_{J = 0}^{GSBPP - 1} GSPLANES[J][x,y] × 2**J)" |
1676 | 0 | Vector<u8> result; |
1677 | 0 | result.resize(inputs.width * inputs.height); |
1678 | 0 | for (u32 y = 0; y < inputs.height; ++y) { |
1679 | 0 | for (u32 x = 0; x < inputs.width; ++x) { |
1680 | 0 | u8 value = 0; |
1681 | 0 | for (int j = 0; j < inputs.bpp; ++j) { |
1682 | 0 | if (bitplanes[j]->get_bit(x, y)) |
1683 | 0 | value |= 1 << j; |
1684 | 0 | } |
1685 | 0 | result[y * inputs.width + x] = value; |
1686 | 0 | } |
1687 | 0 | } |
1688 | 0 | return result; |
1689 | 0 | } |
1690 | | |
1691 | | // 6.6.2 Input parameters |
1692 | | // Table 20 – Parameters for the halftone region decoding procedure |
1693 | | struct HalftoneRegionDecodingInputParameters { |
1694 | | u32 region_width { 0 }; // "HBW" in spec. |
1695 | | u32 region_height { 0 }; // "HBH" in spec. |
1696 | | bool uses_mmr { false }; // "HMMR" in spec. |
1697 | | u8 halftone_template { 0 }; // "HTEMPLATE" in spec. |
1698 | | Vector<NonnullRefPtr<Symbol>> patterns; // "HNUMPATS" / "HPATS" in spec. |
1699 | | bool default_pixel_value { false }; // "HDEFPIXEL" in spec. |
1700 | | CombinationOperator combination_operator { CombinationOperator::Or }; // "HCOMBOP" in spec. |
1701 | | bool enable_skip { false }; // "HENABLESKIP" in spec. |
1702 | | u32 grayscale_width { 0 }; // "HGW" in spec. |
1703 | | u32 grayscale_height { 0 }; // "HGH" in spec. |
1704 | | i32 grid_origin_x_offset { 0 }; // "HGX" in spec. |
1705 | | i32 grid_origin_y_offset { 0 }; // "HGY" in spec. |
1706 | | u16 grid_vector_x { 0 }; // "HRY" in spec. |
1707 | | u16 grid_vector_y { 0 }; // "HRX" in spec. |
1708 | | u8 pattern_width { 0 }; // "HPW" in spec. |
1709 | | u8 pattern_height { 0 }; // "HPH" in spec. |
1710 | | }; |
1711 | | |
1712 | | // 6.6 Halftone Region Decoding Procedure |
1713 | | static ErrorOr<NonnullOwnPtr<BitBuffer>> halftone_region_decoding_procedure(HalftoneRegionDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts) |
1714 | 0 | { |
1715 | | // 6.6.5 Decoding the halftone region |
1716 | | // "1) Fill a bitmap HTREG, of the size given by HBW and HBH, with the HDEFPIXEL value." |
1717 | 0 | auto result = TRY(BitBuffer::create(inputs.region_width, inputs.region_height)); |
1718 | 0 | result->fill(inputs.default_pixel_value); |
1719 | | |
1720 | | // "2) If HENABLESKIP equals 1, compute a bitmap HSKIP as shown in 6.6.5.1." |
1721 | 0 | Optional<BitBuffer const&> skip_pattern; |
1722 | 0 | OwnPtr<BitBuffer> skip_pattern_storage; |
1723 | 0 | if (inputs.enable_skip) { |
1724 | | // FIXME: This is untested; I haven't found a sample that uses HENABLESKIP yet. |
1725 | | // But generic_region_decoding_procedure() currently doesn't implement skip_pattern anyways |
1726 | | // and errors out on it, so we'll notice when this gets hit. |
1727 | 0 | skip_pattern_storage = TRY(BitBuffer::create(inputs.pattern_width, inputs.pattern_height)); |
1728 | 0 | skip_pattern = *skip_pattern_storage; |
1729 | | |
1730 | | // 6.6.5.1 Computing HSKIP |
1731 | | // "1) For each value of mg between 0 and HGH – 1, beginning from 0, perform the following steps:" |
1732 | 0 | for (int m_g = 0; m_g < (int)inputs.grayscale_height; ++m_g) { |
1733 | | // "a) For each value of ng between 0 and HGW – 1, beginning from 0, perform the following steps:" |
1734 | 0 | for (int n_g = 0; n_g < (int)inputs.grayscale_width; ++n_g) { |
1735 | | // "i) Set: |
1736 | | // x = (HGX + m_g × HRY + n_g × HRX) >> 8 |
1737 | | // y = (HGY + m_g × HRX – n_g × HRY) >> 8" |
1738 | 0 | auto x = (inputs.grid_origin_x_offset + m_g * inputs.grid_vector_y + n_g * inputs.grid_vector_x) >> 8; |
1739 | 0 | auto y = (inputs.grid_origin_y_offset + m_g * inputs.grid_vector_x - n_g * inputs.grid_vector_y) >> 8; |
1740 | | |
1741 | | // "ii) If ((x + HPW <= 0) OR (x >= HBW) OR (y + HPH <= 0) OR (y >= HBH)) then set: |
1742 | | // HSKIP[n_g, m_g] = 1 |
1743 | | // Otherwise, set: |
1744 | | // HSKIP[n_g, m_g] = 0" |
1745 | 0 | if (x + inputs.pattern_width <= 0 || x >= (int)inputs.region_width || y + inputs.pattern_height <= 0 || y >= (int)inputs.region_height) |
1746 | 0 | skip_pattern_storage->set_bit(n_g, m_g, true); |
1747 | 0 | else |
1748 | 0 | skip_pattern_storage->set_bit(n_g, m_g, false); |
1749 | 0 | } |
1750 | 0 | } |
1751 | 0 | } |
1752 | | |
1753 | | // "3) Set HBPP to ⌈log2 (HNUMPATS)⌉." |
1754 | 0 | u8 bits_per_pattern = ceil(log2(inputs.patterns.size())); |
1755 | | |
1756 | | // "4) Decode an image GI of size HGW by HGH with HBPP bits per pixel using the gray-scale image decoding |
1757 | | // procedure as described in Annex C. Set the parameters to this decoding procedure as shown in Table 23. |
1758 | | // Let GI be the results of invoking this decoding procedure." |
1759 | 0 | GrayscaleInputParameters grayscale_inputs; |
1760 | 0 | grayscale_inputs.uses_mmr = inputs.uses_mmr; |
1761 | 0 | grayscale_inputs.width = inputs.grayscale_width; |
1762 | 0 | grayscale_inputs.height = inputs.grayscale_height; |
1763 | 0 | grayscale_inputs.bpp = bits_per_pattern; |
1764 | 0 | grayscale_inputs.skip_pattern = skip_pattern; |
1765 | 0 | grayscale_inputs.template_id = inputs.halftone_template; |
1766 | |
|
1767 | 0 | Optional<QMArithmeticDecoder> decoder; |
1768 | 0 | if (!inputs.uses_mmr) { |
1769 | 0 | decoder = TRY(QMArithmeticDecoder::initialize(data)); |
1770 | 0 | grayscale_inputs.arithmetic_decoder = &decoder.value(); |
1771 | 0 | } |
1772 | | |
1773 | 0 | auto grayscale_image = TRY(grayscale_image_decoding_procedure(grayscale_inputs, data, contexts)); |
1774 | | |
1775 | | // "5) Place sequentially the patterns corresponding to the values in GI into HTREG by the procedure described in 6.6.5.2. |
1776 | | // The rendering procedure is illustrated in Figure 26. The outline of two patterns are marked by dotted boxes." |
1777 | 0 | { |
1778 | | // 6.6.5.2 Rendering the patterns |
1779 | | // "Draw the patterns into HTREG using the following procedure: |
1780 | | // 1) For each value of m_g between 0 and HGH – 1, beginning from 0, perform the following steps." |
1781 | 0 | for (int m_g = 0; m_g < (int)inputs.grayscale_height; ++m_g) { |
1782 | | // "a) For each value of n_g between 0 and HGW – 1, beginning from 0, perform the following steps." |
1783 | 0 | for (int n_g = 0; n_g < (int)inputs.grayscale_width; ++n_g) { |
1784 | | // "i) Set: |
1785 | | // x = (HGX + m_g × HRY + n_g × HRX) >> 8 |
1786 | | // y = (HGY + m_g × HRX – n_g × HRY) >> 8" |
1787 | 0 | auto x = (inputs.grid_origin_x_offset + m_g * inputs.grid_vector_y + n_g * inputs.grid_vector_x) >> 8; |
1788 | 0 | auto y = (inputs.grid_origin_y_offset + m_g * inputs.grid_vector_x - n_g * inputs.grid_vector_y) >> 8; |
1789 | | |
1790 | | // "ii) Draw the pattern HPATS[GI[n_g, m_g]] into HTREG such that its upper left pixel is at location (x, y) in HTREG. |
1791 | | // |
1792 | | // A pattern is drawn into HTREG as follows. Each pixel of the pattern shall be combined with |
1793 | | // the current value of the corresponding pixel in the halftone-coded bitmap, using the |
1794 | | // combination operator specified by HCOMBOP. The results of each combination shall be |
1795 | | // written into that pixel in the halftone-coded bitmap. |
1796 | | // |
1797 | | // If any part of a decoded pattern, when placed at location (x, y) lies outside the actual halftone- |
1798 | | // coded bitmap, then this part of the pattern shall be ignored in the process of combining the |
1799 | | // pattern with the bitmap." |
1800 | 0 | u8 grayscale_value = grayscale_image[n_g + m_g * inputs.grayscale_width]; |
1801 | 0 | if (grayscale_value >= inputs.patterns.size()) |
1802 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Grayscale value out of range"); |
1803 | 0 | auto const& pattern = inputs.patterns[grayscale_value]; |
1804 | 0 | composite_bitbuffer(*result, pattern->bitmap(), { x, y }, inputs.combination_operator); |
1805 | 0 | } |
1806 | 0 | } |
1807 | 0 | } |
1808 | | |
1809 | | // "6) After all the patterns have been placed on the bitmap, the current contents of the halftone-coded bitmap are |
1810 | | // the results that shall be obtained by every decoder, whether it performs this exact sequence of steps or not." |
1811 | 0 | return result; |
1812 | 0 | } |
1813 | | |
1814 | | // 6.7.2 Input parameters |
1815 | | // Table 24 – Parameters for the pattern dictionary decoding procedure |
1816 | | struct PatternDictionaryDecodingInputParameters { |
1817 | | bool uses_mmr { false }; // "HDMMR" in spec. |
1818 | | u32 width { 0 }; // "HDPW" in spec. |
1819 | | u32 height { 0 }; // "HDPH" in spec. |
1820 | | u32 gray_max { 0 }; // "GRAYMAX" in spec. |
1821 | | u8 hd_template { 0 }; // "HDTEMPLATE" in spec. |
1822 | | }; |
1823 | | |
1824 | | // 6.7 Pattern Dictionary Decoding Procedure |
1825 | | static ErrorOr<Vector<NonnullRefPtr<Symbol>>> pattern_dictionary_decoding_procedure(PatternDictionaryDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts) |
1826 | 0 | { |
1827 | | // Table 27 – Parameters used to decode a pattern dictionary's collective bitmap |
1828 | 0 | GenericRegionDecodingInputParameters generic_inputs; |
1829 | 0 | generic_inputs.is_modified_modified_read = inputs.uses_mmr; |
1830 | 0 | generic_inputs.region_width = (inputs.gray_max + 1) * inputs.width; |
1831 | 0 | generic_inputs.region_height = inputs.height; |
1832 | 0 | generic_inputs.gb_template = inputs.hd_template; |
1833 | 0 | generic_inputs.is_typical_prediction_used = false; |
1834 | 0 | generic_inputs.is_extended_reference_template_used = false; // Missing from spec in table 27. |
1835 | 0 | generic_inputs.skip_pattern = OptionalNone {}; |
1836 | 0 | generic_inputs.adaptive_template_pixels[0].x = -inputs.width; |
1837 | 0 | generic_inputs.adaptive_template_pixels[0].y = 0; |
1838 | 0 | generic_inputs.adaptive_template_pixels[1].x = -3; |
1839 | 0 | generic_inputs.adaptive_template_pixels[1].y = -1; |
1840 | 0 | generic_inputs.adaptive_template_pixels[2].x = 2; |
1841 | 0 | generic_inputs.adaptive_template_pixels[2].y = -2; |
1842 | 0 | generic_inputs.adaptive_template_pixels[3].x = -2; |
1843 | 0 | generic_inputs.adaptive_template_pixels[3].y = -2; |
1844 | |
|
1845 | 0 | Optional<QMArithmeticDecoder> decoder; |
1846 | 0 | if (!inputs.uses_mmr) { |
1847 | 0 | decoder = TRY(QMArithmeticDecoder::initialize(data)); |
1848 | 0 | generic_inputs.arithmetic_decoder = &decoder.value(); |
1849 | 0 | } |
1850 | | |
1851 | 0 | auto bitmap = TRY(generic_region_decoding_procedure(generic_inputs, data, contexts)); |
1852 | | |
1853 | 0 | Vector<NonnullRefPtr<Symbol>> patterns; |
1854 | 0 | for (u32 gray = 0; gray <= inputs.gray_max; ++gray) { |
1855 | 0 | int x = gray * inputs.width; |
1856 | 0 | auto pattern = TRY(bitmap->subbitmap({ x, 0, static_cast<int>(inputs.width), static_cast<int>(inputs.height) })); |
1857 | 0 | patterns.append(Symbol::create(move(pattern))); |
1858 | 0 | } |
1859 | | |
1860 | 0 | dbgln_if(JBIG2_DEBUG, "Pattern dictionary: {} patterns", patterns.size()); |
1861 | |
|
1862 | 0 | return patterns; |
1863 | 0 | } |
1864 | | |
1865 | | static ErrorOr<void> decode_symbol_dictionary(JBIG2LoadingContext& context, SegmentData& segment) |
1866 | 43 | { |
1867 | | // 7.4.2 Symbol dictionary segment syntax |
1868 | | |
1869 | | // 7.4.2.1 Symbol dictionary segment data header |
1870 | 43 | FixedMemoryStream stream(segment.data); |
1871 | | |
1872 | | // 7.4.2.1.1 Symbol dictionary flags |
1873 | 43 | u16 flags = TRY(stream.read_value<BigEndian<u16>>()); |
1874 | 0 | bool uses_huffman_encoding = (flags & 1) != 0; // "SDHUFF" in spec. |
1875 | 26 | bool uses_refinement_or_aggregate_coding = (flags & 2) != 0; // "SDREFAGG" in spec. |
1876 | | |
1877 | 26 | u8 huffman_table_selection_for_height_differences = (flags >> 2) & 0b11; // "SDHUFFDH" in spec. |
1878 | 26 | if (huffman_table_selection_for_height_differences == 2) |
1879 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid huffman_table_selection_for_height_differences"); |
1880 | 26 | if (!uses_huffman_encoding && huffman_table_selection_for_height_differences != 0) |
1881 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid huffman_table_selection_for_height_differences"); |
1882 | | |
1883 | 25 | u8 huffman_table_selection_for_width_differences = (flags >> 4) & 0b11; // "SDHUFFDW" in spec. |
1884 | 25 | if (huffman_table_selection_for_width_differences == 2) |
1885 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid huffman_table_selection_for_width_differences"); |
1886 | 25 | if (!uses_huffman_encoding && huffman_table_selection_for_width_differences != 0) |
1887 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid huffman_table_selection_for_width_differences"); |
1888 | | |
1889 | 25 | bool uses_user_supplied_size_table = (flags >> 6) & 1; // "SDHUFFBMSIZE" in spec. |
1890 | 25 | if (!uses_huffman_encoding && uses_user_supplied_size_table) |
1891 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid uses_user_supplied_size_table"); |
1892 | | |
1893 | 25 | bool uses_user_supplied_aggregate_table = (flags >> 7) & 1; // "SDHUFFAGGINST" in spec. |
1894 | 25 | if (!uses_huffman_encoding && uses_user_supplied_aggregate_table) |
1895 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid uses_user_supplied_aggregate_table"); |
1896 | | |
1897 | 25 | bool bitmap_coding_context_used = (flags >> 8) & 1; |
1898 | 25 | if (uses_huffman_encoding && !uses_refinement_or_aggregate_coding && bitmap_coding_context_used) |
1899 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid bitmap_coding_context_used"); |
1900 | | |
1901 | 25 | bool bitmap_coding_context_retained = (flags >> 9) & 1; |
1902 | 25 | if (uses_huffman_encoding && !uses_refinement_or_aggregate_coding && bitmap_coding_context_retained) |
1903 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid bitmap_coding_context_retained"); |
1904 | | |
1905 | 25 | u8 template_used = (flags >> 10) & 0b11; // "SDTEMPLATE" in spec. |
1906 | 25 | if (uses_huffman_encoding && template_used != 0) |
1907 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid template_used"); |
1908 | | |
1909 | 24 | u8 refinement_template_used = (flags >> 12) & 0b11; // "SDREFTEMPLATE" in spec. |
1910 | 24 | if (!uses_refinement_or_aggregate_coding && refinement_template_used != 0) |
1911 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid refinement_template_used"); |
1912 | | |
1913 | 24 | if (flags & 0b1110'0000'0000'0000) |
1914 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid symbol dictionary flags"); |
1915 | | |
1916 | | // 7.4.2.1.2 Symbol dictionary AT flags |
1917 | 24 | Array<AdaptiveTemplatePixel, 4> adaptive_template {}; |
1918 | 24 | if (!uses_huffman_encoding) { |
1919 | 23 | int number_of_adaptive_template_pixels = template_used == 0 ? 4 : 1; |
1920 | 72 | for (int i = 0; i < number_of_adaptive_template_pixels; ++i) { |
1921 | 70 | adaptive_template[i].x = TRY(stream.read_value<i8>()); |
1922 | 49 | adaptive_template[i].y = TRY(stream.read_value<i8>()); |
1923 | 49 | } |
1924 | 23 | } |
1925 | | |
1926 | | // 7.4.2.1.3 Symbol dictionary refinement AT flags |
1927 | 3 | Array<AdaptiveTemplatePixel, 2> adaptive_refinement_template {}; |
1928 | 3 | if (uses_refinement_or_aggregate_coding && refinement_template_used == 0) { |
1929 | 2 | for (size_t i = 0; i < adaptive_refinement_template.size(); ++i) { |
1930 | 2 | adaptive_refinement_template[i].x = TRY(stream.read_value<i8>()); |
1931 | 2 | adaptive_refinement_template[i].y = TRY(stream.read_value<i8>()); |
1932 | 1 | } |
1933 | 1 | } |
1934 | | |
1935 | | // 7.4.2.1.4 Number of exported symbols (SDNUMEXSYMS) |
1936 | 2 | u32 number_of_exported_symbols = TRY(stream.read_value<BigEndian<u32>>()); |
1937 | | |
1938 | | // 7.4.2.1.5 Number of new symbols (SDNUMNEWSYMS) |
1939 | 2 | u32 number_of_new_symbols = TRY(stream.read_value<BigEndian<u32>>()); |
1940 | | |
1941 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: uses_huffman_encoding={}", uses_huffman_encoding); |
1942 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: uses_refinement_or_aggregate_coding={}", uses_refinement_or_aggregate_coding); |
1943 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: huffman_table_selection_for_height_differences={}", huffman_table_selection_for_height_differences); |
1944 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: huffman_table_selection_for_width_differences={}", huffman_table_selection_for_width_differences); |
1945 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: uses_user_supplied_size_table={}", uses_user_supplied_size_table); |
1946 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: uses_user_supplied_aggregate_table={}", uses_user_supplied_aggregate_table); |
1947 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: bitmap_coding_context_used={}", bitmap_coding_context_used); |
1948 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: bitmap_coding_context_retained={}", bitmap_coding_context_retained); |
1949 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: template_used={}", template_used); |
1950 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: refinement_template_used={}", refinement_template_used); |
1951 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: number_of_exported_symbols={}", number_of_exported_symbols); |
1952 | 2 | dbgln_if(JBIG2_DEBUG, "Symbol dictionary: number_of_new_symbols={}", number_of_new_symbols); |
1953 | | |
1954 | | // 7.4.2.1.6 Symbol dictionary segment Huffman table selection |
1955 | | // FIXME |
1956 | | |
1957 | | // 7.4.2.2 Decoding a symbol dictionary segment |
1958 | | // "1) Interpret its header, as described in 7.4.2.1." |
1959 | | // Done! |
1960 | | |
1961 | | // "2) Decode (or retrieve the results of decoding) any referred-to symbol dictionary and tables segments." |
1962 | 2 | Vector<NonnullRefPtr<Symbol>> symbols; |
1963 | 2 | for (auto referred_to_segment_number : segment.header.referred_to_segment_numbers) { |
1964 | 2 | auto opt_referred_to_segment = context.segments_by_number.get(referred_to_segment_number); |
1965 | 2 | if (!opt_referred_to_segment.has_value()) |
1966 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Symbol segment refers to non-existent segment"); |
1967 | 1 | dbgln_if(JBIG2_DEBUG, "Symbol segment refers to segment id {} index {}", referred_to_segment_number, opt_referred_to_segment.value()); |
1968 | 1 | auto const& referred_to_segment = context.segments[opt_referred_to_segment.value()]; |
1969 | 1 | if (!referred_to_segment.symbols.has_value()) |
1970 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Symbol segment referred-to segment without symbols"); |
1971 | 0 | symbols.extend(referred_to_segment.symbols.value()); |
1972 | 0 | } |
1973 | | |
1974 | | // "3) If the "bitmap coding context used" bit in the header was 1, ..." |
1975 | 0 | if (bitmap_coding_context_used) |
1976 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode bitmap coding context segment yet"); |
1977 | | |
1978 | | // "4) If the "bitmap coding context used" bit in the header was 0, then, as described in E.3.7, |
1979 | | // reset all the arithmetic coding statistics for the generic region and generic refinement region decoding procedures to zero." |
1980 | | // Nothing to do. |
1981 | | |
1982 | | // "5) Reset the arithmetic coding statistics for all the contexts of all the arithmetic integer coders to zero." |
1983 | | // FIXME |
1984 | | |
1985 | | // "6) Invoke the symbol dictionary decoding procedure described in 6.5, with the parameters to the symbol dictionary decoding procedure set as shown in Table 31." |
1986 | 0 | SymbolDictionaryDecodingInputParameters inputs; |
1987 | 0 | inputs.uses_huffman_encoding = uses_huffman_encoding; |
1988 | 0 | inputs.uses_refinement_or_aggregate_coding = uses_refinement_or_aggregate_coding; |
1989 | 0 | inputs.input_symbols = move(symbols); |
1990 | 0 | inputs.number_of_new_symbols = number_of_new_symbols; |
1991 | 0 | inputs.number_of_exported_symbols = number_of_exported_symbols; |
1992 | | // FIXME: SDHUFFDH, SDHUFFDW, SDHUFFBMSIZE, SDHUFFAGGINST |
1993 | 0 | inputs.symbol_template = template_used; |
1994 | 0 | inputs.adaptive_template_pixels = adaptive_template; |
1995 | 0 | inputs.refinement_template = refinement_template_used; |
1996 | 0 | inputs.refinement_adaptive_template_pixels = adaptive_refinement_template; |
1997 | 0 | auto result = TRY(symbol_dictionary_decoding_procedure(inputs, segment.data.slice(TRY(stream.tell())))); |
1998 | | |
1999 | | // "7) If the "bitmap coding context retained" bit in the header was 1, then, as described in E.3.8, preserve the current contents |
2000 | | // of the arithmetic coding statistics for the generic region and generic refinement region decoding procedures." |
2001 | 0 | if (bitmap_coding_context_retained) |
2002 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot retain bitmap coding context yet"); |
2003 | | |
2004 | 0 | segment.symbols = move(result); |
2005 | |
|
2006 | 0 | return {}; |
2007 | 0 | } |
2008 | | |
2009 | | static ErrorOr<void> decode_intermediate_text_region(JBIG2LoadingContext&, SegmentData const&) |
2010 | 0 | { |
2011 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode intermediate text region yet"); |
2012 | 0 | } |
2013 | | |
2014 | | static ErrorOr<void> decode_immediate_text_region(JBIG2LoadingContext& context, SegmentData const& segment) |
2015 | 152 | { |
2016 | | // 7.4.3 Text region segment syntax |
2017 | 152 | auto data = segment.data; |
2018 | 152 | auto information_field = TRY(decode_region_segment_information_field(data)); |
2019 | 0 | data = data.slice(sizeof(information_field)); |
2020 | | |
2021 | 147 | dbgln_if(JBIG2_DEBUG, "Text region: width={}, height={}, x={}, y={}, flags={:#x}", information_field.width, information_field.height, information_field.x_location, information_field.y_location, information_field.flags); |
2022 | | |
2023 | 147 | FixedMemoryStream stream(data); |
2024 | | |
2025 | | // 7.4.3.1.1 Text region segment flags |
2026 | 147 | u16 text_region_segment_flags = TRY(stream.read_value<BigEndian<u16>>()); |
2027 | 0 | bool uses_huffman_encoding = (text_region_segment_flags & 1) != 0; // "SBHUFF" in spec. |
2028 | 147 | bool uses_refinement_coding = (text_region_segment_flags >> 1) & 1; // "SBREFINE" in spec. |
2029 | 147 | u8 log_strip_size = (text_region_segment_flags >> 2) & 3; // "LOGSBSTRIPS" in spec. |
2030 | 147 | u8 strip_size = 1u << log_strip_size; |
2031 | 147 | u8 reference_corner = (text_region_segment_flags >> 4) & 3; // "REFCORNER" |
2032 | 147 | bool is_transposed = (text_region_segment_flags >> 6) & 1; // "TRANSPOSED" in spec. |
2033 | 147 | u8 combination_operator = (text_region_segment_flags >> 7) & 3; // "SBCOMBOP" in spec. |
2034 | 147 | if (combination_operator > 4) |
2035 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid text region combination operator"); |
2036 | | |
2037 | 147 | u8 default_pixel_value = (text_region_segment_flags >> 9) & 1; // "SBDEFPIXEL" in spec. |
2038 | | |
2039 | 147 | u8 delta_s_offset_value = (text_region_segment_flags >> 10) & 0x1f; // "SBDSOFFSET" in spec. |
2040 | 147 | i8 delta_s_offset = delta_s_offset_value; |
2041 | 147 | if (delta_s_offset_value & 0x10) { |
2042 | | // This is converting a 5-bit two's complement number ot i8. |
2043 | | // FIXME: There's probably a simpler way to do this? Probably just sign-extend by or-ing in the top 3 bits? |
2044 | 1 | delta_s_offset_value = (~delta_s_offset_value + 1) & 0x1f; |
2045 | 1 | delta_s_offset = -delta_s_offset_value; |
2046 | 1 | } |
2047 | | |
2048 | 147 | u8 refinement_template = (text_region_segment_flags >> 15) != 0; // "SBRTEMPLATE" in spec. |
2049 | 147 | if (!uses_refinement_coding && refinement_template != 0) |
2050 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid refinement_template"); |
2051 | | |
2052 | | // 7.4.3.1.2 Text region segment Huffman flags |
2053 | | // "This field is only present if SBHUFF is 1." |
2054 | | // FIXME: Support this eventually. |
2055 | 147 | if (uses_huffman_encoding) |
2056 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode huffman text regions yet"); |
2057 | | |
2058 | | // 7.4.3.1.3 Text region refinement AT flags |
2059 | | // "This field is only present if SBREFINE is 1 and SBRTEMPLATE is 0." |
2060 | 147 | Array<AdaptiveTemplatePixel, 2> adaptive_refinement_template {}; |
2061 | 147 | if (uses_refinement_coding && refinement_template == 0) { |
2062 | 3 | for (size_t i = 0; i < adaptive_refinement_template.size(); ++i) { |
2063 | 2 | adaptive_refinement_template[i].x = TRY(stream.read_value<i8>()); |
2064 | 2 | adaptive_refinement_template[i].y = TRY(stream.read_value<i8>()); |
2065 | 2 | } |
2066 | 1 | } |
2067 | | |
2068 | | // 7.4.3.1.4 Number of symbol instances (SBNUMINSTANCES) |
2069 | 147 | u32 number_of_symbol_instances = TRY(stream.read_value<BigEndian<u32>>()); |
2070 | | |
2071 | | // 7.4.3.1.5 Text region segment symbol ID Huffman decoding table |
2072 | | // "It is only present if SBHUFF is 1." |
2073 | | // FIXME: Support this eventually. |
2074 | | |
2075 | 147 | dbgln_if(JBIG2_DEBUG, "Text region: uses_huffman_encoding={}, uses_refinement_coding={}, strip_size={}, reference_corner={}, is_transposed={}", uses_huffman_encoding, uses_refinement_coding, strip_size, reference_corner, is_transposed); |
2076 | 147 | dbgln_if(JBIG2_DEBUG, "Text region: combination_operator={}, default_pixel_value={}, delta_s_offset={}, refinement_template={}, number_of_symbol_instances={}", combination_operator, default_pixel_value, delta_s_offset, refinement_template, number_of_symbol_instances); |
2077 | 147 | dbgln_if(JBIG2_DEBUG, "Text region: number_of_symbol_instances={}", number_of_symbol_instances); |
2078 | | |
2079 | | // 7.4.3.2 Decoding a text region segment |
2080 | | // "1) Interpret its header, as described in 7.4.3.1." |
2081 | | // Done! |
2082 | | |
2083 | | // "2) Decode (or retrieve the results of decoding) any referred-to symbol dictionary and tables segments." |
2084 | 147 | Vector<NonnullRefPtr<Symbol>> symbols; |
2085 | 147 | for (auto referred_to_segment_number : segment.header.referred_to_segment_numbers) { |
2086 | 0 | auto opt_referred_to_segment = context.segments_by_number.get(referred_to_segment_number); |
2087 | 0 | if (!opt_referred_to_segment.has_value()) |
2088 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Text segment refers to non-existent segment"); |
2089 | 0 | dbgln_if(JBIG2_DEBUG, "Text segment refers to segment id {} index {}", referred_to_segment_number, opt_referred_to_segment.value()); |
2090 | 0 | auto const& referred_to_segment = context.segments[opt_referred_to_segment.value()]; |
2091 | 0 | if (!referred_to_segment.symbols.has_value()) |
2092 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Text segment referred-to segment without symbols"); |
2093 | 0 | symbols.extend(referred_to_segment.symbols.value()); |
2094 | 0 | } |
2095 | | |
2096 | | // "3) As described in E.3.7, reset all the arithmetic coding statistics to zero." |
2097 | | // FIXME |
2098 | | |
2099 | | // "4) Invoke the text region decoding procedure described in 6.4, with the parameters to the text region decoding procedure set as shown in Table 34." |
2100 | 147 | TextRegionDecodingInputParameters inputs; |
2101 | 147 | inputs.uses_huffman_encoding = uses_huffman_encoding; |
2102 | 147 | inputs.uses_refinement_coding = uses_refinement_coding; |
2103 | 147 | inputs.default_pixel = default_pixel_value; |
2104 | 147 | inputs.operator_ = static_cast<CombinationOperator>(combination_operator); |
2105 | 147 | inputs.is_transposed = is_transposed; |
2106 | 147 | inputs.reference_corner = static_cast<TextRegionDecodingInputParameters::Corner>(reference_corner); |
2107 | 147 | inputs.delta_s_offset = delta_s_offset; |
2108 | 147 | inputs.region_width = information_field.width; |
2109 | 147 | inputs.region_height = information_field.height; |
2110 | 147 | inputs.number_of_instances = number_of_symbol_instances; |
2111 | 147 | inputs.size_of_symbol_instance_strips = strip_size; |
2112 | 147 | inputs.id_symbol_code_length = ceil(log2(symbols.size())); |
2113 | 147 | inputs.symbols = move(symbols); |
2114 | | // FIXME: Huffman tables. |
2115 | 147 | inputs.refinement_template = refinement_template; |
2116 | 147 | inputs.refinement_adaptive_template_pixels = adaptive_refinement_template; |
2117 | | |
2118 | 147 | auto result = TRY(text_region_decoding_procedure(inputs, data.slice(TRY(stream.tell())))); |
2119 | | |
2120 | 0 | composite_bitbuffer(*context.page.bits, *result, { information_field.x_location, information_field.y_location }, information_field.external_combination_operator()); |
2121 | | |
2122 | 135 | return {}; |
2123 | 147 | } |
2124 | | |
2125 | | static ErrorOr<void> decode_pattern_dictionary(JBIG2LoadingContext&, SegmentData& segment) |
2126 | 0 | { |
2127 | | // 7.4.4 Pattern dictionary segment syntax |
2128 | 0 | FixedMemoryStream stream(segment.data); |
2129 | | |
2130 | | // 7.4.4.1.1 Pattern dictionary flags |
2131 | 0 | u8 flags = TRY(stream.read_value<u8>()); |
2132 | 0 | bool uses_mmr = flags & 1; |
2133 | 0 | u8 hd_template = (flags >> 1) & 3; |
2134 | 0 | if (uses_mmr && hd_template != 0) |
2135 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid hd_template"); |
2136 | 0 | if (flags & 0b1111'1000) |
2137 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid flags"); |
2138 | | |
2139 | | // 7.4.4.1.2 Width of the patterns in the pattern dictionary (HDPW) |
2140 | 0 | u8 width = TRY(stream.read_value<u8>()); |
2141 | 0 | if (width == 0) |
2142 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid width"); |
2143 | | |
2144 | | // 7.4.4.1.3 Height of the patterns in the pattern dictionary (HDPH) |
2145 | 0 | u8 height = TRY(stream.read_value<u8>()); |
2146 | 0 | if (height == 0) |
2147 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid height"); |
2148 | | |
2149 | | // 7.4.4.1.4 Largest gray-scale value (GRAYMAX) |
2150 | 0 | u32 gray_max = TRY(stream.read_value<BigEndian<u32>>()); |
2151 | | |
2152 | | // 7.4.4.2 Decoding a pattern dictionary segment |
2153 | 0 | dbgln_if(JBIG2_DEBUG, "Pattern dictionary: uses_mmr={}, hd_template={}, width={}, height={}, gray_max={}", uses_mmr, hd_template, width, height, gray_max); |
2154 | 0 | auto data = segment.data.slice(TRY(stream.tell())); |
2155 | | |
2156 | | // "1) Interpret its header, as described in 7.4.4.1." |
2157 | | // Done! |
2158 | | |
2159 | | // "2) As described in E.3.7, reset all the arithmetic coding statistics to zero." |
2160 | 0 | Vector<QMArithmeticDecoder::Context> contexts; |
2161 | 0 | if (!uses_mmr) |
2162 | 0 | contexts.resize(1 << number_of_context_bits_for_template(hd_template)); |
2163 | | |
2164 | | // "3) Invoke the pattern dictionary decoding procedure described in 6.7, with the parameters to the pattern |
2165 | | // dictionary decoding procedure set as shown in Table 35." |
2166 | 0 | PatternDictionaryDecodingInputParameters inputs; |
2167 | 0 | inputs.uses_mmr = uses_mmr; |
2168 | 0 | inputs.width = width; |
2169 | 0 | inputs.height = height; |
2170 | 0 | inputs.gray_max = gray_max; |
2171 | 0 | inputs.hd_template = hd_template; |
2172 | 0 | auto result = TRY(pattern_dictionary_decoding_procedure(inputs, data, contexts)); |
2173 | | |
2174 | 0 | segment.patterns = move(result); |
2175 | |
|
2176 | 0 | return {}; |
2177 | 0 | } |
2178 | | |
2179 | | static ErrorOr<void> decode_intermediate_halftone_region(JBIG2LoadingContext&, SegmentData const&) |
2180 | 0 | { |
2181 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode intermediate halftone region yet"); |
2182 | 0 | } |
2183 | | |
2184 | | static ErrorOr<void> decode_immediate_halftone_region(JBIG2LoadingContext& context, SegmentData const& segment) |
2185 | 0 | { |
2186 | | // 7.4.5 Halftone region segment syntax |
2187 | 0 | auto data = segment.data; |
2188 | 0 | auto information_field = TRY(decode_region_segment_information_field(data)); |
2189 | 0 | data = data.slice(sizeof(information_field)); |
2190 | |
|
2191 | 0 | dbgln_if(JBIG2_DEBUG, "Halftone region: width={}, height={}, x={}, y={}, flags={:#x}", information_field.width, information_field.height, information_field.x_location, information_field.y_location, information_field.flags); |
2192 | |
|
2193 | 0 | FixedMemoryStream stream(data); |
2194 | | |
2195 | | // 7.4.5.1.1 Halftone region segment flags |
2196 | 0 | u8 flags = TRY(stream.read_value<u8>()); |
2197 | 0 | bool uses_mmr = flags & 1; // "HMMR" in spec. |
2198 | 0 | u8 template_used = (flags >> 1) & 3; // "HTTEMPLATE" in spec. |
2199 | 0 | if (uses_mmr && template_used != 0) |
2200 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid template_used"); |
2201 | 0 | bool enable_skip = (flags >> 3) & 1; // "HENABLESKIP" in spec. |
2202 | 0 | u8 combination_operator = (flags >> 4) & 7; // "HCOMBOP" in spec. |
2203 | 0 | if (combination_operator > 4) |
2204 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid combination_operator"); |
2205 | 0 | bool default_pixel_value = (flags >> 7) & 1; // "HDEFPIXEL" in spec. |
2206 | |
|
2207 | 0 | dbgln_if(JBIG2_DEBUG, "Halftone region: uses_mmr={}, template_used={}, enable_skip={}, combination_operator={}, default_pixel_value={}", uses_mmr, template_used, enable_skip, combination_operator, default_pixel_value); |
2208 | | |
2209 | | // 7.4.5.1.2 Halftone grid position and size |
2210 | | // 7.4.5.1.2.1 Width of the gray-scale image (HGW) |
2211 | 0 | u32 gray_width = TRY(stream.read_value<BigEndian<u32>>()); |
2212 | | |
2213 | | // 7.4.5.1.2.2 Height of the gray-scale image (HGH) |
2214 | 0 | u32 gray_height = TRY(stream.read_value<BigEndian<u32>>()); |
2215 | | |
2216 | | // 7.4.5.1.2.3 Horizontal offset of the grid (HGX) |
2217 | 0 | i32 grid_x = TRY(stream.read_value<BigEndian<i32>>()); |
2218 | | |
2219 | | // 7.4.5.1.2.4 Vertical offset of the grid (HGY) |
2220 | 0 | i32 grid_y = TRY(stream.read_value<BigEndian<i32>>()); |
2221 | | |
2222 | | // 7.4.5.1.3 Halftone grid vector |
2223 | | // 7.4.5.1.3.1 Horizontal coordinate of the halftone grid vector (HRX) |
2224 | 0 | u16 grid_vector_x = TRY(stream.read_value<BigEndian<u16>>()); |
2225 | | |
2226 | | // 7.4.5.1.3.2 Vertical coordinate of the halftone grid vector (HRY) |
2227 | 0 | u16 grid_vector_y = TRY(stream.read_value<BigEndian<u16>>()); |
2228 | | |
2229 | 0 | dbgln_if(JBIG2_DEBUG, "Halftone region: gray_width={}, gray_height={}, grid_x={}, grid_y={}, grid_vector_x={}, grid_vector_y={}", gray_width, gray_height, grid_x, grid_y, grid_vector_x, grid_vector_y); |
2230 | | |
2231 | | // 7.4.5.2 Decoding a halftone region segment |
2232 | | // "1) Interpret its header, as described in 7.4.5.1." |
2233 | | // Done! |
2234 | | |
2235 | | // "2) Decode (or retrieve the results of decoding) the referred-to pattern dictionary segment." |
2236 | 0 | if (segment.header.referred_to_segment_numbers.size() != 1) |
2237 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Halftone segment refers to wrong number of segments"); |
2238 | 0 | auto opt_referred_to_segment = context.segments_by_number.get(segment.header.referred_to_segment_numbers[0]); |
2239 | 0 | if (!opt_referred_to_segment.has_value()) |
2240 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Halftone segment refers to non-existent segment"); |
2241 | 0 | dbgln_if(JBIG2_DEBUG, "Halftone segment refers to segment id {} index {}", segment.header.referred_to_segment_numbers[0], opt_referred_to_segment.value()); |
2242 | 0 | auto const& referred_to_segment = context.segments[opt_referred_to_segment.value()]; |
2243 | 0 | if (!referred_to_segment.patterns.has_value()) |
2244 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Halftone segment referred-to segment without patterns"); |
2245 | 0 | Vector<NonnullRefPtr<Symbol>> patterns = referred_to_segment.patterns.value(); |
2246 | 0 | if (patterns.is_empty()) |
2247 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Halftone segment without patterns"); |
2248 | | |
2249 | | // "3) As described in E.3.7, reset all the arithmetic coding statistics to zero." |
2250 | 0 | Vector<QMArithmeticDecoder::Context> contexts; |
2251 | 0 | if (!uses_mmr) |
2252 | 0 | contexts.resize(1 << number_of_context_bits_for_template(template_used)); |
2253 | | |
2254 | | // "4) Invoke the halftone region decoding procedure described in 6.6, with the parameters to the halftone |
2255 | | // region decoding procedure set as shown in Table 36." |
2256 | 0 | data = data.slice(TRY(stream.tell())); |
2257 | 0 | HalftoneRegionDecodingInputParameters inputs; |
2258 | 0 | inputs.region_width = information_field.width; |
2259 | 0 | inputs.region_height = information_field.height; |
2260 | 0 | inputs.uses_mmr = uses_mmr; |
2261 | 0 | inputs.halftone_template = template_used; |
2262 | 0 | inputs.enable_skip = enable_skip; |
2263 | 0 | inputs.combination_operator = static_cast<CombinationOperator>(combination_operator); |
2264 | 0 | inputs.default_pixel_value = default_pixel_value; |
2265 | 0 | inputs.grayscale_width = gray_width; |
2266 | 0 | inputs.grayscale_height = gray_height; |
2267 | 0 | inputs.grid_origin_x_offset = grid_x; |
2268 | 0 | inputs.grid_origin_y_offset = grid_y; |
2269 | 0 | inputs.grid_vector_x = grid_vector_x; |
2270 | 0 | inputs.grid_vector_y = grid_vector_y; |
2271 | 0 | inputs.patterns = move(patterns); |
2272 | 0 | inputs.pattern_width = inputs.patterns[0]->bitmap().width(); |
2273 | 0 | inputs.pattern_height = inputs.patterns[0]->bitmap().height(); |
2274 | 0 | auto result = TRY(halftone_region_decoding_procedure(inputs, data, contexts)); |
2275 | | |
2276 | 0 | composite_bitbuffer(*context.page.bits, *result, { information_field.x_location, information_field.y_location }, information_field.external_combination_operator()); |
2277 | |
|
2278 | 0 | return {}; |
2279 | 0 | } |
2280 | | |
2281 | | static ErrorOr<void> decode_immediate_lossless_halftone_region(JBIG2LoadingContext&, SegmentData const&) |
2282 | 0 | { |
2283 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode immediate lossless halftone region yet"); |
2284 | 0 | } |
2285 | | |
2286 | | static ErrorOr<void> decode_intermediate_generic_region(JBIG2LoadingContext&, SegmentData const&) |
2287 | 0 | { |
2288 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode intermediate generic region yet"); |
2289 | 0 | } |
2290 | | |
2291 | | static ErrorOr<void> decode_immediate_generic_region(JBIG2LoadingContext& context, SegmentData const& segment) |
2292 | 4.31k | { |
2293 | | // 7.4.6 Generic region segment syntax |
2294 | 4.31k | auto data = segment.data; |
2295 | 4.31k | auto information_field = TRY(decode_region_segment_information_field(data)); |
2296 | 0 | data = data.slice(sizeof(information_field)); |
2297 | | |
2298 | 4.30k | dbgln_if(JBIG2_DEBUG, "Generic region: width={}, height={}, x={}, y={}, flags={:#x}", information_field.width, information_field.height, information_field.x_location, information_field.y_location, information_field.flags); |
2299 | | |
2300 | | // 7.4.6.2 Generic region segment flags |
2301 | 4.30k | if (data.is_empty()) |
2302 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: No segment data"); |
2303 | 4.30k | u8 flags = data[0]; |
2304 | 4.30k | bool uses_mmr = (flags & 1) != 0; |
2305 | 4.30k | u8 arithmetic_coding_template = (flags >> 1) & 3; // "GBTEMPLATE" |
2306 | 4.30k | bool typical_prediction_generic_decoding_on = (flags >> 3) & 1; // "TPGDON"; "TPGD" is short for "Typical Prediction for Generic Direct coding" |
2307 | 4.30k | bool uses_extended_reference_template = (flags >> 4) & 1; // "EXTTEMPLATE" |
2308 | 4.30k | if (flags & 0b1110'0000) |
2309 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid flags"); |
2310 | 4.30k | data = data.slice(sizeof(flags)); |
2311 | | |
2312 | | // 7.4.6.3 Generic region segment AT flags |
2313 | 4.30k | Array<AdaptiveTemplatePixel, 12> adaptive_template_pixels {}; |
2314 | 4.30k | if (!uses_mmr) { |
2315 | 3.32k | dbgln_if(JBIG2_DEBUG, "Non-MMR generic region, GBTEMPLATE={} TPGDON={} EXTTEMPLATE={}", arithmetic_coding_template, typical_prediction_generic_decoding_on, uses_extended_reference_template); |
2316 | | |
2317 | 3.32k | if (arithmetic_coding_template == 0 && uses_extended_reference_template) { |
2318 | | // This was added in T.88 Amendment 2 (https://www.itu.int/rec/T-REC-T.88-200306-S!Amd2/en) mid-2003. |
2319 | | // I haven't seen it being used in the wild, and the spec says "32-byte field as shown below" and then shows 24 bytes, |
2320 | | // so it's not clear how much data to read. |
2321 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: GBTEMPLATE=0 EXTTEMPLATE=1 not yet implemented"); |
2322 | 0 | } |
2323 | | |
2324 | 3.32k | size_t number_of_adaptive_template_pixels = arithmetic_coding_template == 0 ? 4 : 1; |
2325 | 3.32k | if (data.size() < 2 * number_of_adaptive_template_pixels) |
2326 | 2 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: No adaptive template data"); |
2327 | 12.1k | for (size_t i = 0; i < number_of_adaptive_template_pixels; ++i) { |
2328 | 8.86k | adaptive_template_pixels[i].x = static_cast<i8>(data[2 * i]); |
2329 | 8.86k | adaptive_template_pixels[i].y = static_cast<i8>(data[2 * i + 1]); |
2330 | 8.86k | } |
2331 | 3.32k | data = data.slice(2 * number_of_adaptive_template_pixels); |
2332 | 3.32k | } |
2333 | | |
2334 | | // 7.4.6.4 Decoding a generic region segment |
2335 | | // "1) Interpret its header, as described in 7.4.6.1" |
2336 | | // Done above. |
2337 | | // "2) As described in E.3.7, reset all the arithmetic coding statistics to zero." |
2338 | 4.30k | Vector<QMArithmeticDecoder::Context> contexts; |
2339 | 4.30k | contexts.resize(1 << number_of_context_bits_for_template(arithmetic_coding_template)); |
2340 | | |
2341 | | // "3) Invoke the generic region decoding procedure described in 6.2, with the parameters to the generic region decoding procedure set as shown in Table 37." |
2342 | 4.30k | GenericRegionDecodingInputParameters inputs; |
2343 | 4.30k | inputs.is_modified_modified_read = uses_mmr; |
2344 | 4.30k | inputs.region_width = information_field.width; |
2345 | 4.30k | inputs.region_height = information_field.height; |
2346 | 4.30k | inputs.gb_template = arithmetic_coding_template; |
2347 | 4.30k | inputs.is_typical_prediction_used = typical_prediction_generic_decoding_on; |
2348 | 4.30k | inputs.is_extended_reference_template_used = uses_extended_reference_template; |
2349 | 4.30k | inputs.skip_pattern = OptionalNone {}; |
2350 | 4.30k | inputs.adaptive_template_pixels = adaptive_template_pixels; |
2351 | | |
2352 | 4.30k | Optional<QMArithmeticDecoder> decoder; |
2353 | 4.30k | if (!uses_mmr) { |
2354 | 3.32k | decoder = TRY(QMArithmeticDecoder::initialize(data)); |
2355 | 0 | inputs.arithmetic_decoder = &decoder.value(); |
2356 | 3.32k | } |
2357 | | |
2358 | 4.30k | auto result = TRY(generic_region_decoding_procedure(inputs, data, contexts)); |
2359 | | |
2360 | | // 8.2 Page image composition step 5) |
2361 | 4.15k | if (information_field.x_location + information_field.width > (u32)context.page.size.width() |
2362 | 4.15k | || information_field.y_location + information_field.height > (u32)context.page.size.height()) { |
2363 | 55 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Region bounds outsize of page bounds"); |
2364 | 55 | } |
2365 | | |
2366 | 4.09k | composite_bitbuffer(*context.page.bits, *result, { information_field.x_location, information_field.y_location }, information_field.external_combination_operator()); |
2367 | | |
2368 | 4.09k | return {}; |
2369 | 4.15k | } |
2370 | | |
2371 | | static ErrorOr<void> decode_intermediate_generic_refinement_region(JBIG2LoadingContext&, SegmentData const&) |
2372 | 0 | { |
2373 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode intermediate generic refinement region yet"); |
2374 | 0 | } |
2375 | | |
2376 | | static ErrorOr<void> decode_immediate_generic_refinement_region(JBIG2LoadingContext&, SegmentData const&) |
2377 | 0 | { |
2378 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode immediate generic refinement region yet"); |
2379 | 0 | } |
2380 | | |
2381 | | static ErrorOr<void> decode_immediate_lossless_generic_refinement_region(JBIG2LoadingContext&, SegmentData const&) |
2382 | 0 | { |
2383 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode immediate lossless generic refinement region yet"); |
2384 | 0 | } |
2385 | | |
2386 | | static ErrorOr<void> decode_page_information(JBIG2LoadingContext& context, SegmentData const& segment) |
2387 | 493 | { |
2388 | | // 7.4.8 Page information segment syntax and 8.1 Decoder model steps 1) - 3). |
2389 | | |
2390 | | // "1) Decode the page information segment."" |
2391 | 493 | auto page_information = TRY(decode_page_information_segment(segment.data)); |
2392 | | |
2393 | 0 | bool page_is_striped = (page_information.striping_information & 0x80) != 0; |
2394 | 492 | if (page_information.bitmap_height == 0xffff'ffff && !page_is_striped) |
2395 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Non-striped bitmaps of indeterminate height not allowed"); |
2396 | | |
2397 | 492 | u16 maximum_stripe_height = page_information.striping_information & 0x7F; |
2398 | 492 | u8 default_color = (page_information.flags >> 2) & 1; |
2399 | 492 | u8 default_combination_operator = (page_information.flags >> 3) & 3; |
2400 | 492 | context.page.default_combination_operator = static_cast<CombinationOperator>(default_combination_operator); |
2401 | | |
2402 | 492 | dbgln_if(JBIG2_DEBUG, "Page information: width={}, height={}, is_striped={}, max_stripe_height={}, default_color={}, default_combination_operator={}", page_information.bitmap_width, page_information.bitmap_height, page_is_striped, maximum_stripe_height, default_color, default_combination_operator); |
2403 | | |
2404 | | // FIXME: Do something with the other fields in page_information. |
2405 | | |
2406 | | // "2) Create the page buffer, of the size given in the page information segment. |
2407 | | // |
2408 | | // If the page height is unknown, then this is not possible. However, in this case the page must be striped, |
2409 | | // and the maximum stripe height specified, and the initial page buffer can be created with height initially |
2410 | | // equal to this maximum stripe height." |
2411 | 492 | size_t height = page_information.bitmap_height; |
2412 | 492 | if (height == 0xffff'ffff) |
2413 | 0 | height = maximum_stripe_height; |
2414 | 492 | context.page.bits = TRY(BitBuffer::create(page_information.bitmap_width, height)); |
2415 | | |
2416 | | // "3) Fill the page buffer with the page's default pixel value." |
2417 | 0 | context.page.bits->fill(default_color != 0); |
2418 | | |
2419 | 492 | return {}; |
2420 | 492 | } |
2421 | | |
2422 | | static ErrorOr<void> decode_end_of_page(JBIG2LoadingContext&, SegmentData const& segment) |
2423 | 18 | { |
2424 | | // 7.4.9 End of page segment syntax |
2425 | 18 | if (segment.data.size() != 0) |
2426 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: End of page segment has non-zero size"); |
2427 | | // FIXME: If the page had unknown height, check that previous segment was end-of-stripe. |
2428 | | // FIXME: Maybe mark page as completed and error if we see more segments for it? |
2429 | 17 | return {}; |
2430 | 18 | } |
2431 | | |
2432 | | static ErrorOr<void> decode_end_of_stripe(JBIG2LoadingContext&, SegmentData const& segment) |
2433 | 0 | { |
2434 | | // 7.4.10 End of stripe segment syntax |
2435 | | // "The segment data of an end of stripe segment consists of one four-byte value, specifying the Y coordinate of the end row." |
2436 | 0 | if (segment.data.size() != 4) |
2437 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: End of strip segment has wrong size"); |
2438 | | |
2439 | | // FIXME: Once we implement support for images with initially indeterminate height, we need these values to determine the height at the end. |
2440 | 0 | u32 y_coordinate = *reinterpret_cast<BigEndian<u32> const*>(segment.data.data()); |
2441 | 0 | dbgln_if(JBIG2_DEBUG, "End of stripe: y={}", y_coordinate); |
2442 | |
|
2443 | 0 | return {}; |
2444 | 0 | } |
2445 | | |
2446 | | static ErrorOr<void> decode_end_of_file(JBIG2LoadingContext&, SegmentData const& segment) |
2447 | 0 | { |
2448 | | // 7.4.11 End of file segment syntax |
2449 | 0 | if (segment.data.size() != 0) |
2450 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: End of file segment has non-zero size"); |
2451 | 0 | return {}; |
2452 | 0 | } |
2453 | | |
2454 | | static ErrorOr<void> decode_profiles(JBIG2LoadingContext&, SegmentData const&) |
2455 | 0 | { |
2456 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode profiles yet"); |
2457 | 0 | } |
2458 | | |
2459 | | static ErrorOr<void> decode_tables(JBIG2LoadingContext&, SegmentData const&) |
2460 | 1 | { |
2461 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode tables yet"); |
2462 | 1 | } |
2463 | | |
2464 | | static ErrorOr<void> decode_color_palette(JBIG2LoadingContext&, SegmentData const&) |
2465 | 1 | { |
2466 | 1 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode color palette yet"); |
2467 | 1 | } |
2468 | | |
2469 | | static ErrorOr<void> decode_extension(JBIG2LoadingContext&, SegmentData const& segment) |
2470 | 0 | { |
2471 | | // 7.4.14 Extension segment syntax |
2472 | 0 | FixedMemoryStream stream { segment.data }; |
2473 | |
|
2474 | 0 | enum ExtensionType { |
2475 | 0 | SingleByteCodedComment = 0x20000000, |
2476 | 0 | MultiByteCodedComment = 0x20000002, |
2477 | 0 | }; |
2478 | 0 | u32 type = TRY(stream.read_value<BigEndian<u32>>()); |
2479 | | |
2480 | 0 | auto read_string = [&]<class T>() -> ErrorOr<Vector<T>> { |
2481 | 0 | Vector<T> result; |
2482 | 0 | do { |
2483 | 0 | result.append(TRY(stream.read_value<BigEndian<T>>())); |
2484 | 0 | } while (result.last()); |
2485 | 0 | result.take_last(); |
2486 | 0 | return result; |
2487 | 0 | }; Unexecuted instantiation: JBIG2Loader.cpp:AK::ErrorOr<AK::Vector<unsigned char, 0ul>, AK::Error> Gfx::decode_extension(Gfx::JBIG2LoadingContext&, Gfx::SegmentData const&)::$_0::operator()<unsigned char>() const Unexecuted instantiation: JBIG2Loader.cpp:AK::ErrorOr<AK::Vector<unsigned short, 0ul>, AK::Error> Gfx::decode_extension(Gfx::JBIG2LoadingContext&, Gfx::SegmentData const&)::$_0::operator()<unsigned short>() const |
2488 | |
|
2489 | 0 | switch (type) { |
2490 | 0 | case SingleByteCodedComment: { |
2491 | | // 7.4.15.1 Single-byte coded comment |
2492 | | // Pairs of zero-terminated ISO/IEC 8859-1 (latin1) pairs, terminated by another \0. |
2493 | 0 | while (true) { |
2494 | 0 | auto first_bytes = TRY(read_string.template operator()<u8>()); |
2495 | 0 | if (first_bytes.is_empty()) |
2496 | 0 | break; |
2497 | | |
2498 | 0 | auto second_bytes = TRY(read_string.template operator()<u8>()); |
2499 | | |
2500 | 0 | auto first = TRY(TextCodec::decoder_for_exact_name("ISO-8859-1"sv)->to_utf8(StringView { first_bytes })); |
2501 | 0 | auto second = TRY(TextCodec::decoder_for_exact_name("ISO-8859-1"sv)->to_utf8(StringView { second_bytes })); |
2502 | 0 | dbgln("JBIG2ImageDecoderPlugin: key '{}', value '{}'", first, second); |
2503 | 0 | } |
2504 | 0 | if (!stream.is_eof()) |
2505 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Trailing data after SingleByteCodedComment"); |
2506 | 0 | return {}; |
2507 | 0 | } |
2508 | 0 | case MultiByteCodedComment: { |
2509 | | // 7.4.15.2 Multi-byte coded comment |
2510 | | // Pairs of (two-byte-)zero-terminated UCS-2 pairs, terminated by another \0\0. |
2511 | 0 | while (true) { |
2512 | 0 | auto first_ucs2 = TRY(read_string.template operator()<u16>()); |
2513 | 0 | if (first_ucs2.is_empty()) |
2514 | 0 | break; |
2515 | | |
2516 | 0 | auto second_ucs2 = TRY(read_string.template operator()<u16>()); |
2517 | | |
2518 | 0 | auto first = TRY(Utf16View(first_ucs2).to_utf8()); |
2519 | 0 | auto second = TRY(Utf16View(second_ucs2).to_utf8()); |
2520 | 0 | dbgln("JBIG2ImageDecoderPlugin: key '{}', value '{}'", first, second); |
2521 | 0 | } |
2522 | 0 | if (!stream.is_eof()) |
2523 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Trailing data after MultiByteCodedComment"); |
2524 | 0 | return {}; |
2525 | 0 | } |
2526 | 0 | } |
2527 | | |
2528 | | // FIXME: If bit 31 in `type` is not set, the extension isn't necessary, and we could ignore it. |
2529 | 0 | dbgln("JBIG2ImageDecoderPlugin: Unknown extension type {:#x}", type); |
2530 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Unknown extension type"); |
2531 | 0 | } |
2532 | | |
2533 | | static ErrorOr<void> decode_data(JBIG2LoadingContext& context) |
2534 | 386 | { |
2535 | 386 | TRY(warn_about_multiple_pages(context)); |
2536 | | |
2537 | 9.85k | for (size_t i = 0; i < context.segments.size(); ++i) { |
2538 | 9.75k | auto& segment = context.segments[i]; |
2539 | | |
2540 | 9.75k | if (segment.header.page_association != 0 && segment.header.page_association != 1) |
2541 | 4.25k | continue; |
2542 | | |
2543 | 5.49k | switch (segment.header.type) { |
2544 | 43 | case SegmentType::SymbolDictionary: |
2545 | 43 | TRY(decode_symbol_dictionary(context, segment)); |
2546 | 0 | break; |
2547 | 0 | case SegmentType::IntermediateTextRegion: |
2548 | 0 | TRY(decode_intermediate_text_region(context, segment)); |
2549 | 0 | break; |
2550 | 152 | case SegmentType::ImmediateTextRegion: |
2551 | 152 | case SegmentType::ImmediateLosslessTextRegion: |
2552 | | // 7.4.3 Text region segment syntax |
2553 | | // "The data parts of all three of the text region segment types ("intermediate text region", "immediate text region" and |
2554 | | // "immediate lossless text region") are coded identically, but are acted upon differently, see 8.2." |
2555 | | // But 8.2 only describes a difference between intermediate and immediate regions as far as I can tell, |
2556 | | // and calling the immediate text region handler for immediate lossless text regions seems to do the right thing (?). |
2557 | 152 | TRY(decode_immediate_text_region(context, segment)); |
2558 | 0 | break; |
2559 | 0 | case SegmentType::PatternDictionary: |
2560 | 0 | TRY(decode_pattern_dictionary(context, segment)); |
2561 | 0 | break; |
2562 | 0 | case SegmentType::IntermediateHalftoneRegion: |
2563 | 0 | TRY(decode_intermediate_halftone_region(context, segment)); |
2564 | 0 | break; |
2565 | 0 | case SegmentType::ImmediateHalftoneRegion: |
2566 | 0 | TRY(decode_immediate_halftone_region(context, segment)); |
2567 | 0 | break; |
2568 | 0 | case SegmentType::ImmediateLosslessHalftoneRegion: |
2569 | 0 | TRY(decode_immediate_lossless_halftone_region(context, segment)); |
2570 | 0 | break; |
2571 | 0 | case SegmentType::IntermediateGenericRegion: |
2572 | 0 | TRY(decode_intermediate_generic_region(context, segment)); |
2573 | 0 | break; |
2574 | 4.31k | case SegmentType::ImmediateGenericRegion: |
2575 | 4.31k | case SegmentType::ImmediateLosslessGenericRegion: |
2576 | | // 7.4.6 Generic region segment syntax |
2577 | | // "The data parts of all three of the generic region segment types ("intermediate generic region", "immediate generic region" and |
2578 | | // "immediate lossless generic region") are coded identically, but are acted upon differently, see 8.2." |
2579 | | // But 8.2 only describes a difference between intermediate and immediate regions as far as I can tell, |
2580 | | // and calling the immediate generic region handler for immediate generic lossless regions seems to do the right thing (?). |
2581 | 4.31k | TRY(decode_immediate_generic_region(context, segment)); |
2582 | 0 | break; |
2583 | 0 | case SegmentType::IntermediateGenericRefinementRegion: |
2584 | 0 | TRY(decode_intermediate_generic_refinement_region(context, segment)); |
2585 | 0 | break; |
2586 | 0 | case SegmentType::ImmediateGenericRefinementRegion: |
2587 | 0 | TRY(decode_immediate_generic_refinement_region(context, segment)); |
2588 | 0 | break; |
2589 | 0 | case SegmentType::ImmediateLosslessGenericRefinementRegion: |
2590 | 0 | TRY(decode_immediate_lossless_generic_refinement_region(context, segment)); |
2591 | 0 | break; |
2592 | 493 | case SegmentType::PageInformation: |
2593 | 493 | TRY(decode_page_information(context, segment)); |
2594 | 0 | break; |
2595 | 18 | case SegmentType::EndOfPage: |
2596 | 18 | TRY(decode_end_of_page(context, segment)); |
2597 | 0 | break; |
2598 | 0 | case SegmentType::EndOfStripe: |
2599 | 0 | TRY(decode_end_of_stripe(context, segment)); |
2600 | 0 | break; |
2601 | 0 | case SegmentType::EndOfFile: |
2602 | 0 | TRY(decode_end_of_file(context, segment)); |
2603 | | // "If a file contains an end of file segment, it must be the last segment." |
2604 | 0 | if (i != context.segments.size() - 1) |
2605 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: End of file segment not last segment"); |
2606 | 0 | break; |
2607 | 0 | case SegmentType::Profiles: |
2608 | 0 | TRY(decode_profiles(context, segment)); |
2609 | 0 | break; |
2610 | 1 | case SegmentType::Tables: |
2611 | 1 | TRY(decode_tables(context, segment)); |
2612 | 0 | break; |
2613 | 1 | case SegmentType::ColorPalette: |
2614 | 1 | TRY(decode_color_palette(context, segment)); |
2615 | 0 | break; |
2616 | 0 | case SegmentType::Extension: |
2617 | 0 | TRY(decode_extension(context, segment)); |
2618 | 0 | break; |
2619 | 5.49k | } |
2620 | 5.49k | } |
2621 | | |
2622 | 108 | return {}; |
2623 | 386 | } |
2624 | | |
2625 | | JBIG2ImageDecoderPlugin::JBIG2ImageDecoderPlugin() |
2626 | 502 | { |
2627 | 502 | m_context = make<JBIG2LoadingContext>(); |
2628 | 502 | } |
2629 | | |
2630 | 502 | JBIG2ImageDecoderPlugin::~JBIG2ImageDecoderPlugin() = default; |
2631 | | |
2632 | | IntSize JBIG2ImageDecoderPlugin::size() |
2633 | 0 | { |
2634 | 0 | return m_context->page.size; |
2635 | 0 | } |
2636 | | |
2637 | | bool JBIG2ImageDecoderPlugin::sniff(ReadonlyBytes data) |
2638 | 502 | { |
2639 | 502 | return data.starts_with(id_string); |
2640 | 502 | } |
2641 | | |
2642 | | ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JBIG2ImageDecoderPlugin::create(ReadonlyBytes data) |
2643 | 502 | { |
2644 | 502 | auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) JBIG2ImageDecoderPlugin())); |
2645 | 502 | TRY(decode_jbig2_header(*plugin->m_context, data)); |
2646 | | |
2647 | 495 | data = data.slice(sizeof(id_string) + sizeof(u8) + (plugin->m_context->number_of_pages.has_value() ? sizeof(u32) : 0)); |
2648 | 495 | TRY(decode_segment_headers(*plugin->m_context, data)); |
2649 | | |
2650 | 431 | TRY(scan_for_page_size(*plugin->m_context)); |
2651 | | |
2652 | 0 | return plugin; |
2653 | 431 | } |
2654 | | |
2655 | | ErrorOr<ImageFrameDescriptor> JBIG2ImageDecoderPlugin::frame(size_t index, Optional<IntSize>) |
2656 | 386 | { |
2657 | | // FIXME: Use this for multi-page JBIG2 files? |
2658 | 386 | if (index != 0) |
2659 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid frame index"); |
2660 | | |
2661 | 386 | if (m_context->state == JBIG2LoadingContext::State::Error) |
2662 | 0 | return Error::from_string_literal("JBIG2ImageDecoderPlugin: Decoding failed"); |
2663 | | |
2664 | 386 | if (m_context->state < JBIG2LoadingContext::State::Decoded) { |
2665 | 386 | auto result = decode_data(*m_context); |
2666 | 386 | if (result.is_error()) { |
2667 | 278 | m_context->state = JBIG2LoadingContext::State::Error; |
2668 | 278 | return result.release_error(); |
2669 | 278 | } |
2670 | 108 | m_context->state = JBIG2LoadingContext::State::Decoded; |
2671 | 108 | } |
2672 | | |
2673 | 108 | auto bitmap = TRY(m_context->page.bits->to_gfx_bitmap()); |
2674 | 0 | return ImageFrameDescriptor { move(bitmap), 0 }; |
2675 | 108 | } |
2676 | | |
2677 | | ErrorOr<ByteBuffer> JBIG2ImageDecoderPlugin::decode_embedded(Vector<ReadonlyBytes> data) |
2678 | 0 | { |
2679 | 0 | auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) JBIG2ImageDecoderPlugin())); |
2680 | 0 | plugin->m_context->organization = Organization::Embedded; |
2681 | |
|
2682 | 0 | for (auto const& segment_data : data) |
2683 | 0 | TRY(decode_segment_headers(*plugin->m_context, segment_data)); |
2684 | | |
2685 | 0 | TRY(scan_for_page_size(*plugin->m_context)); |
2686 | 0 | TRY(decode_data(*plugin->m_context)); |
2687 | | |
2688 | 0 | return plugin->m_context->page.bits->to_byte_buffer(); |
2689 | 0 | } |
2690 | | |
2691 | | } |