diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-09-19 12:49:36 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-09-19 12:49:36 +0200 |
| commit | 59f67b79c7ff50f0bc9a27373d0fa36d1523e08a (patch) | |
| tree | 4687eea50b231b630563dd14e5de85551f661efb /src/export | |
| parent | 30be75c6687f1e03cf867d258b3ddba353cc7aa2 (diff) | |
Remove image store
Diffstat (limited to 'src/export')
| -rw-r--r-- | src/export/pdf/font.rs | 2 | ||||
| -rw-r--r-- | src/export/pdf/image.rs | 46 | ||||
| -rw-r--r-- | src/export/pdf/mod.rs | 43 | ||||
| -rw-r--r-- | src/export/pdf/page.rs | 21 | ||||
| -rw-r--r-- | src/export/render.rs | 42 |
5 files changed, 77 insertions, 77 deletions
diff --git a/src/export/pdf/font.rs b/src/export/pdf/font.rs index 99268f9c..b3481c43 100644 --- a/src/export/pdf/font.rs +++ b/src/export/pdf/font.rs @@ -9,7 +9,7 @@ use crate::util::SliceExt; /// Embed all used fonts into the PDF. pub fn write_fonts(ctx: &mut PdfContext) { - for font_id in ctx.font_map.layout_indices() { + for &font_id in ctx.font_map.items() { let type0_ref = ctx.alloc.bump(); let cid_ref = ctx.alloc.bump(); let descriptor_ref = ctx.alloc.bump(); diff --git a/src/export/pdf/image.rs b/src/export/pdf/image.rs index 90ab228f..7886524c 100644 --- a/src/export/pdf/image.rs +++ b/src/export/pdf/image.rs @@ -1,25 +1,26 @@ use std::io::Cursor; -use image::{DynamicImage, GenericImageView, ImageFormat, ImageResult, Rgba}; +use image::{DynamicImage, GenericImageView, ImageResult, Rgba}; use pdf_writer::{Filter, Finish}; use super::{deflate, PdfContext, RefExt}; -use crate::image::{Image, RasterImage}; +use crate::image::{DecodedImage, ImageFormat}; /// Embed all used images into the PDF. pub fn write_images(ctx: &mut PdfContext) { - for image_id in ctx.image_map.layout_indices() { + for image in ctx.image_map.items() { let image_ref = ctx.alloc.bump(); ctx.image_refs.push(image_ref); - let img = ctx.images.get(image_id); - let width = img.width(); - let height = img.height(); + let width = image.width(); + let height = image.height(); // Add the primary image. - match img { - Image::Raster(img) => { - if let Ok((data, filter, has_color)) = encode_image(img) { + match image.decode().unwrap() { + DecodedImage::Raster(dynamic) => { + if let Ok((data, filter, has_color)) = + encode_image(image.format(), &dynamic) + { let mut image = ctx.writer.image_xobject(image_ref, &data); image.filter(filter); image.width(width as i32); @@ -35,8 +36,8 @@ pub fn write_images(ctx: &mut PdfContext) { // 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); + 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(); @@ -59,9 +60,9 @@ pub fn write_images(ctx: &mut PdfContext) { .device_gray(); } } - Image::Svg(img) => { + DecodedImage::Svg(svg) => { let next_ref = svg2pdf::convert_tree_into( - &img.0, + &svg, svg2pdf::Options::default(), &mut ctx.writer, image_ref, @@ -76,19 +77,22 @@ pub fn write_images(ctx: &mut PdfContext) { /// whether the image has color. /// /// Skips the alpha channel as that's encoded separately. -fn encode_image(img: &RasterImage) -> ImageResult<(Vec<u8>, Filter, bool)> { - Ok(match (img.format, &img.buf) { +fn encode_image( + format: ImageFormat, + dynamic: &DynamicImage, +) -> ImageResult<(Vec<u8>, Filter, bool)> { + Ok(match (format, dynamic) { // 8-bit gray JPEG. - (ImageFormat::Jpeg, DynamicImage::ImageLuma8(_)) => { + (ImageFormat::Jpg, DynamicImage::ImageLuma8(_)) => { let mut data = Cursor::new(vec![]); - img.buf.write_to(&mut data, img.format)?; + dynamic.write_to(&mut data, image::ImageFormat::Jpeg)?; (data.into_inner(), Filter::DctDecode, false) } // 8-bit RGB JPEG (CMYK JPEGs get converted to RGB earlier). - (ImageFormat::Jpeg, DynamicImage::ImageRgb8(_)) => { + (ImageFormat::Jpg, DynamicImage::ImageRgb8(_)) => { let mut data = Cursor::new(vec![]); - img.buf.write_to(&mut data, img.format)?; + dynamic.write_to(&mut data, image::ImageFormat::Jpeg)?; (data.into_inner(), Filter::DctDecode, true) } @@ -117,7 +121,7 @@ fn encode_image(img: &RasterImage) -> ImageResult<(Vec<u8>, Filter, bool)> { } /// Encode an image's alpha channel if present. -fn encode_alpha(img: &RasterImage) -> (Vec<u8>, Filter) { - let pixels: Vec<_> = img.buf.pixels().map(|(_, _, Rgba([_, _, _, a]))| a).collect(); +fn encode_alpha(dynamic: &DynamicImage) -> (Vec<u8>, Filter) { + let pixels: Vec<_> = dynamic.pixels().map(|(_, _, Rgba([_, _, _, a]))| a).collect(); (deflate(&pixels), Filter::FlateDecode) } diff --git a/src/export/pdf/mod.rs b/src/export/pdf/mod.rs index 9ab3df24..7468f7d7 100644 --- a/src/export/pdf/mod.rs +++ b/src/export/pdf/mod.rs @@ -17,7 +17,7 @@ use self::page::Page; use crate::font::{FontId, FontStore}; use crate::frame::Frame; use crate::geom::{Dir, Em, Length}; -use crate::image::{ImageId, ImageStore}; +use crate::image::Image; use crate::library::text::Lang; use crate::Context; @@ -46,7 +46,6 @@ const D65_GRAY: Name<'static> = Name(b"d65gray"); pub struct PdfContext<'a> { writer: PdfWriter, fonts: &'a FontStore, - images: &'a ImageStore, pages: Vec<Page>, page_heights: Vec<f32>, alloc: Ref, @@ -55,7 +54,7 @@ pub struct PdfContext<'a> { image_refs: Vec<Ref>, page_refs: Vec<Ref>, font_map: Remapper<FontId>, - image_map: Remapper<ImageId>, + image_map: Remapper<Image>, glyph_sets: HashMap<FontId, HashSet<u16>>, languages: HashMap<Lang, usize>, heading_tree: Vec<HeadingNode>, @@ -68,7 +67,6 @@ impl<'a> PdfContext<'a> { Self { writer: PdfWriter::new(), fonts: &ctx.fonts, - images: &ctx.images, pages: vec![], page_heights: vec![], alloc, @@ -147,36 +145,33 @@ fn deflate(data: &[u8]) -> Vec<u8> { miniz_oxide::deflate::compress_to_vec_zlib(data, COMPRESSION_LEVEL) } -/// Assigns new, consecutive PDF-internal indices to things. -struct Remapper<Index> { - /// Forwards from the old indices to the new pdf indices. - to_pdf: HashMap<Index, usize>, - /// Backwards from the pdf indices to the old indices. - to_layout: Vec<Index>, +/// Assigns new, consecutive PDF-internal indices to items. +struct Remapper<T> { + /// Forwards from the items to the pdf indices. + to_pdf: HashMap<T, usize>, + /// Backwards from the pdf indices to the items. + to_items: Vec<T>, } -impl<Index> Remapper<Index> +impl<T> Remapper<T> where - Index: Copy + Eq + Hash, + T: Eq + Hash + Clone, { fn new() -> Self { - Self { - to_pdf: HashMap::new(), - to_layout: vec![], - } + Self { to_pdf: HashMap::new(), to_items: vec![] } } - fn insert(&mut self, index: Index) { - let to_layout = &mut self.to_layout; - self.to_pdf.entry(index).or_insert_with(|| { + fn insert(&mut self, item: T) { + let to_layout = &mut self.to_items; + self.to_pdf.entry(item.clone()).or_insert_with(|| { let pdf_index = to_layout.len(); - to_layout.push(index); + to_layout.push(item); pdf_index }); } - fn map(&self, index: Index) -> usize { - self.to_pdf[&index] + fn map(&self, item: T) -> usize { + self.to_pdf[&item] } fn pdf_indices<'a>( @@ -186,8 +181,8 @@ where refs.iter().copied().zip(0 .. self.to_pdf.len()) } - fn layout_indices(&self) -> impl Iterator<Item = Index> + '_ { - self.to_layout.iter().copied() + fn items(&self) -> impl Iterator<Item = &T> + '_ { + self.to_items.iter() } } diff --git a/src/export/pdf/page.rs b/src/export/pdf/page.rs index e5739a82..6df7531b 100644 --- a/src/export/pdf/page.rs +++ b/src/export/pdf/page.rs @@ -11,7 +11,7 @@ use crate::geom::{ self, Color, Em, Geometry, Length, Numeric, Paint, Point, Ratio, Shape, Size, Stroke, Transform, }; -use crate::image::ImageId; +use crate::image::Image; /// Construct page objects. pub fn construct_pages(ctx: &mut PdfContext, frames: &[Frame]) { @@ -290,13 +290,12 @@ fn write_frame(ctx: &mut PageContext, frame: &Frame) { for &(pos, ref element) in frame.elements() { let x = pos.x.to_f32(); let y = pos.y.to_f32(); - match *element { - Element::Group(ref group) => write_group(ctx, pos, group), - Element::Text(ref text) => write_text(ctx, x, y, text), - Element::Shape(ref shape) => write_shape(ctx, x, y, shape), - Element::Image(id, size) => write_image(ctx, x, y, id, size), - Element::Link(ref dest, size) => write_link(ctx, pos, dest, size), - Element::Pin(_) => {} + match element { + Element::Group(group) => write_group(ctx, pos, group), + Element::Text(text) => write_text(ctx, x, y, text), + Element::Shape(shape) => write_shape(ctx, x, y, shape), + Element::Image(image, size) => write_image(ctx, x, y, image, *size), + Element::Link(dest, size) => write_link(ctx, pos, dest, *size), } } } @@ -449,9 +448,9 @@ fn write_path(ctx: &mut PageContext, x: f32, y: f32, path: &geom::Path) { } /// Encode a vector or raster image into the content stream. -fn write_image(ctx: &mut PageContext, x: f32, y: f32, id: ImageId, size: Size) { - ctx.parent.image_map.insert(id); - let name = format_eco!("Im{}", ctx.parent.image_map.map(id)); +fn write_image(ctx: &mut PageContext, x: f32, y: f32, image: &Image, size: Size) { + ctx.parent.image_map.insert(image.clone()); + let name = format_eco!("Im{}", ctx.parent.image_map.map(image.clone())); let w = size.x.to_f32(); let h = size.y.to_f32(); ctx.content.save_state(); diff --git a/src/export/render.rs b/src/export/render.rs index 525d764d..688cf979 100644 --- a/src/export/render.rs +++ b/src/export/render.rs @@ -12,7 +12,7 @@ use crate::frame::{Element, Frame, Group, Text}; use crate::geom::{ self, Geometry, Length, Paint, PathElement, Shape, Size, Stroke, Transform, }; -use crate::image::{Image, RasterImage, Svg}; +use crate::image::{DecodedImage, Image}; use crate::Context; /// Export a frame into a rendered image. @@ -49,21 +49,20 @@ fn render_frame( let y = pos.y.to_f32(); let ts = ts.pre_translate(x, y); - match *element { - Element::Group(ref group) => { + match element { + Element::Group(group) => { render_group(canvas, ts, mask, ctx, group); } - Element::Text(ref text) => { + Element::Text(text) => { render_text(canvas, ts, mask, ctx, text); } - Element::Shape(ref shape) => { + Element::Shape(shape) => { render_shape(canvas, ts, mask, shape); } - Element::Image(id, size) => { - render_image(canvas, ts, mask, ctx.images.get(id), size); + Element::Image(image, size) => { + render_image(canvas, ts, mask, image, *size); } Element::Link(_, _) => {} - Element::Pin(_) => {} } } } @@ -197,17 +196,20 @@ fn render_bitmap_glyph( let ppem = size * ts.sy; let font = ctx.fonts.get(text.font_id); let raster = font.ttf().glyph_raster_image(id, ppem as u16)?; - let img = RasterImage::parse(&raster.data).ok()?; + let ext = match raster.format { + ttf_parser::RasterImageFormat::PNG => "png", + }; + let image = Image::new(raster.data.into(), ext).ok()?; // FIXME: Vertical alignment isn't quite right for Apple Color Emoji, // and maybe also for Noto Color Emoji. And: Is the size calculation // correct? let h = text.size; - let w = (img.width() as f64 / img.height() as f64) * h; - let dx = (raster.x as f32) / (img.width() as f32) * size; - let dy = (raster.y as f32) / (img.height() as f32) * size; + let w = (image.width() as f64 / image.height() as f64) * h; + let dx = (raster.x as f32) / (image.width() as f32) * size; + let dy = (raster.y as f32) / (image.height() as f32) * size; let ts = ts.pre_translate(dx, -size - dy); - render_image(canvas, ts, mask, &Image::Raster(img), Size::new(w, h)) + render_image(canvas, ts, mask, &image, Size::new(w, h)) } /// Render an outline glyph into the canvas. This is the "normal" case. @@ -338,33 +340,33 @@ fn render_image( canvas: &mut sk::Pixmap, ts: sk::Transform, mask: Option<&sk::ClipMask>, - img: &Image, + image: &Image, size: Size, ) -> Option<()> { let view_width = size.x.to_f32(); let view_height = size.y.to_f32(); - let aspect = (img.width() as f32) / (img.height() as f32); + let aspect = (image.width() as f32) / (image.height() as f32); let scale = ts.sx.max(ts.sy); let w = (scale * view_width.max(aspect * view_height)).ceil() as u32; let h = ((w as f32) / aspect).ceil() as u32; let mut pixmap = sk::Pixmap::new(w, h)?; - match img { - Image::Raster(img) => { - let downscale = w < img.width(); + match image.decode().unwrap() { + DecodedImage::Raster(dynamic) => { + let downscale = w < image.width(); let filter = if downscale { FilterType::Lanczos3 } else { FilterType::CatmullRom }; - let buf = img.buf.resize(w, h, filter); + let buf = dynamic.resize(w, h, filter); for ((_, _, src), dest) in buf.pixels().zip(pixmap.pixels_mut()) { let Rgba([r, g, b, a]) = src; *dest = sk::ColorU8::from_rgba(r, g, b, a).premultiply(); } } - Image::Svg(Svg(tree)) => { + DecodedImage::Svg(tree) => { resvg::render( &tree, FitTo::Size(w, h), |
