LibPDF: Add support for image masks

An image mask is a 1-bit-per-pixel bitmap that's black where the
current color should be painted, and white where it should be
transparent (think: like ink).

load_image() already converts images like this into 8-bit-per-pixel
images that have 0xff, 0xff, 0xff in rgb for opaque (originally 0 bit)
pixels and 0, 0, 0 in rgb for transparent pixels.

So we just move copy the image mask's image data into the alpha
channel and replace rgb with the current color, and then draw
it like a regular bitmap.
This commit is contained in:
Nico Weber 2024-01-09 19:17:02 -05:00 committed by Sam Atkins
parent 675b242e84
commit 4fd5d450be
Notes: sideshowbarker 2024-07-17 18:06:52 +09:00

View file

@ -1207,10 +1207,20 @@ PDFErrorOr<void> Renderer::show_image(NonnullRefPtr<StreamObject> image)
return {};
}
auto image_bitmap = TRY(load_image(image));
if (image_bitmap.is_image_mask)
return Error(Error::Type::RenderingUnsupported, "Image masks");
if (image_bitmap.is_image_mask) {
// PDF 1.7 spec, 4.8.5 Masked Images, Stencil Masking:
// "An image mask (an image XObject whose ImageMask entry is true) [...] is treated as a stencil mask [...].
// Sample values [...] designate places on the page that should either be marked with the current color or masked out (not marked at all)."
if (!state().paint_style.has<Gfx::Color>())
return Error(Error::Type::RenderingUnsupported, "Image masks with pattern fill not yet implemented");
if (image_dict->contains(CommonNames::SMask)) {
// Move mask to alpha channel, and put current color in RGB.
auto current_color = state().paint_style.get<Gfx::Color>();
for (auto& pixel : *image_bitmap.bitmap) {
u8 mask_alpha = Color::from_argb(pixel).luminosity();
pixel = current_color.with_alpha(mask_alpha).value();
}
} else 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.bitmap, smask_bitmap.bitmap));
} else if (image_dict->contains(CommonNames::Mask)) {