From a3507ef65b59c4c2a4f44a61e8d4c0625b704a1d Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Fri, 22 Dec 2023 18:56:42 -0500 Subject: [PATCH] LibPDF: Move error for /ImageMask out of load_image() ...and tweak load_image() to support loading mask images (which don't have a color space and are always 1 bit per pixel). --- Userland/Libraries/LibPDF/Renderer.cpp | 40 ++++++++++++++++++-------- Userland/Libraries/LibPDF/Renderer.h | 8 +++++- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/Userland/Libraries/LibPDF/Renderer.cpp b/Userland/Libraries/LibPDF/Renderer.cpp index 6e39cb37a5..a17ca28213 100644 --- a/Userland/Libraries/LibPDF/Renderer.cpp +++ b/Userland/Libraries/LibPDF/Renderer.cpp @@ -1030,7 +1030,7 @@ static Vector upsample_to_8_bit(ReadonlyBytes content, int samples_per_line, return upsampled_storage; } -PDFErrorOr> Renderer::load_image(NonnullRefPtr image) +PDFErrorOr Renderer::load_image(NonnullRefPtr image) { auto image_dict = image->dict(); auto width = TRY(m_document->resolve_to(image_dict->get_value(CommonNames::Width))); @@ -1051,17 +1051,19 @@ PDFErrorOr> Renderer::load_image(NonnullRefPtrcontains(CommonNames::ImageMask)) { - auto is_mask = TRY(m_document->resolve_to(image_dict->get_value(CommonNames::ImageMask))); - if (is_mask) { - return Error(Error::Type::RenderingUnsupported, "Image masks"); - } + is_image_mask = TRY(m_document->resolve_to(image_dict->get_value(CommonNames::ImageMask))); } // "(Required for images, except those that use the JPXDecode filter; not allowed for image masks) [...] // it can be any type of color space except Pattern." - auto color_space_object = MUST(image_dict->get_object(m_document, CommonNames::ColorSpace)); - auto color_space = TRY(get_color_space_from_document(color_space_object)); + NonnullRefPtr color_space = DeviceGrayColorSpace::the(); + if (!is_image_mask) { + auto color_space_object = MUST(image_dict->get_object(m_document, CommonNames::ColorSpace)); + color_space = TRY(get_color_space_from_document(color_space_object)); + } auto color_rendering_intent = state().color_rendering_intent; if (image_dict->contains(CommonNames::Intent)) @@ -1069,7 +1071,11 @@ PDFErrorOr> Renderer::load_image(NonnullRefPtrresolve_to(image_dict->get_value(CommonNames::BitsPerComponent))); + // Per spec, this is required even for /Mask images, but it's required to be 1 there. + // In practice, it's sometimes missing for /Mask images. + auto bits_per_component = 1; + if (!is_image_mask) + bits_per_component = TRY(m_document->resolve_to(image_dict->get_value(CommonNames::BitsPerComponent))); switch (bits_per_component) { case 1: case 2: @@ -1091,6 +1097,13 @@ PDFErrorOr> Renderer::load_image(NonnullRefPtr> Renderer::load_image(NonnullRefPtr to avoid serialisation/deserialisation here - return TRY(Gfx::Bitmap::create_from_serialized_bytes(image->bytes())); + return LoadedImage { TRY(Gfx::Bitmap::create_from_serialized_bytes(image->bytes())), is_image_mask }; } auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, { width, height })); @@ -1146,7 +1159,7 @@ PDFErrorOr> Renderer::load_image(NonnullRefPtr Renderer::show_image(NonnullRefPtr image) return {}; } auto image_bitmap = TRY(load_image(image)); + if (image_bitmap.is_image_mask) + return Error(Error::Type::RenderingUnsupported, "Image masks"); + if (image_dict->contains(CommonNames::SMask)) { auto smask_bitmap = TRY(load_image(TRY(image_dict->get_stream(m_document, CommonNames::SMask)))); - TRY(apply_alpha_channel(image_bitmap, smask_bitmap)); + TRY(apply_alpha_channel(image_bitmap.bitmap, smask_bitmap.bitmap)); } else if (image_dict->contains(CommonNames::Mask)) { auto mask_object = TRY(image_dict->get_object(m_document, CommonNames::Mask)); if (mask_object->is()) { @@ -1213,7 +1229,7 @@ PDFErrorOr Renderer::show_image(NonnullRefPtr image) auto image_space = calculate_image_space_transformation(width, height); auto image_rect = Gfx::FloatRect { 0, 0, width, height }; - m_painter.draw_scaled_bitmap_with_transform(image_bitmap->rect(), image_bitmap, image_rect, image_space); + m_painter.draw_scaled_bitmap_with_transform(image_bitmap.bitmap->rect(), image_bitmap.bitmap, image_rect, image_space); return {}; } diff --git a/Userland/Libraries/LibPDF/Renderer.h b/Userland/Libraries/LibPDF/Renderer.h index b249a4e799..827fe0b70b 100644 --- a/Userland/Libraries/LibPDF/Renderer.h +++ b/Userland/Libraries/LibPDF/Renderer.h @@ -131,7 +131,13 @@ private: void end_path_paint(); PDFErrorOr set_graphics_state_from_dict(NonnullRefPtr); PDFErrorOr show_text(ByteString const&); - PDFErrorOr> load_image(NonnullRefPtr); + + struct LoadedImage { + NonnullRefPtr bitmap; + bool is_image_mask = false; + }; + PDFErrorOr load_image(NonnullRefPtr); + PDFErrorOr show_image(NonnullRefPtr); void show_empty_image(int width, int height); PDFErrorOr> get_color_space_from_resources(Value const&, NonnullRefPtr);