diff options
Diffstat (limited to 'src/export/pdf/image.rs')
| -rw-r--r-- | src/export/pdf/image.rs | 143 |
1 files changed, 0 insertions, 143 deletions
diff --git a/src/export/pdf/image.rs b/src/export/pdf/image.rs deleted file mode 100644 index 48472d9f..00000000 --- a/src/export/pdf/image.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::io::Cursor; - -use image::{DynamicImage, GenericImageView, Rgba}; -use pdf_writer::{Filter, Finish}; - -use super::{deflate, PdfContext, RefExt}; -use crate::image::{DecodedImage, Image, RasterFormat}; -use crate::util::Bytes; - -/// Embed all used images into the PDF. -#[tracing::instrument(skip_all)] -pub fn write_images(ctx: &mut PdfContext) { - for image in ctx.image_map.items() { - let image_ref = ctx.alloc.bump(); - let icc_ref = ctx.alloc.bump(); - ctx.image_refs.push(image_ref); - - let width = image.width(); - let height = image.height(); - - // Add the primary image. - // TODO: Error if image could not be encoded. - match image.decoded().as_ref() { - DecodedImage::Raster(dynamic, icc, _) => { - // TODO: Error if image could not be encoded. - let (data, filter, has_color) = encode_image(image); - let mut image = ctx.writer.image_xobject(image_ref, &data); - image.filter(filter); - image.width(width as i32); - image.height(height as i32); - image.bits_per_component(8); - - let space = image.color_space(); - if icc.is_some() { - space.icc_based(icc_ref); - } else if has_color { - space.device_rgb(); - } else { - space.device_gray(); - } - - // Add a second gray-scale image containing the alpha values if - // this image has an alpha channel. - if dynamic.color().has_alpha() { - let (alpha_data, alpha_filter) = encode_alpha(dynamic); - let mask_ref = ctx.alloc.bump(); - image.s_mask(mask_ref); - image.finish(); - - let mut mask = ctx.writer.image_xobject(mask_ref, &alpha_data); - mask.filter(alpha_filter); - mask.width(width as i32); - mask.height(height as i32); - mask.color_space().device_gray(); - mask.bits_per_component(8); - } else { - image.finish(); - } - - if let Some(icc) = icc { - let compressed = deflate(&icc.0); - let mut stream = ctx.writer.icc_profile(icc_ref, &compressed); - stream.filter(Filter::FlateDecode); - if has_color { - stream.n(3); - stream.alternate().srgb(); - } else { - stream.n(1); - stream.alternate().d65_gray(); - } - } - } - DecodedImage::Svg(svg) => { - let next_ref = svg2pdf::convert_tree_into( - svg, - svg2pdf::Options::default(), - &mut ctx.writer, - image_ref, - ); - ctx.alloc = next_ref; - } - } - } -} - -/// Encode an image with a suitable filter and return the data, filter and -/// whether the image has color. -/// -/// Skips the alpha channel as that's encoded separately. -#[comemo::memoize] -#[tracing::instrument(skip_all)] -fn encode_image(image: &Image) -> (Bytes, Filter, bool) { - let decoded = image.decoded(); - let (dynamic, format) = match decoded.as_ref() { - DecodedImage::Raster(dynamic, _, format) => (dynamic, *format), - _ => panic!("can only encode raster image"), - }; - - match (format, dynamic) { - // 8-bit gray JPEG. - (RasterFormat::Jpg, DynamicImage::ImageLuma8(_)) => { - let mut data = Cursor::new(vec![]); - dynamic.write_to(&mut data, image::ImageFormat::Jpeg).unwrap(); - (data.into_inner().into(), Filter::DctDecode, false) - } - - // 8-bit RGB JPEG (CMYK JPEGs get converted to RGB earlier). - (RasterFormat::Jpg, DynamicImage::ImageRgb8(_)) => { - let mut data = Cursor::new(vec![]); - dynamic.write_to(&mut data, image::ImageFormat::Jpeg).unwrap(); - (data.into_inner().into(), Filter::DctDecode, true) - } - - // TODO: Encode flate streams with PNG-predictor? - - // 8-bit gray PNG. - (RasterFormat::Png, DynamicImage::ImageLuma8(luma)) => { - let data = deflate(luma.as_raw()); - (data.into(), Filter::FlateDecode, false) - } - - // Anything else (including Rgb(a) PNGs). - (_, buf) => { - let (width, height) = buf.dimensions(); - let mut pixels = Vec::with_capacity(3 * width as usize * height as usize); - for (_, _, Rgba([r, g, b, _])) in buf.pixels() { - pixels.push(r); - pixels.push(g); - pixels.push(b); - } - - let data = deflate(&pixels); - (data.into(), Filter::FlateDecode, true) - } - } -} - -/// Encode an image's alpha channel if present. -#[tracing::instrument(skip_all)] -fn encode_alpha(dynamic: &DynamicImage) -> (Vec<u8>, Filter) { - let pixels: Vec<_> = dynamic.pixels().map(|(_, _, Rgba([_, _, _, a]))| a).collect(); - (deflate(&pixels), Filter::FlateDecode) -} |
