mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-07 20:31:04 +03:00
LibGfx/JBIG2: Implement support for context templates 1, 2, and 3
Template 2 is needed by some symbols in 0000372.pdf page 11 and 0000857.pdf pages 1-4. Implement the others too while here. (The mentioned pages in those two PDFs also use the "end of stripe" segment, so they still don't render yet. We still don't support EXTTEMPLATE.
This commit is contained in:
parent
e2f02f4df7
commit
b45a4508c7
Notes:
sideshowbarker
2024-07-17 03:18:29 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/b45a4508c7 Pull-request: https://github.com/SerenityOS/serenity/pull/23695
@ -356,6 +356,12 @@ TEST_CASE(test_jbig2_decode)
|
||||
Array test_inputs = {
|
||||
TEST_INPUT("jbig2/bitmap.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-tpgdon.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-template1.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-template1-tpgdon.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-template2.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-template2-tpgdon.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-template3.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-template3-tpgdon.jbig2"sv),
|
||||
TEST_INPUT("jbig2/bitmap-symbol.jbig2"sv),
|
||||
};
|
||||
|
||||
|
@ -292,6 +292,16 @@ Optional<int> ArithmeticIntegerDecoder::decode()
|
||||
|
||||
}
|
||||
|
||||
static u8 number_of_context_bits_for_template(u8 template_)
|
||||
{
|
||||
if (template_ == 0)
|
||||
return 16;
|
||||
if (template_ == 1)
|
||||
return 13;
|
||||
VERIFY(template_ == 2 || template_ == 3);
|
||||
return 10;
|
||||
}
|
||||
|
||||
// JBIG2 spec, Annex D, D.4.1 ID string
|
||||
static constexpr u8 id_string[] = { 0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A };
|
||||
|
||||
@ -879,18 +889,24 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(Gener
|
||||
}
|
||||
|
||||
// 6.2.5 Decoding using a template and arithmetic coding
|
||||
if (inputs.gb_template != 0)
|
||||
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode GBTEMPLATE != 0 yet");
|
||||
|
||||
if (inputs.adaptive_template_pixels[0].x != 3 || inputs.adaptive_template_pixels[0].y != -1
|
||||
|| inputs.adaptive_template_pixels[1].x != -3 || inputs.adaptive_template_pixels[1].y != -1
|
||||
|| inputs.adaptive_template_pixels[2].x != 2 || inputs.adaptive_template_pixels[2].y != -2
|
||||
|| inputs.adaptive_template_pixels[3].x != -2 || inputs.adaptive_template_pixels[3].y != -2)
|
||||
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot handle custom adaptive pixels yet");
|
||||
|
||||
if (inputs.is_extended_reference_template_used)
|
||||
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode EXTTEMPLATE yet");
|
||||
|
||||
if (inputs.gb_template == 0) {
|
||||
if (inputs.adaptive_template_pixels[0].x != 3 || inputs.adaptive_template_pixels[0].y != -1
|
||||
|| inputs.adaptive_template_pixels[1].x != -3 || inputs.adaptive_template_pixels[1].y != -1
|
||||
|| inputs.adaptive_template_pixels[2].x != 2 || inputs.adaptive_template_pixels[2].y != -2
|
||||
|| inputs.adaptive_template_pixels[3].x != -2 || inputs.adaptive_template_pixels[3].y != -2)
|
||||
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot handle custom adaptive pixels yet");
|
||||
} else if (inputs.gb_template == 1) {
|
||||
if (inputs.adaptive_template_pixels[0].x != 3 || inputs.adaptive_template_pixels[0].y != -1)
|
||||
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot handle custom adaptive pixels yet");
|
||||
} else {
|
||||
VERIFY(inputs.gb_template == 2 || inputs.gb_template == 3);
|
||||
if (inputs.adaptive_template_pixels[0].x != 2 || inputs.adaptive_template_pixels[0].y != -1)
|
||||
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot handle custom adaptive pixels yet");
|
||||
}
|
||||
|
||||
if (inputs.skip_pattern.has_value())
|
||||
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode USESKIP yet");
|
||||
|
||||
@ -903,7 +919,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(Gener
|
||||
};
|
||||
|
||||
// Figure 3(a) – Template when GBTEMPLATE = 0 and EXTTEMPLATE = 0,
|
||||
auto compute_context = [&get_pixel](NonnullOwnPtr<BitBuffer> const& buffer, int x, int y) -> u16 {
|
||||
auto compute_context_0 = [&get_pixel](NonnullOwnPtr<BitBuffer> const& buffer, int x, int y) -> u16 {
|
||||
u16 result = 0;
|
||||
for (int i = 0; i < 5; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y - 2);
|
||||
@ -914,6 +930,51 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(Gener
|
||||
return result;
|
||||
};
|
||||
|
||||
// Figure 4 – Template when GBTEMPLATE = 1
|
||||
auto compute_context_1 = [&get_pixel](NonnullOwnPtr<BitBuffer> const& buffer, int x, int y) -> u16 {
|
||||
u16 result = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 1 + i, y - 2);
|
||||
for (int i = 0; i < 6; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y - 1);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 3 + i, y);
|
||||
return result;
|
||||
};
|
||||
|
||||
// Figure 5 – Template when GBTEMPLATE = 2
|
||||
auto compute_context_2 = [&get_pixel](NonnullOwnPtr<BitBuffer> const& buffer, int x, int y) -> u16 {
|
||||
u16 result = 0;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 1 + i, y - 2);
|
||||
for (int i = 0; i < 5; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y - 1);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 2 + i, y);
|
||||
return result;
|
||||
};
|
||||
|
||||
// Figure 6 – Template when GBTEMPLATE = 3
|
||||
auto compute_context_3 = [&get_pixel](NonnullOwnPtr<BitBuffer> const& buffer, int x, int y) -> u16 {
|
||||
u16 result = 0;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 3 + i, y - 1);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
result = (result << 1) | (u16)get_pixel(buffer, x - 4 + i, y);
|
||||
return result;
|
||||
};
|
||||
|
||||
auto compute_context = [&inputs, &compute_context_0, &compute_context_1, &compute_context_2, &compute_context_3](NonnullOwnPtr<BitBuffer> const& buffer, int x, int y) -> u16 {
|
||||
if (inputs.gb_template == 0)
|
||||
return compute_context_0(buffer, x, y);
|
||||
if (inputs.gb_template == 1)
|
||||
return compute_context_1(buffer, x, y);
|
||||
if (inputs.gb_template == 2)
|
||||
return compute_context_2(buffer, x, y);
|
||||
VERIFY(inputs.gb_template == 3);
|
||||
return compute_context_3(buffer, x, y);
|
||||
};
|
||||
|
||||
// "The values of the pixels in this neighbourhood define a context. Each context has its own adaptive probability estimate
|
||||
// used by the arithmetic coder (see Annex E)."
|
||||
// "* Decode the current pixel by invoking the arithmetic entropy decoding procedure, with CX set to the value formed by
|
||||
@ -925,13 +986,33 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(Gener
|
||||
// Figure 8 – Reused context for coding the SLTP value when GBTEMPLATE is 0
|
||||
constexpr u16 sltp_context_for_template_0 = 0b10011'0110010'0101;
|
||||
|
||||
// Figure 9 – Reused context for coding the SLTP value when GBTEMPLATE is 1
|
||||
constexpr u16 sltp_context_for_template_1 = 0b0011'110010'101;
|
||||
|
||||
// Figure 10 – Reused context for coding the SLTP value when GBTEMPLATE is 2
|
||||
constexpr u16 sltp_context_for_template_2 = 0b001'11001'01;
|
||||
|
||||
// Figure 11 – Reused context for coding the SLTP value when GBTEMPLATE is 3
|
||||
constexpr u16 sltp_context_for_template_3 = 0b011001'0101;
|
||||
|
||||
u16 sltp_context = [](u8 gb_template) {
|
||||
if (gb_template == 0)
|
||||
return sltp_context_for_template_0;
|
||||
if (gb_template == 1)
|
||||
return sltp_context_for_template_1;
|
||||
if (gb_template == 2)
|
||||
return sltp_context_for_template_2;
|
||||
VERIFY(gb_template == 3);
|
||||
return sltp_context_for_template_3;
|
||||
}(inputs.gb_template);
|
||||
|
||||
// 6.2.5.7 Decoding the bitmap
|
||||
JBIG2::ArithmeticDecoder& decoder = *inputs.arithmetic_decoder;
|
||||
bool ltp = false; // "LTP" in spec. "Line (uses) Typical Prediction" maybe?
|
||||
for (size_t y = 0; y < inputs.region_height; ++y) {
|
||||
if (inputs.is_typical_prediction_used) {
|
||||
// "SLTP" in spec. "Swap LTP" or "Switch LTP" maybe?
|
||||
bool sltp = decoder.get_next_bit(contexts[sltp_context_for_template_0]);
|
||||
bool sltp = decoder.get_next_bit(contexts[sltp_context]);
|
||||
ltp = ltp ^ sltp;
|
||||
if (ltp) {
|
||||
for (size_t x = 0; x < inputs.region_width; ++x)
|
||||
@ -1383,8 +1464,7 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
|
||||
|
||||
auto decoder = TRY(JBIG2::ArithmeticDecoder::initialize(data));
|
||||
Vector<JBIG2::ArithmeticDecoder::Context> contexts;
|
||||
u8 template_size = inputs.symbol_template == 0 ? 16 : (inputs.symbol_template == 1 ? 13 : 10);
|
||||
contexts.resize(1 << template_size);
|
||||
contexts.resize(1 << number_of_context_bits_for_template(inputs.symbol_template));
|
||||
|
||||
// 6.5.6 Height class delta height
|
||||
// "If SDHUFF is 1, decode a value using the Huffman table specified by SDHUFFDH.
|
||||
@ -1875,7 +1955,7 @@ static ErrorOr<void> decode_immediate_generic_region(JBIG2LoadingContext& contex
|
||||
// Done above.
|
||||
// "2) As described in E.3.7, reset all the arithmetic coding statistics to zero."
|
||||
Vector<JBIG2::ArithmeticDecoder::Context> contexts;
|
||||
contexts.resize(1 << 16);
|
||||
contexts.resize(1 << number_of_context_bits_for_template(arithmetic_coding_template));
|
||||
|
||||
// "3) Invoke the generic region decoding procedure described in 6.2, with the parameters to the generic region decoding procedure set as shown in Table 37."
|
||||
GenericRegionDecodingInputParameters inputs;
|
||||
|
Loading…
Reference in New Issue
Block a user