LibGfx/JBIG2: Scan for the first PageInformation segment and decode it

This allows `file` to correctly print the dimensions of a .jbig2 file,
and it allows us to write a test that covers much of all the code
written so far.
This commit is contained in:
Nico Weber 2024-03-05 20:42:28 -05:00 committed by Andreas Kling
parent 1eaaa8c3e9
commit 8f4930f2df
Notes: sideshowbarker 2024-07-17 05:02:42 +09:00
2 changed files with 45 additions and 0 deletions

View File

@ -13,6 +13,7 @@
#include <LibGfx/ImageFormats/ICOLoader.h> #include <LibGfx/ImageFormats/ICOLoader.h>
#include <LibGfx/ImageFormats/ILBMLoader.h> #include <LibGfx/ImageFormats/ILBMLoader.h>
#include <LibGfx/ImageFormats/ImageDecoder.h> #include <LibGfx/ImageFormats/ImageDecoder.h>
#include <LibGfx/ImageFormats/JBIG2Loader.h>
#include <LibGfx/ImageFormats/JPEGLoader.h> #include <LibGfx/ImageFormats/JPEGLoader.h>
#include <LibGfx/ImageFormats/JPEGXLLoader.h> #include <LibGfx/ImageFormats/JPEGXLLoader.h>
#include <LibGfx/ImageFormats/PAMLoader.h> #include <LibGfx/ImageFormats/PAMLoader.h>
@ -316,6 +317,14 @@ TEST_CASE(test_ilbm_malformed_frame)
} }
} }
TEST_CASE(test_jbig2_size)
{
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()));
EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(399, 400));
}
TEST_CASE(test_jpeg_sof0_one_scan) TEST_CASE(test_jpeg_sof0_one_scan)
{ {
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/rgb24.jpg"sv))); auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/rgb24.jpg"sv)));

View File

@ -266,6 +266,38 @@ static ErrorOr<void> decode_segment_headers(JBIG2LoadingContext& context, Readon
return {}; return {};
} }
// 7.4.8 Page information segment syntax
struct [[gnu::packed]] PageInformationSegment {
BigEndian<u32> bitmap_width;
BigEndian<u32> bitmap_height;
BigEndian<u32> page_x_resolution; // In pixels/meter.
BigEndian<u32> page_y_resolution; // In pixels/meter.
u8 flags;
BigEndian<u16> striping_information;
};
static_assert(AssertSize<PageInformationSegment, 19>());
static ErrorOr<PageInformationSegment> decode_page_information_segment(ReadonlyBytes data)
{
// 7.4.8 Page information segment syntax
if (data.size() != sizeof(PageInformationSegment))
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Invalid page information segment size");
return *(PageInformationSegment const*)data.data();
}
static ErrorOr<void> scan_for_page_size(JBIG2LoadingContext& context)
{
// We only decode the first page at the moment.
for (auto const& segment : context.segments) {
if (segment.header.type != SegmentType::PageInformation)
continue;
auto page_information = TRY(decode_page_information_segment(segment.data));
context.size = { page_information.bitmap_width, page_information.bitmap_height };
return {};
}
return Error::from_string_literal("JBIG2ImageDecoderPlugin: No page information segment found");
}
JBIG2ImageDecoderPlugin::JBIG2ImageDecoderPlugin() JBIG2ImageDecoderPlugin::JBIG2ImageDecoderPlugin()
{ {
m_context = make<JBIG2LoadingContext>(); m_context = make<JBIG2LoadingContext>();
@ -289,6 +321,8 @@ ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JBIG2ImageDecoderPlugin::create(Reado
data = data.slice(sizeof(id_string) + sizeof(u8) + (plugin->m_context->number_of_pages.has_value() ? sizeof(u32) : 0)); data = data.slice(sizeof(id_string) + sizeof(u8) + (plugin->m_context->number_of_pages.has_value() ? sizeof(u32) : 0));
TRY(decode_segment_headers(*plugin->m_context, data)); TRY(decode_segment_headers(*plugin->m_context, data));
TRY(scan_for_page_size(*plugin->m_context));
return plugin; return plugin;
} }
@ -312,6 +346,8 @@ ErrorOr<ByteBuffer> JBIG2ImageDecoderPlugin::decode_embedded(Vector<ReadonlyByte
for (auto const& segment_data : data) for (auto const& segment_data : data)
TRY(decode_segment_headers(*plugin->m_context, segment_data)); TRY(decode_segment_headers(*plugin->m_context, segment_data));
TRY(scan_for_page_size(*plugin->m_context));
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode embedded JBIG2 yet"); return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode embedded JBIG2 yet");
} }