From d71b51c3bc907bb2e97e40cd25fbc9108ad6eb2a Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 17 Nov 2025 16:04:16 -0500 Subject: [PATCH 1/7] LibGfx/JBIG2Shared: Give RegionSegmentInformationField rect() accessor No behavior change. --- Userland/Libraries/LibGfx/ImageFormats/JBIG2Shared.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Shared.h b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Shared.h index 76faa9cc682208..3bf3958a156250 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Shared.h +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Shared.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace Gfx::JBIG2 { @@ -118,6 +119,11 @@ struct [[gnu::packed]] RegionSegmentInformationField { BigEndian y_location; u8 flags { 0 }; + IntRect rect() const + { + return { x_location, y_location, width, height }; + } + CombinationOperator external_combination_operator() const { VERIFY((flags & 0x7) <= 4); From 195626d4a6d179e8da6f175e75134712a7187248 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 16 Nov 2025 16:52:11 -0500 Subject: [PATCH 2/7] LibGfx/JBIG2Loader: Add support for refinement regions refining the page This was blocked on not having test files. We're about to teach the writer to generate test files and to add test files, so we can add support for this now :^) --- .../LibGfx/ImageFormats/JBIG2Loader.cpp | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp index d26523cceb1374..1430ea3c0df0c4 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp @@ -3190,16 +3190,19 @@ static ErrorOr decode_generic_refinement_region(JBIG2LoadingContex // "3) Determine the buffer associated with the region segment that this segment refers to." // Details described in 7.4.7.4 Reference bitmap selection. - BilevelImage const* reference_bitmap = nullptr; - if (segment.referred_to_segments.size() == 1) { - reference_bitmap = segment.referred_to_segments[0]->aux_buffer.ptr(); - VERIFY(reference_bitmap->width() == segment.referred_to_segments[0]->aux_buffer_information_field.width); - VERIFY(reference_bitmap->height() == segment.referred_to_segments[0]->aux_buffer_information_field.height); - } else { - // When adding support for this and for intermediate generic refinement regions, make sure to only allow - // this case for immediate generic refinement regions. - return Error::from_string_literal("JBIG2ImageDecoderPlugin: Generic refinement region without reference segment not yet implemented"); - } + BilevelSubImage reference_bitmap = [&]() { + if (segment.referred_to_segments.size() == 1) { + auto reference_bitmap = segment.referred_to_segments[0]->aux_buffer; + VERIFY(reference_bitmap->width() == segment.referred_to_segments[0]->aux_buffer_information_field.width); + VERIFY(reference_bitmap->height() == segment.referred_to_segments[0]->aux_buffer_information_field.height); + return reference_bitmap->as_subbitmap(); + } + + // Enforced by validate_segment_header_references() earlier. + VERIFY(segment.type() != JBIG2::SegmentType::IntermediateGenericRefinementRegion); + + return context.page.bits->subbitmap(information_field.rect()); + }(); // "4) Invoke the generic refinement region decoding procedure described in 6.3, with the parameters to the // generic refinement region decoding procedure set as shown in Table 38." @@ -3208,8 +3211,7 @@ static ErrorOr decode_generic_refinement_region(JBIG2LoadingContex inputs.region_width = information_field.width; inputs.region_height = information_field.height; inputs.gr_template = arithmetic_coding_template; - auto subbitmap = reference_bitmap->as_subbitmap(); - inputs.reference_bitmap = &subbitmap; + inputs.reference_bitmap = &reference_bitmap; inputs.reference_x_offset = 0; inputs.reference_y_offset = 0; inputs.is_typical_prediction_used = typical_prediction_generic_refinement_on; From c32a6f7510b163268d2410508f0f2c367ef5e140 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 16 Nov 2025 13:52:49 -0500 Subject: [PATCH 3/7] LibGfx/JBIG2Loader: Make decode_embedded() return BilevelImage No behavior change. --- Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp | 4 ++-- Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.h | 3 ++- Userland/Libraries/LibPDF/Filter.cpp | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp index 1430ea3c0df0c4..1cba3d8d3740d9 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp @@ -3668,7 +3668,7 @@ ErrorOr JBIG2ImageDecoderPlugin::frame(size_t index, Optio return ImageFrameDescriptor { move(bitmap), 0 }; } -ErrorOr JBIG2ImageDecoderPlugin::decode_embedded(Vector data) +ErrorOr> JBIG2ImageDecoderPlugin::decode_embedded(Vector data) { auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) JBIG2ImageDecoderPlugin({}))); plugin->m_context->organization = JBIG2::Organization::Embedded; @@ -3685,7 +3685,7 @@ ErrorOr JBIG2ImageDecoderPlugin::decode_embedded(Vectorm_context)); - return plugin->m_context->page.bits->to_byte_buffer(); + return *plugin->m_context->page.bits; } } diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.h b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.h index 20395377a7512e..02784bbb2115e4 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.h +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.h @@ -12,6 +12,7 @@ namespace Gfx { +class BilevelImage; struct JBIG2LoadingContext; struct MQArithmeticCoderContext; class MQArithmeticDecoder; @@ -69,7 +70,7 @@ class JBIG2ImageDecoderPlugin : public ImageDecoderPlugin { virtual size_t frame_count() override; virtual ErrorOr frame(size_t index, Optional ideal_size = {}) override; - static ErrorOr decode_embedded(Vector); + static ErrorOr> decode_embedded(Vector); private: JBIG2ImageDecoderPlugin(JBIG2DecoderOptions); diff --git a/Userland/Libraries/LibPDF/Filter.cpp b/Userland/Libraries/LibPDF/Filter.cpp index a64c37302caf3b..9641b2e9a2297e 100644 --- a/Userland/Libraries/LibPDF/Filter.cpp +++ b/Userland/Libraries/LibPDF/Filter.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -309,7 +310,7 @@ PDFErrorOr Filter::decode_jbig2(Document* document, ReadonlyBytes by } segments.append(bytes); - auto decoded = TRY(Gfx::JBIG2ImageDecoderPlugin::decode_embedded(segments)); + auto decoded = TRY(TRY(Gfx::JBIG2ImageDecoderPlugin::decode_embedded(segments))->to_byte_buffer()); // JBIG2 treats `1` as "ink present" (black) and `0` as "no ink" (white). // PDF treats `1` as "light present" (white) and `1` as "no light" (black). From 54dc8d8d9976c54528b315fb5afd1eac1deaf09b Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 16 Nov 2025 15:34:05 -0500 Subject: [PATCH 4/7] LibGfx/JBIG2Writer: Put reference_bitmap computation into IIFE ...and add some spec comments. No behavior change. --- .../LibGfx/ImageFormats/JBIG2Writer.cpp | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp index e4ff5d689d0a63..d71c2dc02d108b 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp @@ -2266,24 +2266,36 @@ static ErrorOr encode_generic_refinement_region(JBIG2::GenericRefinementRe // 7.4.7 Generic refinement region syntax if (header.referred_to_segments.size() > 1) return Error::from_string_literal("JBIG2Writer: Generic refinement region must refer to at most one segment"); - if (header.referred_to_segments.size() == 0) - return Error::from_string_literal("JBIG2Writer: Generic refinement region refining page not yet implemented"); - auto maybe_segment = context.segment_by_id.get(header.referred_to_segments[0].segment_number); - if (!maybe_segment.has_value()) - return Error::from_string_literal("JBIG2Writer: Could not find referred-to segment for generic refinement region"); - auto const& referred_to_segment = *maybe_segment.value(); + // 7.4.7.4 Reference bitmap selection + auto const* reference_bitmap = TRY([&]() -> ErrorOr { + // "If this segment refers to another region segment, then set the reference bitmap GRREFERENCE to be the current + // contents of the auxiliary buffer associated with the region segment that this segment refers to." + if (header.referred_to_segments.size() == 1) { + auto maybe_segment = context.segment_by_id.get(header.referred_to_segments[0].segment_number); + if (!maybe_segment.has_value()) + return Error::from_string_literal("JBIG2Writer: Could not find referred-to segment for generic refinement region"); + auto const& referred_to_segment = *maybe_segment.value(); + + return referred_to_segment.data.visit( + [](JBIG2::IntermediateGenericRegionSegmentData const& generic_region_wrapper) -> ErrorOr { + return generic_region_wrapper.generic_region.image; + }, + [](JBIG2::IntermediateGenericRefinementRegionSegmentData const& generic_refinement_region_wrapper) -> ErrorOr { + return generic_refinement_region_wrapper.generic_refinement_region.image; + }, + [](auto const&) -> ErrorOr { + return Error::from_string_literal("JBIG2Writer: Generic refinement region can only refer to intermediate region segments"); + }); + } - auto const* reference_bitmap = TRY(referred_to_segment.data.visit( - [](JBIG2::IntermediateGenericRegionSegmentData const& generic_region_wrapper) -> ErrorOr { - return generic_region_wrapper.generic_region.image; - }, - [](JBIG2::IntermediateGenericRefinementRegionSegmentData const& generic_refinement_region_wrapper) -> ErrorOr { - return generic_refinement_region_wrapper.generic_refinement_region.image; - }, - [](auto const&) -> ErrorOr { - return Error::from_string_literal("JBIG2Writer: Generic refinement region can only refer to intermediate region segments"); - })); + // "If this segment does not refer to another region segment, set GRREFERENCE to be a bitmap containing the current + // contents of the page buffer (see clause 8), restricted to the area of the page buffer specified by this segment's region + // segment information field." + // FIXME + VERIFY(header.referred_to_segments.size() == 0); + return Error::from_string_literal("JBIG2Writer: Generic refinement region refining page not yet implemented"); + }()); GenericRefinementRegionEncodingInputParameters inputs { .image = *generic_refinement_region.image, From ad5620b5c99dae9577dbbde4918ed5c02646f088 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 17 Nov 2025 15:58:49 -0500 Subject: [PATCH 5/7] LibGfx/JBIG2Writer: Make refinement reference image a BilevelSubImage The page refinement code will have to apply a crop to the page buffer. With this, that's easy to do. No behavior change. --- .../LibGfx/ImageFormats/JBIG2Writer.cpp | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp index d71c2dc02d108b..8a270dd5dc189e 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp @@ -337,7 +337,7 @@ namespace { struct GenericRefinementRegionEncodingInputParameters { BilevelImage const& image; // Of dimensions "GRW" x "GRH" in spec terms. u8 gr_template { 0 }; // "GRTEMPLATE" in spec. - BilevelImage const* reference_bitmap { nullptr }; // "GRREFERENCE" in spec. + BilevelSubImage reference_bitmap; // "GRREFERENCE" in spec. i32 reference_x_offset { 0 }; // "GRREFERENCEDX" in spec. i32 reference_y_offset { 0 }; // "GRREFERENCEDY" in spec. bool is_typical_prediction_used { false }; // "TPGRON" in spec. @@ -378,7 +378,7 @@ static ErrorOr generic_refinement_region_encoding_procedure(GenericRefinem }; // Figure 12 – 13-pixel refinement template showing the AT pixels at their nominal locations - constexpr auto compute_context_0 = [](ReadonlySpan adaptive_pixels, BilevelImage const& reference, int reference_x, int reference_y, BilevelImage const& buffer, int x, int y) -> u16 { + constexpr auto compute_context_0 = [](ReadonlySpan adaptive_pixels, BilevelSubImage const& reference, int reference_x, int reference_y, BilevelImage const& buffer, int x, int y) -> u16 { u16 result = 0; for (int dy = -1; dy <= 1; ++dy) { @@ -399,7 +399,7 @@ static ErrorOr generic_refinement_region_encoding_procedure(GenericRefinem }; // Figure 13 – 10-pixel refinement template - constexpr auto compute_context_1 = [](ReadonlySpan, BilevelImage const& reference, int reference_x, int reference_y, BilevelImage const& buffer, int x, int y) -> u16 { + constexpr auto compute_context_1 = [](ReadonlySpan, BilevelSubImage const& reference, int reference_x, int reference_y, BilevelImage const& buffer, int x, int y) -> u16 { u16 result = 0; for (int dy = -1; dy <= 1; ++dy) { @@ -440,10 +440,10 @@ static ErrorOr generic_refinement_region_encoding_procedure(GenericRefinem auto predict = [&](size_t x, size_t y) -> Optional { // "• a 3 × 3 pixel array in the reference bitmap (Figure 16), centred at the location // corresponding to the current pixel, contains pixels all of the same value." - bool prediction = get_pixel(*inputs.reference_bitmap, x - inputs.reference_x_offset - 1, y - inputs.reference_y_offset - 1); + bool prediction = get_pixel(inputs.reference_bitmap, x - inputs.reference_x_offset - 1, y - inputs.reference_y_offset - 1); for (int dy = -1; dy <= 1; ++dy) for (int dx = -1; dx <= 1; ++dx) - if (get_pixel(*inputs.reference_bitmap, x - inputs.reference_x_offset + dx, y - inputs.reference_y_offset + dy) != prediction) + if (get_pixel(inputs.reference_bitmap, x - inputs.reference_x_offset + dx, y - inputs.reference_y_offset + dy) != prediction) return {}; return prediction; }; @@ -471,7 +471,7 @@ static ErrorOr generic_refinement_region_encoding_procedure(GenericRefinem // "c) If LTP = 0 then, from left to right, explicitly decode all pixels of the current row of GRREG. The // procedure for each pixel is as follows:" for (size_t x = 0; x < width; ++x) { - u16 context = compute_context(inputs.adaptive_template_pixels, *inputs.reference_bitmap, x - inputs.reference_x_offset, y - inputs.reference_y_offset, inputs.image, x, y); + u16 context = compute_context(inputs.adaptive_template_pixels, inputs.reference_bitmap, x - inputs.reference_x_offset, y - inputs.reference_y_offset, inputs.image, x, y); encoder.encode_bit(inputs.image.get_bit(x, y), contexts.contexts[context]); } } else { @@ -484,7 +484,7 @@ static ErrorOr generic_refinement_region_encoding_procedure(GenericRefinem // TPGRON must be 1 if LTP is set. (The spec has an explicit "TPGRON is 1 AND" check here, but it is pointless.) VERIFY(inputs.is_typical_prediction_used); if (!prediction.has_value()) { - u16 context = compute_context(inputs.adaptive_template_pixels, *inputs.reference_bitmap, x - inputs.reference_x_offset, y - inputs.reference_y_offset, inputs.image, x, y); + u16 context = compute_context(inputs.adaptive_template_pixels, inputs.reference_bitmap, x - inputs.reference_x_offset, y - inputs.reference_y_offset, inputs.image, x, y); encoder.encode_bit(inputs.image.get_bit(x, y), contexts.contexts[context]); } } @@ -726,7 +726,7 @@ static ErrorOr text_region_encoding_procedure(TextRegionEncodingInputParam auto reference_bitmap = TRY(symbol_image(symbol)); GenericRefinementRegionEncodingInputParameters refinement_inputs { .image = symbol_instance.refinement_data->refines_to, - .reference_bitmap = reference_bitmap, + .reference_bitmap = reference_bitmap->as_subbitmap(), }; // FIXME: Instead, just compute the delta here instead of having it be passed in? @@ -1136,7 +1136,7 @@ static ErrorOr symbol_dictionary_encoding_procedure(SymbolDictionary // Table 18 – Parameters used to decode a symbol's bitmap when REFAGGNINST = 1 GenericRefinementRegionEncodingInputParameters refinement_inputs { .image = *refinement_image.refines_to, - .reference_bitmap = IBO, + .reference_bitmap = IBO->as_subbitmap(), }; refinement_inputs.gr_template = inputs.refinement_template; refinement_inputs.reference_x_offset = refinement_image.delta_x_offset; @@ -2268,7 +2268,7 @@ static ErrorOr encode_generic_refinement_region(JBIG2::GenericRefinementRe return Error::from_string_literal("JBIG2Writer: Generic refinement region must refer to at most one segment"); // 7.4.7.4 Reference bitmap selection - auto const* reference_bitmap = TRY([&]() -> ErrorOr { + auto const reference_bitmap = TRY([&]() -> ErrorOr { // "If this segment refers to another region segment, then set the reference bitmap GRREFERENCE to be the current // contents of the auxiliary buffer associated with the region segment that this segment refers to." if (header.referred_to_segments.size() == 1) { @@ -2277,16 +2277,17 @@ static ErrorOr encode_generic_refinement_region(JBIG2::GenericRefinementRe return Error::from_string_literal("JBIG2Writer: Could not find referred-to segment for generic refinement region"); auto const& referred_to_segment = *maybe_segment.value(); - return referred_to_segment.data.visit( - [](JBIG2::IntermediateGenericRegionSegmentData const& generic_region_wrapper) -> ErrorOr { - return generic_region_wrapper.generic_region.image; - }, - [](JBIG2::IntermediateGenericRefinementRegionSegmentData const& generic_refinement_region_wrapper) -> ErrorOr { - return generic_refinement_region_wrapper.generic_refinement_region.image; - }, - [](auto const&) -> ErrorOr { - return Error::from_string_literal("JBIG2Writer: Generic refinement region can only refer to intermediate region segments"); - }); + return TRY(referred_to_segment.data.visit( + [](JBIG2::IntermediateGenericRegionSegmentData const& generic_region_wrapper) -> ErrorOr { + return generic_region_wrapper.generic_region.image; + }, + [](JBIG2::IntermediateGenericRefinementRegionSegmentData const& generic_refinement_region_wrapper) -> ErrorOr { + return generic_refinement_region_wrapper.generic_refinement_region.image; + }, + [](auto const&) -> ErrorOr { + return Error::from_string_literal("JBIG2Writer: Generic refinement region can only refer to intermediate region segments"); + })) + ->as_subbitmap(); } // "If this segment does not refer to another region segment, set GRREFERENCE to be a bitmap containing the current From 906c2088297a300e9f527329d443c2b08e2b6a48 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 16 Nov 2025 16:06:54 -0500 Subject: [PATCH 6/7] LibGfx/JBIG2Writer: Add support for refinement regions refining the page Encoding a generic refinement region that refines the page contents requires that the writer has access to the current page contents. For some region types (text, halftone), computing the output bitmap isn't trivial, and handling all the composition operators and so on is also not trivial. Reimplementing all this in the writer doesn't seem ideal. So instead, when encountering a generic refinement region refining the page contents in the writer, collect the encoded segment data for all segments for the current page (and for the "global page" 0) that are in front of the refinement region, and call into the *loader* to decode the data so far, and then refine the bitmap returned by the loader. This requires storing the encoded data for each segment, but we do that already for implementing writing files in random access organization. It also requires making the list of segments available on JBIG2EncodingContext. --- .../LibGfx/ImageFormats/JBIG2Writer.cpp | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp index 8a270dd5dc189e..3fa749dbba088e 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1543,6 +1544,13 @@ struct SerializedSegmentData { }; struct JBIG2EncodingContext { + JBIG2EncodingContext(Vector const& segments) + : segments(segments) + { + } + + Vector const& segments; + HashMap segment_by_id; HashMap segment_data_by_id; @@ -2293,9 +2301,18 @@ static ErrorOr encode_generic_refinement_region(JBIG2::GenericRefinementRe // "If this segment does not refer to another region segment, set GRREFERENCE to be a bitmap containing the current // contents of the page buffer (see clause 8), restricted to the area of the page buffer specified by this segment's region // segment information field." - // FIXME VERIFY(header.referred_to_segments.size() == 0); - return Error::from_string_literal("JBIG2Writer: Generic refinement region refining page not yet implemented"); + Vector preceding_segments_on_same_page; + for (auto const& segment : context.segments) { + if (segment.header.page_association == 0 || segment.header.page_association == header.page_association) { + if (&segment.header == &header) + break; + auto const& data = context.segment_data_by_id.get(segment.header.segment_number); + preceding_segments_on_same_page.append(data->data); + } + } + auto bitmap = TRY(JBIG2ImageDecoderPlugin::decode_embedded(preceding_segments_on_same_page)); + return bitmap->subbitmap(generic_refinement_region.region_segment_information.rect()); }()); GenericRefinementRegionEncodingInputParameters inputs { @@ -2637,7 +2654,7 @@ ErrorOr JBIG2Writer::encode_with_explicit_data(Stream& stream, JBIG2::File TRY(encode_jbig2_header(stream, file_data.header)); - JBIG2EncodingContext context; + JBIG2EncodingContext context { file_data.segments }; for (auto const& segment : file_data.segments) { if (context.segment_by_id.set(segment.header.segment_number, &segment) != HashSetResult::InsertedNewEntry) return Error::from_string_literal("JBIG2Writer: Duplicate segment number"); From 2bbcd3842a709701f0959270fbea7d80eb97cede Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 16 Nov 2025 16:53:22 -0500 Subject: [PATCH 7/7] Tests/LibGfx: Add JBIG2 tests for refinement regions refining the page The decode ok in Preview.app, Acrobat Reader, poppler, and HEAD PDFium. --- Tests/LibGfx/TestImageDecoder.cpp | 3 +- .../jbig2/bitmap-refine-page-subrect.jbig2 | Bin 0 -> 397 bytes .../jbig2/bitmap-refine-page.jbig2 | Bin 0 -> 414 bytes .../json/bitmap-refine-page-subrect.json | 60 ++++++++++++++++++ .../jbig2/json/bitmap-refine-page.json | 50 +++++++++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 Tests/LibGfx/test-inputs/jbig2/bitmap-refine-page-subrect.jbig2 create mode 100644 Tests/LibGfx/test-inputs/jbig2/bitmap-refine-page.jbig2 create mode 100644 Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page-subrect.json create mode 100644 Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page.json diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index d33d6494105b1d..1b5e97a759446d 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -366,6 +366,8 @@ TEST_CASE(test_jbig2_decode) TEST_INPUT("jbig2/bitmap-trailing-7fff-stripped-harder.jbig2"sv), TEST_INPUT("jbig2/bitmap-trailing-7fff-stripped-harder-refine.jbig2"sv), TEST_INPUT("jbig2/bitmap-refine.jbig2"sv), + TEST_INPUT("jbig2/bitmap-refine-page.jbig2"sv), + TEST_INPUT("jbig2/bitmap-refine-page-subrect.jbig2"sv), TEST_INPUT("jbig2/bitmap-refine-customat.jbig2"sv), TEST_INPUT("jbig2/bitmap-refine-lossless.jbig2"sv), TEST_INPUT("jbig2/bitmap-refine-refine.jbig2"sv), @@ -420,7 +422,6 @@ TEST_CASE(test_jbig2_decode) // - intermediate direct regions (code support added in #26197) // - symbol refinement referring to symbol in same segment // Missing tests for things that aren't implemented yet: - // - immediate refinement regions not referring to a direct region (i.e. refining the page) // - exttemplate // - colors }; diff --git a/Tests/LibGfx/test-inputs/jbig2/bitmap-refine-page-subrect.jbig2 b/Tests/LibGfx/test-inputs/jbig2/bitmap-refine-page-subrect.jbig2 new file mode 100644 index 0000000000000000000000000000000000000000..04d00fcd662f52cfdaffb52627cbbe047753e088 GIT binary patch literal 397 zcmbR4sC_(JzBz5XK`)ZzqloD%|+8Pm7Es^&kXt)o!FI4ITirq}zx>LbV{ppj4ws~Dzfs1&j{P+BBT>s^N z;07yk*Y~*z`}0NgbkCO^UGcn^?QOVE^rw{z=4CI`4RL?}!CX?+N9&t)xz<(vNjg6J zPJVl~)TQ@uOz=dG-*;W+&EBt`)+8vwbpBXS#`LE%94EDZt>>Ro|9=fIRG75DA!Y$& z<^jW{21s)Ou?P#pe;`=>x47f+NkMPR{cqX@Iu{xKuLnZkmt7|dT=|)cUKE3kU^aw= FJpctlosa+k literal 0 HcmV?d00001 diff --git a/Tests/LibGfx/test-inputs/jbig2/bitmap-refine-page.jbig2 b/Tests/LibGfx/test-inputs/jbig2/bitmap-refine-page.jbig2 new file mode 100644 index 0000000000000000000000000000000000000000..87c9dc1c975c031b9abc589a77e401b64d0c2dad GIT binary patch literal 414 zcmbR4sC_(JzBz5XK`)ZzqloD%|+8Pm7Es^&kXt)o!FI4ITirq}zx>LbV{ppj4ws~Dzfs1&j{P+BBT>s^N z;07yk*Y~*z`}0NgbkCO^UGcn^?QOVE^rw{z=4CI`4RL?}!CX?+N9&t)xz<(vNjg6J zPJVl~)TQ@uOz=dG-*;W+&EBt`)+8vwbpBXS#`LE%94EDZt>>Ro|9=fIRG75DA?Ar5 zCM*p9fnW{8qe#KET^y5rjQ$z^6Wag39ti6cEy~x3I$r^?L9nLTF(mi3*IeGp1=e6Q JnGGS40RZitrLq73 literal 0 HcmV?d00001 diff --git a/Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page-subrect.json b/Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page-subrect.json new file mode 100644 index 00000000000000..0a04f558103532 --- /dev/null +++ b/Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page-subrect.json @@ -0,0 +1,60 @@ +{ + "global_header": { + "organization": "sequential", + "number_of_pages": 1 + }, + "segments": [ + { + "segment_number": 0, + "type": "page_information", + "page_association": 1, + "data": { + "page_width": 399, + "page_height": 400, + "flags": { + "direct_region_segments_override_default_combination_operator": true + } + } + }, + { + "segment_number": 1, + "type": "generic_region", + "page_association": 1, + "data": { + "image_data": { + "from_file": "bitmap-blemish.bmp" + } + } + }, + { + "segment_number": 2, + "type": "generic_refinement_region", + "page_association": 1, + "data": { + "region_segment_information": { + "x": 10, + "y": 20, + "width": 110, + "height": 380, + "flags": { + "external_combination_operator": "replace" + } + }, + "image_data": { + "from_file": "bitmap.bmp", + "crop": { + "x": 10, + "y": 20, + "width": 110, + "height": 380 + } + } + } + }, + { + "segment_number": 3, + "type": "end_of_page", + "page_association": 1 + } + ] +} diff --git a/Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page.json b/Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page.json new file mode 100644 index 00000000000000..f9781934924fae --- /dev/null +++ b/Tests/LibGfx/test-inputs/jbig2/json/bitmap-refine-page.json @@ -0,0 +1,50 @@ +{ + "global_header": { + "organization": "sequential", + "number_of_pages": 1 + }, + "segments": [ + { + "segment_number": 0, + "type": "page_information", + "page_association": 1, + "data": { + "page_width": 399, + "page_height": 400, + "flags": { + "direct_region_segments_override_default_combination_operator": true + } + } + }, + { + "segment_number": 1, + "type": "generic_region", + "page_association": 1, + "data": { + "image_data": { + "from_file": "bitmap-blemish.bmp" + } + } + }, + { + "segment_number": 2, + "type": "generic_refinement_region", + "page_association": 1, + "data": { + "region_segment_information": { + "flags": { + "external_combination_operator": "replace" + } + }, + "image_data": { + "from_file": "bitmap.bmp" + } + } + }, + { + "segment_number": 3, + "type": "end_of_page", + "page_association": 1 + } + ] +}