LibPDF: Add a fastpath for 1bpp grayscale to load_image()

We used to expand every bit in an 1bpp image to a 0 or 255 byte,
then map that to a float that's either 0.0f or 1.0f (or whatever's
in /DecodeArray), then multiply that by 255.0f to convert it to a
u8 and put that in the rgb channels of a Color.

Now we precompute the two possible outcomes (almost always Black
and White) and do a per-bit lookup.

Reduces time for

    Build/lagom/bin/pdf --render-bench --render-repeats 20 --page 36 \
        ~/Downloads/Flatland.pdf

(the "decoded data cached" case) from 3.3s to 1.1s on my system.

Reduces time for

    Build/lagom/bin/pdf --debugging-stats ~/Downloads/0000/0000231.pdf

(the "need to decode each page" case) from 52s to 43s on my machine.

Also makes paging through PDFs that contain a 1700x2200 pixel CCITT
or JBIG2 bitmap on each page noticeably snappier.
This commit is contained in:
Nico Weber 2024-03-30 20:45:15 -07:00 committed by Andreas Kling
commit 40780304b8
Notes: sideshowbarker 2024-07-17 02:08:15 +09:00

View file

@ -1173,6 +1173,30 @@ PDFErrorOr<Renderer::LoadedImage> Renderer::load_image(NonnullRefPtr<StreamObjec
decode_array = color_space->default_decode();
}
if (bits_per_component == 1 && color_space->family() == ColorSpaceFamily::DeviceGray) {
// Fast path for 1bpp grayscale. Used for masks and scanned pages (CCITT or JBIG2).
// FIXME: This fast path could work for CalGray and Indexed too,
// but IndexedColorSpace::default_decode() currently assumes 8bpp.
auto bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, { width, height }));
Color colors[] = {
TRY(color_space->style({ &decode_array[0], 1 })).get<Color>(),
TRY(color_space->style({ &decode_array[1], 1 })).get<Color>(),
};
auto const bytes_per_line = ceil_div(width, 8);
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
auto byte = content[y * bytes_per_line + x / 8];
auto bit = 7 - (x % 8);
auto color = colors[(byte >> bit) & 1];
bitmap->set_pixel(x, y, color);
}
}
return LoadedImage { bitmap, is_image_mask };
}
Vector<u8> resampled_storage;
if (bits_per_component < 8) {
UpsampleMode mode = color_space->family() == ColorSpaceFamily::Indexed ? UpsampleMode::StoreValuesUnchanged : UpsampleMode::UpsampleTo8Bit;