From eacbf23265f932a5b6b6568a49f1008d02d65ae6 Mon Sep 17 00:00:00 2001 From: cqql Date: Sun, 30 Jun 2024 11:16:25 +0200 Subject: [PATCH] making the code public --- .gitignore | 4 + Cargo.lock | 1519 +++++++++++++++++ Cargo.toml | 16 + README.md | 70 + ...31362291924172-p(e5f9e0-a3f7b5-40c9a2).png | Bin 0 -> 78093 bytes src/main.rs | 405 +++++ 6 files changed, 2014 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 drawing-100x100s5-p2000-s9503131362291924172-p(e5f9e0-a3f7b5-40c9a2).png create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d9f746 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +/plots +/notes +.vscode/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b7e8ecd --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1519 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + +[[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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +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.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + +[[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 = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.3.0", +] + +[[package]] +name = "autocfg" +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 = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +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 = "built" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cgmath" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7" +dependencies = [ + "approx", + "num-traits", + "rand 0.6.5", +] + +[[package]] +name = "clap" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "color_quant" +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.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "draw" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "788472df3488f59b77624dd88327dd8d247b1ebcb916bf096255750c8c3df512" +dependencies = [ + "cgmath", + "rand 0.7.3", + "rgb", + "svg", +] + +[[package]] +name = "either" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "frost_patterns" +version = "0.1.0" +dependencies = [ + "clap", + "draw", + "hex", + "image", + "rand 0.8.5", + "rand_chacha 0.3.1", + "regex", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "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 = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "image" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "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 = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +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 = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +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 = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg 1.3.0", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[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.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +dependencies = [ + "adler", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg 1.3.0", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "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.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +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.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.8", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg 0.1.2", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", + "rand_pcg 0.2.1", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.8", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[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 0.3.1", + "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" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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.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 = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "svg" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a863ec1f8e7cfd4ea449f77445cca06aac240b9a677ccf12b0f65ef020db52c7" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "toml" +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 = "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 = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[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 = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[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.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" +dependencies = [ + "memchr", +] + +[[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.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +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 new file mode 100644 index 0000000..cc35c7a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "frost_patterns" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.5.7", features = ["derive", "cargo"] } +draw = "0.3.0" +hex = "0.4.3" +image = "0.25.1" +rand = "0.8.5" +rand_chacha = "0.3.1" +regex = "1.10.5" + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ca8426 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# Frost Patterns +#### Making Diffusion Limited Aggregation look nice + +![a result of the DLA algorithm where a cell is a light blue square and empty space is very dark blue, blurred slightly, with the unblurred result overlaid on top in purple](https://cqql.site/assets/articles/frost_patterns/gallery_5.png) + +I learned about an algorithm called [Diffusion-Limited Aggregation](https://en.wikipedia.org/wiki/Diffusion-limited_aggregation) from [this youtube video](https://www.youtube.com/watch?v=gsJHzBTPG0Y) about procedural landscape generation for games. It happens on an empty grid with one cell in the middle. Let's call that cell the shape for now. Then, in each step of the algorithm, a new cell is spawned in a random location and does a random walk until it touches the side of the shape, after which it stays there and becomes a part of the shape. + +I wrote more about how I made it on my website in the [Frost Patterns](https://cqql.site/articles/frost_patterns.html) article. + +## This repository + +This is the code I wrote for generating those images. It builds into a binary that can be used to generate an image with any initialization parameters. The result can either be saved to a file, or written to stdout to pipe into other programs. + +### Usage + +Here's how to use it: +``` +Usage: frost_patterns [OPTIONS] --width --height --num-particles --scale --palette <123456-abcdef-000000> + +Options: + --width + The width of the grid on which particles will be placed + --height + The height of the grid on which particles will be placed + --num-particles + The number of particles to place on the grid + --scale + How much scaled up should the image be, i.e. the image width will be the grid width multiplied by the grid height + --seed + Optional randomness seed for the generator - providing the same seed will generate the same result. Leave empty for a random value + --palette <123456-abcdef-000000> + Shorthand notation of the color palette to use. Three RGB values in hex, where the first is the background color, the second is the blurry shape color, and the third is the sharp overlaid shape color + --filename + Filename to save the image as. If not provided, a descriptive filename will be generated. Can't be used together with -i + --cell-placement-strategy + [default: anywhere] [possible values: anywhere, corners] + -v + Verbose - prints the progress of generating the image and the filename it has been saved to. Can't be used together with -i + -i + Output PNG bytes to stdout. Can't be used together with -v or --filename + -h, --help + Print help +``` + +Cell placement strategy determines where the new cells will be placed before they start their random walk. +- `anywhere` - place the new cell anywhere there's an empty space but not right next to the shape. +- `corners` - place the new cell in any randomly picked corner of the grid that isn't occupied by the shape yet. If all corners are occupied, it falls back to `anywhere`. + +Keeping a `--seed` value set will generate the same shape every time that seed is used, given the same grid size, number of particles, and cell placement strategy are used. + +#### Example + +Generate on a 100 by 100 grid, walk 2000 particles on it (so the shape will be made up of 2000 cells). Scale the grid by 5 to generate the final image (500 by 500 pixels). Use #e5f9e0 for the background color, #a3f7b5 for the gradient under the shape, and #40c9a2 for the shape. Print the progress of generating the image (`-v`). +``` +./target/release/frost_patterns --width 100 --height 100 --num-particles 2000 --scale 5 --palette e5f9e0-a3f7b5-40c9a2 -v +``` + +### Building + +To build the project, run: +```sh +cargo build --release +``` +and the executable binary will be in `target/release/frost_patterns`. + +### Attribution + +Feel free to use and modify this software. I would appreciate if you could attribute me if you do (most preferrably by using my website [https://cqql.site](cqql.site)) and let me know, I'll be curious! But I don't require attribution. I do not consent for the software, images generated by it, or any derivative work of them, to be used for commercial purposes without my written permission. You can contact me by email at cqql.0@proton.me. I will be very open to talk, the only reason I'm going non-commercial is because I want to prevent someone from making a no-effort dropshipping business selling posters of my generative art projects. + +The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software. \ No newline at end of file diff --git a/drawing-100x100s5-p2000-s9503131362291924172-p(e5f9e0-a3f7b5-40c9a2).png b/drawing-100x100s5-p2000-s9503131362291924172-p(e5f9e0-a3f7b5-40c9a2).png new file mode 100644 index 0000000000000000000000000000000000000000..556c0678aef5c90470a044da6381c263c92377ef GIT binary patch literal 78093 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Ł=-iRTA!miCHzecB2+l3y=V=#pYCM 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 U+ fmt::Result { + match self { + CellPlacementStrategy::Corners => write!(f, "corners"), + CellPlacementStrategy::Anywhere => write!(f, "anywhere"), + } + } +} + +impl CellPlacementStrategy { + fn new(string: &str) -> Result { + match string { + "anywhere" => Ok(CellPlacementStrategy::Anywhere), + "corners" => Ok(CellPlacementStrategy::Corners), + _ => Err(format!( + "\"{}\" is not a valid option for CellPlacementStrategy", + string + )), + } + } +} + +use clap::Parser; + +#[derive(Parser)] +#[clap()] +struct Cli { + /// The width of the grid on which particles will be placed. + #[clap(long, value_name = "grid width")] + width: usize, + + /// The height of the grid on which particles will be placed. + #[clap(long, value_name = "grid height")] + height: usize, + + /// The number of particles to place on the grid + #[clap(long, value_name = "number of particles")] + num_particles: usize, + + /// How much scaled up should the image be, i.e. the image + /// width will be the grid width multiplied by the grid height. + #[clap(long, value_name = "image scale")] + scale: usize, + + /// Optional randomness seed for the generator - providing the same + /// seed will generate the same result. Leave empty for a random value. + #[clap(long, value_name = "randomness seed")] + seed: Option, + + /// Shorthand notation of the color palette to use. Three RGB + /// values in hex, where the first is the background color, the + /// second is the blurry shape color, and the third is the sharp + /// overlaid shape color. + /* examples + ffdddd-b4e1ff-ab87ff + e5f9e0-a3f7b5-40c9a2 + f2f3ae-edd382-fc9e4f + 392f5a-f092dd-ffaff0 + 19535f-0b7a75-d7c9aa + 32021f-006d77-e8f7ee + */ + #[clap(long, value_name = "123456-abcdef-000000")] + palette: String, + + /// Filename to save the image as. If not provided, a descriptive + /// filename will be generated. Can't be used together with -i + #[clap(long)] + filename: Option, + + #[clap(long, default_value_t=String::from("anywhere"), value_parser=clap::builder::PossibleValuesParser::new(["anywhere", "corners"]))] + cell_placement_strategy: String, + + /// Verbose - prints the progress of generating the image and + /// the filename it has been saved to. Can't be used together with -i + #[clap(short)] + v: bool, + + /// Output PNG bytes to stdout. Can't be used together with -v or --filename + #[clap(short)] + i: bool, +} + +fn main() { + let cli = Cli::parse(); + + let width = cli.width; + let height = cli.height; + let num_particles = cli.num_particles; + let scale = cli.scale; + let blur = 4.0 * scale as f32; + let strategy = match CellPlacementStrategy::new(cli.cell_placement_strategy.as_str()) { + Ok(strategy) => strategy, + Err(e) => panic!("{}", e), + }; + + let seed = match cli.seed { + Some(seed) => seed, + None => thread_rng().gen(), + }; + + let verbose = cli.v; + let write_to_stdout = cli.i; + + if verbose && write_to_stdout { + panic!("Can't use -i and -v together"); + } + + let filename = cli.filename; + + if write_to_stdout && filename.is_some() { + panic!("Can't use -i and --filename together"); + } + + let palette_str = cli.palette; + let palette_regex = Regex::new(r"([0-9a-fA-F]{6})-([0-9a-fA-F]{6})-([0-9a-fA-F]{6})").unwrap(); + let palette: [&str; 3] = match palette_regex.captures(&palette_str) { + Some(captures) => captures.extract().1, + None => panic!("The color palette has to be 3 colors as 6 digit hex strings representing their RGB values"), + }; + + let grid = generate_grid(width, height, num_particles, seed, strategy, verbose); + + let imgx = width * scale; + let imgy = height * scale; + + let mut imgbuf: image::ImageBuffer, Vec> = + image::ImageBuffer::new(imgx as u32, imgy as u32); + for x in 0..width { + for y in 0..height { + for img_x in (x * scale)..((x + 1) * scale) { + for img_y in (y * scale)..((y + 1) * scale) { + let pixel = imgbuf.get_pixel_mut(img_x as u32, img_y as u32); + *pixel = image::Rgb(match grid[x][y] { + true => [255u8, 255u8, 255u8], + false => [0u8, 0u8, 0u8], + }); + } + } + } + } + + let image = make_blurred_colored_overlaid(&imgbuf, &grid, &palette, scale, blur); + + if write_to_stdout { + let mut buffer = Cursor::new(Vec::new()); + { + let mut writer = BufWriter::new(&mut buffer); + match image.write_to(&mut writer, image::ImageFormat::Png) { + Ok(_) => {} + Err(e) => { + panic!("Failed to load image bytes: {}", e) + } + }; + } + + match std::io::stdout().write_all(&buffer.into_inner()) { + Ok(_) => {} + Err(e) => { + panic!("Failed to write image bytes to stdout: {}", e) + } + }; + } else { + save_image( + image, + width, + height, + scale, + num_particles, + seed, + &palette_str, + filename, + verbose, + ) + .unwrap(); + } +} + +fn make_blurred_colored_overlaid( + imgbuf: &image::ImageBuffer, Vec>, + grid: &Vec>, + palette: &[&str; 3], + scale: usize, + blur: f32, +) -> image::ImageBuffer, Vec> { + let width = grid.len(); + let height = grid.get(0).unwrap().len(); + + let blurred = imageops::blur(imgbuf, blur); + + let start_color = hex::decode(&palette[0]).unwrap().try_into().unwrap(); + let end_color = hex::decode(&palette[1]).unwrap().try_into().unwrap(); + let overlay_color = hex::decode(&palette[2]).unwrap().try_into().unwrap(); + + let mut blurred_colored_overlaid: image::ImageBuffer, Vec> = blurred.clone(); + blurred_colored_overlaid.pixels_mut().for_each(|pixel| { + *pixel = image::Rgb(make_gradient( + &start_color, + &end_color, + pixel[0] as f64 / 255.0, + )) + }); + + for x in 0..width { + for y in 0..height { + if !grid[x][y] { + continue; + } + + for img_x in (x * scale + (scale as f64 * OVERLAY_SPACING) as usize) + ..((x + 1) * scale - (scale as f64 * OVERLAY_SPACING) as usize) + { + for img_y in (y * scale + (scale as f64 * OVERLAY_SPACING) as usize) + ..((y + 1) * scale - (scale as f64 * OVERLAY_SPACING) as usize) + { + let pixel = blurred_colored_overlaid.get_pixel_mut(img_x as u32, img_y as u32); + *pixel = image::Rgb(overlay_color) + } + } + } + } + + blurred_colored_overlaid +} + +fn save_image( + image: image::RgbImage, + width: usize, + height: usize, + scale: usize, + num_particles: usize, + seed: u64, + palette: &String, + filename: Option, + verbose: bool, +) -> Result<(), ImageError> { + let filename = match filename { + Some(filename) => filename, + None => format!( + "drawing-{}x{}s{}-p{}-s{}-p({}).png", + width, height, scale, num_particles, seed, palette + ), + }; + + image.save(&filename)?; + + if verbose { + println!("saved as {}", filename) + } + + Ok(()) +} + +fn make_gradient(start: &[u8; 3], end: &[u8; 3], distance: f64) -> [u8; 3] { + let distance = if distance <= 0.0 { + 0.0 + } else if distance >= 1.0 { + 1.0 + } else { + distance + }; + + let mut result: [u8; 3] = [0, 0, 0]; + + for i in 0..3 { + result[i] = ((1.0 - distance) * start[i] as f64 + distance * end[i] as f64) as u8; + } + + result +} + +fn generate_grid( + width: usize, + height: usize, + num_particles: usize, + seed: u64, + cell_placement_strategy: CellPlacementStrategy, + verbose: bool, +) -> Vec> { + let mut rng = ChaCha8Rng::seed_from_u64(seed); + + let mut grid: Vec> = vec![vec![false; height]; width]; + + grid[width / 2][height / 2] = true; + + for particle_i in 0..num_particles { + let (mut x, mut y) = + random_cell_placement(cell_placement_strategy.clone(), &rng, &grid, width, height); + + while !is_stuck((x, y), width, height, &grid) { + let diff_x: isize = rng.gen_range(-1..=1); + let diff_y: isize = rng.gen_range(-1..=1); + + if x + diff_x < width as isize + && x + diff_x >= 0 + && y + diff_y < height as isize + && y + diff_y >= 0 + && !grid[(x + diff_x) as usize][(y + diff_y) as usize] + { + x += diff_x; + y += diff_y; + } + } + + grid[x as usize][y as usize] = true; + if verbose { + println!("particle {:5>}/{}", particle_i + 1, num_particles); + } + } + + grid +} + +fn random_cell_placement( + strategy: CellPlacementStrategy, + rng: &ChaCha8Rng, + grid: &Vec>, + width: usize, + height: usize, +) -> (isize, isize) { + let mut rng = rng.to_owned(); + match strategy { + CellPlacementStrategy::Anywhere => { + let mut x: isize = rng.gen_range(0..width).try_into().unwrap(); + let mut y: isize = rng.gen_range(0..height).try_into().unwrap(); + + while is_stuck((x, y), width, height, &grid) || grid[x as usize][y as usize] { + x = rng.gen_range(0..width).try_into().unwrap(); + y = rng.gen_range(0..height).try_into().unwrap(); + } + + (x, y) + } + CellPlacementStrategy::Corners => { + let possibilities: Vec<(isize, isize)> = vec![ + (0, 0), + (0, height as isize - 1), + (width as isize - 1, 0), + (width as isize - 1, height as isize - 1), + ]; + let possibilities: Vec<&(isize, isize)> = possibilities + .iter() + .filter(|(pos_x, pos_y)| { + !grid + .get(*pos_x as usize) + .unwrap() + .get(*pos_y as usize) + .unwrap() + }) + .collect(); + + if possibilities.is_empty() { + // corners are filled - place anywhere + random_cell_placement(CellPlacementStrategy::Anywhere, &rng, grid, width, height) + } else { + // pick any of the available corners + let index = rng.gen_range(0..possibilities.len()); + possibilities.get(index).unwrap().to_owned().to_owned() + } + } + } +} + +fn is_stuck(xy: (isize, isize), width: usize, height: usize, grid: &Vec>) -> bool { + let (x, y) = xy; + if x - 1 >= 0 && grid[usize::try_from(x - 1).unwrap()][usize::try_from(y).unwrap()] { + return true; + } + + if x + 1 < width.try_into().unwrap() + && grid[usize::try_from(x + 1).unwrap()][usize::try_from(y).unwrap()] + { + return true; + } + + if y - 1 >= 0 && grid[usize::try_from(x).unwrap()][usize::try_from(y - 1).unwrap()] { + return true; + } + + if y + 1 < height.try_into().unwrap() + && grid[usize::try_from(x).unwrap()][usize::try_from(y + 1).unwrap()] + { + return true; + } + + return false; +}