summaryrefslogtreecommitdiff
path: root/src/export/pdf/image.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/export/pdf/image.rs')
-rw-r--r--src/export/pdf/image.rs143
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)
-}