From 33199e1c00caad207b7216a7a7a56ac8d47bfd37 Mon Sep 17 00:00:00 2001 From: Laurenz Stampfl Date: Mon, 10 Mar 2025 10:21:13 +0100 Subject: [PATCH] Part 2 --- Cargo.lock | 222 +++++------------- Cargo.toml | 6 +- crates/typst-cli/src/compile.rs | 2 +- .../src/visualize/image/raster.rs | 11 +- crates/typst-pdf/src/convert.rs | 2 +- crates/typst-pdf/src/image.rs | 29 ++- crates/typst-pdf/src/link.rs | 5 + crates/typst-pdf/src/outline.rs | 2 +- crates/typst-pdf/src/shape.rs | 4 +- crates/typst-pdf/src/text.rs | 3 +- 10 files changed, 106 insertions(+), 180 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06256acf2..189d53235 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -786,9 +786,9 @@ checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "font-types" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492" +checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd" dependencies = [ "bytemuck", ] @@ -802,44 +802,18 @@ dependencies = [ "roxmltree", ] -[[package]] -name = "fontdb" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37be9fc20d966be438cd57a45767f73349477fb0f85ce86e000557f787298afb" -dependencies = [ - "fontconfig-parser", - "log", - "memmap2", - "slotmap", - "tinyvec", - "ttf-parser 0.24.1", -] - -[[package]] -name = "fontdb" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3a6f9af55fb97ad673fb7a69533eb2f967648a06fa21f8c9bb2cd6d33975716" -dependencies = [ - "fontconfig-parser", - "log", - "memmap2", - "slotmap", - "tinyvec", - "ttf-parser 0.24.1", -] - [[package]] name = "fontdb" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" dependencies = [ + "fontconfig-parser", "log", + "memmap2", "slotmap", "tinyvec", - "ttf-parser 0.25.1", + "ttf-parser", ] [[package]] @@ -1024,7 +998,7 @@ checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "serde", - "yoke", + "yoke 0.7.5", "zerofrom", "zerovec", ] @@ -1122,7 +1096,7 @@ dependencies = [ "stable_deref_trait", "tinystr", "writeable", - "yoke", + "yoke 0.7.5", "zerofrom", "zerovec", ] @@ -1231,16 +1205,6 @@ dependencies = [ "zune-jpeg", ] -[[package]] -name = "image-webp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904" -dependencies = [ - "byteorder-lite", - "quick-error", -] - [[package]] name = "image-webp" version = "0.2.1" @@ -1381,29 +1345,28 @@ dependencies = [ [[package]] name = "krilla" version = "0.3.0" -source = "git+https://github.com/LaurenzV/krilla#478e4639001bc96118a6f651f06d42d37d0be7a8" dependencies = [ "base64", "bumpalo", "flate2", "float-cmp 0.10.0", - "fontdb 0.22.0", + "fontdb", "gif", - "image-webp 0.1.3", + "image-webp", "imagesize", "miniz_oxide", "once_cell", "pdf-writer", - "resvg 0.44.0", - "rustybuzz 0.18.0", + "resvg", + "rustybuzz", "siphasher", "skrifa", "subsetter", "tiny-skia", "tiny-skia-path", - "usvg 0.44.0", + "usvg", "xmp-writer", - "yoke", + "yoke 0.8.0", "zune-jpeg", "zune-png", ] @@ -1901,11 +1864,11 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pixglyph" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15afa937836bf3d876f5a04ce28810c06045857bf46c3d0d31073b8aada5494" +checksum = "3c1106193bc18a4b840eb075ff6664c8a0b0270f0531bb12a7e9c803e53b55c5" dependencies = [ - "ttf-parser 0.24.1", + "ttf-parser", ] [[package]] @@ -2096,9 +2059,9 @@ dependencies = [ [[package]] name = "read-fonts" -version = "0.22.7" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69aacb76b5c29acfb7f90155d39759a29496aebb49395830e928a9703d2eec2f" +checksum = "f004ee5c610b8beb5f33273246893ac6258ec22185a6eb8ee132bccdb904cdaa" dependencies = [ "bytemuck", "font-types", @@ -2153,23 +2116,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "resvg" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a325d5e8d1cebddd070b13f44cec8071594ab67d1012797c121f27a669b7958" -dependencies = [ - "gif", - "image-webp 0.1.3", - "log", - "pico-args", - "rgb", - "svgtypes", - "tiny-skia", - "usvg 0.44.0", - "zune-jpeg", -] - [[package]] name = "resvg" version = "0.45.0" @@ -2177,13 +2123,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd43d1c474e9dadf09a8fdf22d713ba668b499b5117b9b9079500224e26b5b29" dependencies = [ "gif", - "image-webp 0.2.1", + "image-webp", "log", "pico-args", "rgb", "svgtypes", "tiny-skia", - "usvg 0.45.0", + "usvg", "zune-jpeg", ] @@ -2243,24 +2189,6 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" -[[package]] -name = "rustybuzz" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181" -dependencies = [ - "bitflags 2.8.0", - "bytemuck", - "core_maths", - "log", - "smallvec", - "ttf-parser 0.24.1", - "unicode-bidi-mirroring 0.3.0", - "unicode-ccc 0.3.0", - "unicode-properties", - "unicode-script", -] - [[package]] name = "rustybuzz" version = "0.20.1" @@ -2272,9 +2200,9 @@ dependencies = [ "core_maths", "log", "smallvec", - "ttf-parser 0.25.1", - "unicode-bidi-mirroring 0.4.0", - "unicode-ccc 0.4.0", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", "unicode-properties", "unicode-script", ] @@ -2459,9 +2387,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "skrifa" -version = "0.22.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe" +checksum = "16e7936ca3627fdb516e97aca3c8ab5103f94ae32fe5ce80a0a02edcbacb7b53" dependencies = [ "bytemuck", "read-fonts", @@ -2838,15 +2766,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "ttf-parser" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" -dependencies = [ - "core_maths", -] - [[package]] name = "ttf-parser" version = "0.25.1" @@ -3037,7 +2956,7 @@ dependencies = [ "ecow", "env_proxy", "flate2", - "fontdb 0.21.0", + "fontdb", "native-tls", "once_cell", "openssl", @@ -3067,9 +2986,9 @@ dependencies = [ "icu_provider_blob", "icu_segmenter", "kurbo", - "rustybuzz 0.20.1", + "rustybuzz", "smallvec", - "ttf-parser 0.25.1", + "ttf-parser", "typst-assets", "typst-library", "typst-macros", @@ -3096,7 +3015,7 @@ dependencies = [ "csv", "ecow", "flate2", - "fontdb 0.21.0", + "fontdb", "hayagriva", "icu_properties", "icu_provider", @@ -3116,7 +3035,7 @@ dependencies = [ "regex-syntax", "roxmltree", "rust_decimal", - "rustybuzz 0.20.1", + "rustybuzz", "serde", "serde_json", "serde_yaml 0.9.34+deprecated", @@ -3125,7 +3044,7 @@ dependencies = [ "syntect", "time", "toml", - "ttf-parser 0.25.1", + "ttf-parser", "two-face", "typed-arena", "typst-assets", @@ -3138,7 +3057,7 @@ dependencies = [ "unicode-normalization", "unicode-segmentation", "unscanny", - "usvg 0.45.0", + "usvg", "wasmi", "xmlwriter", ] @@ -3194,9 +3113,9 @@ dependencies = [ "comemo", "image", "pixglyph", - "resvg 0.45.0", + "resvg", "tiny-skia", - "ttf-parser 0.25.1", + "ttf-parser", "typst-library", "typst-macros", "typst-timing", @@ -3211,7 +3130,7 @@ dependencies = [ "ecow", "flate2", "image", - "ttf-parser 0.25.1", + "ttf-parser", "typst-library", "typst-macros", "typst-timing", @@ -3314,24 +3233,12 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" -[[package]] -name = "unicode-bidi-mirroring" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f" - [[package]] name = "unicode-bidi-mirroring" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" -[[package]] -name = "unicode-ccc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42" - [[package]] name = "unicode-ccc" version = "0.4.0" @@ -3429,33 +3336,6 @@ dependencies = [ "serde", ] -[[package]] -name = "usvg" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447e703d7223b067607655e625e0dbca80822880248937da65966194c4864e6" -dependencies = [ - "base64", - "data-url", - "flate2", - "fontdb 0.22.0", - "imagesize", - "kurbo", - "log", - "pico-args", - "roxmltree", - "rustybuzz 0.18.0", - "simplecss", - "siphasher", - "strict-num", - "svgtypes", - "tiny-skia-path", - "unicode-bidi", - "unicode-script", - "unicode-vo", - "xmlwriter", -] - [[package]] name = "usvg" version = "0.45.0" @@ -3465,13 +3345,13 @@ dependencies = [ "base64", "data-url", "flate2", - "fontdb 0.23.0", + "fontdb", "imagesize", "kurbo", "log", "pico-args", "roxmltree", - "rustybuzz 0.20.1", + "rustybuzz", "simplecss", "siphasher", "strict-num", @@ -3869,7 +3749,19 @@ checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", - "yoke-derive", + "yoke-derive 0.7.5", + "zerofrom", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive 0.8.0", "zerofrom", ] @@ -3885,6 +3777,18 @@ dependencies = [ "synstructure", ] +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -3946,7 +3850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "serde", - "yoke", + "yoke 0.7.5", "zerofrom", "zerovec-derive", ] diff --git a/Cargo.toml b/Cargo.toml index b38f6bc57..df1b1eea4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ dirs = "6" ecow = { version = "0.2", features = ["serde"] } env_proxy = "0.4" flate2 = "1" -fontdb = { version = "0.21", default-features = false } +fontdb = { version = "0.23", default-features = false } fs_extra = "1.3" hayagriva = "0.8.1" heck = "0.5" @@ -70,7 +70,7 @@ if_chain = "1" image = { version = "0.25.5", default-features = false, features = ["png", "jpeg", "gif"] } indexmap = { version = "2", features = ["serde"] } kamadak-exif = "0.6" -krilla = { git = "https://github.com/LaurenzV/krilla" } +krilla = { path = "../krilla/crates/krilla" } kurbo = "0.11" libfuzzer-sys = "0.4" lipsum = "0.9" @@ -87,7 +87,7 @@ parking_lot = "0.12.1" pathdiff = "0.2" pdf-writer = "0.12.1" phf = { version = "0.11", features = ["macros"] } -pixglyph = "0.5.1" +pixglyph = "0.6.0" png = "0.17" portable-atomic = "1.6" proc-macro2 = "1" diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs index ae71e298c..d8a2e771f 100644 --- a/crates/typst-cli/src/compile.rs +++ b/crates/typst-cli/src/compile.rs @@ -18,7 +18,7 @@ use typst::html::HtmlDocument; use typst::layout::{Frame, Page, PageRanges, PagedDocument}; use typst::syntax::{FileId, Source, Span}; use typst::WorldExt; -use typst_pdf::{PdfOptions, PdfStandards, Timestamp}; +use typst_pdf::{PdfOptions, Timestamp}; use crate::args::{ CompileArgs, CompileCommand, DiagnosticFormat, Input, Output, OutputFormat, diff --git a/crates/typst-library/src/visualize/image/raster.rs b/crates/typst-library/src/visualize/image/raster.rs index 9b4a310b1..4f228507a 100644 --- a/crates/typst-library/src/visualize/image/raster.rs +++ b/crates/typst-library/src/visualize/image/raster.rs @@ -23,6 +23,7 @@ struct Repr { data: Bytes, format: RasterFormat, dynamic: Arc, + is_rotated: bool, icc: Option, dpi: Option, } @@ -50,6 +51,8 @@ impl RasterImage { format: RasterFormat, icc: Smart, ) -> StrResult { + let mut is_rotated = false; + let (dynamic, icc, dpi) = match format { RasterFormat::Exchange(format) => { fn decode( @@ -85,6 +88,7 @@ impl RasterImage { // Apply rotation from EXIF metadata. if let Some(rotation) = exif.as_ref().and_then(exif_rotation) { apply_rotation(&mut dynamic, rotation); + is_rotated = true; } // Extract pixel density. @@ -136,7 +140,7 @@ impl RasterImage { } }; - Ok(Self(Arc::new(Repr { data, format, dynamic: Arc::new(dynamic), icc, dpi }))) + Ok(Self(Arc::new(Repr { data, format, is_rotated, dynamic: Arc::new(dynamic), icc, dpi }))) } /// The raw image data. @@ -159,6 +163,11 @@ impl RasterImage { self.dynamic().height() } + /// Whether the image has been rotated due to EXIF metadata. + pub fn is_rotated(&self) -> bool { + self.0.is_rotated + } + /// The image's pixel density in pixels per inch, if known. /// /// This is guaranteed to be positive. diff --git a/crates/typst-pdf/src/convert.rs b/crates/typst-pdf/src/convert.rs index 491c5f221..f0052141a 100644 --- a/crates/typst-pdf/src/convert.rs +++ b/crates/typst-pdf/src/convert.rs @@ -319,7 +319,7 @@ pub(crate) fn handle_group( /// Finish a krilla document and handle export errors. fn finish(document: Document, gc: GlobalContext) -> SourceResult> { - let validator: krilla::configure::Validator = gc.options.validator.into(); + let validator: krilla::configure::Validator = gc.options.validator.map(|v| v.into()).unwrap_or(krilla::configure::Validator::None); match document.finish() { Ok(r) => Ok(r), diff --git a/crates/typst-pdf/src/image.rs b/crates/typst-pdf/src/image.rs index 33c456245..7040ed4a2 100644 --- a/crates/typst-pdf/src/image.rs +++ b/crates/typst-pdf/src/image.rs @@ -6,8 +6,9 @@ use krilla::image::{BitsPerComponent, CustomImage, ImageColorspace}; use krilla::surface::Surface; use krilla::SvgSettings; use typst_library::diag::{bail, SourceResult}; +use typst_library::foundations::Smart; use typst_library::layout::Size; -use typst_library::visualize::{Image, ImageKind, RasterFormat, RasterImage}; +use typst_library::visualize::{ExchangeFormat, Image, ImageKind, ImageScaling, RasterFormat, RasterImage}; use typst_syntax::Span; use crate::convert::{FrameContext, GlobalContext}; @@ -22,10 +23,12 @@ pub(crate) fn handle_image( span: Span, ) -> SourceResult<()> { surface.push_transform(&fc.state().transform().to_krilla()); + + let interpolate = image.scaling() == Smart::Custom(ImageScaling::Smooth); match image.kind() { ImageKind::Raster(raster) => { - let image = match convert_raster(raster.clone()) { + let image = match convert_raster(raster.clone(), interpolate) { None => bail!(span, "failed to process image"), Some(i) => i, }; @@ -41,7 +44,7 @@ pub(crate) fn handle_image( svg.tree(), size.to_krilla(), SvgSettings { - embed_text: !svg.flatten_text(), + embed_text: true, ..Default::default() }, ); @@ -156,16 +159,20 @@ impl CustomImage for PdfImage { } #[comemo::memoize] -fn convert_raster(raster: RasterImage) -> Option { +fn convert_raster(raster: RasterImage, interpolate: bool) -> Option { match raster.format() { - RasterFormat::Jpg => { - if !raster.is_rotated() { - krilla::image::Image::from_jpeg(Arc::new(raster.data().clone())) - } else { - // Can't embed original JPEG data if it had to be rotated. - krilla::image::Image::from_custom(PdfImage::new(raster)) + RasterFormat::Exchange(e) => match e { + ExchangeFormat::Jpg => { + if !raster.is_rotated() { + let image_data: Arc + Send + Sync> = Arc::new(raster.data().clone()); + krilla::image::Image::from_jpeg(image_data.into(), interpolate) + } else { + // Can't embed original JPEG data if it had to be rotated. + krilla::image::Image::from_custom(PdfImage::new(raster), interpolate) + } } + _ => krilla::image::Image::from_custom(PdfImage::new(raster), interpolate), } - _ => krilla::image::Image::from_custom(PdfImage::new(raster)), + RasterFormat::Pixel(_) => krilla::image::Image::from_custom(PdfImage::new(raster), interpolate) } } diff --git a/crates/typst-pdf/src/link.rs b/crates/typst-pdf/src/link.rs index e03130d4c..316c0391e 100644 --- a/crates/typst-pdf/src/link.rs +++ b/crates/typst-pdf/src/link.rs @@ -41,12 +41,15 @@ pub(crate) fn handle_link( let y2 = max_y.to_f32(); let rect = Rect::from_ltrb(x1, y1, x2, y2).unwrap(); + + // TODO: Support quad points. let pos = match dest { Destination::Url(u) => { fc.push_annotation( LinkAnnotation::new( rect, + None, Target::Action(Action::Link(LinkAction::new(u.to_string()))), ) .into(), @@ -61,6 +64,7 @@ pub(crate) fn handle_link( fc.push_annotation( LinkAnnotation::new( rect, + None, Target::Destination(krilla::destination::Destination::Named( nd.clone(), )), @@ -79,6 +83,7 @@ pub(crate) fn handle_link( fc.push_annotation( LinkAnnotation::new( rect, + None, Target::Destination(krilla::destination::Destination::Xyz( XyzDestination::new(page_index, pos.point.to_krilla()), )), diff --git a/crates/typst-pdf/src/outline.rs b/crates/typst-pdf/src/outline.rs index 8839bee1f..16a19c478 100644 --- a/crates/typst-pdf/src/outline.rs +++ b/crates/typst-pdf/src/outline.rs @@ -124,7 +124,7 @@ impl<'a> HeadingNode<'a> { fn to_krilla(&self, gc: &GlobalContext) -> Option { let loc = self.element.location().unwrap(); - let title = self.element.body().plain_text().to_string(); + let title = self.element.body.plain_text().to_string(); let pos = gc.document.introspector.position(loc); let page_index = pos.page.get() - 1; diff --git a/crates/typst-pdf/src/shape.rs b/crates/typst-pdf/src/shape.rs index e2b8afa21..e963571c8 100644 --- a/crates/typst-pdf/src/shape.rs +++ b/crates/typst-pdf/src/shape.rs @@ -85,8 +85,8 @@ fn convert_geometry(geometry: &Geometry) -> Option { path_builder.push_rect(rect); } } - Geometry::Path(p) => { - convert_path(p, &mut path_builder); + Geometry::Curve(c) => { + convert_path(c, &mut path_builder); } } diff --git a/crates/typst-pdf/src/text.rs b/crates/typst-pdf/src/text.rs index 7e242f1d2..7f9f7bb75 100644 --- a/crates/typst-pdf/src/text.rs +++ b/crates/typst-pdf/src/text.rs @@ -79,8 +79,9 @@ fn convert_font( if let Some(font) = gc.fonts_forward.get(&typst_font) { Ok(font.clone()) } else { + let font_data: Arc + Send + Sync> = Arc::new(typst_font.data().clone()); let font = match krilla::font::Font::new( - Arc::new(typst_font.data().clone()), + font_data.into(), typst_font.index(), true, ) {