From a0ad59237408ec256f0198eab4cb807123a44bd3 Mon Sep 17 00:00:00 2001 From: aria Date: Mon, 7 Jul 2025 23:16:13 +1000 Subject: [PATCH] feat(main): very early version of image output --- Cargo.lock | 984 +++++++++++++++++++++++++++++++++- Cargo.toml | 3 + font/Minecraft-Bold.ttf | Bin 0 -> 12668 bytes font/Minecraft-BoldItalic.ttf | Bin 0 -> 13908 bytes font/Minecraft-Italic.ttf | Bin 0 -> 15452 bytes font/Minecraft-Regular.ttf | Bin 0 -> 14004 bytes src/main.rs | 126 ++++- 7 files changed, 1092 insertions(+), 21 deletions(-) create mode 100644 font/Minecraft-Bold.ttf create mode 100644 font/Minecraft-BoldItalic.ttf create mode 100644 font/Minecraft-Italic.ttf create mode 100644 font/Minecraft-Regular.ttf diff --git a/Cargo.lock b/Cargo.lock index 5f1b76f..d4cf8dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,28 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ab_glyph" +version = "0.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f4f6fbdc5ee39f2ede9f5f3ec79477271a6d6a2baff22310d51736bda6cea" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169" + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -11,6 +33,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "anstream" version = "0.6.19" @@ -67,18 +98,136 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "av1-grain" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ea8ef51aced2b9191c08197f55450d830876d9933f8f48a429b354f1d496b42" +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 = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" + +[[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.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -125,6 +274,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[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.4" @@ -157,6 +312,15 @@ dependencies = [ "windows-sys 0.60.2", ] +[[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.6" @@ -182,6 +346,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "csv" version = "1.3.1" @@ -228,6 +398,32 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.13" @@ -238,12 +434,59 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + [[package]] name = "getrandom" version = "0.3.3" @@ -253,15 +496,108 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi", + "wasi 0.14.2+wasi-0.2.4", ] +[[package]] +name = "gif" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imageproc" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2393fb7808960751a52e8a154f67e7dd3f8a2ef9bd80d1553078a7b4e8ed3f0d" +dependencies = [ + "ab_glyph", + "approx", + "getrandom 0.2.16", + "image", + "itertools", + "nalgebra", + "num", + "rand", + "rand_distr", + "rayon", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "indicatif" version = "0.18.0" @@ -275,18 +611,54 @@ dependencies = [ "web-time", ] +[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[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.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + [[package]] name = "js-sys" version = "0.3.77" @@ -297,12 +669,34 @@ dependencies = [ "wasm-bindgen", ] +[[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.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -315,15 +709,47 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[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 = "mc-chat-export" version = "0.1.0" dependencies = [ + "ab_glyph", "anyhow", "clap", "console 0.16.0", "csv", "dialoguer", + "image", + "imageproc", "indicatif", "once_cell", "rayon", @@ -336,6 +762,144 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[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.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "nalgebra" +version = "0.32.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" +dependencies = [ + "approx", + "matrixmultiply", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[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" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "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-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "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", + "libm", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -348,12 +912,55 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "owned_ttf_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +dependencies = [ + "ttf-parser", +] + +[[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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "portable-atomic" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -363,6 +970,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +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.40" @@ -378,6 +1019,102 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[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", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] + +[[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", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.10.0" @@ -427,25 +1164,46 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rgb" +version = "0.8.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a457e416a0f90d246a4c3288bd7a25b2304ca727f253f95be383dd17af56be8f" + [[package]] name = "rustix" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "serde" version = "1.0.219" @@ -466,12 +1224,61 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "shell-words" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[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.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "strsim" version = "0.11.1" @@ -489,6 +1296,25 @@ dependencies = [ "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.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "tempfile" version = "3.20.0" @@ -496,7 +1322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -522,6 +1348,63 @@ dependencies = [ "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.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -546,6 +1429,29 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +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.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasi" version = "0.14.2+wasi-0.2.4" @@ -563,6 +1469,7 @@ checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] @@ -622,6 +1529,22 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + +[[package]] +name = "wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -768,13 +1691,42 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags", + "bitflags 2.9.1", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -782,3 +1734,27 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9e525af0a6a658e031e95f14b7f889976b74a11ba0eca5a5fc9ac8a1c43a6a" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index caa0b33..2c353bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,14 @@ version = "0.1.0" edition = "2024" [dependencies] +ab_glyph = "0.2.30" anyhow = "1.0.98" clap = { version = "4.5.40", features = ["derive"] } console = "0.16.0" csv = "1.3.1" dialoguer = "0.11.0" +image = "0.25.6" +imageproc = "0.25.0" indicatif = "0.18.0" once_cell = "1.21.3" rayon = "1.10.0" diff --git a/font/Minecraft-Bold.ttf b/font/Minecraft-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d4d85b20cd0a3fb811991d1865c514865209cb41 GIT binary patch literal 12668 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 literal 0 HcmV?d00001 diff --git a/font/Minecraft-Regular.ttf b/font/Minecraft-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f9a16f09164ee790fc39678b5295ed44fa712713 GIT binary patch literal 14004 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 Result<()> { .interact()?; match &args.format { - OutputFormat::Image => todo!(), + OutputFormat::Image => save_image_file(&args.output, extracted, selection)?, OutputFormat::CSV => save_csv_file(&args.output, extracted, selection)?, OutputFormat::TXT => save_txt_file(&args.output, extracted, selection)?, } @@ -97,16 +101,88 @@ fn main() -> Result<()> { Ok(()) } +fn save_image_file( + output: &String, + extracted: Vec, + selection: Vec, +) -> Result<(), Error> { + let out_path = Path::new(output); + + let font = FontRef::try_from_slice(include_bytes!("../font/Minecraft-Regular.ttf")).unwrap(); + + let height = 40.0; + let scale = PxScale { + x: height * 2.0, + y: height, + }; + + let mut selected: Vec = vec![]; + + if selection.is_empty() { + selected = extracted; + } else { + for x in selection { + selected.push(extracted[x].clone()); + } + } + + let mut longest: String = selected.first().expect("selected list is empty?").clone(); + + for msg in &selected { + if msg.len() > longest.len() { + longest = msg.clone(); + } + } + + // let text = extracted[selection[0]].clone(); + let (w, h) = text_size(scale, &font, &longest); + println!("Text size: {}x{}", w, h); + + let image_width = w + 8; + let image_height = (h * selected.len() as u32) + (4 * selected.len() as u32) + 4; + + let mut image = RgbImage::new(image_width, image_height); + + let mut current_line: u32 = 0; + + for msg in &selected { + draw_text_mut( + &mut image, + Rgb([254u8, 254u8, 254u8]), + 4, + ((current_line * h) + (4 * current_line)) + .try_into() + .unwrap(), + scale, + &font, + &msg, + ); + current_line += 1; + } + + Ok(image.save(out_path).unwrap()) +} + fn save_txt_file( output: &String, extracted: Vec, selection: Vec, ) -> Result<(), Error> { let mut out_file = File::create(output)?; - Ok(for msg in selection { - out_file.write(extracted[msg].as_bytes())?; - out_file.write(b"\n")?; - }) + + if selection.is_empty() { + for msg in extracted { + out_file.write(msg.as_bytes())?; + out_file.write(b"\n")?; + } + } else { + for msg in selection { + out_file.write(extracted[msg].as_bytes())?; + out_file.write(b"\n")?; + } + } + + Ok(()) } fn save_csv_file( @@ -117,26 +193,42 @@ fn save_csv_file( let mut out_file = Writer::from_path(output)?; out_file.write_record(&["date", "time", "msg"])?; - Ok(for msg in selection { + let mut selected: Vec = vec![]; + + if selection.is_empty() { + selected = extracted; + } else { + for x in selection { + selected.push(extracted[x].clone()); + } + } + + for msg in selected { let time: Vec<&str> = EXTRACT_TIME - .captures(&extracted[msg]) + .captures(&msg) .expect("Unable to extract time") .get(0) .unwrap() .as_str() - .strip_prefix("[").expect("Unable to remove time prefix") - .strip_suffix("]").expect("Unable to remove time suffix") - .split(' ').collect(); + .strip_prefix("[") + .expect("Unable to remove time prefix") + .strip_suffix("]") + .expect("Unable to remove time suffix") + .split(' ') + .collect(); out_file.write_record(&[ time[0], time[1], EXTRACT_MSG - .captures(&extracted[msg]) - .expect("Unable to extract time") - .get(0) - .unwrap() - .as_str()])?; - }) + .captures(&msg) + .expect("Unable to extract time") + .get(0) + .unwrap() + .as_str(), + ])?; + } + + Ok(()) } fn is_possible_chat_msg(input: &str) -> bool {