mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 09:07: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)
|
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);
|
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& dc_table = maybe_table.value();
|
||||||
auto& scan = context.current_scan;
|
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.
|
// For DC coefficients, symbol encodes the length of the coefficient.
|
||||||
auto dc_length = TRY(get_next_symbol(scan.huffman_stream, dc_table));
|
auto dc_length = TRY(get_next_symbol(scan.huffman_stream, dc_table));
|
||||||
if (dc_length > 11) {
|
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)))
|
if (dc_length != 0 && dc_diff < (1 << (dc_length - 1)))
|
||||||
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];
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -375,6 +394,14 @@ static ErrorOr<bool> read_eob(Scan& scan, u32 symbol)
|
||||||
return false;
|
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)
|
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);
|
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;
|
u32 to_skip = 0;
|
||||||
Optional<u8> saved_symbol;
|
Optional<u8> saved_symbol;
|
||||||
|
Optional<u8> saved_bit_for_rule_a;
|
||||||
bool in_zrl = false;
|
bool in_zrl = false;
|
||||||
|
|
||||||
for (int j = first_coefficient; j <= scan.spectral_selection_end; ++j) {
|
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
|
// AC symbols encode 2 pieces of information, the high 4 bits represent
|
||||||
// number of zeroes to be stuffed before reading the coefficient. Low 4
|
// number of zeroes to be stuffed before reading the coefficient. Low 4
|
||||||
// bits represent the magnitude of the coefficient.
|
// bits represent the magnitude of the coefficient.
|
||||||
|
@ -412,9 +442,20 @@ static ErrorOr<void> add_ac(JPEGLoadingContext& context, Macroblock& macroblock,
|
||||||
to_skip++;
|
to_skip++;
|
||||||
saved_symbol.clear();
|
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) {
|
if (to_skip > 0) {
|
||||||
--to_skip;
|
--to_skip;
|
||||||
if (to_skip == 0)
|
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)
|
if (scan.end_of_bands_run_count > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
u8 coeff_length = *saved_symbol & 0x0F;
|
if (is_progressive(context.frame.type) && scan.successive_approximation_high != 0) {
|
||||||
if (coeff_length > 10) {
|
// G.1.2.3 - Coding model for subsequent scans of successive approximation
|
||||||
dbgln_if(JPEG_DEBUG, "AC coefficient too long: {}!", coeff_length);
|
if (auto const low_bits = *saved_symbol & 0x0F; low_bits != 1) {
|
||||||
return Error::from_string_literal("AC coefficient too long");
|
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) {
|
coefficient = (*saved_bit_for_rule_a == 0 ? -1 : 1) << scan.successive_approximation_low;
|
||||||
i32 ac_coefficient = TRY(read_huffman_bits(scan.huffman_stream, coeff_length));
|
saved_bit_for_rule_a.clear();
|
||||||
if (ac_coefficient < (1 << (coeff_length - 1)))
|
} else {
|
||||||
ac_coefficient -= (1 << coeff_length) - 1;
|
// 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();
|
saved_symbol.clear();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue