From 21611ff5a390bac5acc0a331e047d753da121816 Mon Sep 17 00:00:00 2001 From: Laurenz Stampfl Date: Wed, 21 Aug 2024 17:37:26 +0200 Subject: [PATCH] First attempt at checking ref images --- Cargo.lock | 589 ++++++++++++++++++++- Cargo.toml | 1 + tests/refs/linear_gradient/ghostscript.png | Bin 0 -> 850 bytes tests/refs/linear_gradient/mupdf.png | Bin 0 -> 2509 bytes tests/refs/linear_gradient/pdfbox.png | Bin 0 -> 1153 bytes tests/refs/linear_gradient/pdfium.png | Bin 0 -> 1773 bytes tests/refs/linear_gradient/pdfjs.png | Bin 0 -> 849 bytes tests/refs/linear_gradient/poppler.png | Bin 0 -> 584 bytes tests/refs/linear_gradient/quartz.png | Bin 0 -> 21931 bytes tests/refs/linear_gradient/xpdf.png | Bin 0 -> 763 bytes tests/refs/text_rendering/ghostscript.png | Bin 0 -> 3717 bytes tests/refs/text_rendering/mupdf.png | Bin 0 -> 5707 bytes tests/refs/text_rendering/pdfbox.png | Bin 0 -> 6043 bytes tests/refs/text_rendering/pdfium.png | Bin 0 -> 13644 bytes tests/refs/text_rendering/pdfjs.png | Bin 0 -> 3577 bytes tests/refs/text_rendering/poppler.png | Bin 0 -> 6700 bytes tests/refs/text_rendering/quartz.png | Bin 0 -> 8630 bytes tests/visreg.rs | 108 +++- 18 files changed, 695 insertions(+), 3 deletions(-) create mode 100644 tests/refs/linear_gradient/ghostscript.png create mode 100644 tests/refs/linear_gradient/mupdf.png create mode 100644 tests/refs/linear_gradient/pdfbox.png create mode 100644 tests/refs/linear_gradient/pdfium.png create mode 100644 tests/refs/linear_gradient/pdfjs.png create mode 100644 tests/refs/linear_gradient/poppler.png create mode 100644 tests/refs/linear_gradient/quartz.png create mode 100644 tests/refs/linear_gradient/xpdf.png create mode 100644 tests/refs/text_rendering/ghostscript.png create mode 100644 tests/refs/text_rendering/mupdf.png create mode 100644 tests/refs/text_rendering/pdfbox.png create mode 100644 tests/refs/text_rendering/pdfium.png create mode 100644 tests/refs/text_rendering/pdfjs.png create mode 100644 tests/refs/text_rendering/poppler.png create mode 100644 tests/refs/text_rendering/quartz.png diff --git a/Cargo.lock b/Cargo.lock index 37ac5325..12a9e012 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,35 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "arrayref" version = "0.3.8" @@ -35,6 +64,29 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +dependencies = [ + "arrayvec", +] + [[package]] name = "base64" version = "0.22.1" @@ -59,6 +111,24 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitstream-io" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcde5f311c85b8ca30c2e4198d4326bc342c76541590106f5fa4a50946ea499" + +[[package]] +name = "built" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "bytemuck" version = "1.16.3" @@ -91,6 +161,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" +[[package]] +name = "cc" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb8dd288a69fc53a1996d7ecfbf4a20d59065bff137ce7e56bbd620de191189" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -192,6 +283,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "exr" version = "1.72.0" @@ -288,6 +385,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gif" version = "0.13.1" @@ -308,6 +416,18 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "image" version = "0.24.9" @@ -335,10 +455,16 @@ dependencies = [ "bytemuck", "byteorder-lite", "color_quant", + "exr", "gif", "image-webp", "num-traits", "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", "zune-core", "zune-jpeg", ] @@ -359,12 +485,57 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "jpeg-decoder" version = "0.3.1" @@ -420,6 +591,17 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + [[package]] name = "libm" version = "0.2.8" @@ -442,6 +624,24 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", +] + [[package]] name = "memchr" version = "2.7.4" @@ -457,6 +657,12 @@ dependencies = [ "libc", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -467,6 +673,69 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -505,6 +774,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "png" version = "0.17.13" @@ -518,6 +793,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -527,6 +811,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "qoi" version = "0.4.1" @@ -564,6 +867,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -579,12 +903,70 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rangemap" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5797d09f9bd33604689e87e8380df4951d4912f01b63f71205e2abd4ae25e6b6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rgb", +] + [[package]] name = "rayon" version = "1.10.0" @@ -772,12 +1154,36 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "simd-adler32" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simplecss" version = "0.2.1" @@ -922,16 +1328,55 @@ dependencies = [ "libc", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "tempdir" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" dependencies = [ - "rand", + "rand 0.4.6", "remove_dir_all", ] +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tiff" version = "0.9.1" @@ -983,6 +1428,40 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "ttf-parser" version = "0.24.0" @@ -1072,6 +1551,23 @@ dependencies = [ "xmlwriter", ] +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.5" @@ -1088,6 +1584,67 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + [[package]] name = "weezl" version = "0.1.8" @@ -1198,6 +1755,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "xmlwriter" version = "0.1.0" @@ -1240,6 +1806,27 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerofrom" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index f9a5ec5e..c6f909fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ tiny-skia-path = {git = "https://github.com/RazrFalcon/tiny-skia", rev="eec0a47" [dev-dependencies] difference = "2.0.0" +image = "0.25.1" paste = "1.0.15" sitro = {git = "https://github.com/LaurenzV/sitro", rev = "666b4ee"} diff --git a/tests/refs/linear_gradient/ghostscript.png b/tests/refs/linear_gradient/ghostscript.png new file mode 100644 index 0000000000000000000000000000000000000000..994313ebd7610af151bc0315409e07ffa4f21cda GIT binary patch literal 850 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 literal 0 HcmV?d00001 diff --git a/tests/refs/linear_gradient/pdfbox.png b/tests/refs/linear_gradient/pdfbox.png new file mode 100644 index 0000000000000000000000000000000000000000..3c6b32ba2809ac5a0e45a01bc71d1afcb265eba6 GIT binary patch literal 1153 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k2}mkgS)K$^oCO|{#S9GG!XV7ZFl&wk0|Se( zr;B4q#jUrOIL)te${c@qud-R^ii9e-YSQ_9In&$uS)dO!9p zc{a!L{PUXo2i}*@W8c5z{sm@zfe0q=1kVIcokrD0)eS7uSf(8iiV#8w{=L3I&Th}? zACJwnA6uz^)-wOBWdC~4gNu=Y-!eVVd1jvbc=^uaQ+x7F`}wmzU!M4<{?)uU<{~wj zzlzuIELgs^VE5V#>!>|f12^4_+;lH?+r8jz*P{2`3g37sexpsqPMeUOB4N5mSN-=3 zS>85(=_FI`WQb7nd4;{(5<3+scr`Pl6slIlfIqN-R$M7@9cZCU47p+^-HpyCFy^n)BkMHF8iWZcSqLx zW#`;|d*dsvNzdEMt^e!L>3$u(xZCoY56({b zU?uZIk|&1s@ASm`t{2MXs>{W`{p;9k+xvA+i|zf#caMKGcmKHVaK&@SMaFYqc&Ojn z&$s`ceBZlXmvZ;Gw<@>o)T6ggT01*gS9-DT{A07PADbPfHfx%?^mH{T@#RuM!C$#A zfBkG+`knp!8Qb~ux_!>LtBGZ~2b-R}viV_1Y0XBhm^EB>VSKvwwfloE?hm@RJ?h@? zm21-XZpmJ}quVIBHyI17y{_r#}@pGKx<2uK~|0avS{NrJ@|C_@4R|e}pX>5N~ z?f25N>|_6%MVsAOpGWrV8yBxPlDnIda<_?9EFz(Clo%diaP7YoM$W~^&M&`z)qgfc WBeFg5qcX5eVeoYIb6Mw<&;$Sm&d0(4 literal 0 HcmV?d00001 diff --git a/tests/refs/linear_gradient/pdfium.png b/tests/refs/linear_gradient/pdfium.png new file mode 100644 index 0000000000000000000000000000000000000000..a86721bfb1de2faad4f5ab2c233eaca5ce70ff2f GIT binary patch literal 1773 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>fo+SYi(^OyEiEh*2+Bd=`x#n*5|Gj1;UHVm(%jr!T6WK#$#vc*Exf$6yxjjh$V#82 zt-0%Vy;}9W{Zwdp?ANA%ov&7{juX%dk1f5*?euij>UC9)D`HBohU#-nT@6&oy0GYK zX!u@*5RfME7V2rTzm;BZHtmFxj8gXog>DFaKyedC`w1n6O&vN+ojQk@fb0n;lynL> z+JR`p0Y#ZZK*ZGUfS{NTC{6&$F>tB?B^hLxIDxWEDnKz69S0^(2r&U9-2xKV+q~hR zgmlh-FJ~y=S`HD@%qif~nR5t60a+UgxTNne zEkAHb6Ue#41d^O{NEgi2E#L;qE-&B)3ImlCaNB*p%>BQSE}==kcpJ5e?pb9t$cJr^ oH|5L*m9jr+Rmu{VbUySKGoBWEbMm1muo`3VboFyt=akR{07p1%4FCWD literal 0 HcmV?d00001 diff --git a/tests/refs/linear_gradient/pdfjs.png b/tests/refs/linear_gradient/pdfjs.png new file mode 100644 index 0000000000000000000000000000000000000000..359267f9282b4148430d07f10e65fcfef4a4259c GIT binary patch literal 849 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VJUX<4B-HR z8jh3>1_q|zo-U3d6?5KRJ==H7K*AyL_{ly0f0rq|YnneZ& z&)L6j{ol%%_j8Wd?AbSW@4fZ4`_i-j@7nzB^_xv{#cOusz1N&_}$#2BR01_s7o zo-U3d6}R4A-I#aCLB!?a_iI1jxI8+(ck-cx(?>#-*nTuWxUUc00fH`K6b$yz`A0KVQ+)UHSh* zW?8Cb+OIDq^RMbZFN?3OyH#3ax9e5ir}uaGljTZo$1~iKZPHd PG#ETx{an^LB{Ts5;_cGE literal 0 HcmV?d00001 diff --git a/tests/refs/linear_gradient/quartz.png b/tests/refs/linear_gradient/quartz.png new file mode 100644 index 0000000000000000000000000000000000000000..9dc39009bfa65f55ad4708dc26115da6ad5179f2 GIT binary patch literal 21931 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 literal 0 HcmV?d00001 diff --git a/tests/refs/linear_gradient/xpdf.png b/tests/refs/linear_gradient/xpdf.png new file mode 100644 index 0000000000000000000000000000000000000000..21dc767fddb3ea7a9f409dccf899011c0030d389 GIT binary patch literal 763 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k2}mkgS)K$^oCO|{#S9GG!XV7ZFl&wk0|V1q zPZ!6KiaBquIOg3p5OHt}dbd+}%lBkQRt=Ag<=l*^r z{-9b&j5Bef0FlIxk2CGp$J<|*`JKBi_uclL_n*yr9I+n6zP;nx@rt$b#~%kK+sXDH z-TB#I-(JgSJMEuUe!jKS@BCcz$AwnMe=koyV|Yv|dF^NOYkRI`ui5zQ*7M)Xk5|ln z_u1y}=HhwpKF^>1+a}+x@A$deYAdrwH4`D&c^MX0p6IuTFQG57eK?LNpPX#q^l44$rjF6*2Ung9cf0k!}D literal 0 HcmV?d00001 diff --git a/tests/refs/text_rendering/ghostscript.png b/tests/refs/text_rendering/ghostscript.png new file mode 100644 index 0000000000000000000000000000000000000000..83c7d40deb18e7ce4f6b6a597e764cd628ac5e0e GIT binary patch literal 3717 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 S$F165qmHjvz5>C_{}SwDLyPhIam0yULYQ| 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 u65#6Ozs`R#_* literal 0 HcmV?d00001 diff --git a/tests/refs/text_rendering/pdfbox.png b/tests/refs/text_rendering/pdfbox.png new file mode 100644 index 0000000000000000000000000000000000000000..bd451d4babde8f18601afc8f7f27e07c7cae15b1 GIT binary patch literal 6043 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 literal 0 HcmV?d00001 diff --git a/tests/refs/text_rendering/pdfium.png b/tests/refs/text_rendering/pdfium.png new file mode 100644 index 0000000000000000000000000000000000000000..44881e9f5984ad21150d56d05ecee1667bd05ee1 GIT binary patch literal 13644 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 literal 0 HcmV?d00001 diff --git a/tests/refs/text_rendering/pdfjs.png b/tests/refs/text_rendering/pdfjs.png new file mode 100644 index 0000000000000000000000000000000000000000..7c7e3e7f69186efd15a2abba1677c39ffec65beb GIT binary patch literal 3577 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 literal 0 HcmV?d00001 diff --git a/tests/refs/text_rendering/poppler.png b/tests/refs/text_rendering/poppler.png new file mode 100644 index 0000000000000000000000000000000000000000..8687d43546eaae66c29c96ce9d4f415eb1a948aa GIT binary patch literal 6700 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 literal 0 HcmV?d00001 diff --git a/tests/visreg.rs b/tests/visreg.rs index 5c03ef30..fa72a1e4 100644 --- a/tests/visreg.rs +++ b/tests/visreg.rs @@ -1,9 +1,19 @@ +use cosmic_text::{Attrs, Buffer, FontSystem, Metrics, Shaping}; +use fontdb::Source; +use image::{load_from_memory, Rgba}; use krilla::document::Document; use krilla::rgb::Rgb; use krilla::serialize::SerializeSettings; +use krilla::stream::TestGlyph; use krilla::{rgb, Fill, LinearGradient, Paint, SpreadMethod, Stop}; -use sitro::{render_mupdf, render_pdfbox, render_pdfium, render_pdfjs, render_quartz, RenderOptions, RenderedDocument, Renderer, render_poppler, render_ghostscript}; +use sitro::{ + render_ghostscript, render_mupdf, render_pdfbox, render_pdfium, render_pdfjs, render_poppler, + render_quartz, RenderOptions, RenderedDocument, Renderer, +}; +use skrifa::GlyphId; +use std::cmp::max; use std::path::PathBuf; +use std::sync::Arc; use tiny_skia_path::{PathBuilder, Rect, Size, Transform}; use usvg::NormalizedF32; @@ -17,7 +27,7 @@ pub fn render_doc(doc: &[u8], renderer: &Renderer) -> RenderedDocument { Renderer::Quartz => render_quartz(doc, &options).unwrap(), Renderer::Pdfjs => render_pdfjs(doc, &options).unwrap(), Renderer::Pdfbox => render_pdfbox(doc, &options).unwrap(), - Renderer::Ghostscript => render_ghostscript(doc, &options).unwrap() + Renderer::Ghostscript => render_ghostscript(doc, &options).unwrap(), } } @@ -32,6 +42,42 @@ pub fn save_refs(name: &str, renderer: &Renderer, document: RenderedDocument) { panic!("empty document"); } else if document.len() == 1 { let ref_path = refs_path.join(format!("{}.png", renderer.name())); + + let reference = load_from_memory(&std::fs::read(&ref_path).unwrap()).unwrap().into_rgba8(); + let actual = load_from_memory(&document[0]).unwrap().into_rgba8(); + + let width = max(reference.width(), actual.width()); + let height = max(reference.height(), actual.height()); + + let mut pixel_diff = 0; + + for x in 0..width { + for y in 0..height { + let actual_pixel = actual.get_pixel_checked(x, y); + let expected_pixel = reference.get_pixel_checked(x, y); + + + + match (actual_pixel, expected_pixel) { + (Some(actual), Some(expected)) => { + if is_pix_diff(expected, actual) { + pixel_diff += 1; + } + } + (Some(actual), None) => { + pixel_diff += 1; + } + (None, Some(expected)) => { + pixel_diff += 1; + } + _ => unreachable!(), + } + } + } + + assert_eq!(pixel_diff, 0); + + std::fs::write(&ref_path, &document[0]).unwrap(); } else { for (index, page) in document.iter().enumerate() { @@ -41,6 +87,17 @@ pub fn save_refs(name: &str, renderer: &Renderer, document: RenderedDocument) { } } +fn is_pix_diff(pixel1: &Rgba, pixel2: &Rgba) -> bool { + if pixel1.0[3] == 0 && pixel2.0[3] == 0 { + return false; + } + + pixel1.0[0] != pixel2.0[0] + || pixel1.0[1] != pixel2.0[1] + || pixel1.0[2] != pixel2.0[2] + || pixel1.0[3] != pixel2.0[3] +} + macro_rules! generate_renderer_tests { ($test_name:ident, $test_body:expr) => { paste::item! { @@ -140,3 +197,50 @@ generate_renderer_tests!(linear_gradient, |renderer| { let rendered = render_doc(&pdf, &renderer); save_refs(stringify!(linear_gradient), &renderer, rendered); }); + +generate_renderer_tests!(cosmic_text, |renderer| { + let mut font_system = FontSystem::new_with_fonts([Source::Binary(Arc::new(include_bytes!( + "fonts/NotoSans-Regular.ttf" + )))]); + let metrics = Metrics::new(14.0, 20.0); + let mut buffer = Buffer::new(&mut font_system, metrics); + buffer.set_size(&mut font_system, Some(200.0), None); + let attrs = Attrs::new(); + let text = "Some text here. Let's make it a bit longer so that line wrapping kicks in"; + buffer.set_text(&mut font_system, text, attrs, Shaping::Advanced); + buffer.shape_until_scroll(&mut font_system, false); + + let page_size = tiny_skia_path::Size::from_wh(200.0, 400.0).unwrap(); + let mut document_builder = Document::new(SerializeSettings::default()); + let mut builder = document_builder.start_page(page_size); + let mut surface = builder.surface(); + + let font_map = surface.convert_fontdb(font_system.db_mut(), None); + + // Inspect the output runs + for run in buffer.layout_runs() { + let y_offset = run.line_y; + let iter = run + .glyphs + .iter() + .map(|g| { + TestGlyph::new( + font_map.get(&g.font_id).unwrap().clone(), + GlyphId::new(g.glyph_id as u32), + g.w, + g.x_offset, + g.font_size, + run.text[g.start..g.end].to_string(), + ) + }) + .peekable(); + surface.fill_glyph_run(0.0, y_offset, Fill::::default(), iter); + } + + surface.finish(); + builder.finish(); + + let pdf = document_builder.finish(); + let rendered = render_doc(&pdf, &renderer); + save_refs(stringify!(text_rendering), &renderer, rendered); +});