summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2023-05-02 13:53:20 +0200
committerGitHub <noreply@github.com>2023-05-02 13:53:20 +0200
commit17cef8dcee022ca89ccef62eaec23ff6c0e4cdf9 (patch)
tree253ea22f94ac90f0df91d6e20758ecc9d7271ce8
parent021694de239ca5d6d799dde98423036bb1da405e (diff)
Add ICC profiles to images in PDF and update `usvg`, `svg2pdf` (#822)
-rw-r--r--Cargo.lock262
-rw-r--r--Cargo.toml16
-rw-r--r--library/Cargo.toml6
-rw-r--r--library/src/compute/data.rs1
-rw-r--r--src/diag.rs1
-rw-r--r--src/export/pdf/image.rs22
-rw-r--r--src/export/pdf/outline.rs2
-rw-r--r--src/export/pdf/page.rs4
-rw-r--r--src/export/render.rs72
-rw-r--r--src/image.rs132
-rw-r--r--tests/Cargo.toml2
-rw-r--r--tests/ref/bugs/math-realize.pngbin20296 -> 23272 bytes
-rw-r--r--tests/ref/bugs/smartquotes-in-outline.pngbin8184 -> 10122 bytes
-rw-r--r--tests/ref/layout/clip.pngbin44908 -> 30275 bytes
-rw-r--r--tests/ref/layout/grid-3.pngbin47591 -> 47584 bytes
-rw-r--r--tests/ref/layout/pad.pngbin51665 -> 51646 bytes
-rw-r--r--tests/ref/layout/par-bidi.pngbin25290 -> 25303 bytes
-rw-r--r--tests/ref/layout/par-indent.pngbin64040 -> 64257 bytes
-rw-r--r--tests/ref/layout/place.pngbin44724 -> 44931 bytes
-rw-r--r--tests/ref/layout/transform.pngbin52123 -> 53066 bytes
-rw-r--r--tests/ref/math/content.pngbin8329 -> 8357 bytes
-rw-r--r--tests/ref/math/numbering.pngbin14195 -> 14239 bytes
-rw-r--r--tests/ref/meta/bibliography-ordering.pngbin144132 -> 145159 bytes
-rw-r--r--tests/ref/meta/bibliography.pngbin118062 -> 119134 bytes
-rw-r--r--tests/ref/meta/figure.pngbin103112 -> 63931 bytes
-rw-r--r--tests/ref/meta/link.pngbin92205 -> 71696 bytes
-rw-r--r--tests/ref/meta/outline.pngbin81300 -> 82493 bytes
-rw-r--r--tests/ref/meta/query-before-after.pngbin180629 -> 122197 bytes
-rw-r--r--tests/ref/meta/query-figure.pngbin289118 -> 290886 bytes
-rw-r--r--tests/ref/meta/query-header.pngbin121102 -> 121241 bytes
-rw-r--r--tests/ref/meta/ref.pngbin179188 -> 137626 bytes
-rw-r--r--tests/ref/text/baseline.pngbin29799 -> 29911 bytes
-rw-r--r--tests/ref/text/emoji.pngbin3821 -> 3836 bytes
-rw-r--r--tests/ref/text/fallback.pngbin10947 -> 10955 bytes
-rw-r--r--tests/ref/text/font.pngbin34487 -> 20418 bytes
-rw-r--r--tests/ref/text/linebreak-obj.pngbin44191 -> 55876 bytes
-rw-r--r--tests/ref/text/symbol.pngbin4446 -> 4457 bytes
-rw-r--r--tests/ref/visualize/image.pngbin175595 -> 175691 bytes
-rw-r--r--tests/ref/visualize/stroke.pngbin4382 -> 4254 bytes
-rw-r--r--tests/ref/visualize/svg-text.pngbin14244 -> 14241 bytes
40 files changed, 309 insertions, 211 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1a1c3f55..72d97bc4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -95,12 +95,6 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
[[package]]
name = "arrayvec"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
-
-[[package]]
-name = "arrayvec"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
@@ -129,6 +123,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
+name = "base64"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
+
+[[package]]
name = "biblatex"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -519,12 +519,9 @@ dependencies = [
[[package]]
name = "data-url"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193"
-dependencies = [
- "matches",
-]
+checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5"
[[package]]
name = "dirs"
@@ -686,13 +683,14 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "fontdb"
-version = "0.9.3"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d52186a39c335aa6f79fc0bf1c3cf854870b6ad4e50a7bb8a59b4ba1331f478a"
+checksum = "237ff9f0813bbfc9de836016472e0c9ae7802f174a51594607e5f4ff334cb2f5"
dependencies = [
"log",
"memmap2",
- "ttf-parser 0.17.1",
+ "slotmap",
+ "ttf-parser",
]
[[package]]
@@ -741,16 +739,6 @@ dependencies = [
[[package]]
name = "gif"
-version = "0.11.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
-dependencies = [
- "color_quant",
- "weezl",
-]
-
-[[package]]
-name = "gif"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045"
@@ -885,14 +873,20 @@ dependencies = [
"bytemuck",
"byteorder",
"color_quant",
- "gif 0.12.0",
- "jpeg-decoder 0.3.0",
+ "gif",
+ "jpeg-decoder",
"num-rational",
"num-traits",
"png",
]
[[package]]
+name = "imagesize"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b72ad49b554c1728b1e83254a1b1565aea4161e28dabbfa171fc15fe62299caf"
+
+[[package]]
name = "include_dir"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1042,12 +1036,6 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "jpeg-decoder"
-version = "0.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b"
-
-[[package]]
-name = "jpeg-decoder"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
@@ -1083,11 +1071,11 @@ dependencies = [
[[package]]
name = "kurbo"
-version = "0.8.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a53776d271cfb873b17c618af0298445c88afc52837f3e948fa3fafd131f449"
+checksum = "d676038719d1c892f91e6e85121550143c75880b42f7feff6d413a078cf91fb3"
dependencies = [
- "arrayvec 0.7.2",
+ "arrayvec",
]
[[package]]
@@ -1171,12 +1159,6 @@ dependencies = [
]
[[package]]
-name = "matches"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
-
-[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1202,15 +1184,6 @@ dependencies = [
[[package]]
name = "miniz_oxide"
-version = "0.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
-dependencies = [
- "adler",
-]
-
-[[package]]
-name = "miniz_oxide"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
@@ -1285,7 +1258,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
dependencies = [
- "arrayvec 0.7.2",
+ "arrayvec",
"itoa",
]
@@ -1414,9 +1387,9 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "pdf-writer"
-version = "0.6.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "249f9b33a3192626f2cd9f4b0cd66c1ec32d65968d58cf4d8239977feddddead"
+checksum = "63f45f7c7538e67c58cb4977e4f97bbd75fbd3990d827d28d597ec746291f644"
dependencies = [
"bitflags 1.3.2",
"itoa",
@@ -1449,9 +1422,9 @@ dependencies = [
[[package]]
name = "pico-args"
-version = "0.4.2"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
+checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "pin-project-lite"
@@ -1465,7 +1438,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9eefadd393715fe315c8cdcd587f893b818a6dfe4f6f9faeb44b764c7c38fd8b"
dependencies = [
- "ttf-parser 0.18.1",
+ "ttf-parser",
]
[[package]]
@@ -1590,9 +1563,9 @@ dependencies = [
[[package]]
name = "rctree"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ae028b272a6e99d9f8260ceefa3caa09300a8d6c8d2b2001316474bc52122e9"
+checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f"
[[package]]
name = "redox_syscall"
@@ -1648,15 +1621,12 @@ checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
[[package]]
name = "resvg"
-version = "0.22.0"
+version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e702d1e8e00a3a0717b96244cba840f34f542d8f23097c8903266c4e2975658"
+checksum = "142e83d8ae8c8c639f304698a5567b229ba65caba867bf4387bbc0ae158827cf"
dependencies = [
- "gif 0.11.4",
- "jpeg-decoder 0.2.6",
"log",
"pico-args",
- "png",
"rgb",
"svgtypes",
"tiny-skia",
@@ -1694,10 +1664,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
[[package]]
+name = "rosvgtree"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad747e7384940e7bf33b15ba433b7bad9f44c0c6d5287a67c2cb22cd1743d497"
+dependencies = [
+ "log",
+ "roxmltree",
+ "simplecss",
+ "siphasher",
+ "svgtypes",
+]
+
+[[package]]
name = "roxmltree"
-version = "0.14.1"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
+checksum = "d8f595a457b6b8c6cda66a48503e92ee8d19342f905948f29c383200ec9eb1d8"
dependencies = [
"xmlparser",
]
@@ -1751,14 +1734,14 @@ checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
[[package]]
name = "rustybuzz"
-version = "0.5.1"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a617c811f5c9a7060fe511d35d13bf5b9f0463ce36d63ce666d05779df2b4eba"
+checksum = "162bdf42e261bee271b3957691018634488084ef577dddeb6420a9684cab2a6a"
dependencies = [
"bitflags 1.3.2",
"bytemuck",
"smallvec",
- "ttf-parser 0.15.2",
+ "ttf-parser",
"unicode-bidi-mirroring",
"unicode-ccc",
"unicode-general-category",
@@ -1772,15 +1755,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
-name = "safe_arch"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05"
-dependencies = [
- "bytemuck",
-]
-
-[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1900,6 +1874,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
+name = "slotmap"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1949,6 +1932,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb"
[[package]]
+name = "strict-num"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9df65f20698aeed245efdde3628a6b559ea1239bbb871af1b6e3b58c413b2bd1"
+dependencies = [
+ "float-cmp",
+]
+
+[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1985,21 +1977,21 @@ checksum = "09eab8a83bff89ba2200bd4c59be45c7c787f988431b936099a5a266c957f2f9"
[[package]]
name = "svg2pdf"
version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd5736713f3850a24060c3cdd7ac9efdc0c5138779386c6c8975b46d54d2d3d5"
+source = "git+https://github.com/typst/svg2pdf#fec20fb9e2ab42f76060f349688005af1d182444"
dependencies = [
"image",
- "miniz_oxide 0.5.4",
+ "miniz_oxide 0.7.1",
"pdf-writer",
"usvg",
]
[[package]]
name = "svgtypes"
-version = "0.8.2"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22975e8a2bac6a76bb54f898a6b18764633b00e780330f0b689f65afb3975564"
+checksum = "ed4b0611e7f3277f68c0fa18e385d9e2d26923691379690039548f867cef02a7"
dependencies = [
+ "kurbo",
"siphasher",
]
@@ -2112,16 +2104,28 @@ dependencies = [
[[package]]
name = "tiny-skia"
-version = "0.6.6"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d049bfef0eaa2521e75d9ffb5ce86ad54480932ae19b85f78bec6f52c4d30d78"
+checksum = "5b610cd8b9a29feb9029c30f1e7bff634651b6e4e925388ee6cff4c68d901a3e"
dependencies = [
"arrayref",
- "arrayvec 0.5.2",
+ "arrayvec",
"bytemuck",
"cfg-if",
+ "log",
"png",
- "safe_arch",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7acb0ccda1ac91084353a56d0b69b0e29c311fd809d2088b1ed2f9ae1841c47"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
]
[[package]]
@@ -2262,18 +2266,6 @@ dependencies = [
[[package]]
name = "ttf-parser"
-version = "0.15.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
-
-[[package]]
-name = "ttf-parser"
-version = "0.17.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
-
-[[package]]
-name = "ttf-parser"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633"
@@ -2313,7 +2305,7 @@ dependencies = [
"svg2pdf",
"tiny-skia",
"tracing",
- "ttf-parser 0.18.1",
+ "ttf-parser",
"typst-macros",
"unicode-math-class",
"unicode-segmentation",
@@ -2393,7 +2385,7 @@ dependencies = [
"syntect",
"toml",
"tracing",
- "ttf-parser 0.18.1",
+ "ttf-parser",
"typed-arena",
"typst",
"unicode-bidi",
@@ -2425,7 +2417,7 @@ dependencies = [
"oxipng",
"rayon",
"tiny-skia",
- "ttf-parser 0.18.1",
+ "ttf-parser",
"typst",
"typst-library",
"unscanny",
@@ -2479,9 +2471,9 @@ checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
[[package]]
name = "unicode-general-category"
-version = "0.4.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742"
+checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
[[package]]
name = "unicode-ident"
@@ -2558,7 +2550,7 @@ version = "2.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
dependencies = [
- "base64",
+ "base64 0.13.1",
"flate2",
"log",
"once_cell",
@@ -2583,28 +2575,62 @@ dependencies = [
[[package]]
name = "usvg"
-version = "0.22.0"
+version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a261d60a7215fa339482047cc3dafd4e22e2bf34396aaebef2b707355bbb39c0"
+checksum = "4b44e14b7678bcc5947b397991432d0c4e02a103958a0ed5e1b9b961ddd08b21"
+dependencies = [
+ "base64 0.21.0",
+ "log",
+ "pico-args",
+ "usvg-parser",
+ "usvg-text-layout",
+ "usvg-tree",
+ "xmlwriter",
+]
+
+[[package]]
+name = "usvg-parser"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90c8251d965c2882a636ffcc054340b1f13a6bce68779cb5b2084d8ffc2535be"
dependencies = [
- "base64",
"data-url",
"flate2",
- "float-cmp",
+ "imagesize",
+ "kurbo",
+ "log",
+ "rosvgtree",
+ "strict-num",
+ "svgtypes",
+ "usvg-tree",
+]
+
+[[package]]
+name = "usvg-text-layout"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c4fed019d1af07bfe0f3bac13d120d7b51bc65b38cb24809cf4ed0b8b631138"
+dependencies = [
"fontdb",
"kurbo",
"log",
- "pico-args",
- "rctree",
- "roxmltree",
"rustybuzz",
- "simplecss",
- "siphasher",
- "svgtypes",
- "ttf-parser 0.15.2",
"unicode-bidi",
"unicode-script",
"unicode-vo",
+ "usvg-tree",
+]
+
+[[package]]
+name = "usvg-tree"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7371265c467cdae0ccc3655e2e3f310c695fb9f717c0d25187bf3b333f7b5159"
+dependencies = [
+ "kurbo",
+ "rctree",
+ "strict-num",
+ "svgtypes",
]
[[package]]
@@ -2957,6 +2983,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
+[[package]]
name = "xmp-writer"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index bb313c77..a0e51002 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,31 +26,31 @@ bytemuck = "1"
comemo = "0.2.2"
ecow = "0.1"
flate2 = "1"
-fontdb = "0.9"
+fontdb = "0.13"
if_chain = "1"
image = { version = "0.24", default-features = false, features = ["png", "jpeg", "gif"] }
indexmap = "1.9.3"
log = "0.4"
miniz_oxide = "0.7"
once_cell = "1"
-pdf-writer = "0.6"
+pdf-writer = "0.7"
pixglyph = "0.1"
regex = "1"
-resvg = { version = "0.22", default-features = false }
-roxmltree = "0.14"
-rustybuzz = "0.5"
+resvg = { version = "0.32", default-features = false }
+roxmltree = "0.18"
+rustybuzz = "0.7"
serde = { version = "1", features = ["derive"] }
siphasher = "0.3"
subsetter = "0.1.1"
-svg2pdf = "0.4"
-tiny-skia = "0.6.6"
+svg2pdf = { git = "https://github.com/typst/svg2pdf" }
+tiny-skia = "0.9.0"
tracing = "0.1.37"
ttf-parser = "0.18.1"
unicode-math-class = "0.1"
unicode-segmentation = "1"
unicode-xid = "0.2"
unscanny = "0.1"
-usvg = { version = "0.22", default-features = false, features = ["text"] }
+usvg = { version = "0.32", default-features = false, features = ["text"] }
xmp-writer = "0.1"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
diff --git a/library/Cargo.toml b/library/Cargo.toml
index 630b4403..033058f3 100644
--- a/library/Cargo.toml
+++ b/library/Cargo.toml
@@ -22,12 +22,12 @@ csv = "1"
ecow = "0.1"
hayagriva = "0.3"
hypher = "0.1"
-kurbo = "0.8"
+kurbo = "0.9"
lipsum = "0.9"
log = "0.4"
once_cell = "1"
-roxmltree = "0.14"
-rustybuzz = "0.5"
+roxmltree = "0.18"
+rustybuzz = "0.7"
serde_json = "1"
serde_yaml = "0.8"
smallvec = "1.10"
diff --git a/library/src/compute/data.rs b/library/src/compute/data.rs
index 14ae304b..d104cf27 100644
--- a/library/src/compute/data.rs
+++ b/library/src/compute/data.rs
@@ -448,7 +448,6 @@ fn convert_xml(node: roxmltree::Node) -> Value {
let tag: Str = node.tag_name().name().into();
let attrs: Dict = node
.attributes()
- .iter()
.map(|attr| (attr.name().into(), attr.value().into()))
.collect();
diff --git a/src/diag.rs b/src/diag.rs
index 88141062..556d3255 100644
--- a/src/diag.rs
+++ b/src/diag.rs
@@ -273,7 +273,6 @@ pub fn format_xml_like_error(format: &str, error: roxmltree::Error) -> EcoString
roxmltree::Error::NoRootNode => {
eco_format!("failed to parse {format}: missing root node")
}
- roxmltree::Error::SizeLimit => "file is too large".into(),
_ => eco_format!("failed to parse {format}"),
}
}
diff --git a/src/export/pdf/image.rs b/src/export/pdf/image.rs
index 04d4dcc3..dcd5a45a 100644
--- a/src/export/pdf/image.rs
+++ b/src/export/pdf/image.rs
@@ -11,6 +11,7 @@ use crate::image::{DecodedImage, RasterFormat};
pub fn write_images(ctx: &mut PdfContext) {
for image in ctx.image_map.items() {
let image_ref = ctx.alloc.bump();
+ let icc_ref = ctx.alloc.bump();
ctx.image_refs.push(image_ref);
let width = image.width();
@@ -19,7 +20,7 @@ pub fn write_images(ctx: &mut PdfContext) {
// Add the primary image.
// TODO: Error if image could not be encoded.
match image.decoded() {
- DecodedImage::Raster(dynamic, format) => {
+ DecodedImage::Raster(dynamic, icc, format) => {
// TODO: Error if image could not be encoded.
let (data, filter, has_color) = encode_image(*format, dynamic).unwrap();
let mut image = ctx.writer.image_xobject(image_ref, &data);
@@ -29,7 +30,9 @@ pub fn write_images(ctx: &mut PdfContext) {
image.bits_per_component(8);
let space = image.color_space();
- if has_color {
+ if icc.is_some() {
+ space.icc_based(icc_ref);
+ } else if has_color {
space.device_rgb();
} else {
space.device_gray();
@@ -49,6 +52,21 @@ pub fn write_images(ctx: &mut PdfContext) {
mask.height(height as i32);
mask.color_space().device_gray();
mask.bits_per_component(8);
+ } else {
+ image.finish();
+ }
+
+ if let Some(icc) = icc {
+ let compressed = deflate(&icc.0);
+ let mut stream = ctx.writer.icc_profile(icc_ref, &compressed);
+ stream.filter(Filter::FlateDecode);
+ if has_color {
+ stream.n(3);
+ stream.alternate().srgb();
+ } else {
+ stream.n(1);
+ stream.alternate().d65_gray();
+ }
}
}
DecodedImage::Svg(svg) => {
diff --git a/src/export/pdf/outline.rs b/src/export/pdf/outline.rs
index f8f12d71..c156ecaf 100644
--- a/src/export/pdf/outline.rs
+++ b/src/export/pdf/outline.rs
@@ -118,7 +118,7 @@ fn write_outline_item(
let index = pos.page.get() - 1;
if let Some(&height) = ctx.page_heights.get(index) {
let y = (pos.point.y - Abs::pt(10.0)).max(Abs::zero());
- outline.dest_direct().page(ctx.page_refs[index]).xyz(
+ outline.dest().page(ctx.page_refs[index]).xyz(
pos.point.x.to_f32(),
height - y.to_f32(),
None,
diff --git a/src/export/pdf/page.rs b/src/export/pdf/page.rs
index acf5062e..35a4f5dc 100644
--- a/src/export/pdf/page.rs
+++ b/src/export/pdf/page.rs
@@ -139,7 +139,7 @@ fn write_page(ctx: &mut PdfContext, page: Page) {
annotation
.action()
.action_type(ActionType::GoTo)
- .destination_direct()
+ .destination()
.page(ctx.page_refs[index])
.xyz(pos.point.x.to_f32(), height - y.to_f32(), None);
}
@@ -499,7 +499,7 @@ fn write_image(ctx: &mut PageContext, x: f32, y: f32, image: &Image, size: Size)
if let Some(alt) = image.alt() {
let mut image_span =
ctx.content.begin_marked_content_with_properties(Name(b"Span"));
- let mut image_alt = image_span.properties_direct();
+ let mut image_alt = image_span.properties();
image_alt.pair(Name(b"Alt"), pdf_writer::Str(alt.as_bytes()));
image_alt.finish();
image_span.finish();
diff --git a/src/export/render.rs b/src/export/render.rs
index fa3dc4b5..31e440d1 100644
--- a/src/export/render.rs
+++ b/src/export/render.rs
@@ -5,9 +5,10 @@ use std::sync::Arc;
use image::imageops::FilterType;
use image::{GenericImageView, Rgba};
+use resvg::FitTo;
use tiny_skia as sk;
use ttf_parser::{GlyphId, OutlineBuilder};
-use usvg::{FitTo, NodeExt};
+use usvg::{NodeExt, TreeParsing};
use crate::doc::{Frame, FrameItem, GroupItem, Meta, TextItem};
use crate::geom::{
@@ -38,7 +39,7 @@ pub fn render(frame: &Frame, pixel_per_pt: f32, fill: Color) -> sk::Pixmap {
fn render_frame(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
frame: &Frame,
) {
for (pos, item) in frame.items() {
@@ -73,13 +74,13 @@ fn render_frame(
fn render_group(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
group: &GroupItem,
) {
let ts = ts.pre_concat(group.transform.into());
let mut mask = mask;
- let mut storage;
+ let storage;
if group.clips {
let size = group.frame.size();
let w = size.x.to_f32();
@@ -88,22 +89,33 @@ fn render_group(
.map(sk::PathBuilder::from_rect)
.and_then(|path| path.transform(ts))
{
- let result = if let Some(mask) = mask {
- storage = mask.clone();
- storage.intersect_path(&path, sk::FillRule::default(), false)
+ if let Some(mask) = mask {
+ let mut mask = mask.clone();
+ mask.intersect_path(
+ &path,
+ sk::FillRule::default(),
+ false,
+ sk::Transform::default(),
+ );
+ storage = mask;
} else {
let pxw = canvas.width();
let pxh = canvas.height();
- storage = sk::ClipMask::new();
- storage.set_path(pxw, pxh, &path, sk::FillRule::default(), false)
+ let Some(mut mask) = sk::Mask::new(pxw, pxh) else {
+ // Fails if clipping rect is empty. In that case we just
+ // clip everything by returning.
+ return;
+ };
+
+ mask.fill_path(
+ &path,
+ sk::FillRule::default(),
+ false,
+ sk::Transform::default(),
+ );
+ storage = mask;
};
- // Clipping fails if clipping rect is empty. In that case we just
- // clip everything by returning.
- if result.is_none() {
- return;
- }
-
mask = Some(&storage);
}
}
@@ -115,7 +127,7 @@ fn render_group(
fn render_text(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
) {
let mut x = 0.0;
@@ -136,7 +148,7 @@ fn render_text(
fn render_svg_glyph(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
id: GlyphId,
) -> Option<()> {
@@ -157,8 +169,8 @@ fn render_svg_glyph(
// Parse SVG.
let opts = usvg::Options::default();
- let tree = usvg::Tree::from_xmltree(&document, &opts.to_ref()).ok()?;
- let view_box = tree.svg_node().view_box.rect;
+ let tree = usvg::Tree::from_xmltree(&document, &opts).ok()?;
+ let view_box = tree.view_box.rect;
// If there's no viewbox defined, use the em square for our scale
// transformation ...
@@ -182,7 +194,7 @@ fn render_svg_glyph(
// See https://github.com/RazrFalcon/resvg/issues/602 for why
// using the svg size is problematic here.
let mut bbox = usvg::Rect::new_bbox();
- for node in tree.root().descendants() {
+ for node in tree.root.descendants() {
if let Some(rect) = node.calculate_bbox().and_then(|b| b.to_rect()) {
bbox = bbox.expand(rect);
}
@@ -224,14 +236,16 @@ fn render_svg_glyph(
&sk::PixmapPaint::default(),
sk::Transform::identity(),
mask,
- )
+ );
+
+ Some(())
}
/// Render a bitmap glyph into the canvas.
fn render_bitmap_glyph(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
id: GlyphId,
) -> Option<()> {
@@ -255,7 +269,7 @@ fn render_bitmap_glyph(
fn render_outline_glyph(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
text: &TextItem,
id: GlyphId,
) -> Option<()> {
@@ -278,7 +292,7 @@ fn render_outline_glyph(
// system is Y-up.
let scale = text.size.to_f32() / text.font.units_per_em() as f32;
let ts = ts.pre_scale(scale, -scale);
- canvas.fill_path(&path, &paint, rule, ts, mask)?;
+ canvas.fill_path(&path, &paint, rule, ts, mask);
return Some(());
}
@@ -318,7 +332,9 @@ fn render_outline_glyph(
&sk::PixmapPaint::default(),
sk::Transform::identity(),
mask,
- )
+ );
+
+ Some(())
} else {
let cw = canvas.width() as i32;
let ch = canvas.height() as i32;
@@ -365,7 +381,7 @@ fn render_outline_glyph(
fn render_shape(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
shape: &Shape,
) -> Option<()> {
let path = match shape.geometry {
@@ -465,7 +481,7 @@ fn convert_path(path: &geom::Path) -> Option<sk::Path> {
fn render_image(
canvas: &mut sk::Pixmap,
ts: sk::Transform,
- mask: Option<&sk::ClipMask>,
+ mask: Option<&sk::Mask>,
image: &Image,
size: Size,
) -> Option<()> {
@@ -503,7 +519,7 @@ fn render_image(
fn scaled_texture(image: &Image, w: u32, h: u32) -> Option<Arc<sk::Pixmap>> {
let mut pixmap = sk::Pixmap::new(w, h)?;
match image.decoded() {
- DecodedImage::Raster(dynamic, _) => {
+ DecodedImage::Raster(dynamic, _, _) => {
let downscale = w < image.width();
let filter =
if downscale { FilterType::Lanczos3 } else { FilterType::CatmullRom };
diff --git a/src/image.rs b/src/image.rs
index 49d91908..d78c7428 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -1,6 +1,6 @@
//! Image handling.
-use std::collections::BTreeSet;
+use std::collections::BTreeMap;
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::io;
@@ -8,6 +8,12 @@ use std::sync::Arc;
use comemo::Tracked;
use ecow::EcoString;
+use image::codecs::gif::GifDecoder;
+use image::codecs::jpeg::JpegDecoder;
+use image::codecs::png::PngDecoder;
+use image::io::Limits;
+use image::{ImageDecoder, ImageResult};
+use usvg::{TreeParsing, TreeTextToPath};
use crate::diag::{format_xml_like_error, StrResult};
use crate::util::Buffer;
@@ -171,8 +177,8 @@ impl From<ttf_parser::RasterImageFormat> for ImageFormat {
/// A decoded image.
pub enum DecodedImage {
- /// A decoded pixel raster.
- Raster(image::DynamicImage, RasterFormat),
+ /// A decoded pixel raster with its ICC profile.
+ Raster(image::DynamicImage, Option<IccProfile>, RasterFormat),
/// An decoded SVG tree.
Svg(usvg::Tree),
}
@@ -181,34 +187,52 @@ impl DecodedImage {
/// The width of the image in pixels.
pub fn width(&self) -> u32 {
match self {
- Self::Raster(dynamic, _) => dynamic.width(),
- Self::Svg(tree) => tree.svg_node().size.width().ceil() as u32,
+ Self::Raster(dynamic, _, _) => dynamic.width(),
+ Self::Svg(tree) => tree.size.width().ceil() as u32,
}
}
/// The height of the image in pixels.
pub fn height(&self) -> u32 {
match self {
- Self::Raster(dynamic, _) => dynamic.height(),
- Self::Svg(tree) => tree.svg_node().size.height().ceil() as u32,
+ Self::Raster(dynamic, _, _) => dynamic.height(),
+ Self::Svg(tree) => tree.size.height().ceil() as u32,
}
}
}
+/// Raw data for of an ICC profile.
+pub struct IccProfile(pub Vec<u8>);
+
/// Decode a raster image.
#[comemo::memoize]
fn decode_raster(data: &Buffer, format: RasterFormat) -> StrResult<Arc<DecodedImage>> {
- let cursor = io::Cursor::new(&data);
- let reader = image::io::Reader::with_format(cursor, format.into());
- let dynamic = reader.decode().map_err(format_image_error)?;
- Ok(Arc::new(DecodedImage::Raster(dynamic, format)))
+ fn decode_with<'a, T: ImageDecoder<'a>>(
+ decoder: ImageResult<T>,
+ ) -> ImageResult<(image::DynamicImage, Option<IccProfile>)> {
+ let mut decoder = decoder?;
+ let icc = decoder.icc_profile().map(IccProfile);
+ decoder.set_limits(Limits::default())?;
+ let dynamic = image::DynamicImage::from_decoder(decoder)?;
+ Ok((dynamic, icc))
+ }
+
+ let cursor = io::Cursor::new(data);
+ let (dynamic, icc) = match format {
+ RasterFormat::Jpg => decode_with(JpegDecoder::new(cursor)),
+ RasterFormat::Png => decode_with(PngDecoder::new(cursor)),
+ RasterFormat::Gif => decode_with(GifDecoder::new(cursor)),
+ }
+ .map_err(format_image_error)?;
+
+ Ok(Arc::new(DecodedImage::Raster(dynamic, icc, format)))
}
/// Decode an SVG image.
#[comemo::memoize]
fn decode_svg(data: &Buffer) -> StrResult<Arc<DecodedImage>> {
let opts = usvg::Options::default();
- let tree = usvg::Tree::from_data(data, &opts.to_ref()).map_err(format_usvg_error)?;
+ let tree = usvg::Tree::from_data(data, &opts).map_err(format_usvg_error)?;
Ok(Arc::new(DecodedImage::Svg(tree)))
}
@@ -219,79 +243,89 @@ fn decode_svg_with_fonts(
world: Tracked<dyn World>,
fallback_family: Option<&str>,
) -> StrResult<Arc<DecodedImage>> {
- // Parse XML.
- let xml = std::str::from_utf8(data)
- .map_err(|_| format_usvg_error(usvg::Error::NotAnUtf8Str))?;
- let document = roxmltree::Document::parse(xml)
- .map_err(|err| format_xml_like_error("svg", err))?;
-
- // Parse SVG.
- let mut opts = usvg::Options {
- fontdb: load_svg_fonts(&document, world, fallback_family),
- ..Default::default()
- };
+ let mut opts = usvg::Options::default();
// Recover the non-lowercased version of the family because
// usvg is case sensitive.
let book = world.book();
- if let Some(family) = fallback_family
+ let fallback_family = fallback_family
.and_then(|lowercase| book.select_family(lowercase).next())
.and_then(|index| book.info(index))
- .map(|info| info.family.clone())
- {
- opts.font_family = family;
+ .map(|info| info.family.clone());
+
+ if let Some(family) = &fallback_family {
+ opts.font_family = family.clone();
}
- let tree =
- usvg::Tree::from_xmltree(&document, &opts.to_ref()).map_err(format_usvg_error)?;
+ let mut tree = usvg::Tree::from_data(data, &opts).map_err(format_usvg_error)?;
+ if tree.has_text_nodes() {
+ let fontdb = load_svg_fonts(&tree, world, fallback_family.as_deref());
+ tree.convert_text(&fontdb);
+ }
Ok(Arc::new(DecodedImage::Svg(tree)))
}
/// Discover and load the fonts referenced by an SVG.
fn load_svg_fonts(
- document: &roxmltree::Document,
+ tree: &usvg::Tree,
world: Tracked<dyn World>,
fallback_family: Option<&str>,
) -> fontdb::Database {
- // Find out which font families are referenced by the SVG. We simply do a
- // search for `font-family` attributes. This won't help with CSS, but usvg
- // 22.0 doesn't seem to support it anyway. Once we bump to the latest usvg,
- // this can be replaced by a scan for text elements in the SVG:
- // https://github.com/RazrFalcon/resvg/issues/555
- let mut referenced = BTreeSet::<EcoString>::new();
- traverse_xml(&document.root(), &mut |node| {
- if let Some(list) = node.attribute("font-family") {
- for family in list.split(',') {
- referenced.insert(EcoString::from(family.trim()).to_lowercase());
- }
+ let mut referenced = BTreeMap::<EcoString, bool>::new();
+ let mut fontdb = fontdb::Database::new();
+ let mut load = |family: &str| {
+ let lower = EcoString::from(family.trim()).to_lowercase();
+ if let Some(&success) = referenced.get(&lower) {
+ return success;
}
- });
- // Prepare font database.
- let mut fontdb = fontdb::Database::new();
- for family in referenced.iter().map(|family| family.as_str()).chain(fallback_family) {
// We load all variants for the family, since we don't know which will
// be used.
- for id in world.book().select_family(family) {
+ let mut success = false;
+ for id in world.book().select_family(&lower) {
if let Some(font) = world.font(id) {
let source = Arc::new(font.data().clone());
fontdb.load_font_source(fontdb::Source::Binary(source));
+ success = true;
}
}
+
+ referenced.insert(lower, success);
+ success
+ };
+
+ // Load fallback family.
+ if let Some(family) = fallback_family {
+ load(family);
}
+ // Find out which font families are referenced by the SVG.
+ traverse_svg(&tree.root, &mut |node| {
+ let usvg::NodeKind::Text(text) = &mut *node.borrow_mut() else { return };
+ for chunk in &mut text.chunks {
+ for span in &mut chunk.spans {
+ for family in &mut span.font.families {
+ if !load(family) {
+ let Some(fallback) = fallback_family else { continue };
+ *family = fallback.into();
+ }
+ }
+ }
+ }
+ });
+
fontdb
}
/// Search for all font families referenced by an SVG.
-fn traverse_xml<F>(node: &roxmltree::Node, f: &mut F)
+fn traverse_svg<F>(node: &usvg::Node, f: &mut F)
where
- F: FnMut(&roxmltree::Node),
+ F: FnMut(&usvg::Node),
{
f(node);
for child in node.children() {
- traverse_xml(&child, f);
+ traverse_svg(&child, f);
}
}
diff --git a/tests/Cargo.toml b/tests/Cargo.toml
index e0b3a24a..0b704ec2 100644
--- a/tests/Cargo.toml
+++ b/tests/Cargo.toml
@@ -14,7 +14,7 @@ iai = { git = "https://github.com/reknih/iai" }
once_cell = "1"
oxipng = "8.0.0"
rayon = "1.7.0"
-tiny-skia = "0.6.6"
+tiny-skia = "0.9.0"
ttf-parser = "0.18.1"
unscanny = "0.1"
walkdir = "2"
diff --git a/tests/ref/bugs/math-realize.png b/tests/ref/bugs/math-realize.png
index 941f965b..c4824403 100644
--- a/tests/ref/bugs/math-realize.png
+++ b/tests/ref/bugs/math-realize.png
Binary files differ
diff --git a/tests/ref/bugs/smartquotes-in-outline.png b/tests/ref/bugs/smartquotes-in-outline.png
index c8d763b4..8a2cbc6a 100644
--- a/tests/ref/bugs/smartquotes-in-outline.png
+++ b/tests/ref/bugs/smartquotes-in-outline.png
Binary files differ
diff --git a/tests/ref/layout/clip.png b/tests/ref/layout/clip.png
index f6ec0ba9..11c48681 100644
--- a/tests/ref/layout/clip.png
+++ b/tests/ref/layout/clip.png
Binary files differ
diff --git a/tests/ref/layout/grid-3.png b/tests/ref/layout/grid-3.png
index abae5c7b..0f54f2cc 100644
--- a/tests/ref/layout/grid-3.png
+++ b/tests/ref/layout/grid-3.png
Binary files differ
diff --git a/tests/ref/layout/pad.png b/tests/ref/layout/pad.png
index c33b9736..d228f07f 100644
--- a/tests/ref/layout/pad.png
+++ b/tests/ref/layout/pad.png
Binary files differ
diff --git a/tests/ref/layout/par-bidi.png b/tests/ref/layout/par-bidi.png
index 8751d93e..8b626b2a 100644
--- a/tests/ref/layout/par-bidi.png
+++ b/tests/ref/layout/par-bidi.png
Binary files differ
diff --git a/tests/ref/layout/par-indent.png b/tests/ref/layout/par-indent.png
index 23352925..cceaa3b9 100644
--- a/tests/ref/layout/par-indent.png
+++ b/tests/ref/layout/par-indent.png
Binary files differ
diff --git a/tests/ref/layout/place.png b/tests/ref/layout/place.png
index 968e613c..2ef85a4d 100644
--- a/tests/ref/layout/place.png
+++ b/tests/ref/layout/place.png
Binary files differ
diff --git a/tests/ref/layout/transform.png b/tests/ref/layout/transform.png
index cb4b0af2..0b26a7f7 100644
--- a/tests/ref/layout/transform.png
+++ b/tests/ref/layout/transform.png
Binary files differ
diff --git a/tests/ref/math/content.png b/tests/ref/math/content.png
index 433c8ddc..f7af513b 100644
--- a/tests/ref/math/content.png
+++ b/tests/ref/math/content.png
Binary files differ
diff --git a/tests/ref/math/numbering.png b/tests/ref/math/numbering.png
index 72abfed6..8ccb3ac6 100644
--- a/tests/ref/math/numbering.png
+++ b/tests/ref/math/numbering.png
Binary files differ
diff --git a/tests/ref/meta/bibliography-ordering.png b/tests/ref/meta/bibliography-ordering.png
index e59e792b..a03236cd 100644
--- a/tests/ref/meta/bibliography-ordering.png
+++ b/tests/ref/meta/bibliography-ordering.png
Binary files differ
diff --git a/tests/ref/meta/bibliography.png b/tests/ref/meta/bibliography.png
index 8e5e18ec..22d7355c 100644
--- a/tests/ref/meta/bibliography.png
+++ b/tests/ref/meta/bibliography.png
Binary files differ
diff --git a/tests/ref/meta/figure.png b/tests/ref/meta/figure.png
index a86b4d6d..35d7b4a0 100644
--- a/tests/ref/meta/figure.png
+++ b/tests/ref/meta/figure.png
Binary files differ
diff --git a/tests/ref/meta/link.png b/tests/ref/meta/link.png
index 075ca6e1..1232f413 100644
--- a/tests/ref/meta/link.png
+++ b/tests/ref/meta/link.png
Binary files differ
diff --git a/tests/ref/meta/outline.png b/tests/ref/meta/outline.png
index c485ca9e..bf9c4abe 100644
--- a/tests/ref/meta/outline.png
+++ b/tests/ref/meta/outline.png
Binary files differ
diff --git a/tests/ref/meta/query-before-after.png b/tests/ref/meta/query-before-after.png
index 8757ce8e..80f8fe1f 100644
--- a/tests/ref/meta/query-before-after.png
+++ b/tests/ref/meta/query-before-after.png
Binary files differ
diff --git a/tests/ref/meta/query-figure.png b/tests/ref/meta/query-figure.png
index 3b8d3398..2537ebf0 100644
--- a/tests/ref/meta/query-figure.png
+++ b/tests/ref/meta/query-figure.png
Binary files differ
diff --git a/tests/ref/meta/query-header.png b/tests/ref/meta/query-header.png
index 80981202..c2dc4689 100644
--- a/tests/ref/meta/query-header.png
+++ b/tests/ref/meta/query-header.png
Binary files differ
diff --git a/tests/ref/meta/ref.png b/tests/ref/meta/ref.png
index dc25a0ab..c904fc99 100644
--- a/tests/ref/meta/ref.png
+++ b/tests/ref/meta/ref.png
Binary files differ
diff --git a/tests/ref/text/baseline.png b/tests/ref/text/baseline.png
index 4ad82e1f..dcd6eb12 100644
--- a/tests/ref/text/baseline.png
+++ b/tests/ref/text/baseline.png
Binary files differ
diff --git a/tests/ref/text/emoji.png b/tests/ref/text/emoji.png
index 2036a6fc..715cc30f 100644
--- a/tests/ref/text/emoji.png
+++ b/tests/ref/text/emoji.png
Binary files differ
diff --git a/tests/ref/text/fallback.png b/tests/ref/text/fallback.png
index d5d79ee2..544a0434 100644
--- a/tests/ref/text/fallback.png
+++ b/tests/ref/text/fallback.png
Binary files differ
diff --git a/tests/ref/text/font.png b/tests/ref/text/font.png
index 856d556b..cb5ad984 100644
--- a/tests/ref/text/font.png
+++ b/tests/ref/text/font.png
Binary files differ
diff --git a/tests/ref/text/linebreak-obj.png b/tests/ref/text/linebreak-obj.png
index 60231290..7159aae6 100644
--- a/tests/ref/text/linebreak-obj.png
+++ b/tests/ref/text/linebreak-obj.png
Binary files differ
diff --git a/tests/ref/text/symbol.png b/tests/ref/text/symbol.png
index 9c09732f..8848a89e 100644
--- a/tests/ref/text/symbol.png
+++ b/tests/ref/text/symbol.png
Binary files differ
diff --git a/tests/ref/visualize/image.png b/tests/ref/visualize/image.png
index 0d1a0b8a..060b4b8a 100644
--- a/tests/ref/visualize/image.png
+++ b/tests/ref/visualize/image.png
Binary files differ
diff --git a/tests/ref/visualize/stroke.png b/tests/ref/visualize/stroke.png
index 1c887070..3aa87c4b 100644
--- a/tests/ref/visualize/stroke.png
+++ b/tests/ref/visualize/stroke.png
Binary files differ
diff --git a/tests/ref/visualize/svg-text.png b/tests/ref/visualize/svg-text.png
index fbaa8576..e9f02aea 100644
--- a/tests/ref/visualize/svg-text.png
+++ b/tests/ref/visualize/svg-text.png
Binary files differ