Skip to content

Commit 217364b

Browse files
committed
LibGfx/JBIG2+jbig2-from-json: Write intermediate halftone, text regions
Similar to #26410, the challenge with refining halftone and text regions is that the writer needs to know the decoded halftone and text region bitmap. That data is easily available in the loader, but not in the writer. Similar to #26410, the approach is to call into the *loader* with a list of segments needed to decode the intermediate region's data. ...and then some minor plumbing to hook up the intermediate region types in jbig2-from-json. With this, we can write all region segment types :^)
1 parent 9b811ac commit 217364b

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,13 +2275,19 @@ static ErrorOr<void> encode_generic_refinement_region(JBIG2::GenericRefinementRe
22752275
if (header.referred_to_segments.size() > 1)
22762276
return Error::from_string_literal("JBIG2Writer: Generic refinement region must refer to at most one segment");
22772277

2278-
auto collect_related_segments = [&context](u32 page, u32 segment_number) {
2278+
enum class CollectionBehavior {
2279+
ExcludeSelf,
2280+
IncludeSelf,
2281+
};
2282+
auto collect_related_segments = [&context](u32 page, u32 segment_number, CollectionBehavior behavior) {
22792283
Vector<ReadonlyBytes> preceding_segments_on_same_page;
22802284
bool found = false;
22812285
for (auto const& segment : context.segments) {
22822286
if (segment.header.page_association == 0 || segment.header.page_association == page) {
22832287
auto const& data = context.segment_data_by_id.get(segment.header.segment_number);
22842288
if (segment.header.segment_number == segment_number) {
2289+
if (behavior == CollectionBehavior::IncludeSelf)
2290+
preceding_segments_on_same_page.append(data->data);
22852291
found = true;
22862292
break;
22872293
}
@@ -2303,12 +2309,21 @@ static ErrorOr<void> encode_generic_refinement_region(JBIG2::GenericRefinementRe
23032309
auto const& referred_to_segment = *maybe_segment.value();
23042310

23052311
return TRY(referred_to_segment.data.visit(
2312+
[&]<OneOf<JBIG2::IntermediateTextRegionSegmentData, JBIG2::IntermediateHalftoneRegionSegmentData> T>(T const&) -> ErrorOr<NonnullRefPtr<BilevelImage>> {
2313+
auto related_segments_on_same_page = collect_related_segments(referred_to_segment.header.page_association, referred_to_segment.header.segment_number, CollectionBehavior::IncludeSelf);
2314+
auto bitmap = TRY(JBIG2ImageDecoderPlugin::decode_embedded_intermediate_region_segment(related_segments_on_same_page, referred_to_segment.header.segment_number));
2315+
return bitmap;
2316+
},
2317+
2318+
// Optimization: IntermediateGenericRegionSegmentData, IntermediateGenericRefinementRegionSegmentData could also use
2319+
// the implementation above, but since we happen to have the final bitmap at hand for them, just return it immediately.
23062320
[](JBIG2::IntermediateGenericRegionSegmentData const& generic_region_wrapper) -> ErrorOr<NonnullRefPtr<BilevelImage>> {
23072321
return generic_region_wrapper.generic_region.image;
23082322
},
23092323
[](JBIG2::IntermediateGenericRefinementRegionSegmentData const& generic_refinement_region_wrapper) -> ErrorOr<NonnullRefPtr<BilevelImage>> {
23102324
return generic_refinement_region_wrapper.generic_refinement_region.image;
23112325
},
2326+
23122327
[](auto const&) -> ErrorOr<NonnullRefPtr<BilevelImage>> {
23132328
return Error::from_string_literal("JBIG2Writer: Generic refinement region can only refer to intermediate region segments");
23142329
}))
@@ -2319,7 +2334,7 @@ static ErrorOr<void> encode_generic_refinement_region(JBIG2::GenericRefinementRe
23192334
// contents of the page buffer (see clause 8), restricted to the area of the page buffer specified by this segment's region
23202335
// segment information field."
23212336
VERIFY(header.referred_to_segments.size() == 0);
2322-
auto preceding_segments_on_same_page = collect_related_segments(header.page_association, header.segment_number);
2337+
auto preceding_segments_on_same_page = collect_related_segments(header.page_association, header.segment_number, CollectionBehavior::ExcludeSelf);
23232338
auto bitmap = TRY(JBIG2ImageDecoderPlugin::decode_embedded(preceding_segments_on_same_page));
23242339
return bitmap->subbitmap(generic_refinement_region.region_segment_information.rect());
23252340
}());
@@ -2550,6 +2565,10 @@ static ErrorOr<SerializedSegmentData> encode_segment(JBIG2::SegmentData const& s
25502565
TRY(encode_text_region(text_region_wrapper.text_region, segment_data.header, context, scratch_buffer));
25512566
return scratch_buffer;
25522567
},
2568+
[&scratch_buffer, &segment_data, &context](JBIG2::IntermediateTextRegionSegmentData const& text_region_wrapper) -> ErrorOr<ReadonlyBytes> {
2569+
TRY(encode_text_region(text_region_wrapper.text_region, segment_data.header, context, scratch_buffer));
2570+
return scratch_buffer;
2571+
},
25532572
[&scratch_buffer](JBIG2::PatternDictionarySegmentData const& pattern_dictionary) -> ErrorOr<ReadonlyBytes> {
25542573
TRY(encode_pattern_dictionary(pattern_dictionary, scratch_buffer));
25552574
return scratch_buffer;
@@ -2562,6 +2581,10 @@ static ErrorOr<SerializedSegmentData> encode_segment(JBIG2::SegmentData const& s
25622581
TRY(encode_halftone_region(halftone_region_wrapper.halftone_region, segment_data.header, context, scratch_buffer));
25632582
return scratch_buffer;
25642583
},
2584+
[&scratch_buffer, &segment_data, &context](JBIG2::IntermediateHalftoneRegionSegmentData const& halftone_region_wrapper) -> ErrorOr<ReadonlyBytes> {
2585+
TRY(encode_halftone_region(halftone_region_wrapper.halftone_region, segment_data.header, context, scratch_buffer));
2586+
return scratch_buffer;
2587+
},
25652588
[&scratch_buffer](JBIG2::ImmediateGenericRegionSegmentData const& generic_region_wrapper) -> ErrorOr<ReadonlyBytes> {
25662589
TRY(encode_generic_region(generic_region_wrapper.generic_region, scratch_buffer));
25672590
return scratch_buffer;
@@ -2619,9 +2642,11 @@ static ErrorOr<SerializedSegmentData> encode_segment(JBIG2::SegmentData const& s
26192642
[](JBIG2::SymbolDictionarySegmentData const&) { return JBIG2::SegmentType::SymbolDictionary; },
26202643
[](JBIG2::ImmediateTextRegionSegmentData const&) { return JBIG2::SegmentType::ImmediateTextRegion; },
26212644
[](JBIG2::ImmediateLosslessTextRegionSegmentData const&) { return JBIG2::SegmentType::ImmediateLosslessTextRegion; },
2645+
[](JBIG2::IntermediateTextRegionSegmentData const&) { return JBIG2::SegmentType::IntermediateTextRegion; },
26222646
[](JBIG2::PatternDictionarySegmentData const&) { return JBIG2::SegmentType::PatternDictionary; },
26232647
[](JBIG2::ImmediateHalftoneRegionSegmentData const&) { return JBIG2::SegmentType::ImmediateHalftoneRegion; },
26242648
[](JBIG2::ImmediateLosslessHalftoneRegionSegmentData const&) { return JBIG2::SegmentType::ImmediateLosslessHalftoneRegion; },
2649+
[](JBIG2::IntermediateHalftoneRegionSegmentData const&) { return JBIG2::SegmentType::IntermediateHalftoneRegion; },
26252650
[](JBIG2::ImmediateGenericRegionSegmentData const&) { return JBIG2::SegmentType::ImmediateGenericRegion; },
26262651
[](JBIG2::ImmediateLosslessGenericRegionSegmentData const&) { return JBIG2::SegmentType::ImmediateLosslessGenericRegion; },
26272652
[](JBIG2::IntermediateGenericRegionSegmentData const&) { return JBIG2::SegmentType::IntermediateGenericRegion; },

Userland/Libraries/LibGfx/ImageFormats/JBIG2Writer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ struct ImmediateLosslessTextRegionSegmentData {
149149
TextRegionSegmentData text_region;
150150
};
151151

152+
struct IntermediateTextRegionSegmentData {
153+
TextRegionSegmentData text_region;
154+
};
155+
152156
struct PatternDictionarySegmentData {
153157
u8 flags { 0 };
154158
u8 pattern_width { 0 };
@@ -188,6 +192,10 @@ struct ImmediateLosslessHalftoneRegionSegmentData {
188192
HalftoneRegionSegmentData halftone_region;
189193
};
190194

195+
struct IntermediateHalftoneRegionSegmentData {
196+
HalftoneRegionSegmentData halftone_region;
197+
};
198+
191199
struct GenericRegionSegmentData {
192200
RegionSegmentInformationField region_segment_information {};
193201
u8 flags { 0 };
@@ -263,9 +271,11 @@ struct SegmentData {
263271
SymbolDictionarySegmentData,
264272
ImmediateTextRegionSegmentData,
265273
ImmediateLosslessTextRegionSegmentData,
274+
IntermediateTextRegionSegmentData,
266275
PatternDictionarySegmentData,
267276
ImmediateHalftoneRegionSegmentData,
268277
ImmediateLosslessHalftoneRegionSegmentData,
278+
IntermediateHalftoneRegionSegmentData,
269279
ImmediateGenericRegionSegmentData,
270280
ImmediateLosslessGenericRegionSegmentData,
271281
IntermediateGenericRegionSegmentData,

Userland/Utilities/jbig2-from-json.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,11 @@ static ErrorOr<Gfx::JBIG2::SegmentData> jbig2_immediate_lossless_text_region_fro
13241324
return Gfx::JBIG2::SegmentData { header, Gfx::JBIG2::ImmediateLosslessTextRegionSegmentData { TRY(jbig2_text_region_from_json(options, object)) } };
13251325
}
13261326

1327+
static ErrorOr<Gfx::JBIG2::SegmentData> jbig2_intermediate_text_region_from_json(ToJSONOptions const& options, Gfx::JBIG2::SegmentHeaderData const& header, Optional<JsonObject const&> object)
1328+
{
1329+
return Gfx::JBIG2::SegmentData { header, Gfx::JBIG2::IntermediateTextRegionSegmentData { TRY(jbig2_text_region_from_json(options, object)) } };
1330+
}
1331+
13271332
static ErrorOr<u8> jbig2_pattern_dictionary_flags_from_json(JsonObject const& object)
13281333
{
13291334
u8 flags = 0;
@@ -1764,6 +1769,11 @@ static ErrorOr<Gfx::JBIG2::SegmentData> jbig2_immediate_lossless_halftone_region
17641769
return Gfx::JBIG2::SegmentData { header, Gfx::JBIG2::ImmediateLosslessHalftoneRegionSegmentData { TRY(jbig2_halftone_region_from_json(options, object)) } };
17651770
}
17661771

1772+
static ErrorOr<Gfx::JBIG2::SegmentData> jbig2_intermediate_halftone_region_from_json(ToJSONOptions const& options, Gfx::JBIG2::SegmentHeaderData const& header, Optional<JsonObject const&> object)
1773+
{
1774+
return Gfx::JBIG2::SegmentData { header, Gfx::JBIG2::IntermediateHalftoneRegionSegmentData { TRY(jbig2_halftone_region_from_json(options, object)) } };
1775+
}
1776+
17671777
static ErrorOr<u8> jbig2_generic_region_flags_from_json(JsonObject const& object)
17681778
{
17691779
u8 flags = 0;
@@ -2664,12 +2674,16 @@ static ErrorOr<Gfx::JBIG2::SegmentData> jbig2_segment_from_json(ToJSONOptions co
26642674
return jbig2_immediate_text_region_from_json(options, header, segment_data_object);
26652675
if (type_string == "lossless_text_region")
26662676
return jbig2_immediate_lossless_text_region_from_json(options, header, segment_data_object);
2677+
if (type_string == "intermediate_text_region")
2678+
return jbig2_intermediate_text_region_from_json(options, header, segment_data_object);
26672679
if (type_string == "pattern_dictionary")
26682680
return jbig2_pattern_dictionary_from_json(options, header, segment_data_object);
26692681
if (type_string == "halftone_region")
26702682
return jbig2_immediate_halftone_region_from_json(options, header, segment_data_object);
26712683
if (type_string == "lossless_halftone_region")
26722684
return jbig2_immediate_lossless_halftone_region_from_json(options, header, segment_data_object);
2685+
if (type_string == "intermediate_halftone_region")
2686+
return jbig2_intermediate_halftone_region_from_json(options, header, segment_data_object);
26732687
if (type_string == "generic_region")
26742688
return jbig2_immediate_generic_region_from_json(options, header, segment_data_object);
26752689
if (type_string == "lossless_generic_region")

0 commit comments

Comments
 (0)