mirror of
https://github.com/typst/typst
synced 2025-05-18 11:05:28 +08:00
Make SVG encoding in PDF export incremental (#2290)
This commit is contained in:
parent
077218db3a
commit
9e4a96cd42
@ -1,22 +1,18 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use image::{DynamicImage, GenericImageView, Rgba};
|
use image::{DynamicImage, GenericImageView, Rgba};
|
||||||
use pdf_writer::{Filter, Finish};
|
use pdf_writer::{Chunk, Filter, Finish, Ref};
|
||||||
|
|
||||||
use super::{deflate, PdfContext};
|
use super::{deflate, PdfContext};
|
||||||
use crate::{
|
use crate::geom::ColorSpace;
|
||||||
geom::ColorSpace,
|
use crate::image::{ImageKind, RasterFormat, RasterImage, SvgImage};
|
||||||
image::{ImageKind, RasterFormat, RasterImage},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Embed all used images into the PDF.
|
/// Embed all used images into the PDF.
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub fn write_images(ctx: &mut PdfContext) {
|
pub fn write_images(ctx: &mut PdfContext) {
|
||||||
for image in ctx.image_map.items() {
|
for image in ctx.image_map.items() {
|
||||||
let image_ref = ctx.alloc.bump();
|
|
||||||
ctx.image_refs.push(image_ref);
|
|
||||||
|
|
||||||
// Add the primary image.
|
// Add the primary image.
|
||||||
match image.kind() {
|
match image.kind() {
|
||||||
ImageKind::Raster(raster) => {
|
ImageKind::Raster(raster) => {
|
||||||
@ -25,6 +21,9 @@ pub fn write_images(ctx: &mut PdfContext) {
|
|||||||
let width = image.width();
|
let width = image.width();
|
||||||
let height = image.height();
|
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);
|
let mut image = ctx.pdf.image_xobject(image_ref, &data);
|
||||||
image.filter(filter);
|
image.filter(filter);
|
||||||
image.width(width as i32);
|
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) => {
|
||||||
ImageKind::Svg(svg) => unsafe {
|
let chunk = encode_svg(svg);
|
||||||
svg.with(|tree| {
|
let mut map = HashMap::new();
|
||||||
let next_ref = svg2pdf::convert_tree_into(
|
chunk.renumber_into(&mut ctx.pdf, |old| {
|
||||||
tree,
|
*map.entry(old).or_insert_with(|| ctx.alloc.bump())
|
||||||
svg2pdf::Options::default(),
|
|
||||||
&mut ctx.pdf,
|
|
||||||
image_ref,
|
|
||||||
);
|
|
||||||
ctx.alloc = next_ref;
|
|
||||||
});
|
});
|
||||||
},
|
ctx.image_refs.push(map[&Ref::new(1)]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,3 +144,27 @@ fn encode_alpha(raster: &RasterImage) -> (Arc<Vec<u8>>, Filter) {
|
|||||||
.collect();
|
.collect();
|
||||||
(Arc::new(deflate(&pixels)), Filter::FlateDecode)
|
(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)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user