Make SVG encoding in PDF export incremental (#2290)

This commit is contained in:
Laurenz 2023-10-04 14:56:54 +02:00 committed by GitHub
parent 077218db3a
commit 9e4a96cd42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,22 +1,18 @@
use std::collections::HashMap;
use std::io::Cursor;
use std::sync::Arc;
use image::{DynamicImage, GenericImageView, Rgba};
use pdf_writer::{Filter, Finish};
use pdf_writer::{Chunk, Filter, Finish, Ref};
use super::{deflate, PdfContext};
use crate::{
geom::ColorSpace,
image::{ImageKind, RasterFormat, RasterImage},
};
use crate::geom::ColorSpace;
use crate::image::{ImageKind, RasterFormat, RasterImage, SvgImage};
/// 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();
ctx.image_refs.push(image_ref);
// Add the primary image.
match image.kind() {
ImageKind::Raster(raster) => {
@ -25,6 +21,9 @@ pub fn write_images(ctx: &mut PdfContext) {
let width = image.width();
let height = image.height();
let image_ref = ctx.alloc.bump();
ctx.image_refs.push(image_ref);
let mut image = ctx.pdf.image_xobject(image_ref, &data);
image.filter(filter);
image.width(width as i32);
@ -74,19 +73,15 @@ pub fn write_images(ctx: &mut PdfContext) {
}
}
}
// Safety: We do not keep any references to tree nodes beyond the
// scope of `with`.
ImageKind::Svg(svg) => unsafe {
svg.with(|tree| {
let next_ref = svg2pdf::convert_tree_into(
tree,
svg2pdf::Options::default(),
&mut ctx.pdf,
image_ref,
);
ctx.alloc = next_ref;
ImageKind::Svg(svg) => {
let chunk = encode_svg(svg);
let mut map = HashMap::new();
chunk.renumber_into(&mut ctx.pdf, |old| {
*map.entry(old).or_insert_with(|| ctx.alloc.bump())
});
},
ctx.image_refs.push(map[&Ref::new(1)]);
}
}
}
}
@ -149,3 +144,27 @@ fn encode_alpha(raster: &RasterImage) -> (Arc<Vec<u8>>, Filter) {
.collect();
(Arc::new(deflate(&pixels)), Filter::FlateDecode)
}
/// Encode an SVG into a chunk of PDF objects.
///
/// The main XObject will have ID 1.
#[comemo::memoize]
#[tracing::instrument(skip_all)]
fn encode_svg(svg: &SvgImage) -> Arc<Chunk> {
let mut chunk = Chunk::new();
// Safety: We do not keep any references to tree nodes beyond the
// scope of `with`.
unsafe {
svg.with(|tree| {
svg2pdf::convert_tree_into(
tree,
svg2pdf::Options::default(),
&mut chunk,
Ref::new(1),
);
});
}
Arc::new(chunk)
}