LibGfx/CCITT: Make decoding of wide ccitt3-2d and ccitt-4 images faster

`take_first()` on a Vector is O(n), meaning this function used to have
O(n^2) behavior in the width of an image.

We can just use a span instead, which can be be advanced in O(1) time.

Makes

    pdf --debugging-stats ~/Downloads/ignition.pdf

go from 10.2s to 6.7s, 34% faster.

Makes the first 50 pages of

    pdf --debugging-stats pdf-stuff/Mellor_ACTITC_10.pdf

go from 65.9s to 13.2s, 80% faster.

Fixes #26082.
This commit is contained in:
Nico Weber committed 2025-07-31 14:59:21 -04:00
1 parent c2a1571183
commit 787c439271
1 file changed
+4 -3
@@ -478,20 +478,21 @@ ErrorOr<CCITTStatus> decode_single_ccitt_2d_line(
u32 column {};
u32 remainder_from_pass_mode {};
auto reference_line_span = reference_line.span();
auto const next_change_on_reference_line = [&]() -> ErrorOr<Change> {
// 4.2.1.3.1 Definition of changing picture elements
Optional<Change> next_change {}; // This is referred to as b1 in the spec.
u32 offset {};
while (!next_change.has_value()) {
if (reference_line.is_empty() || reference_line.size() <= offset)
if (reference_line_span.is_empty() || reference_line_span.size() <= offset)
return Error::from_string_literal("CCITTDecoder: Corrupted stream");
auto const change = reference_line[0 + offset];
auto const change = reference_line_span[0 + offset];
// 4.2.1.3.4 Processing the first and last picture elements in a line
// "The first starting picture element a0 on each coding line is imaginarily set at a position just
// before the first picture element, and is regarded as a white picture element."
// To emulate this behavior we check for column == 0 here.
if (change.column <= column && column != 0) {
reference_line.take_first();
reference_line_span = reference_line_span.slice(1);
continue;
}
if (change.color != current_color || change.column == image_width)