This commit is contained in:
Laurenz Stampfl 2025-03-10 10:21:13 +01:00
parent b464c46a8a
commit 33199e1c00
10 changed files with 106 additions and 180 deletions

222
Cargo.lock generated
View File

@ -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",
]

View File

@ -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"

View File

@ -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,

View File

@ -23,6 +23,7 @@ struct Repr {
data: Bytes,
format: RasterFormat,
dynamic: Arc<DynamicImage>,
is_rotated: bool,
icc: Option<Bytes>,
dpi: Option<f64>,
}
@ -50,6 +51,8 @@ impl RasterImage {
format: RasterFormat,
icc: Smart<Bytes>,
) -> StrResult<RasterImage> {
let mut is_rotated = false;
let (dynamic, icc, dpi) = match format {
RasterFormat::Exchange(format) => {
fn decode<T: ImageDecoder>(
@ -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.

View File

@ -319,7 +319,7 @@ pub(crate) fn handle_group(
/// Finish a krilla document and handle export errors.
fn finish(document: Document, gc: GlobalContext) -> SourceResult<Vec<u8>> {
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),

View File

@ -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};
@ -23,9 +24,11 @@ pub(crate) fn handle_image(
) -> 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<krilla::image::Image> {
fn convert_raster(raster: RasterImage, interpolate: bool) -> Option<krilla::image::Image> {
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<dyn AsRef<[u8]> + 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)
}
}

View File

@ -42,11 +42,14 @@ pub(crate) fn handle_link(
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()),
)),

View File

@ -124,7 +124,7 @@ impl<'a> HeadingNode<'a> {
fn to_krilla(&self, gc: &GlobalContext) -> Option<OutlineNode> {
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;

View File

@ -85,8 +85,8 @@ fn convert_geometry(geometry: &Geometry) -> Option<Path> {
path_builder.push_rect(rect);
}
}
Geometry::Path(p) => {
convert_path(p, &mut path_builder);
Geometry::Curve(c) => {
convert_path(c, &mut path_builder);
}
}

View File

@ -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<dyn AsRef<[u8]> + 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,
) {