diff options
| author | Martin Haug <mhaug@live.de> | 2021-12-06 14:58:57 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2021-12-06 14:58:57 +0100 |
| commit | f15ee7efb68eff188b5993d21d663e2120b5dd08 (patch) | |
| tree | 4cd7afa806c62a55234f359ad46177266093d7ee /src/export | |
| parent | 2982020480fc3d9061e26ca24dd467f315981dff (diff) | |
Add SVG capabilities
Diffstat (limited to 'src/export')
| -rw-r--r-- | src/export/pdf.rs | 95 |
1 files changed, 55 insertions, 40 deletions
diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 8df31660..100a53f9 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -10,13 +10,14 @@ use pdf_writer::types::{ ActionType, AnnotationType, CidFontType, FontFlags, SystemInfo, UnicodeCmap, }; use pdf_writer::{Content, Filter, Finish, Name, PdfWriter, Rect, Ref, Str, TextStr}; +use svg2pdf::{convert_tree_into, Options}; use ttf_parser::{name_id, GlyphId, Tag}; use super::subset; use crate::font::{find_name, FaceId, FontStore}; use crate::frame::{Element, Frame, Geometry, Group, Shape, Stroke, Text}; use crate::geom::{self, Color, Em, Length, Paint, Point, Size, Transform}; -use crate::image::{Image, ImageId, ImageStore}; +use crate::image::{Image, ImageId, ImageStore, RasterImage}; use crate::Context; /// Export a collection of frames into a PDF file. @@ -90,7 +91,7 @@ impl<'a> PdfExporter<'a> { let postscript_name = find_name(ttf.names(), name_id::POST_SCRIPT_NAME) .unwrap_or_else(|| "unknown".to_string()); - let base_font = format!("ABCDEF+{}", postscript_name); + let base_font = format_eco!("ABCDEF+{}", postscript_name); let base_font = Name(base_font.as_bytes()); let cmap_name = Name(b"Custom"); let system_info = SystemInfo { @@ -218,44 +219,58 @@ impl<'a> PdfExporter<'a> { let height = img.height(); // Add the primary image. - if let Ok((data, filter, has_color)) = encode_image(img) { - let mut image = self.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 has_color { - space.device_rgb(); - } else { - space.device_gray(); + match img { + Image::Raster(img) => { + if let Ok((data, filter, has_color)) = encode_image(img) { + let mut image = self.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 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 img.buf.color().has_alpha() { + let (alpha_data, alpha_filter) = encode_alpha(img); + let mask_ref = self.alloc.bump(); + image.s_mask(mask_ref); + image.finish(); + + let mut mask = + self.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 { + // TODO: Warn that image could not be encoded. + self.writer + .image_xobject(image_ref, &[]) + .width(0) + .height(0) + .bits_per_component(1) + .color_space() + .device_gray(); + } } - - // Add a second gray-scale image containing the alpha values if - // this image has an alpha channel. - if img.buf.color().has_alpha() { - let (alpha_data, alpha_filter) = encode_alpha(img); - let mask_ref = self.alloc.bump(); - image.s_mask(mask_ref); - image.finish(); - - let mut mask = self.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); + Image::Svg(img) => { + let next_ref = convert_tree_into( + &img.0, + Options::default(), + &mut self.writer, + image_ref, + ); + self.alloc = next_ref; } - } else { - // TODO: Warn that image could not be encoded. - self.writer - .image_xobject(image_ref, &[]) - .width(0) - .height(0) - .bits_per_component(1) - .color_space() - .device_gray(); } } } @@ -636,7 +651,7 @@ impl<'a> PageExporter<'a> { /// whether the image has color. /// /// Skips the alpha channel as that's encoded separately. -fn encode_image(img: &Image) -> ImageResult<(Vec<u8>, Filter, bool)> { +fn encode_image(img: &RasterImage) -> ImageResult<(Vec<u8>, Filter, bool)> { Ok(match (img.format, &img.buf) { // 8-bit gray JPEG. (ImageFormat::Jpeg, DynamicImage::ImageLuma8(_)) => { @@ -677,7 +692,7 @@ fn encode_image(img: &Image) -> ImageResult<(Vec<u8>, Filter, bool)> { } /// Encode an image's alpha channel if present. -fn encode_alpha(img: &Image) -> (Vec<u8>, Filter) { +fn encode_alpha(img: &RasterImage) -> (Vec<u8>, Filter) { let pixels: Vec<_> = img.buf.pixels().map(|(_, _, Rgba([_, _, _, a]))| a).collect(); (deflate(&pixels), Filter::FlateDecode) } |
