Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Tests/LibGfx/TestImageDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ TEST_CASE(test_jbig2_decode)

Array test_inputs = {
TEST_INPUT("jbig2/bitmap.jbig2"sv),
TEST_INPUT("jbig2/bitmap-randomaccess.jbig2"sv),
TEST_INPUT("jbig2/bitmap-p32-eof.jbig2"sv),
TEST_INPUT("jbig2/bitmap-initially-unknown-size.jbig2"sv),
TEST_INPUT("jbig2/bitmap-composite-and-xnor.jbig2"sv),
Expand Down
Binary file not shown.
40 changes: 40 additions & 0 deletions Tests/LibGfx/test-inputs/jbig2/json/bitmap-randomaccess.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"global_header": {
"organization": "random_access",
"number_of_pages": 1
},
"segments": [
{
"segment_number": 0,
"type": "page_information",
"page_association": 1,
"data": {
"page_width": 399,
"page_height": 400,
"flags": {
"is_eventually_lossless": true
}
}
},
{
"segment_number": 1,
"type": "lossless_generic_region",
"page_association": 1,
"data": {
"image_data": {
"from_file": "bitmap.bmp"
}
}
},
{
"segment_number": 2,
"type": "end_of_page",
"page_association": 1
},
{
"segment_number": 3,
"type": "end_of_file",
"page_association": 0
}
]
}
47 changes: 40 additions & 7 deletions Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1537,9 +1537,16 @@ static ErrorOr<void> encode_jbig2_header(Stream& stream, JBIG2::FileHeaderData c

namespace {

struct SerializedSegmentData {
ByteBuffer data;
size_t header_size { 0 };
};

struct JBIG2EncodingContext {
HashMap<u32, JBIG2::SegmentData const*> segment_by_id;

HashMap<u32, SerializedSegmentData> segment_data_by_id;

HashMap<u32, Vector<JBIG2::Code>> codes_by_segment_id;
HashMap<u32, JBIG2::HuffmanTable> tables_by_segment_id;

Expand Down Expand Up @@ -2487,7 +2494,7 @@ static ErrorOr<void> encode_extension(JBIG2::ExtensionData const& extension, Vec
return {};
}

static ErrorOr<void> encode_segment(Stream& stream, JBIG2::SegmentData const& segment_data, JBIG2EncodingContext& context)
static ErrorOr<SerializedSegmentData> encode_segment(JBIG2::SegmentData const& segment_data, JBIG2EncodingContext& context)
{
Vector<u8> scratch_buffer;

Expand Down Expand Up @@ -2597,16 +2604,23 @@ static ErrorOr<void> encode_segment(Stream& stream, JBIG2::SegmentData const& se
header.data_length = segment_data.header.is_immediate_generic_region_of_initially_unknown_size ? 0xffff'ffff : encoded_data.size();

auto page_association_size = segment_data.header.force_32_bit_page_association ? PageAssociationSize::Force32Bit : PageAssociationSize::Auto;
TRY(encode_segment_header(stream, header, page_association_size));
TRY(stream.write_until_depleted(encoded_data));
AllocatingMemoryStream header_stream;
TRY(encode_segment_header(header_stream, header, page_association_size));
auto header_data = TRY(header_stream.read_until_eof());

return {};
SerializedSegmentData data;
data.header_size = header_data.size();
data.data = TRY(ByteBuffer::create_uninitialized(header_data.size() + encoded_data.size()));
header_data.span().copy_to(data.data.span());
encoded_data.copy_to(data.data.span().slice(header_data.size()));

return data;
}

ErrorOr<void> JBIG2Writer::encode_with_explicit_data(Stream& stream, JBIG2::FileData const& file_data)
{
if (file_data.header.organization != JBIG2::Organization::Sequential)
return Error::from_string_literal("JBIG2Writer: Can only encode sequential files yet");
if (file_data.header.organization == JBIG2::Organization::Embedded)
return Error::from_string_literal("JBIG2Writer: Can only encode sequential or random-access files");

TRY(encode_jbig2_header(stream, file_data.header));

Expand All @@ -2617,7 +2631,26 @@ ErrorOr<void> JBIG2Writer::encode_with_explicit_data(Stream& stream, JBIG2::File
}

for (auto const& segment : file_data.segments) {
TRY(encode_segment(stream, segment, context));
auto data = TRY(encode_segment(segment, context));
VERIFY(context.segment_data_by_id.set(segment.header.segment_number, data) == HashSetResult::InsertedNewEntry);
}

if (file_data.header.organization == JBIG2::Organization::Sequential) {
for (auto const& segment : file_data.segments) {
auto const& data = context.segment_data_by_id.get(segment.header.segment_number);
TRY(stream.write_until_depleted(data->data));
}
return {};
}

VERIFY(file_data.header.organization == JBIG2::Organization::RandomAccess);
for (auto const& segment : file_data.segments) {
auto const& data = context.segment_data_by_id.get(segment.header.segment_number);
TRY(stream.write_until_depleted(data->data.span().slice(0, data->header_size)));
}
for (auto const& segment : file_data.segments) {
auto const& data = context.segment_data_by_id.get(segment.header.segment_number);
TRY(stream.write_until_depleted(data->data.span().slice(data->header_size)));
}

return {};
Expand Down
Loading