diff --git a/Cargo.lock b/Cargo.lock index d1a128c..e5a3c79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,6 +33,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -54,6 +60,61 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + [[package]] name = "approx" version = "0.5.1" @@ -64,22 +125,57 @@ dependencies = [ ] [[package]] -name = "atty" -version = "0.2.14" +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 = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "proc-macro2", + "quote", + "syn 2.0.63", ] +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[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 = "bit_field" version = "0.10.2" @@ -92,6 +188,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitstream-io" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c12d1856e42f0d817a835fe55853957c85c8c8a470114029143d3f12671446e" + [[package]] name = "bitvec" version = "1.0.1" @@ -125,12 +227,24 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "built" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41bfbdb21256b87a8b5e80fab81a8eed158178e812fd7ba451907518b2742f16" + [[package]] name = "bumpalo" version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + [[package]] name = "bytemuck" version = "1.13.1" @@ -143,6 +257,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.4.0" @@ -155,6 +275,27 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cc" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[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" @@ -190,27 +331,30 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.23" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ - "atty", - "bitflags", + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", "clap_lex", - "indexmap", "strsim", - "termcolor", - "textwrap", ] [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "color_quant" @@ -218,6 +362,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + [[package]] name = "crc32fast" version = "1.3.2" @@ -229,19 +379,19 @@ dependencies = [ [[package]] name = "criterion" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ "anes", - "atty", "cast", "ciborium", "clap", "criterion-plot", - "itertools", - "lazy_static", + "is-terminal", + "itertools 0.10.5", "num-traits", + "once_cell", "oorandom", "plotters", "rayon", @@ -260,7 +410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools", + "itertools 0.10.5", ] [[package]] @@ -327,6 +477,12 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "exr" version = "1.6.3" @@ -344,13 +500,10 @@ dependencies = [ ] [[package]] -name = "find-crate" -version = "0.6.3" +name = "fast-srgb8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" -dependencies = [ - "toml", -] +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" [[package]] name = "flate2" @@ -414,9 +567,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.12.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" dependencies = [ "color_quant", "weezl", @@ -439,18 +592,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -461,35 +611,89 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "image" -version = "0.24.6" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" dependencies = [ "bytemuck", "byteorder", "color_quant", "exr", "gif", - "jpeg-decoder", - "num-rational", + "image-webp", "num-traits", "png", "qoi", + "ravif", + "rayon", + "rgb", "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d" +dependencies = [ + "byteorder-lite", + "thiserror", ] +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + [[package]] name = "indexmap" -version = "1.9.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "autocfg", + "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 2.0.63", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.10.5" @@ -499,20 +703,35 @@ dependencies = [ "either", ] +[[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.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + [[package]] name = "jpeg-decoder" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" -dependencies = [ - "rayon", -] [[package]] name = "js-sys" @@ -523,12 +742,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "lebe" version = "0.5.2" @@ -541,6 +754,17 @@ version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +[[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 = "lock_api" version = "0.4.9" @@ -560,6 +784,25 @@ dependencies = [ "cfg-if", ] +[[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", + "rayon", +] + [[package]] name = "memchr" version = "2.5.0" @@ -575,6 +818,12 @@ dependencies = [ "autocfg", ] +[[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.6.2" @@ -593,6 +842,50 @@ dependencies = [ "getrandom", ] +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "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 2.0.63", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -610,6 +903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", + "num-bigint", "num-integer", "num-traits", ] @@ -635,9 +929,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -645,12 +939,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - [[package]] name = "owned_ttf_parser" version = "0.18.1" @@ -662,26 +950,26 @@ dependencies = [ [[package]] name = "palette" -version = "0.6.1" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f9cd68f7112581033f157e56c77ac4a5538ec5836a2e39284e65bd7d7275e49" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" dependencies = [ "approx", - "num-traits", + "fast-srgb8", "palette_derive", "phf", ] [[package]] name = "palette_derive" -version = "0.6.1" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05eedf46a8e7c27f74af0c9cfcdb004ceca158cb1b918c6f68f8d7a549b3e427" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" dependencies = [ - "find-crate", + "by_address", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] @@ -752,6 +1040,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "plotters" version = "0.3.4" @@ -792,15 +1086,40 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" 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 2.0.63", +] + [[package]] name = "qoi" version = "0.4.1" @@ -810,11 +1129,17 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -831,6 +1156,18 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[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", ] @@ -839,6 +1176,59 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[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 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc13288f5ab39e6d7c9d501759712e6969fcc9734220846fc9ed26cae2cc4234" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] [[package]] name = "rayon" @@ -879,6 +1269,15 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] + [[package]] name = "ryu" version = "1.0.13" @@ -928,7 +1327,7 @@ checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.63", ] [[package]] @@ -942,12 +1341,30 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + [[package]] name = "simd-adler32" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "siphasher" version = "0.3.10" @@ -971,9 +1388,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" @@ -988,9 +1405,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" dependencies = [ "proc-macro2", "quote", @@ -998,51 +1415,55 @@ dependencies = [ ] [[package]] -name = "tap" -version = "1.0.1" +name = "system-deps" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] [[package]] -name = "termcolor" -version = "1.2.0" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] -name = "textwrap" -version = "0.16.0" +name = "target-lexicon" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.63", ] [[package]] name = "tiff" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" dependencies = [ "flate2", "jpeg-decoder", @@ -1061,13 +1482,38 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.11" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.22.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "ttf-parser" version = "0.18.1" @@ -1080,6 +1526,29 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[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 = "walkdir" version = "2.3.3" @@ -1098,9 +1567,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1108,24 +1577,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1133,22 +1602,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wcloud" @@ -1180,9 +1649,9 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "winapi" @@ -1215,10 +1684,92 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +dependencies = [ + "memchr", +] + [[package]] name = "woff2" version = "0.3.0" -source = "git+https://github.com/isaackd/woff2-rs.git#6560fea81b97b4c6660d0c5a68b4c37f24a4dd78" +source = "git+https://github.com/jizizr/woff2-rs.git#cbbaf3bbe80c66a21ee6795efdcfbd5acc29cf27" dependencies = [ "bitvec", "brotli", @@ -1237,6 +1788,12 @@ dependencies = [ "tap", ] +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + [[package]] name = "zune-inflate" version = "0.2.53" @@ -1245,3 +1802,12 @@ checksum = "440a08fd59c6442e4b846ea9b10386c38307eae728b216e1ab2c305d1c9daaf8" dependencies = [ "simd-adler32", ] + +[[package]] +name = "zune-jpeg" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index ca378c1..ecc7b83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,11 +12,11 @@ debug = true [dependencies] regex = "1.7.3" ab_glyph = "0.2.20" -image = "0.24.6" -palette = "0.6.1" -clap = "3.2.23" +image = "0.25" +palette = "0.7" +clap = "4.0" csscolorparser = "0.6.2" -woff2 = { git = "https://github.com/isaackd/woff2-rs.git" } +woff2 = { git = "https://github.com/jizizr/woff2-rs.git" } nanorand = "0.7.0" serde = { version = "1.0.164", optional = true } @@ -24,7 +24,7 @@ serde_derive = { version = "1.0.164", optional = true } serde_json = { version = "1.0.99", optional = true } [dev-dependencies] -criterion = { version = "0.4.0", features = ["html_reports"] } +criterion = { version = "0.5", features = ["html_reports"] } [[bench]] name = "create_wordcloud" diff --git a/src/lib.rs b/src/lib.rs index 2e4e462..d489b60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,9 @@ -use std::fs; -use std::path::{PathBuf}; -use image::{GrayImage, Luma, RgbaImage, Rgba}; -use ab_glyph::{PxScale, Point, point, FontVec, Font, Glyph}; -use palette::{Pixel, Srgb, Hsl, IntoColor}; +use ab_glyph::{point, Font, FontVec, Glyph, Point, PxScale}; +use image::{GrayImage, Luma, Rgba, RgbaImage}; +use palette::{Hsl, IntoColor, Srgb}; +use std::path::PathBuf; use std::process::exit; +use std::{collections::HashMap, fs}; use woff2::decode::{convert_woff2_to_ttf, is_woff2}; mod text; @@ -12,8 +12,8 @@ pub mod sat; mod tokenizer; pub use tokenizer::{Tokenizer, DEFAULT_EXCLUDE_WORDS_TEXT}; -use nanorand::{Rng, WyRand}; use crate::sat::{Rect, Region}; +use nanorand::{Rng, WyRand}; #[cfg(feature = "visualize")] mod visualize; @@ -87,18 +87,19 @@ impl WordCloud { let buffer = fs::read(path).unwrap(); assert!(is_woff2(&buffer)); convert_woff2_to_ttf(&mut std::io::Cursor::new(buffer)).expect("Invalid WOFF2 file") - } - else { + } else { fs::read(path).expect("Unable to read font file") }; - self.font = FontVec::try_from_vec(font_file) - .expect("Font file may be invalid"); + self.font = FontVec::try_from_vec(font_file).expect("Font file may be invalid"); self } pub fn with_min_font_size(mut self, value: f32) -> Self { - assert!(value >= 0.0, "The minimum font size for a word cloud cannot be less than 0"); + assert!( + value >= 0.0, + "The minimum font size for a word cloud cannot be less than 0" + ); self.min_font_size = value; self } @@ -119,7 +120,10 @@ impl WordCloud { self } pub fn with_relative_font_scaling(mut self, value: f32) -> Self { - assert!((0.0..=1.0).contains(&value), "Relative scaling must be between 0 and 1"); + assert!( + (0.0..=1.0).contains(&value), + "Relative scaling must be between 0 and 1" + ); self.relative_font_scaling = value; self } @@ -137,7 +141,7 @@ impl WordCloud { word_positions: Vec, scale: f32, background_color: Rgba, - color_func: fn(&Word, &mut WyRand) -> Rgba + color_func: fn(&Word, &mut WyRand) -> Rgba, ) -> RgbaImage { // TODO: Refactor this so that we can fail earlier if !(0.0..=100.0).contains(&scale) { @@ -146,7 +150,11 @@ impl WordCloud { exit(1); } - let mut final_image_buffer = RgbaImage::from_pixel((width as f32 * scale) as u32, (height as f32 * scale) as u32, background_color); + let mut final_image_buffer = RgbaImage::from_pixel( + (width as f32 * scale) as u32, + (height as f32 * scale) as u32, + background_color, + ); for mut word in word_positions.into_iter() { let col = color_func(&word, rng); @@ -161,7 +169,14 @@ impl WordCloud { word.glyphs = text::text_to_glyphs(word.text, word.font, word.font_size); } - text::draw_glyphs_to_rgba_buffer(&mut final_image_buffer, word.glyphs, word.font, word.position, word.rotated, col); + text::draw_glyphs_to_rgba_buffer( + &mut final_image_buffer, + word.glyphs, + word.font, + word.position, + word.rotated, + col, + ); } final_image_buffer @@ -173,25 +188,33 @@ impl WordCloud { if next_font_size >= min_font_size && next_font_size > 0.0 { *font_size = next_font_size; true - } - else { + } else { false } } fn glyphs_height(&self, glyphs: &[Glyph]) -> u32 { - glyphs.iter().map(|g| { - let outlined = self.font.outline_glyph(g.clone()) - .expect("Unable to outline glyph"); - - let bounds = outlined.px_bounds(); - bounds.height() as u32 - }).max().expect("No glyphs!") + glyphs + .iter() + .map(|g| { + let outlined = self + .font + .outline_glyph(g.clone()) + .expect("Unable to outline glyph"); + + let bounds = outlined.px_bounds(); + bounds.height() as u32 + }) + .max() + .expect("No glyphs!") } fn text_dimensions_at_font_size(&self, text: &str, font_size: PxScale) -> Rect { let glyphs = text::text_to_glyphs(text, &self.font, font_size); - Rect { width: glyphs.width + self.word_margin, height: glyphs.height + self.word_margin } + Rect { + width: glyphs.width + self.word_margin, + height: glyphs.height + self.word_margin, + } } pub fn generate_from_text(&self, text: &str, size: WordCloudSize, scale: f32) -> RgbaImage { @@ -203,10 +226,39 @@ impl WordCloud { text: &str, size: WordCloudSize, scale: f32, - color_func: fn(&Word, &mut WyRand) -> Rgba + color_func: fn(&Word, &mut WyRand) -> Rgba, ) -> RgbaImage { let words = self.tokenizer.get_normalized_word_frequencies(text); + self.generate_with_color_func(words, size, scale, color_func) + } + pub fn generate_from_map( + &self, + map: HashMap<&str, usize>, + size: WordCloudSize, + scale: f32, + ) -> RgbaImage { + self.generate_from_map_with_color_func(map, size, scale, random_color_rgba) + } + + pub fn generate_from_map_with_color_func( + &self, + map: HashMap<&str, usize>, + size: WordCloudSize, + scale: f32, + color_func: fn(&Word, &mut WyRand) -> Rgba, + ) -> RgbaImage { + let words = self.tokenizer.get_normalized_word_frequencies_from_map(map); + self.generate_with_color_func(words, size, scale, color_func) + } + + fn generate_with_color_func( + &self, + words: Vec<(&str, f32)>, + size: WordCloudSize, + scale: f32, + color_func: fn(&Word, &mut WyRand) -> Rgba, + ) -> RgbaImage { let (mut summed_area_table, mut gray_buffer) = match size { WordCloudSize::FromDimensions { width, height } => { let buf = GrayImage::from_pixel(width, height, Luma([0])); @@ -214,14 +266,12 @@ impl WordCloud { u8_to_u32_vec(&buf, &mut summed_area_table); (summed_area_table, buf) - }, + } WordCloudSize::FromMask(image) => { let mut table = vec![0; image.len()]; u8_to_u32_vec(&image, &mut table); - sat::to_summed_area_table( - &mut table, image.width() as usize, 0 - ); + sat::to_summed_area_table(&mut table, image.width() as usize, 0); (table, image) } }; @@ -230,8 +280,7 @@ impl WordCloud { { let mask = if matches!(WordCloudSize::FromMask, _size) { Some(gray_buffer.to_vec()) - } - else { + } else { None }; @@ -241,7 +290,8 @@ impl WordCloud { mask, font: self.font.as_slice().to_vec(), background_color: self.background_color.0, - })).unwrap(); + })) + .unwrap(); println!("{}", serialized); }; @@ -254,18 +304,18 @@ impl WordCloud { None => WyRand::new(), }; - let first_word = words.first() - .expect("There are no words!"); + let first_word = words.first().expect("There are no words!"); let skip_list = create_mask_skip_list(&gray_buffer); let mut font_size = { let rect_at_image_height = self.text_dimensions_at_font_size( first_word.0, - PxScale::from(gray_buffer.height() as f32 * 0.95) + PxScale::from(gray_buffer.height() as f32 * 0.95), ); - let height_ratio = rect_at_image_height.height as f32 / rect_at_image_height.width as f32; + let height_ratio = + rect_at_image_height.height as f32 / rect_at_image_height.width as f32; let mut start_height = gray_buffer.width() as f32 * height_ratio; @@ -277,15 +327,15 @@ impl WordCloud { if let Some(max) = self.max_font_size { start_height.min(max) - } - else { + } else { start_height } }; 'outer: for (word, freq) in &words { if !self.tokenizer.repeat && self.relative_font_scaling != 0.0 { - font_size *= self.relative_font_scaling * (freq / last_freq) + (1.0 - self.relative_font_scaling); + font_size *= self.relative_font_scaling * (freq / last_freq) + + (1.0 - self.relative_font_scaling); } if font_size < self.min_font_size { @@ -305,92 +355,123 @@ impl WordCloud { let glyphs_height = self.glyphs_height(&glyphs.glyphs); let rect = if !should_rotate { - Rect { width: glyphs.width + self.word_margin, height: glyphs.height + self.word_margin } - } - else { - Rect { width: glyphs.height + self.word_margin, height: glyphs.width + self.word_margin } + Rect { + width: glyphs.width + self.word_margin, + height: glyphs.height + self.word_margin, + } + } else { + Rect { + width: glyphs.height + self.word_margin, + height: glyphs.width + self.word_margin, + } }; #[cfg(feature = "visualize")] { - let serialized = serde_json::to_string(&Message::ChangeWordMessage(visualize::Word { - text: word.to_string(), - font_size: font_size as u32, - rect_width: rect.width, - rect_height: rect.height, - rotation: if should_rotate { 270 } else { 0 }, - })).unwrap(); + let serialized = + serde_json::to_string(&Message::ChangeWordMessage(visualize::Word { + text: word.to_string(), + font_size: font_size as u32, + rect_width: rect.width, + rect_height: rect.height, + rotation: if should_rotate { 270 } else { 0 }, + })) + .unwrap(); println!("{}", serialized); }; if rect.width > gray_buffer.width() || rect.height > gray_buffer.height() { if Self::check_font_size(&mut font_size, self.font_step, self.min_font_size) { continue; - } - else { + } else { break 'outer; }; } if has_mask { - match sat::find_space_for_rect_masked(&summed_area_table, gray_buffer.width(), gray_buffer.height(), &skip_list, &rect, &mut rng) { + match sat::find_space_for_rect_masked( + &summed_area_table, + gray_buffer.width(), + gray_buffer.height(), + &skip_list, + &rect, + &mut rng, + ) { Some(pos) => { let half_margin = self.word_margin as f32 / 2.0; let x = pos.x as f32 + half_margin; let y = pos.y as f32 + half_margin; - break point(x, y) - }, + break point(x, y); + } None => { - if !Self::check_font_size(&mut font_size, self.font_step, self.min_font_size) { + if !Self::check_font_size( + &mut font_size, + self.font_step, + self.min_font_size, + ) { if !tried_rotate { should_rotate = true; tried_rotate = true; font_size = initial_font_size; - } - else { + } else { break 'outer; } } } }; - } - else { - match sat::find_space_for_rect(&summed_area_table, gray_buffer.width(), gray_buffer.height(), &rect, &mut rng) { + } else { + match sat::find_space_for_rect( + &summed_area_table, + gray_buffer.width(), + gray_buffer.height(), + &rect, + &mut rng, + ) { Some(pos) => { let half_margin = self.word_margin as f32 / 2.0; let x = pos.x as f32 + half_margin; let y = pos.y as f32 + half_margin; - break point(x, y) - }, + break point(x, y); + } None => { - if !Self::check_font_size(&mut font_size, self.font_step, self.min_font_size) { + if !Self::check_font_size( + &mut font_size, + self.font_step, + self.min_font_size, + ) { if !tried_rotate { should_rotate = true; tried_rotate = true; font_size = initial_font_size; - } - else { + } else { break 'outer; } } } }; } - }; - text::draw_glyphs_to_gray_buffer(&mut gray_buffer, glyphs.clone(), &self.font, pos, should_rotate); + text::draw_glyphs_to_gray_buffer( + &mut gray_buffer, + glyphs.clone(), + &self.font, + pos, + should_rotate, + ); #[cfg(feature = "visualize")] { - let serialized = serde_json::to_string(&Message::PlacedWordMessage(visualize::PlaceWord { - text: word.to_string(), - font_size: font_size as u32, - x: pos.x as u32, - y: pos.y as u32, - rotation: if should_rotate { 270 } else { 0 }, - })).unwrap(); + let serialized = + serde_json::to_string(&Message::PlacedWordMessage(visualize::PlaceWord { + text: word.to_string(), + font_size: font_size as u32, + x: pos.x as u32, + y: pos.y as u32, + rotation: if should_rotate { 270 } else { 0 }, + })) + .unwrap(); println!("{}", serialized); }; @@ -402,19 +483,29 @@ impl WordCloud { rotated: should_rotate, position: pos, frequency: *freq, - index: final_words.len() + index: final_words.len(), }); // TODO: Do a partial sat like the Python implementation u8_to_u32_vec(&gray_buffer, &mut summed_area_table); let start_row = (pos.y - 1.0).min(0.0) as usize; - sat::to_summed_area_table(&mut summed_area_table, gray_buffer.width() as usize, start_row); + sat::to_summed_area_table( + &mut summed_area_table, + gray_buffer.width() as usize, + start_row, + ); last_freq = *freq; } WordCloud::generate_from_word_positions( - &mut rng, gray_buffer.width(), gray_buffer.height(), final_words, scale, self.background_color, color_func + &mut rng, + gray_buffer.width(), + gray_buffer.height(), + final_words, + scale, + self.background_color, + color_func, ) } } @@ -428,8 +519,7 @@ fn random_color_rgba(_word: &Word, rng: &mut WyRand) -> Rgba { let col = Hsl::new(hue as f32, 1.0, 0.5); let rgb: Srgb = col.into_color(); - let raw: [u8; 3] = rgb.into_format() - .into_raw(); + let raw: [u8; 3] = rgb.into_format().into(); Rgba([raw[0], raw[1], raw[2], 1]) } @@ -468,8 +558,7 @@ fn _find_image_bounds(img: &GrayImage) -> Region { if last_pos.0 > max_x { max_x = last_pos.0; } - } - else if pos > max_x as usize { + } else if pos > max_x as usize { max_x = pos as u32; } } @@ -478,17 +567,26 @@ fn _find_image_bounds(img: &GrayImage) -> Region { let width = max_x - min_x; let height = max_y - min_y; - Region { x: min_x, y: min_y, width, height } + Region { + x: min_x, + y: min_y, + width, + height, + } } /// Finds the outline of a mask on the x axis /// /// Useful for skipping white pixels that can't be used when looking for a space to place a word fn create_mask_skip_list(img: &GrayImage) -> Vec<(usize, usize)> { - img.rows().map(|mut row| { - let furthest_left = row.rposition(|p| p == &Luma::from([0])).unwrap_or(img.width() as usize); - let furthest_right = row.position(|p| p == &Luma::from([0])).unwrap_or(0); - - (furthest_right, furthest_left) - }).collect() -} \ No newline at end of file + img.rows() + .map(|mut row| { + let furthest_left = row + .rposition(|p| p == &Luma::from([0])) + .unwrap_or(img.width() as usize); + let furthest_right = row.position(|p| p == &Luma::from([0])).unwrap_or(0); + + (furthest_right, furthest_left) + }) + .collect() +} diff --git a/src/tokenizer.rs b/src/tokenizer.rs index ddc56a0..6a5d484 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -1,5 +1,5 @@ -use regex::{Regex, Match}; -use std::collections::{HashSet, HashMap}; +use regex::{Match, Regex}; +use std::collections::{HashMap, HashSet}; // TODO: Use lazy_static or PHF to make this a HashSet? pub const DEFAULT_EXCLUDE_WORDS_TEXT: &str = include_str!("../exclude_words.txt"); @@ -15,8 +15,7 @@ pub struct Tokenizer { impl Default for Tokenizer { fn default() -> Self { - let regex = Regex::new("\\w[\\w']*") - .expect("Unable to compile tokenization regex"); + let regex = Regex::new("\\w[\\w']*").expect("Unable to compile tokenization regex"); let filter = DEFAULT_EXCLUDE_WORDS_TEXT .lines() @@ -35,9 +34,9 @@ impl Default for Tokenizer { } impl<'a> Tokenizer { - fn tokenize(&'a self, text: &'a str) -> Box> + 'a> { - let mut result: Box> + 'a> - = Box::new(self.regex.find_iter(text)); + fn tokenize(&'a self, text: &'a str) -> Box> + 'a> { + let mut result: Box> + 'a> = + Box::new(self.regex.find_iter(text)); if !self.filter.is_empty() { result = Box::new(result.filter(move |word| { @@ -46,10 +45,13 @@ impl<'a> Tokenizer { })); } if self.min_word_length > 0 { - result = Box::new(result.filter(move |word| word.as_str().len() >= self.min_word_length as usize)); + result = Box::new( + result.filter(move |word| word.as_str().len() >= self.min_word_length as usize), + ); } if self.exclude_numbers { - result = Box::new(result.filter(move |word| !word.as_str().chars().all(char::is_numeric))); + result = + Box::new(result.filter(move |word| !word.as_str().chars().all(char::is_numeric))); } result @@ -60,32 +62,36 @@ impl<'a> Tokenizer { let mut common_cases = HashMap::::new(); for (key, val) in map { - common_cases.entry(key.to_lowercase()) + common_cases + .entry(key.to_lowercase()) .or_default() .insert(key, *val); } - - common_cases.values().map(|val| { - let mut most_common_case: Vec<(&str, usize)> = val.iter().map(|(case_key, case_val)| { - (*case_key, *case_val) - }).collect(); - most_common_case.sort_by(|a, b| { - if a.1 != b.1 { - (b.1).partial_cmp(&a.1).unwrap() - } - else { - (b.0).partial_cmp(a.0).unwrap() - } - }); - - let occurrence_sum = val.values().sum(); - - (most_common_case.first().unwrap().0, occurrence_sum) - }).collect() + common_cases + .values() + .map(|val| { + let mut most_common_case: Vec<(&str, usize)> = val + .iter() + .map(|(case_key, case_val)| (*case_key, *case_val)) + .collect(); + + most_common_case.sort_by(|a, b| { + if a.1 != b.1 { + (b.1).partial_cmp(&a.1).unwrap() + } else { + (b.0).partial_cmp(a.0).unwrap() + } + }); + + let occurrence_sum = val.values().sum(); + + (most_common_case.first().unwrap().0, occurrence_sum) + }) + .collect() } - fn get_word_frequencies(&'a self, text: &'a str) -> (HashMap<&'a str, usize>, usize) { + fn get_word_frequencies(&'a self, text: &'a str) -> HashMap<&'a str, usize> { let mut frequencies = HashMap::new(); let included_words = self.tokenize(text); @@ -96,28 +102,31 @@ impl<'a> Tokenizer { } let common_cased_map = Self::keep_common_case(&frequencies); - let max_freq = *common_cased_map.values().max() - .expect("Can't get max frequency"); - - (common_cased_map, max_freq) + common_cased_map } pub fn get_normalized_word_frequencies(&'a self, text: &'a str) -> Vec<(&'a str, f32)> { - let (frequencies, max_freq) = self.get_word_frequencies(text); + let frequencies = self.get_word_frequencies(text); + self.get_normalized_word_frequencies_from_map(frequencies) + } + pub fn get_normalized_word_frequencies_from_map( + &'a self, + frequencies: HashMap<&'a str, usize>, + ) -> Vec<(&str, f32)> { if frequencies.is_empty() { return Vec::new(); } - - let mut normalized_freqs: Vec<(&str, f32)> = frequencies.iter().map(|(key, val)| { - (*key, *val as f32 / max_freq as f32) - }).collect(); + let max_freq = *frequencies.values().max().expect("Can't get max frequency"); + let mut normalized_freqs: Vec<(&str, f32)> = frequencies + .iter() + .map(|(key, val)| (*key, *val as f32 / max_freq as f32)) + .collect(); normalized_freqs.sort_by(|a, b| { if a.1 != b.1 { (b.1).partial_cmp(&a.1).unwrap() - } - else { + } else { (a.0).partial_cmp(b.0).unwrap() } }); @@ -127,18 +136,20 @@ impl<'a> Tokenizer { } if self.repeat && normalized_freqs.len() < self.max_words as usize { - let times_extend = ((self.max_words as f32 / normalized_freqs.len() as f32).ceil()) as u32 - 1; + let times_extend = + ((self.max_words as f32 / normalized_freqs.len() as f32).ceil()) as u32 - 1; let freqs_clone = normalized_freqs.clone(); - let down_weight = normalized_freqs.last() + let down_weight = normalized_freqs + .last() .expect("The normalized frequencies vec is empty") .1; for i in 1..=times_extend { normalized_freqs.extend( - freqs_clone.iter().map(|(word, freq)| { - (*word, freq * down_weight.powf(i as f32)) - }) + freqs_clone + .iter() + .map(|(word, freq)| (*word, freq * down_weight.powf(i as f32))), ) } } @@ -151,9 +162,7 @@ impl<'a> Tokenizer { self } pub fn with_filter(mut self, value: HashSet<&str>) -> Self { - self.filter = value.iter() - .map(|el| el.to_lowercase()) - .collect(); + self.filter = value.iter().map(|el| el.to_lowercase()).collect(); self } @@ -187,27 +196,42 @@ mod tests { let frequencies = tokenizer.get_word_frequencies(words); let expected: HashMap<&str, usize> = vec![ - ("could", 2), ("much", 1), ("if", 1), ("woodchuck", 3), - ("as", 2), ("wood", 2), ("would", 1), ("chuck", 3), ("a", 3) - ].into_iter().collect(); + ("could", 2), + ("much", 1), + ("if", 1), + ("woodchuck", 3), + ("as", 2), + ("wood", 2), + ("would", 1), + ("chuck", 3), + ("a", 3), + ] + .into_iter() + .collect(); - assert_eq!(frequencies.0, expected); - assert_eq!(frequencies.1, 3); + assert_eq!(frequencies, expected); } #[test] fn simple_normalized_word_frequencies() { let words = "A a wood chuck could could Could ChuCK"; - let tokenizer = Tokenizer::default() - .with_repeat(true) - .with_max_words(12); + let tokenizer = Tokenizer::default().with_repeat(true).with_max_words(12); let frequencies = tokenizer.get_normalized_word_frequencies(words); let expected = vec![ - ("could", 1.0), ("a", 0.6666667), ("chuck", 0.6666667), ("wood", 0.33333334), - ("could", 0.33333334), ("a", 0.22222224), ("chuck", 0.22222224), ("wood", 0.11111112), - ("could", 0.11111112), ("a", 0.07407408), ("chuck", 0.07407408), ("wood", 0.03703704) + ("could", 1.0), + ("a", 0.6666667), + ("chuck", 0.6666667), + ("wood", 0.33333334), + ("could", 0.33333334), + ("a", 0.22222224), + ("chuck", 0.22222224), + ("wood", 0.11111112), + ("could", 0.11111112), + ("a", 0.07407408), + ("chuck", 0.07407408), + ("wood", 0.03703704), ]; assert_eq!(frequencies, expected); @@ -220,30 +244,33 @@ mod tests { let tokenizer = Tokenizer::default(); let frequencies = tokenizer.get_word_frequencies(words); - let expected: HashMap<&str, usize> = vec![ - ("LUKE", 12) - ].into_iter().collect(); + let expected: HashMap<&str, usize> = vec![("LUKE", 12)].into_iter().collect(); - assert_eq!(frequencies.0, expected); + assert_eq!(frequencies, expected); } #[test] fn filter_works() { let words = "The quick brown fox jumps over the lazy dog. The dog was otherwise very fine."; - let filter = DEFAULT_EXCLUDE_WORDS_TEXT - .lines() - .collect::>(); + let filter = DEFAULT_EXCLUDE_WORDS_TEXT.lines().collect::>(); - let tokenizer = Tokenizer::default() - .with_filter(filter); + let tokenizer = Tokenizer::default().with_filter(filter); let frequencies = tokenizer.get_word_frequencies(words); - println!("original words: {:?} changed: {:?}", words, frequencies.0); + println!("original words: {:?} changed: {:?}", words, frequencies); let expected: HashMap<&str, usize> = vec![ - ("fox", 1), ("brown", 1), ("dog", 2), ("lazy", 1), ("jumps", 1), ("fine", 1), ("quick", 1) - ].into_iter().collect(); + ("fox", 1), + ("brown", 1), + ("dog", 2), + ("lazy", 1), + ("jumps", 1), + ("fine", 1), + ("quick", 1), + ] + .into_iter() + .collect(); - assert_eq!(frequencies.0, expected); + assert_eq!(frequencies, expected); } }