Skip to content

Commit

Permalink
LibGfx/JBIG2: Rename JBIG2::ArithmeticDecoder to QMArithmeticDecoder
Browse files Browse the repository at this point in the history
In preparation of moving it to its own file.

No behavior change.
  • Loading branch information
nico authored and awesomekling committed Apr 19, 2024
1 parent 75626c6 commit 5ff75ce
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 59 deletions.
6 changes: 3 additions & 3 deletions Tests/LibGfx/TestImageDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ TEST_CASE(test_jbig2_decode)
}
}

TEST_CASE(test_jbig2_arithmetic_decoder)
TEST_CASE(test_qm_arithmetic_decoder)
{
// https://www.itu.int/rec/T-REC-T.88-201808-I
// H.2 Test sequence for arithmetic coder
Expand All @@ -409,8 +409,8 @@ TEST_CASE(test_jbig2_arithmetic_decoder)
// clang-format on

// "For this entire test, a single value of CX is used. I(CX) is initially 0 and MPS(CX) is initially 0."
Gfx::JBIG2::ArithmeticDecoder::Context context { 0, 0 };
auto decoder = MUST(Gfx::JBIG2::ArithmeticDecoder::initialize(input));
Gfx::QMArithmeticDecoder::Context context { 0, 0 };
auto decoder = MUST(Gfx::QMArithmeticDecoder::initialize(input));

for (auto expected : output) {
u8 actual = 0;
Expand Down
96 changes: 47 additions & 49 deletions Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@

namespace Gfx {

namespace JBIG2 {

// Table E.1 – Qe values and probability estimation process
// See also E.1.2 Coding conventions and approximations
// and E.2.5 Probability estimation.
Expand Down Expand Up @@ -88,14 +86,14 @@ constexpr auto qe_table = to_array<QeEntry>({
{ 0x5601, 46, 46, 0 },
});

ErrorOr<ArithmeticDecoder> ArithmeticDecoder::initialize(ReadonlyBytes data)
ErrorOr<QMArithmeticDecoder> QMArithmeticDecoder::initialize(ReadonlyBytes data)
{
ArithmeticDecoder decoder { data };
QMArithmeticDecoder decoder { data };
decoder.INITDEC();
return decoder;
}

bool ArithmeticDecoder::get_next_bit(Context& context)
bool QMArithmeticDecoder::get_next_bit(Context& context)
{
CX = &context;
// Useful for comparing to Table H.1 – Encoder and decoder trace data.
Expand All @@ -105,12 +103,12 @@ bool ArithmeticDecoder::get_next_bit(Context& context)
return D;
}

u16 ArithmeticDecoder::Qe(u16 index) { return qe_table[index].qe; }
u8 ArithmeticDecoder::NMPS(u16 index) { return qe_table[index].nmps; }
u8 ArithmeticDecoder::NLPS(u16 index) { return qe_table[index].nlps; }
u8 ArithmeticDecoder::SWITCH(u16 index) { return qe_table[index].switch_flag; }
u16 QMArithmeticDecoder::Qe(u16 index) { return qe_table[index].qe; }
u8 QMArithmeticDecoder::NMPS(u16 index) { return qe_table[index].nmps; }
u8 QMArithmeticDecoder::NLPS(u16 index) { return qe_table[index].nlps; }
u8 QMArithmeticDecoder::SWITCH(u16 index) { return qe_table[index].switch_flag; }

u8 ArithmeticDecoder::B(size_t offset) const
u8 QMArithmeticDecoder::B(size_t offset) const
{
// E.2.10 Minimization of the compressed data
// "the convention is used in the decoder that when a marker code is encountered,
Expand All @@ -120,7 +118,7 @@ u8 ArithmeticDecoder::B(size_t offset) const
return m_data[BP + offset];
}

void ArithmeticDecoder::INITDEC()
void QMArithmeticDecoder::INITDEC()
{
// E.3.5 Initialization of the decoder (INITDEC)
// Figure G.1 – Initialization of the software conventions decoder
Expand All @@ -137,7 +135,7 @@ void ArithmeticDecoder::INITDEC()
A = 0x8000;
}

u8 ArithmeticDecoder::DECODE()
u8 QMArithmeticDecoder::DECODE()
{
// E.3.2 Decoding a decision (DECODE)
// Figure G.2 – Decoding an MPS or an LPS in the software-conventions decoder
Expand All @@ -158,7 +156,7 @@ u8 ArithmeticDecoder::DECODE()
return D;
}

u8 ArithmeticDecoder::MPS_EXCHANGE()
u8 QMArithmeticDecoder::MPS_EXCHANGE()
{
// Figure E.16 – Decoder MPS path conditional exchange procedure
u8 D;
Expand All @@ -175,7 +173,7 @@ u8 ArithmeticDecoder::MPS_EXCHANGE()
return D;
}

u8 ArithmeticDecoder::LPS_EXCHANGE()
u8 QMArithmeticDecoder::LPS_EXCHANGE()
{
// Figure E.17 – Decoder LPS path conditional exchange procedure
u8 D;
Expand All @@ -194,7 +192,7 @@ u8 ArithmeticDecoder::LPS_EXCHANGE()
return D;
}

void ArithmeticDecoder::RENORMD()
void QMArithmeticDecoder::RENORMD()
{
// E.3.3 Renormalization in the decoder (RENORMD)
// Figure E.18 – Decoder renormalization procedure
Expand All @@ -207,7 +205,7 @@ void ArithmeticDecoder::RENORMD()
} while ((A & 0x8000) == 0);
}

void ArithmeticDecoder::BYTEIN()
void QMArithmeticDecoder::BYTEIN()
{
// E.3.4 Compressed data input (BYTEIN)
// Figure G.3 – Inserting a new byte into the C register in the software-conventions decoder
Expand All @@ -226,10 +224,12 @@ void ArithmeticDecoder::BYTEIN()
}
}

namespace JBIG2 {

// Annex A, Arithmetic integer decoding procedure
class ArithmeticIntegerDecoder {
public:
ArithmeticIntegerDecoder(ArithmeticDecoder&);
ArithmeticIntegerDecoder(QMArithmeticDecoder&);

// A.2 Procedure for decoding values (except IAID)
// Returns OptionalNone for OOB.
Expand All @@ -239,12 +239,12 @@ class ArithmeticIntegerDecoder {
ErrorOr<i32> decode_non_oob();

private:
ArithmeticDecoder& m_decoder;
QMArithmeticDecoder& m_decoder;
u16 PREV { 0 };
Vector<ArithmeticDecoder::Context> contexts;
Vector<QMArithmeticDecoder::Context> contexts;
};

ArithmeticIntegerDecoder::ArithmeticIntegerDecoder(ArithmeticDecoder& decoder)
ArithmeticIntegerDecoder::ArithmeticIntegerDecoder(QMArithmeticDecoder& decoder)
: m_decoder(decoder)
{
contexts.resize(1 << 9);
Expand Down Expand Up @@ -314,18 +314,18 @@ ErrorOr<i32> ArithmeticIntegerDecoder::decode_non_oob()

class ArithmeticIntegerIDDecoder {
public:
ArithmeticIntegerIDDecoder(ArithmeticDecoder&, u32 code_length);
ArithmeticIntegerIDDecoder(QMArithmeticDecoder&, u32 code_length);

// A.3 The IAID decoding procedure
u32 decode();

private:
ArithmeticDecoder& m_decoder;
QMArithmeticDecoder& m_decoder;
u32 m_code_length { 0 };
Vector<ArithmeticDecoder::Context> contexts;
Vector<QMArithmeticDecoder::Context> contexts;
};

ArithmeticIntegerIDDecoder::ArithmeticIntegerIDDecoder(ArithmeticDecoder& decoder, u32 code_length)
ArithmeticIntegerIDDecoder::ArithmeticIntegerIDDecoder(QMArithmeticDecoder& decoder, u32 code_length)
: m_decoder(decoder)
, m_code_length(code_length)
{
Expand Down Expand Up @@ -951,11 +951,11 @@ struct GenericRegionDecodingInputParameters {
// FIXME: GBCOLS, GBCOMBOP, COLEXTFLAG

// If is_modified_modified_read is false, generic_region_decoding_procedure() reads data off this decoder.
JBIG2::ArithmeticDecoder* arithmetic_decoder { nullptr };
QMArithmeticDecoder* arithmetic_decoder { nullptr };
};

// 6.2 Generic region decoding procedure
static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(GenericRegionDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<JBIG2::ArithmeticDecoder::Context>& contexts)
static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(GenericRegionDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts)
{
if (inputs.is_modified_modified_read) {
dbgln_if(JBIG2_DEBUG, "JBIG2ImageDecoderPlugin: MMR image data");
Expand Down Expand Up @@ -1091,7 +1091,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_region_decoding_procedure(Gener
}(inputs.gb_template);

// 6.2.5.7 Decoding the bitmap
JBIG2::ArithmeticDecoder& decoder = *inputs.arithmetic_decoder;
QMArithmeticDecoder& 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) {
Expand Down Expand Up @@ -1129,7 +1129,7 @@ struct GenericRefinementRegionDecodingInputParameters {
};

// 6.3 Generic Refinement Region Decoding Procedure
static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_refinement_region_decoding_procedure(GenericRefinementRegionDecodingInputParameters& inputs, JBIG2::ArithmeticDecoder& decoder, Vector<JBIG2::ArithmeticDecoder::Context>& contexts)
static ErrorOr<NonnullOwnPtr<BitBuffer>> generic_refinement_region_decoding_procedure(GenericRefinementRegionDecodingInputParameters& inputs, QMArithmeticDecoder& decoder, Vector<QMArithmeticDecoder::Context>& contexts)
{
VERIFY(inputs.gr_template == 0 || inputs.gr_template == 1);

Expand Down Expand Up @@ -1246,7 +1246,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi
if (inputs.uses_huffman_encoding)
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode huffman text regions yet");

auto decoder = TRY(JBIG2::ArithmeticDecoder::initialize(data));
auto decoder = TRY(QMArithmeticDecoder::initialize(data));

// 6.4.6 Strip delta T
// "If SBHUFF is 1, decode a value using the Huffman table specified by SBHUFFDT and multiply the resulting value by SBSTRIPS.
Expand Down Expand Up @@ -1326,7 +1326,7 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> text_region_decoding_procedure(TextRegi

// 6.4.11 Symbol instance bitmap
JBIG2::ArithmeticIntegerDecoder has_refinement_image_decoder(decoder);
Vector<JBIG2::ArithmeticDecoder::Context> refinement_contexts;
Vector<QMArithmeticDecoder::Context> refinement_contexts;
if (inputs.uses_refinement_coding)
refinement_contexts.resize(1 << (inputs.refinement_template == 0 ? 13 : 10));
OwnPtr<BitBuffer> refinement_result;
Expand Down Expand Up @@ -1540,8 +1540,8 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu
if (inputs.uses_huffman_encoding)
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Cannot decode huffman symbol dictionaries yet");

auto decoder = TRY(JBIG2::ArithmeticDecoder::initialize(data));
Vector<JBIG2::ArithmeticDecoder::Context> contexts;
auto decoder = TRY(QMArithmeticDecoder::initialize(data));
Vector<QMArithmeticDecoder::Context> contexts;
contexts.resize(1 << number_of_context_bits_for_template(inputs.symbol_template));

// 6.5.6 Height class delta height
Expand Down Expand Up @@ -1585,7 +1585,7 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> symbol_dictionary_decoding_procedu

// FIXME: When we implement REFAGGNINST > 1 support, do these need to be shared with
// text_region_decoding_procedure() then?
Vector<JBIG2::ArithmeticDecoder::Context> refinement_contexts;
Vector<QMArithmeticDecoder::Context> refinement_contexts;

// This belongs in 6.5.5 1) below, but also needs to be captured by read_bitmap here.
Vector<NonnullRefPtr<Symbol>> new_symbols;
Expand Down Expand Up @@ -1805,10 +1805,10 @@ struct GrayscaleInputParameters {
u8 template_id { 0 }; // "GSTEMPLATE" in spec.

// If uses_mmr is false, grayscale_image_decoding_procedure() reads data off this decoder.
JBIG2::ArithmeticDecoder* arithmetic_decoder { nullptr };
QMArithmeticDecoder* arithmetic_decoder { nullptr };
};

static ErrorOr<Vector<u8>> grayscale_image_decoding_procedure(GrayscaleInputParameters const& inputs, ReadonlyBytes data, Vector<JBIG2::ArithmeticDecoder::Context>& contexts)
static ErrorOr<Vector<u8>> grayscale_image_decoding_procedure(GrayscaleInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts)
{
// FIXME: Support this. generic_region_decoding_procedure() currently doesn't tell us how much data it
// reads for MMR bitmaps, so we can't currently read more than one MMR bitplane here.
Expand Down Expand Up @@ -1906,7 +1906,7 @@ struct HalftoneRegionDecodingInputParameters {
};

// 6.6 Halftone Region Decoding Procedure
static ErrorOr<NonnullOwnPtr<BitBuffer>> halftone_region_decoding_procedure(HalftoneRegionDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<JBIG2::ArithmeticDecoder::Context>& contexts)
static ErrorOr<NonnullOwnPtr<BitBuffer>> halftone_region_decoding_procedure(HalftoneRegionDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts)
{
// 6.6.5 Decoding the halftone region
// "1) Fill a bitmap HTREG, of the size given by HBW and HBH, with the HDEFPIXEL value."
Expand Down Expand Up @@ -1960,9 +1960,9 @@ static ErrorOr<NonnullOwnPtr<BitBuffer>> halftone_region_decoding_procedure(Half
grayscale_inputs.skip_pattern = skip_pattern;
grayscale_inputs.template_id = inputs.halftone_template;

Optional<JBIG2::ArithmeticDecoder> decoder;
Optional<QMArithmeticDecoder> decoder;
if (!inputs.uses_mmr) {
decoder = TRY(JBIG2::ArithmeticDecoder::initialize(data));
decoder = TRY(QMArithmeticDecoder::initialize(data));
grayscale_inputs.arithmetic_decoder = &decoder.value();
}

Expand Down Expand Up @@ -2018,7 +2018,7 @@ struct PatternDictionaryDecodingInputParameters {
};

// 6.7 Pattern Dictionary Decoding Procedure
static ErrorOr<Vector<NonnullRefPtr<Symbol>>> pattern_dictionary_decoding_procedure(PatternDictionaryDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<JBIG2::ArithmeticDecoder::Context>& contexts)
static ErrorOr<Vector<NonnullRefPtr<Symbol>>> pattern_dictionary_decoding_procedure(PatternDictionaryDecodingInputParameters const& inputs, ReadonlyBytes data, Vector<QMArithmeticDecoder::Context>& contexts)
{
// Table 27 – Parameters used to decode a pattern dictionary's collective bitmap
GenericRegionDecodingInputParameters generic_inputs;
Expand All @@ -2038,9 +2038,9 @@ static ErrorOr<Vector<NonnullRefPtr<Symbol>>> pattern_dictionary_decoding_proced
generic_inputs.adaptive_template_pixels[3].x = -2;
generic_inputs.adaptive_template_pixels[3].y = -2;

Optional<JBIG2::ArithmeticDecoder> decoder;
Optional<QMArithmeticDecoder> decoder;
if (!inputs.uses_mmr) {
decoder = TRY(JBIG2::ArithmeticDecoder::initialize(data));
decoder = TRY(QMArithmeticDecoder::initialize(data));
generic_inputs.arithmetic_decoder = &decoder.value();
}

Expand Down Expand Up @@ -2353,7 +2353,7 @@ static ErrorOr<void> decode_pattern_dictionary(JBIG2LoadingContext&, SegmentData
// Done!

// "2) As described in E.3.7, reset all the arithmetic coding statistics to zero."
Vector<JBIG2::ArithmeticDecoder::Context> contexts;
Vector<QMArithmeticDecoder::Context> contexts;
if (!uses_mmr)
contexts.resize(1 << number_of_context_bits_for_template(hd_template));

Expand Down Expand Up @@ -2443,7 +2443,7 @@ static ErrorOr<void> decode_immediate_halftone_region(JBIG2LoadingContext& conte
return Error::from_string_literal("JBIG2ImageDecoderPlugin: Halftone segment without patterns");

// "3) As described in E.3.7, reset all the arithmetic coding statistics to zero."
Vector<JBIG2::ArithmeticDecoder::Context> contexts;
Vector<QMArithmeticDecoder::Context> contexts;
if (!uses_mmr)
contexts.resize(1 << number_of_context_bits_for_template(template_used));

Expand Down Expand Up @@ -2530,11 +2530,9 @@ static ErrorOr<void> decode_immediate_generic_region(JBIG2LoadingContext& contex
// 7.4.6.4 Decoding a generic region segment
// "1) Interpret its header, as described in 7.4.6.1"
// Done above.

// "2) As described in E.3.7, reset all the arithmetic coding statistics to zero."
Vector<JBIG2::ArithmeticDecoder::Context> contexts;
if (!uses_mmr)
contexts.resize(1 << number_of_context_bits_for_template(arithmetic_coding_template));
Vector<QMArithmeticDecoder::Context> contexts;
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;
Expand All @@ -2547,9 +2545,9 @@ static ErrorOr<void> decode_immediate_generic_region(JBIG2LoadingContext& contex
inputs.skip_pattern = OptionalNone {};
inputs.adaptive_template_pixels = adaptive_template_pixels;

Optional<JBIG2::ArithmeticDecoder> decoder;
Optional<QMArithmeticDecoder> decoder;
if (!uses_mmr) {
decoder = TRY(JBIG2::ArithmeticDecoder::initialize(data));
decoder = TRY(QMArithmeticDecoder::initialize(data));
inputs.arithmetic_decoder = &decoder.value();
}

Expand Down
10 changes: 3 additions & 7 deletions Userland/Libraries/LibGfx/ImageFormats/JBIG2Loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,22 @@ namespace Gfx {

struct JBIG2LoadingContext;

namespace JBIG2 {

// E.3 Arithmetic decoding procedure, but with the changes described in
// Annex G Arithmetic decoding procedure (software conventions).
// Exposed for testing.
class ArithmeticDecoder {
class QMArithmeticDecoder {
public:
struct Context {
u8 I { 0 }; // Index I stored for context CX (E.2.4)
u8 is_mps { 0 }; // "More probable symbol" (E.1.1). 0 or 1.
};

static ErrorOr<ArithmeticDecoder> initialize(ReadonlyBytes data);
static ErrorOr<QMArithmeticDecoder> initialize(ReadonlyBytes data);

bool get_next_bit(Context& context);

private:
ArithmeticDecoder(ReadonlyBytes data)
QMArithmeticDecoder(ReadonlyBytes data)
: m_data(data)
{
}
Expand Down Expand Up @@ -72,8 +70,6 @@ class ArithmeticDecoder {
static u8 SWITCH(u16);
};

}

class JBIG2ImageDecoderPlugin : public ImageDecoderPlugin {
public:
static bool sniff(ReadonlyBytes);
Expand Down

0 comments on commit 5ff75ce

Please sign in to comment.