Skip to content

Commit

Permalink
LibGfx/JBIG2: Implement conversion to Gfx::Bitmap and ByteBuffer
Browse files Browse the repository at this point in the history
With this, `image` can convert any jbig2 file, as long as it's
black (or white), and LibPDF can draw jbig2 files (again, as long
as they only contain a single color stored in just a
PageInformation segment).
  • Loading branch information
nico committed Mar 9, 2024
1 parent 7594902 commit d8a60a0
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
22 changes: 22 additions & 0 deletions Tests/LibGfx/TestImageDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,28 @@ TEST_CASE(test_jbig2_size)
EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(399, 400));
}

TEST_CASE(test_jbig2_black_47x23)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jbig2/black_47x23.jbig2"sv)));
EXPECT(Gfx::JBIG2ImageDecoderPlugin::sniff(file->bytes()));
auto plugin_decoder = TRY_OR_FAIL(Gfx::JBIG2ImageDecoderPlugin::create(file->bytes()));

auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 47, 23 }));
for (auto pixel : *frame.image)
EXPECT_EQ(pixel, Gfx::Color(Gfx::Color::Black).value());
}

TEST_CASE(test_jbig2_white_47x23)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jbig2/white_47x23.jbig2"sv)));
EXPECT(Gfx::JBIG2ImageDecoderPlugin::sniff(file->bytes()));
auto plugin_decoder = TRY_OR_FAIL(Gfx::JBIG2ImageDecoderPlugin::create(file->bytes()));

auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 47, 23 }));
for (auto pixel : *frame.image)
EXPECT_EQ(pixel, Gfx::Color(Gfx::Color::White).value());
}

TEST_CASE(test_jpeg_sof0_one_scan)
{
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("jpg/rgb24.jpg"sv)));
Expand Down
25 changes: 23 additions & 2 deletions Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class BitBuffer {
void set_bit(size_t x, size_t y, bool b);
void fill(bool b);

ErrorOr<NonnullRefPtr<Gfx::Bitmap>> to_gfx_bitmap() const;
ErrorOr<ByteBuffer> to_byte_buffer() const;

private:
BitBuffer(Vector<u8>, size_t width, size_t height, size_t pitch);

Expand Down Expand Up @@ -130,6 +133,23 @@ void BitBuffer::fill(bool b)
byte = fill_byte;
}

ErrorOr<NonnullRefPtr<Gfx::Bitmap>> BitBuffer::to_gfx_bitmap() const
{
auto bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { m_width, m_height }));
for (size_t y = 0; y < m_height; ++y) {
for (size_t x = 0; x < m_width; ++x) {
auto color = get_bit(x, y) ? Color::Black : Color::White;
bitmap->set_pixel(x, y, color);
}
}
return bitmap;
}

ErrorOr<ByteBuffer> BitBuffer::to_byte_buffer() const
{
return ByteBuffer::copy(m_bits.data(), m_bits.size());
}

BitBuffer::BitBuffer(Vector<u8> bits, size_t width, size_t height, size_t pitch)
: m_bits(move(bits))
, m_width(width)
Expand Down Expand Up @@ -748,7 +768,8 @@ ErrorOr<ImageFrameDescriptor> JBIG2ImageDecoderPlugin::frame(size_t index, Optio
m_context->state = JBIG2LoadingContext::State::Decoded;
}

return Error::from_string_literal("JBIG2ImageDecoderPlugin: Draw the rest of the owl");
auto bitmap = TRY(m_context->page.bits->to_gfx_bitmap());
return ImageFrameDescriptor { move(bitmap), 0 };
}

ErrorOr<ByteBuffer> JBIG2ImageDecoderPlugin::decode_embedded(Vector<ReadonlyBytes> data)
Expand All @@ -762,7 +783,7 @@ ErrorOr<ByteBuffer> JBIG2ImageDecoderPlugin::decode_embedded(Vector<ReadonlyByte
TRY(scan_for_page_size(*plugin->m_context));
TRY(decode_data(*plugin->m_context));

return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode embedded JBIG2 yet");
return plugin->m_context->page.bits->to_byte_buffer();
}

}

0 comments on commit d8a60a0

Please sign in to comment.