Переглянути джерело

LibGfx/JPEG2000: Read COC marker segments, both in main and tile headers

Not yet used for anything.
Nico Weber 1 рік тому
батько
коміт
b364a58753

+ 38 - 1
Userland/Libraries/LibGfx/ImageFormats/JPEG2000Loader.cpp

@@ -334,6 +334,36 @@ static ErrorOr<CodingStyleDefault> read_coding_style_default(ReadonlyBytes data)
     return cod;
 }
 
+// A.6.2 Coding style component (COC)
+struct CodingStyleComponent {
+    u16 component_index { 0 }; // "Ccoc" in spec.
+
+    // Table A.23 – Coding style parameter values for the Scoc parameter
+    bool has_explicit_precinct_size { false }; // "Scoc" in spec.
+
+    CodingStyleParameters parameters;
+};
+
+static ErrorOr<CodingStyleComponent> read_coding_style_component(ReadonlyBytes data, size_t number_of_components)
+{
+    FixedMemoryStream stream { data };
+
+    // Table A.22 – Coding style component parameter values
+    CodingStyleComponent coc;
+    if (number_of_components < 257)
+        coc.component_index = TRY(stream.read_value<u8>());
+    else
+        coc.component_index = TRY(stream.read_value<BigEndian<u16>>());
+
+    u8 Scoc = TRY(stream.read_value<u8>());
+    coc.has_explicit_precinct_size = Scoc & 1;
+
+    dbgln_if(JPEG2000_DEBUG, "JPEG2000ImageDecoderPlugin: COC marker segment: component_index={}", coc.component_index);
+    coc.parameters = TRY(read_coding_style_parameters(data.slice(TRY(stream.tell())), "COC"sv, coc.has_explicit_precinct_size));
+
+    return coc;
+}
+
 // A.6.4 Quantization default (QCD)
 struct QuantizationDefault {
     enum QuantizationStyle {
@@ -479,6 +509,7 @@ struct TilePartData {
 
 struct TileData {
     Optional<CodingStyleDefault> cod;
+    Vector<CodingStyleComponent> cocs;
     Optional<QuantizationDefault> qcd;
     Vector<QuantizationComponent> qccs;
     Vector<TilePartData> tile_parts;
@@ -502,6 +533,7 @@ struct JPEG2000LoadingContext {
     // Data from marker segments:
     ImageAndTileSize siz;
     CodingStyleDefault cod;
+    Vector<CodingStyleComponent> cocs;
     QuantizationDefault qcd;
     Vector<QuantizationComponent> qccs;
     Vector<Comment> coms;
@@ -587,6 +619,8 @@ static ErrorOr<void> parse_codestream_main_header(JPEG2000LoadingContext& contex
                     return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Multiple COD markers in main header");
                 context.cod = TRY(read_coding_style_default(marker.data.value()));
                 saw_COD_marker = true;
+            } else if (marker.marker == J2K_COC) {
+                context.cocs.append(TRY(read_coding_style_component(marker.data.value(), context.siz.components.size())));
             } else if (marker.marker == J2K_QCD) {
                 if (saw_QCD_marker)
                     return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Multiple QCD markers in main header");
@@ -617,7 +651,8 @@ static ErrorOr<void> parse_codestream_main_header(JPEG2000LoadingContext& contex
                 [](Empty) -> size_t { VERIFY_NOT_REACHED(); },
                 [](Vector<QuantizationDefault::ReversibleStepSize> const& step_sizes) { return step_sizes.size(); },
                 [](Vector<QuantizationDefault::IrreversibleStepSize> const& step_sizes) { return step_sizes.size(); });
-            if (context.qcd.quantization_style != QuantizationDefault::ScalarDerived && step_sizes_count < context.cod.number_of_decomposition_levels * 3u + 1u)
+            // FIXME: What if number_of_decomposition_levels is in context.cocs and varies by component?
+            if (context.qcd.quantization_style != QuantizationDefault::ScalarDerived && step_sizes_count < context.cod.parameters.number_of_decomposition_levels * 3u + 1u)
                 return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Not enough step sizes for number of decomposition levels");
 
             return {};
@@ -676,6 +711,8 @@ static ErrorOr<void> parse_codestream_tile_header(JPEG2000LoadingContext& contex
                 if (tile.cod.has_value())
                     return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Multiple COD markers in tile header");
                 tile.cod = TRY(read_coding_style_default(marker.data.value()));
+            } else if (marker.marker == J2K_COC) {
+                tile.cocs.append(TRY(read_coding_style_component(marker.data.value(), context.siz.components.size())));
             } else if (marker.marker == J2K_QCD) {
                 if (tile.qcd.has_value())
                     return Error::from_string_literal("JPEG2000ImageDecoderPlugin: Multiple QCD markers in tile header");