summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz Stampfl <47084093+LaurenzV@users.noreply.github.com>2024-12-08 18:06:25 +0100
committerGitHub <noreply@github.com>2024-12-08 17:06:25 +0000
commit67ef6066f40c6503471217600f9873774db394c0 (patch)
treeb5396f200fddf8d804888bef8c1eedaa721b5ef8
parent468a60103dca9c6788be2207c9785d5ba771c800 (diff)
Add support for converting text in SVGs to paths (#5390)
-rw-r--r--crates/typst-layout/src/image.rs1
-rw-r--r--crates/typst-library/src/visualize/image/mod.rs9
-rw-r--r--crates/typst-library/src/visualize/image/svg.rs23
-rw-r--r--crates/typst-pdf/src/image.rs6
4 files changed, 35 insertions, 4 deletions
diff --git a/crates/typst-layout/src/image.rs b/crates/typst-layout/src/image.rs
index 84a60282..628fe10d 100644
--- a/crates/typst-layout/src/image.rs
+++ b/crates/typst-layout/src/image.rs
@@ -55,6 +55,7 @@ pub fn layout_image(
elem.alt(styles),
engine.world,
&families(styles).collect::<Vec<_>>(),
+ elem.flatten_text(styles),
)
.at(span)?;
diff --git a/crates/typst-library/src/visualize/image/mod.rs b/crates/typst-library/src/visualize/image/mod.rs
index 868a3c5b..fddb4acb 100644
--- a/crates/typst-library/src/visualize/image/mod.rs
+++ b/crates/typst-library/src/visualize/image/mod.rs
@@ -94,6 +94,12 @@ pub struct ImageElem {
/// ```
#[default(ImageFit::Cover)]
pub fit: ImageFit,
+
+ /// Whether text in SVG images should be converted into paths before
+ /// embedding. This will result in the text becoming unselectable in
+ /// the output.
+ #[default(false)]
+ pub flatten_text: bool,
}
#[scope]
@@ -246,13 +252,14 @@ impl Image {
alt: Option<EcoString>,
world: Tracked<dyn World + '_>,
families: &[&str],
+ flatten_text: bool,
) -> StrResult<Image> {
let kind = match format {
ImageFormat::Raster(format) => {
ImageKind::Raster(RasterImage::new(data, format)?)
}
ImageFormat::Vector(VectorFormat::Svg) => {
- ImageKind::Svg(SvgImage::with_fonts(data, world, families)?)
+ ImageKind::Svg(SvgImage::with_fonts(data, world, flatten_text, families)?)
}
};
diff --git a/crates/typst-library/src/visualize/image/svg.rs b/crates/typst-library/src/visualize/image/svg.rs
index f7a498a8..6b6a1b6b 100644
--- a/crates/typst-library/src/visualize/image/svg.rs
+++ b/crates/typst-library/src/visualize/image/svg.rs
@@ -22,6 +22,7 @@ pub struct SvgImage(Arc<Repr>);
struct Repr {
data: Bytes,
size: Axes<f64>,
+ flatten_text: bool,
font_hash: u128,
tree: usvg::Tree,
}
@@ -32,7 +33,13 @@ impl SvgImage {
pub fn new(data: Bytes) -> StrResult<SvgImage> {
let tree =
usvg::Tree::from_data(&data, &base_options()).map_err(format_usvg_error)?;
- Ok(Self(Arc::new(Repr { data, size: tree_size(&tree), font_hash: 0, tree })))
+ Ok(Self(Arc::new(Repr {
+ data,
+ size: tree_size(&tree),
+ font_hash: 0,
+ flatten_text: false,
+ tree,
+ })))
}
/// Decode an SVG image with access to fonts.
@@ -40,6 +47,7 @@ impl SvgImage {
pub fn with_fonts(
data: Bytes,
world: Tracked<dyn World + '_>,
+ flatten_text: bool,
families: &[&str],
) -> StrResult<SvgImage> {
let book = world.book();
@@ -60,7 +68,13 @@ impl SvgImage {
)
.map_err(format_usvg_error)?;
let font_hash = resolver.into_inner().unwrap().finish();
- Ok(Self(Arc::new(Repr { data, size: tree_size(&tree), font_hash, tree })))
+ Ok(Self(Arc::new(Repr {
+ data,
+ size: tree_size(&tree),
+ font_hash,
+ flatten_text,
+ tree,
+ })))
}
/// The raw image data.
@@ -73,6 +87,11 @@ impl SvgImage {
self.0.size.x
}
+ /// Whether the SVG's text should be flattened.
+ pub fn flatten_text(&self) -> bool {
+ self.0.flatten_text
+ }
+
/// The SVG's height in pixels.
pub fn height(&self) -> f64 {
self.0.size.y
diff --git a/crates/typst-pdf/src/image.rs b/crates/typst-pdf/src/image.rs
index 9651d31b..bff7bfef 100644
--- a/crates/typst-pdf/src/image.rs
+++ b/crates/typst-pdf/src/image.rs
@@ -208,7 +208,11 @@ fn encode_svg(
) -> Result<(Chunk, Ref), svg2pdf::ConversionError> {
svg2pdf::to_chunk(
svg.tree(),
- svg2pdf::ConversionOptions { pdfa, ..Default::default() },
+ svg2pdf::ConversionOptions {
+ pdfa,
+ embed_text: !svg.flatten_text(),
+ ..Default::default()
+ },
)
}