Selaa lähdekoodia

LibGfx/JPEG: Support up to 4 quantization tables

We used to limit this number to two and name them with their usual
usage. The specification is however broader, and you can find files that
use more tables as in the following link:

https://www.w3.org/MarkUp/Test/xhtml-print/20050519/tests/A_2_1-BF-01.htm
Lucas CHOLLET 2 vuotta sitten
vanhempi
commit
dd5d2e3505
1 muutettua tiedostoa jossa 27 lisäystä ja 12 poistoa
  1. 27 12
      Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp

+ 27 - 12
Userland/Libraries/LibGfx/ImageFormats/JPEGLoader.cpp

@@ -237,8 +237,8 @@ struct JPEGLoadingContext {
 
 
     State state { State::NotDecoded };
     State state { State::NotDecoded };
 
 
-    u32 luma_table[64] = { 0 };
-    u32 chroma_table[64] = { 0 };
+    Array<Optional<Array<u16, 64>>, 4> quantization_tables {};
+
     StartOfFrame frame;
     StartOfFrame frame;
     u8 hsample_factor { 0 };
     u8 hsample_factor { 0 };
     u8 vsample_factor { 0 };
     u8 vsample_factor { 0 };
@@ -1064,10 +1064,6 @@ static ErrorOr<void> read_start_of_frame(Stream& stream, JPEGLoadingContext& con
         }
         }
 
 
         component.qtable_id = TRY(stream.read_value<u8>());
         component.qtable_id = TRY(stream.read_value<u8>());
-        if (component.qtable_id > 1) {
-            dbgln_if(JPEG_DEBUG, "Unsupported quantization table id: {}!", component.qtable_id);
-            return Error::from_string_literal("Unsupported quantization table id");
-        }
 
 
         context.components.append(move(component));
         context.components.append(move(component));
     }
     }
@@ -1077,6 +1073,8 @@ static ErrorOr<void> read_start_of_frame(Stream& stream, JPEGLoadingContext& con
 
 
 static ErrorOr<void> read_quantization_table(Stream& stream, JPEGLoadingContext& context)
 static ErrorOr<void> read_quantization_table(Stream& stream, JPEGLoadingContext& context)
 {
 {
+    // B.2.4.1 - Quantization table-specification syntax
+
     u16 bytes_to_read = TRY(stream.read_value<BigEndian<u16>>()) - 2;
     u16 bytes_to_read = TRY(stream.read_value<BigEndian<u16>>()) - 2;
     while (bytes_to_read > 0) {
     while (bytes_to_read > 0) {
         u8 const info_byte = TRY(stream.read_value<u8>());
         u8 const info_byte = TRY(stream.read_value<u8>());
@@ -1086,11 +1084,19 @@ static ErrorOr<void> read_quantization_table(Stream& stream, JPEGLoadingContext&
             return Error::from_string_literal("Unsupported unit hint in quantization table");
             return Error::from_string_literal("Unsupported unit hint in quantization table");
         }
         }
         u8 const table_id = info_byte & 0x0F;
         u8 const table_id = info_byte & 0x0F;
-        if (table_id > 1) {
+
+        if (table_id > 3) {
             dbgln_if(JPEG_DEBUG, "Unsupported quantization table id: {}!", table_id);
             dbgln_if(JPEG_DEBUG, "Unsupported quantization table id: {}!", table_id);
             return Error::from_string_literal("Unsupported quantization table id");
             return Error::from_string_literal("Unsupported quantization table id");
         }
         }
-        u32* const table = table_id == 0 ? context.luma_table : context.chroma_table;
+
+        auto& maybe_table = context.quantization_tables[table_id];
+
+        if (!maybe_table.has_value())
+            maybe_table = Array<u16, 64> {};
+
+        auto& table = maybe_table.value();
+
         for (int i = 0; i < 64; i++) {
         for (int i = 0; i < 64; i++) {
             if (element_unit_hint == 0)
             if (element_unit_hint == 0)
                 table[zigzag_map[i]] = TRY(stream.read_value<u8>());
                 table[zigzag_map[i]] = TRY(stream.read_value<u8>());
@@ -1115,13 +1121,20 @@ static ErrorOr<void> skip_segment(Stream& stream)
     return {};
     return {};
 }
 }
 
 
-static void dequantize(JPEGLoadingContext& context, Vector<Macroblock>& macroblocks)
+static ErrorOr<void> dequantize(JPEGLoadingContext& context, Vector<Macroblock>& macroblocks)
 {
 {
     for (u32 vcursor = 0; vcursor < context.mblock_meta.vcount; vcursor += context.vsample_factor) {
     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 (u32 hcursor = 0; hcursor < context.mblock_meta.hcount; hcursor += context.hsample_factor) {
             for (u32 i = 0; i < context.components.size(); i++) {
             for (u32 i = 0; i < context.components.size(); i++) {
-                auto& component = context.components[i];
-                u32 const* table = component.qtable_id == 0 ? context.luma_table : context.chroma_table;
+                auto const& component = context.components[i];
+
+                if (!context.quantization_tables[component.qtable_id].has_value()) {
+                    dbgln_if(JPEG_DEBUG, "Unknown quantization table id: {}!", component.qtable_id);
+                    return Error::from_string_literal("Unknown quantization table id");
+                }
+
+                auto const& table = context.quantization_tables[component.qtable_id].value();
+
                 for (u32 vfactor_i = 0; vfactor_i < component.vsample_factor; vfactor_i++) {
                 for (u32 vfactor_i = 0; vfactor_i < component.vsample_factor; vfactor_i++) {
                     for (u32 hfactor_i = 0; hfactor_i < component.hsample_factor; hfactor_i++) {
                     for (u32 hfactor_i = 0; hfactor_i < component.hsample_factor; hfactor_i++) {
                         u32 macroblock_index = (vcursor + vfactor_i) * context.mblock_meta.hpadded_count + (hfactor_i + hcursor);
                         u32 macroblock_index = (vcursor + vfactor_i) * context.mblock_meta.hpadded_count + (hfactor_i + hcursor);
@@ -1134,6 +1147,8 @@ static void dequantize(JPEGLoadingContext& context, Vector<Macroblock>& macroblo
             }
             }
         }
         }
     }
     }
+
+    return {};
 }
 }
 
 
 static void inverse_dct(JPEGLoadingContext const& context, Vector<Macroblock>& macroblocks)
 static void inverse_dct(JPEGLoadingContext const& context, Vector<Macroblock>& macroblocks)
@@ -1706,7 +1721,7 @@ static ErrorOr<void> decode_jpeg(JPEGLoadingContext& context)
 {
 {
     TRY(decode_header(context));
     TRY(decode_header(context));
     auto macroblocks = TRY(construct_macroblocks(context));
     auto macroblocks = TRY(construct_macroblocks(context));
-    dequantize(context, macroblocks);
+    TRY(dequantize(context, macroblocks));
     inverse_dct(context, macroblocks);
     inverse_dct(context, macroblocks);
     TRY(handle_color_transform(context, macroblocks));
     TRY(handle_color_transform(context, macroblocks));
     TRY(compose_bitmap(context, macroblocks));
     TRY(compose_bitmap(context, macroblocks));