diff --git a/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp index 554781036c..251375e834 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp @@ -321,6 +321,17 @@ static inline i32* get_component(Macroblock& block, unsigned component) } } +static ErrorOr refine_coefficient(Scan& scan, i32& coefficient) +{ + // G.1.2.3 - Coding model for subsequent scans of successive approximation + // See the correction bit from rule b. + u8 const bit = TRY(read_huffman_bits(scan.huffman_stream, 1)); + if (bit == 1) + coefficient |= 1 << scan.successive_approximation_low; + + return {}; +} + static ErrorOr add_dc(JPEGLoadingContext& context, Macroblock& macroblock, ScanComponent const& scan_component) { auto maybe_table = context.dc_tables.get(scan_component.dc_destination_id); @@ -332,6 +343,14 @@ static ErrorOr add_dc(JPEGLoadingContext& context, Macroblock& macroblock, auto& dc_table = maybe_table.value(); auto& scan = context.current_scan; + auto* select_component = get_component(macroblock, scan_component.component.index); + auto& coefficient = select_component[0]; + + if (context.current_scan.successive_approximation_high > 0) { + TRY(refine_coefficient(scan, coefficient)); + return {}; + } + // For DC coefficients, symbol encodes the length of the coefficient. auto dc_length = TRY(get_next_symbol(scan.huffman_stream, dc_table)); if (dc_length > 11) { @@ -346,9 +365,9 @@ static ErrorOr add_dc(JPEGLoadingContext& context, Macroblock& macroblock, if (dc_length != 0 && dc_diff < (1 << (dc_length - 1))) dc_diff -= (1 << dc_length) - 1; - auto* select_component = get_component(macroblock, scan_component.component.index); auto& previous_dc = context.previous_dc_values[scan_component.component.index]; - select_component[0] = previous_dc += dc_diff; + previous_dc += dc_diff; + coefficient = previous_dc << scan.successive_approximation_low; return {}; } @@ -375,6 +394,14 @@ static ErrorOr read_eob(Scan& scan, u32 symbol) return false; } +static bool is_progressive(StartOfFrame::FrameType frame_type) +{ + return frame_type == StartOfFrame::FrameType::Progressive_DCT + || frame_type == StartOfFrame::FrameType::Progressive_DCT_Arithmetic + || frame_type == StartOfFrame::FrameType::Differential_Progressive_DCT + || frame_type == StartOfFrame::FrameType::Differential_Progressive_DCT_Arithmetic; +} + static ErrorOr add_ac(JPEGLoadingContext& context, Macroblock& macroblock, ScanComponent const& scan_component) { auto maybe_table = context.ac_tables.get(scan_component.ac_destination_id); @@ -395,9 +422,12 @@ static ErrorOr add_ac(JPEGLoadingContext& context, Macroblock& macroblock, u32 to_skip = 0; Optional saved_symbol; + Optional saved_bit_for_rule_a; bool in_zrl = false; for (int j = first_coefficient; j <= scan.spectral_selection_end; ++j) { + auto& coefficient = select_component[zigzag_map[j]]; + // AC symbols encode 2 pieces of information, the high 4 bits represent // number of zeroes to be stuffed before reading the coefficient. Low 4 // bits represent the magnitude of the coefficient. @@ -412,9 +442,20 @@ static ErrorOr add_ac(JPEGLoadingContext& context, Macroblock& macroblock, to_skip++; saved_symbol.clear(); } + + if (!in_zrl && is_progressive(context.frame.type) && scan.successive_approximation_high != 0) { + // G.1.2.3 - Coding model for subsequent scans of successive approximation + // Bit sign from rule a + saved_bit_for_rule_a = TRY(read_huffman_bits(scan.huffman_stream, 1)); + } } } + if (coefficient != 0) { + TRY(refine_coefficient(scan, coefficient)); + continue; + } + if (to_skip > 0) { --to_skip; if (to_skip == 0) @@ -425,18 +466,31 @@ static ErrorOr add_ac(JPEGLoadingContext& context, Macroblock& macroblock, if (scan.end_of_bands_run_count > 0) continue; - u8 coeff_length = *saved_symbol & 0x0F; - if (coeff_length > 10) { - dbgln_if(JPEG_DEBUG, "AC coefficient too long: {}!", coeff_length); - return Error::from_string_literal("AC coefficient too long"); - } + if (is_progressive(context.frame.type) && scan.successive_approximation_high != 0) { + // G.1.2.3 - Coding model for subsequent scans of successive approximation + if (auto const low_bits = *saved_symbol & 0x0F; low_bits != 1) { + dbgln_if(JPEG_DEBUG, "AC coefficient low bits isn't equal to 1: {}!", low_bits); + return Error::from_string_literal("AC coefficient low bits isn't equal to 1"); + } - if (coeff_length != 0) { - i32 ac_coefficient = TRY(read_huffman_bits(scan.huffman_stream, coeff_length)); - if (ac_coefficient < (1 << (coeff_length - 1))) - ac_coefficient -= (1 << coeff_length) - 1; + coefficient = (*saved_bit_for_rule_a == 0 ? -1 : 1) << scan.successive_approximation_low; + saved_bit_for_rule_a.clear(); + } else { + // F.1.2.2 - Huffman encoding of AC coefficients + u8 const coeff_length = *saved_symbol & 0x0F; - select_component[zigzag_map[j]] = ac_coefficient; + if (coeff_length > 10) { + dbgln_if(JPEG_DEBUG, "AC coefficient too long: {}!", coeff_length); + return Error::from_string_literal("AC coefficient too long"); + } + + if (coeff_length != 0) { + i32 ac_coefficient = TRY(read_huffman_bits(scan.huffman_stream, coeff_length)); + if (ac_coefficient < (1 << (coeff_length - 1))) + ac_coefficient -= (1 << coeff_length) - 1; + + coefficient = ac_coefficient * (1 << scan.successive_approximation_low); + } } saved_symbol.clear();