From f391c7822dee7dc3fce48ecaaad7bc311389c24a Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 14 Mar 2024 22:00:01 -0400 Subject: [PATCH] LibGfx/JBIG2: Call decode_immediate_generic_region for lossless regions It seems to do the right thing already, and nothing in the spec says not to do this as far as I can tell. With this, we can finally decode Tests/LibGfx/test-inputs/jbig2/bitmap.jbig2 and add a test for decoding simple arithmetic-coded images. --- Tests/LibGfx/TestImageDecoder.cpp | 17 +++++++++++++++++ .../LibGfx/ImageFormats/JBIG2Loader.cpp | 14 ++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index 423945d5283..8bdcd69e5bf 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -336,6 +336,23 @@ TEST_CASE(test_jbig2_white_47x23) EXPECT_EQ(pixel, Gfx::Color(Gfx::Color::White).value()); } +TEST_CASE(test_jbig2_generic_region_arithmetic_code) +{ + auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jbig2/bitmap.jbig2"sv))); + EXPECT(Gfx::JBIG2ImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::JBIG2ImageDecoderPlugin::create(file->bytes())); + + auto bmp_file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("bmp/bitmap.bmp"sv))); + auto bmp_plugin_decoder = TRY_OR_FAIL(Gfx::JBIG2ImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 399, 400 })); + auto bmp_frame = TRY_OR_FAIL(expect_single_frame_of_size(*bmp_plugin_decoder, { 399, 400 })); + + for (int y = 0; y < frame.image->height(); ++y) + for (int x = 0; x < frame.image->width(); ++x) + EXPECT_EQ(frame.image->get_pixel(x, y), bmp_frame.image->get_pixel(x, y)); +} + TEST_CASE(test_jbig2_arithmetic_decoder) { // https://www.itu.int/rec/T-REC-T.88-201808-I diff --git a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp index bb92f608480..7a59a07c15d 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp @@ -922,11 +922,6 @@ static ErrorOr decode_immediate_generic_region(JBIG2LoadingContext& contex return {}; } -static ErrorOr decode_immediate_lossless_generic_region(JBIG2LoadingContext&, SegmentData const&) -{ - return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode immediate lossless generic region yet"); -} - static ErrorOr decode_intermediate_generic_refinement_region(JBIG2LoadingContext&, SegmentData const&) { return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode intermediate generic refinement region yet"); @@ -1118,10 +1113,13 @@ static ErrorOr decode_data(JBIG2LoadingContext& context) TRY(decode_intermediate_generic_region(context, segment)); break; case SegmentType::ImmediateGenericRegion: - TRY(decode_immediate_generic_region(context, segment)); - break; case SegmentType::ImmediateLosslessGenericRegion: - TRY(decode_immediate_lossless_generic_region(context, segment)); + // 7.4.6 Generic region segment syntax + // "The data parts of all three of the generic region segment types ("intermediate generic region", "immediate generic region" and + // "immediate lossless generic region") are coded identically, but are acted upon differently, see 8.2." + // But 8.2 only describes a difference between intermediate and immediate regions as far as I can tell, + // and calling the immediate generic region handler for immediate generic lossless regions seems to do the right thing (?). + TRY(decode_immediate_generic_region(context, segment)); break; case SegmentType::IntermediateGenericRefinementRegion: TRY(decode_intermediate_generic_refinement_region(context, segment));