1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 04:07:44 +00:00

LibPDF: For indexed images with 1, 2 or 4 bpp, do not repeat bit pattern

When upsampling e.g. the 4-bit value 0b1101 to 8-bit, we used to repeat
the value to fill the full 8-bits, e.g. 0b11011101. This maps RGB colors
to 8-bit nicely, but is the wrong thing to do for palette indices.
Stop doing this for palette indices.

Fixes "Indexed color space index out of range" for 11 files in the
PDF/A 0000.zip test set now that we correctly handle palette indices
as of the previous commit:

    Malformed PDF file: Indexed color space lookup table doesn't match
                        size, in 4 files, on 8 pages, 73 times
      path/to/0000/0000206.pdf 2 4 (2x) 5 (3x) 6 (4x)
      path/to/0000/0000364.pdf 5 6
      path/to/0000/0000918.pdf 5
      path/to/0000/0000683.pdf 8
This commit is contained in:
Nico Weber 2023-12-06 18:47:00 -05:00 committed by Sam Atkins
parent cdbc2a0dcd
commit 06b9633da5

View file

@ -827,7 +827,11 @@ PDFErrorOr<void> Renderer::show_text(DeprecatedString const& string)
return {};
}
static Vector<u8> upsample_to_8_bit(ReadonlyBytes content, int bits_per_component)
enum UpsampleMode {
StoreValuesUnchanged,
UpsampleTo8Bit,
};
static Vector<u8> upsample_to_8_bit(ReadonlyBytes content, int bits_per_component, UpsampleMode mode)
{
VERIFY(bits_per_component == 1 || bits_per_component == 2 || bits_per_component == 4);
Vector<u8> upsampled_storage;
@ -836,7 +840,10 @@ static Vector<u8> upsample_to_8_bit(ReadonlyBytes content, int bits_per_componen
for (auto byte : content) {
for (int i = 0; i < 8; i += bits_per_component) {
auto value = (byte >> (8 - bits_per_component - i)) & mask;
upsampled_storage.append(value * (255 / mask));
if (mode == UpsampleMode::UpsampleTo8Bit)
upsampled_storage.append(value * (255 / mask));
else
upsampled_storage.append(value);
}
}
return upsampled_storage;
@ -895,7 +902,8 @@ PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> Renderer::load_image(NonnullRefPtr<Stream
Vector<u8> upsampled_storage;
if (bits_per_component < 8) {
upsampled_storage = upsample_to_8_bit(content, bits_per_component);
UpsampleMode mode = color_space->family() == ColorSpaceFamily::Indexed ? UpsampleMode::StoreValuesUnchanged : UpsampleMode::UpsampleTo8Bit;
upsampled_storage = upsample_to_8_bit(content, bits_per_component, mode);
content = upsampled_storage;
bits_per_component = 8;
}