mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:57:35 +00:00
LibGfx/JPEG: Support refinement scans
These scans are only present in progressive JPEGs and contains bits to increase the precision of values acquired in previous scans.
This commit is contained in:
parent
8806e66f66
commit
fbad9a70fc
1 changed files with 66 additions and 12 deletions
|
@ -321,6 +321,17 @@ static inline i32* get_component(Macroblock& block, unsigned component)
|
|||
}
|
||||
}
|
||||
|
||||
static ErrorOr<void> 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<void> 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<void> 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<void> 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<bool> 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<void> 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<void> add_ac(JPEGLoadingContext& context, Macroblock& macroblock,
|
|||
|
||||
u32 to_skip = 0;
|
||||
Optional<u8> saved_symbol;
|
||||
Optional<u8> 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<void> 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<void> 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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue