diff options
author | Lucas CHOLLET <lucas.chollet@free.fr> | 2023-05-07 15:04:29 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-05-09 07:00:15 +0200 |
commit | 312c398b5982376e4ea49f8763cd3d8bcebb0930 (patch) | |
tree | 8e96b3f0e84c49fb847e8b176f36812b8506bceb | |
parent | 9b5050a11cb594a020f5c5328709935bc74d1963 (diff) | |
download | serenity-312c398b5982376e4ea49f8763cd3d8bcebb0930.zip |
LibGfx/JPEG: Add support for 12 bits JPEGs
This is done by two distinct things:
- Allowing 12 bits AC and DC coefficients
- Adjusting coefficients in the IDCT
While this patch allows to display them we still don't correctly do
the color transformation and ultimately only truncating coefficients to
8 bits.
-rw-r--r-- | Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp index ba8e64b5c4..fcb8d312d3 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp @@ -486,7 +486,11 @@ static ErrorOr<void> add_dc(JPEGLoadingContext& context, Macroblock& macroblock, // For DC coefficients, symbol encodes the length of the coefficient. auto dc_length = TRY(scan.huffman_stream.next_symbol(dc_table)); - if (dc_length > 11) { + + // F.1.2.1.2 - Defining Huffman tables for the DC coefficients + // F.1.5.1 - Structure of DC code table for 12-bit sample precision + if ((context.frame.precision == 8 && dc_length > 11) + || (context.frame.precision == 12 && dc_length > 15)) { dbgln_if(JPEG_DEBUG, "DC coefficient too long: {}!", dc_length); return Error::from_string_literal("DC coefficient too long"); } @@ -612,7 +616,10 @@ static ErrorOr<void> add_ac(JPEGLoadingContext& context, Macroblock& macroblock, // F.1.2.2 - Huffman encoding of AC coefficients u8 const coeff_length = *saved_symbol & 0x0F; - if (coeff_length > 10) { + // F.1.2.2.1 - Structure of AC code table + // F.1.5.2 - Structure of AC code table for 12-bit sample precision + if ((context.frame.precision == 8 && coeff_length > 10) + || (context.frame.precision == 12 && coeff_length > 14)) { dbgln_if(JPEG_DEBUG, "AC coefficient too long: {}!", coeff_length); return Error::from_string_literal("AC coefficient too long"); } @@ -1137,6 +1144,12 @@ static ErrorOr<void> ensure_standard_precision(StartOfFrame const& frame) if (frame.precision == 8) return {}; + if (frame.type == StartOfFrame::FrameType::Extended_Sequential_DCT && frame.precision == 12) + return {}; + + if (frame.type == StartOfFrame::FrameType::Progressive_DCT && frame.precision == 12) + return {}; + dbgln_if(JPEG_DEBUG, "Unsupported precision: {}, for SOF type: {}!", frame.precision, static_cast<int>(frame.type)); return Error::from_string_literal("Unsupported SOF precision."); } @@ -1457,7 +1470,8 @@ static void inverse_dct(JPEGLoadingContext const& context, Vector<Macroblock>& m } // F.2.1.5 - Inverse DCT (IDCT) - + auto const level_shift = 1 << (context.frame.precision - 1); + auto const max_value = (1 << context.frame.precision) - 1; for (u32 vcursor = 0; vcursor < context.mblock_meta.vcount; vcursor += context.vsample_factor) { for (u32 hcursor = 0; hcursor < context.mblock_meta.hcount; hcursor += context.hsample_factor) { for (u8 vfactor_i = 0; vfactor_i < context.vsample_factor; ++vfactor_i) { @@ -1465,10 +1479,19 @@ static void inverse_dct(JPEGLoadingContext const& context, Vector<Macroblock>& m u32 mb_index = (vcursor + vfactor_i) * context.mblock_meta.hpadded_count + (hcursor + hfactor_i); for (u8 i = 0; i < 8; ++i) { for (u8 j = 0; j < 8; ++j) { - macroblocks[mb_index].r[i * 8 + j] = clamp(macroblocks[mb_index].r[i * 8 + j] + 128, 0, 255); - macroblocks[mb_index].g[i * 8 + j] = clamp(macroblocks[mb_index].g[i * 8 + j] + 128, 0, 255); - macroblocks[mb_index].b[i * 8 + j] = clamp(macroblocks[mb_index].b[i * 8 + j] + 128, 0, 255); - macroblocks[mb_index].k[i * 8 + j] = clamp(macroblocks[mb_index].k[i * 8 + j] + 128, 0, 255); + + // FIXME: This just truncate all coefficients, it's an easy way to support (read hack) + // 12 bits JPEGs without rewriting all color transformations. + auto const clamp_to_8_bits = [&](u16 color) -> u8 { + if (context.frame.precision == 8) + return static_cast<u8>(color); + return static_cast<u8>(color >> 4); + }; + + macroblocks[mb_index].r[i * 8 + j] = clamp_to_8_bits(clamp(macroblocks[mb_index].r[i * 8 + j] + level_shift, 0, max_value)); + macroblocks[mb_index].g[i * 8 + j] = clamp_to_8_bits(clamp(macroblocks[mb_index].g[i * 8 + j] + level_shift, 0, max_value)); + macroblocks[mb_index].b[i * 8 + j] = clamp_to_8_bits(clamp(macroblocks[mb_index].b[i * 8 + j] + level_shift, 0, max_value)); + macroblocks[mb_index].k[i * 8 + j] = clamp_to_8_bits(clamp(macroblocks[mb_index].k[i * 8 + j] + level_shift, 0, max_value)); } } } |