1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 01:17:35 +00:00

LibPDF: Support images with 1, 2, 4 bits per pixel

They just get upsampled to 8 bits per pixel images.
This commit is contained in:
Nico Weber 2023-11-15 14:21:26 -05:00 committed by Sam Atkins
parent bfe27228a3
commit 4440452f92

View file

@ -824,6 +824,21 @@ PDFErrorOr<void> Renderer::show_text(DeprecatedString const& string)
return {}; return {};
} }
static Vector<u8> upsample_to_8_bit(ReadonlyBytes content, int bits_per_component)
{
VERIFY(bits_per_component == 1 || bits_per_component == 2 || bits_per_component == 4);
Vector<u8> upsampled_storage;
upsampled_storage.ensure_capacity(content.size() * 8 / bits_per_component);
u8 const mask = (1 << bits_per_component) - 1;
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));
}
}
return upsampled_storage;
}
PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> Renderer::load_image(NonnullRefPtr<StreamObject> image) PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> Renderer::load_image(NonnullRefPtr<StreamObject> image)
{ {
auto image_dict = image->dict(); auto image_dict = image->dict();
@ -862,8 +877,28 @@ PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> Renderer::load_image(NonnullRefPtr<Stream
// "Valid values are 1, 2, 4, 8, and (in PDF 1.5) 16." // "Valid values are 1, 2, 4, 8, and (in PDF 1.5) 16."
auto bits_per_component = TRY(m_document->resolve_to<int>(image_dict->get_value(CommonNames::BitsPerComponent))); auto bits_per_component = TRY(m_document->resolve_to<int>(image_dict->get_value(CommonNames::BitsPerComponent)));
if (bits_per_component != 8) { switch (bits_per_component) {
return Error(Error::Type::RenderingUnsupported, "Image's bit per component != 8"); case 1:
case 2:
case 4:
case 8:
case 16:
// Ok!
break;
default:
return Error(Error::Type::MalformedPDF, "Image's /BitsPerComponent invalid");
}
auto content = image->bytes();
Vector<u8> upsampled_storage;
if (bits_per_component < 8) {
upsampled_storage = upsample_to_8_bit(content, bits_per_component);
content = upsampled_storage;
bits_per_component = 8;
}
if (bits_per_component == 16) {
return Error(Error::Type::RenderingUnsupported, "16 bpp images not yet supported");
} }
Vector<float> decode_array; Vector<float> decode_array;
@ -892,7 +927,6 @@ PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> Renderer::load_image(NonnullRefPtr<Stream
auto const bytes_per_component = bits_per_component / 8; auto const bytes_per_component = bits_per_component / 8;
Vector<Value> component_values; Vector<Value> component_values;
component_values.resize(n_components); component_values.resize(n_components);
auto content = image->bytes();
while (!content.is_empty() && y < height) { while (!content.is_empty() && y < height) {
auto sample = content.slice(0, bytes_per_component * n_components); auto sample = content.slice(0, bytes_per_component * n_components);
content = content.slice(bytes_per_component * n_components); content = content.slice(bytes_per_component * n_components);