diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index f346f66..b50b2b6 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -29,7 +29,7 @@ jobs: uses: cargo-bins/cargo-binstall@main - name: Install cargo check tools - run: cargo binstall --no-confirm cargo-deny cargo-outdated cargo-udeps cargo-audit || true + run: cargo binstall --no-confirm --force cargo-deny cargo-outdated cargo-udeps cargo-audit # remove advisory-db is required to fetch it correctly - name: Check diff --git a/.github/workflows/fmt.yaml b/.github/workflows/fmt.yaml new file mode 100644 index 0000000..923a6a3 --- /dev/null +++ b/.github/workflows/fmt.yaml @@ -0,0 +1,31 @@ +name: Fmt + +on: + pull_request: + branches: ["main"] + +env: + CARGO_TERM_COLOR: always + +jobs: + lint: + name: Fmt + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install Rust + uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + + - name: Install nasm + uses: ilammy/setup-nasm@v1 + + - uses: Swatinem/rust-cache@v2 + + - name: Lint + run: cargo fmt --all -- --check diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 50cf275..bb1b44d 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -20,7 +20,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - components: rustfmt, clippy + components: clippy - name: Install nasm uses: ilammy/setup-nasm@v1 @@ -28,6 +28,4 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Lint - run: | - cargo fmt --all -- --check - cargo clippy -- -D warnings + run: cargo clippy -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index 5b523e6..907076d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,74 +64,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" -[[package]] -name = "anyhow" -version = "1.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9" - -[[package]] -name = "arbitrary" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569" - -[[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 2.0.48", -] - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -dependencies = [ - "serde", -] - [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "av1-grain" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f6ca6f0c18c02c2fbfc119df551b8aeb8a385f6d5980f1475ba0255f1e97f1e" -dependencies = [ - "anyhow", - "arrayvec", - "itertools", - "log", - "nom", - "num-rational", - "serde", - "v_frame", -] - -[[package]] -name = "avif-serialize" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" -dependencies = [ - "arrayvec", -] - [[package]] name = "base64" -version = "0.21.5" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" [[package]] name = "bitflags" @@ -139,12 +82,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitstream-io" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e445576659fd04a57b44cbd00aa37aaa815ebefa0aa3cb677a6b5e63d883074f" - [[package]] name = "block-padding" version = "0.3.3" @@ -175,21 +112,6 @@ dependencies = [ "alloc-stdlib", ] -[[package]] -name = "built" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9c056b9ed43aee5e064b683aa1ec783e19c6acec7559e3ae931b7490472fbe" -dependencies = [ - "cargo-lock", -] - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - [[package]] name = "bytemuck" version = "1.14.0" @@ -202,18 +124,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "cargo-lock" -version = "8.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996" -dependencies = [ - "semver", - "serde", - "toml 0.5.11", - "url", -] - [[package]] name = "cbc" version = "0.1.2" @@ -233,16 +143,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cfg-expr" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -261,9 +161,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.13" +version = "4.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642" +checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2" dependencies = [ "clap_builder", "clap_derive", @@ -281,9 +181,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.12" +version = "4.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" +checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370" dependencies = [ "anstyle", "clap_lex", @@ -395,34 +295,28 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.17" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crypto-common" @@ -565,12 +459,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "hashbrown" version = "0.14.3" @@ -614,22 +502,11 @@ dependencies = [ "bytemuck", "byteorder", "color_quant", - "jpeg-decoder", "num-rational", "num-traits", "png", - "ravif", - "rgb", - "tiff", - "webp", ] -[[package]] -name = "imgref" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90d944e334f00f4449c9640b440a171f816be0152305c12ef90424fc35fd035c" - [[package]] name = "indexmap" version = "2.1.0" @@ -672,26 +549,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "interpolate_name" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.10" @@ -707,15 +564,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" -dependencies = [ - "rayon", -] - [[package]] name = "lazy-regex" version = "3.1.0" @@ -747,9 +595,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libflate" @@ -771,26 +619,6 @@ dependencies = [ "rle-decode-fast", ] -[[package]] -name = "libfuzzer-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf184a4b6b274f82a5df6b357da6055d3e82272327bba281c28bbba6f1664ef" -dependencies = [ - "arbitrary", - "cc", -] - -[[package]] -name = "libwebp-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0df0a0f9444d52aee6335cd724d21a2ee3285f646291799a72be518ec8ee3c" -dependencies = [ - "cc", - "glob", -] - [[package]] name = "link-cplusplus" version = "1.0.9" @@ -815,15 +643,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "loop9" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a837f917de41d61ab531ba255d1913208d02325cab0d6a66a706e0dbaa699d" -dependencies = [ - "imgref", -] - [[package]] name = "lz4_flex" version = "0.10.0" @@ -843,28 +662,12 @@ dependencies = [ "crc", ] -[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" -[[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.1" @@ -918,7 +721,7 @@ dependencies = [ "lazy-regex", "log", "mltd-utils", - "num-derive 0.4.1", + "num-derive", "num-traits", "num_cpus", "rabex", @@ -953,59 +756,6 @@ dependencies = [ "ureq", ] -[[package]] -name = "nasm-rs" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4d98d0065f4b1daf164b3eafb11974c94662e5e2396cf03f32d0bb5c17da51" -dependencies = [ - "rayon", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "num-derive" version = "0.4.1" @@ -1034,7 +784,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", - "num-bigint", "num-integer", "num-traits", ] @@ -1109,12 +858,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pkg-config" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" - [[package]] name = "png" version = "0.17.10" @@ -1147,7 +890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit 0.19.15", + "toml_edit", ] [[package]] @@ -1159,31 +902,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "profiling" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135ede8821cf6376eb7a64148901e1690b788c11ae94dc297ae917dbc91dc0e" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b322d7d65c1ab449be3c890fcbd0db6e1092d0dd05d79dba2dd28032cebeb05" -dependencies = [ - "quote", - "syn 2.0.48", -] - -[[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.35" @@ -1256,59 +974,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "rav1e" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c383692a5e7abd9f6d1eddb1a5e0269f859392387883361bb09e5555852ec1" -dependencies = [ - "arbitrary", - "arg_enum_proc_macro", - "arrayvec", - "av1-grain", - "bitstream-io", - "built", - "cc", - "cfg-if", - "interpolate_name", - "itertools", - "libc", - "libfuzzer-sys", - "log", - "maybe-rayon", - "nasm-rs", - "new_debug_unreachable", - "noop_proc_macro", - "num-derive 0.3.3", - "num-traits", - "once_cell", - "paste", - "rand", - "rand_chacha", - "rust_hawktracer", - "rustc_version", - "simd_helpers", - "system-deps", - "thiserror", - "v_frame", - "wasm-bindgen", -] - -[[package]] -name = "ravif" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badc69028460108fa7e32d4aec2b0c980710d7a31a896864002c8c1fc61516ee" -dependencies = [ - "avif-serialize", - "imgref", - "loop9", - "quick-error", - "rav1e", - "rayon", - "rgb", -] - [[package]] name = "rayon" version = "1.8.0" @@ -1358,15 +1023,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" -[[package]] -name = "rgb" -version = "0.8.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" -dependencies = [ - "bytemuck", -] - [[package]] name = "ring" version = "0.17.7" @@ -1409,37 +1065,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rust_hawktracer" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3480a29b927f66c6e06527be7f49ef4d291a01d694ec1fe85b0de71d6b02ac1" -dependencies = [ - "rust_hawktracer_normal_macro", - "rust_hawktracer_proc_macro", -] - -[[package]] -name = "rust_hawktracer_normal_macro" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a570059949e1dcdc6f35228fa389f54c2c84dfe0c94c05022baacd56eacd2e9" - -[[package]] -name = "rust_hawktracer_proc_macro" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb626abdbed5e93f031baae60d72032f56bc964e11ac2ff65f2ba3ed98d6d3e1" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustls" version = "0.21.10" @@ -1537,15 +1162,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" -dependencies = [ - "serde", -] - [[package]] name = "serde" version = "1.0.195" @@ -1577,15 +1193,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - [[package]] name = "serde_yaml" version = "0.9.30" @@ -1605,21 +1212,6 @@ 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.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - [[package]] name = "spin" version = "0.9.8" @@ -1654,25 +1246,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "system-deps" -version = "6.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml 0.8.8", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.12.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" - [[package]] name = "termcolor" version = "1.4.0" @@ -1691,37 +1264,6 @@ dependencies = [ "paste", ] -[[package]] -name = "thiserror" -version = "1.0.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "tiff" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -1737,35 +1279,11 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.21.0", -] - [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] [[package]] name = "toml_edit" @@ -1778,19 +1296,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "toml_edit" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - [[package]] name = "twox-hash" version = "1.6.3" @@ -1876,25 +1381,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "v_frame" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c372e4e6fad129795fb86fda6021b258948560b39883b80ed00510a7d19846b0" -dependencies = [ - "cfg-if", - "noop_proc_macro", - "num-derive 0.4.1", - "num-traits", - "profiling", -] - -[[package]] -name = "version-compare" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" - [[package]] name = "version_check" version = "0.9.4" @@ -1907,81 +1393,12 @@ 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.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" - -[[package]] -name = "webp" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb5d8e7814e92297b0e1c773ce43d290bef6c17452dafd9fc49e5edb5beba71" -dependencies = [ - "libwebp-sys", -] - [[package]] name = "webpki-roots" version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" -[[package]] -name = "weezl" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" - [[package]] name = "winapi" version = "0.3.9" @@ -2213,9 +1630,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.32" +version = "0.5.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6" +checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 455368d..d919435 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ serde = "1.0.195" [workspace.dependencies.clap] default-features = false features = ["std", "help", "usage"] -version = "4.4.13" +version = "4.4.14" [workspace.dependencies.env_logger] default-features = false diff --git a/README.ko-KR.md b/README.ko-KR.md deleted file mode 100644 index 581e907..0000000 --- a/README.ko-KR.md +++ /dev/null @@ -1,57 +0,0 @@ -# 밀리시타-에셋-다운로더 - -[![GitHub Check Status](https://img.shields.io/github/actions/workflow/status/nicks96432/mltd-asset-downloader/check.yaml?label=Check)](https://github.com/nicks96432/mltd-asset-downloader/actions/workflows/check.yaml) -[![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/nicks96432/mltd-asset-downloader/build.yaml)](https://github.com/nicks96432/mltd-asset-downloader/actions/workflows/build.yaml) -![GitHub Repo stars](https://img.shields.io/github/stars/nicks96432/mltd-asset-downloader) -![GitHub top language](https://img.shields.io/github/languages/top/nicks96432/mltd-asset-downloader) -[![License](https://img.shields.io/github/license/nicks96432/mltd-asset-downloader)](LICENSE) - -[English](README.md) | [繁體中文](README.zh-TW.md) | 한국어 - -러스트 기반 THE iDOLM@STER® MILLION LIVE! THEATER DAYS (MLTD) 에셋 다운로더. - -## 사용법 - -```console -$ ./mltd --help -THE iDOLM@STER® MILLION LIVE! THEATER DAYS (MLTD) 에셋 다운로더 - -Usage: mltd [OPTIONS] - -Commands: - download Download assets from MLTD asset server - extract Extract media from MLTD assets - manifest Download asset manifest from MLTD asset server - help Print this message or the help of the given subcommand(s) - -Options: - -v, --verbose... More output per occurrence - -q, --quiet... Less output per occurrence - -h, --help Print help - -V, --version Print version -``` - -## 빌드 - -The following is required: - -* A rust toolchain. -* cmake >= 3.2 (for libcgss) -* MSVC v142 or newer version. (Windows) -* ... or any compiler that supports C++14. (gnu environment) - -```shell -cargo build --release -``` - -## Disclaimer - -None of the repo, the tool, nor the repo owner is affiliated with, or sponsored or authorized by -Bandai Namco Entertainment and Unity Technologies, nor their affiliates or subsidiaries. - -## 라이센스 - -Licensed under [MIT](LICENSE). - -The copyright of anything that downloaded or extracted from this program belongs to -Bandai Namco Entertainment. diff --git a/README.md b/README.md index e937aad..a08ebaf 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,15 @@ ![GitHub top language](https://img.shields.io/github/languages/top/nicks96432/mltd-asset-downloader) [![License](https://img.shields.io/github/license/nicks96432/mltd-asset-downloader)](LICENSE) -English | [繁體中文](README.zh-TW.md) | [한국어](README.ko-KR.md) +English | [繁體中文](README.zh-TW.md) Game asset downloader for THE iDOLM@STER® MILLION LIVE! THEATER DAYS (MLTD), written in Rust. ## Usage +> [!NOTE] +> ffmpeg executable is required to be in `$PATH` for asset conversion. + ```console $ ./mltd --help A CLI made for assets in THE iDOLM@STER® MILLION LIVE! THEATER DAYS (MLTD) diff --git a/README.zh-TW.md b/README.zh-TW.md index 065d2f3..5399f01 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -6,12 +6,15 @@ ![GitHub top language](https://img.shields.io/github/languages/top/nicks96432/mltd-asset-downloader) [![License](https://img.shields.io/github/license/nicks96432/mltd-asset-downloader)](LICENSE) -[English](README.md) | 繁體中文 | [한국어](README.ko-KR.md) +[English](README.md) | 繁體中文 用Rust寫的偶像大師 百萬人演唱會! 劇場時光 (MLTD) 遊戲資源下載器 ## 用法 +> [!NOTE] +> 若要轉換資源格式,ffmpeg必須要在`$PATH`中。 + ```console $ ./mltd --help 偶像大師 百萬人演唱會! 劇場時光 (MLTD) 遊戲資源下載器 diff --git a/cli/src/main.rs b/cli/src/main.rs index e0bde69..def8b38 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,4 +1,6 @@ -use clap::Parser; +use clap::{Parser, Subcommand}; +use clap_verbosity_flag::{InfoLevel, Verbosity}; + use mltd_utils::log_formatter; #[cfg(feature = "download")] @@ -18,10 +20,10 @@ struct Cli { command: Command, #[command(flatten)] - verbose: clap_verbosity_flag::Verbosity, + verbose: Verbosity, } -#[derive(clap::Subcommand)] +#[derive(Subcommand)] enum Command { #[cfg(feature = "download")] /// Download assets from MLTD asset server diff --git a/codemagic.yaml b/codemagic.yaml index 0ffc7a9..d67262d 100644 --- a/codemagic.yaml +++ b/codemagic.yaml @@ -26,4 +26,4 @@ workflows: - $HOME/.cargo/registry/index/ - $HOME/.cargo/registry/cache/ - $HOME/.cargo/git/db/ - - target/ + - target/ diff --git a/extract/Cargo.toml b/extract/Cargo.toml index 23f8866..db94ac5 100644 --- a/extract/Cargo.toml +++ b/extract/Cargo.toml @@ -31,16 +31,7 @@ workspace = true # For image encoding [dependencies.image] -features = [ - "avif-encoder", - "bmp", - "jpeg", - "jpeg_rayon", - "png", - "tiff", - "webp", - "webp-encoder", -] +features = ["png"] default-features = false version = "0.24.7" diff --git a/extract/src/class/acb.rs b/extract/src/class/acb.rs deleted file mode 100644 index ee465b8..0000000 --- a/extract/src/class/acb.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::error::Error; -use std::fs::File; -use std::io::Cursor; -use std::io::Write; -use std::mem::size_of_val; -use std::path::Path; -use std::slice::from_raw_parts; - -use byteorder::BigEndian; -use byteorder::ByteOrder; -use byteorder::LittleEndian; -use rabex::{files::SerializedFile, read_ext::ReadUrexExt}; - -use crate::utils::ReadAlignedExt; -use crate::ExtractorArgs; - -pub fn _extract_acb( - data: &[u8], - output_dir: P, - _args: &ExtractorArgs, -) -> Result<(), Box> -where - P: AsRef, - E: ByteOrder, -{ - let mut reader = Cursor::new(data); - reader.read_aligned_string::()?; - - let data = reader.read_bytes::()?; - - // assert that there is only one track in an ACB file - let track = acb::to_tracks(&data)?.swap_remove(0); - - // TODO: Add option to specify output format - let path = output_dir.as_ref().join(Path::new(&track.name).with_extension("wav")); - let mut file = File::create(&path)?; - - log::info!("writing audio to {}", path.display()); - file.write_all(&track.data)?; - - Ok(()) -} - -pub fn extract_acb

( - data: &[u8], - output_dir: P, - args: &ExtractorArgs, - serialized_file: &SerializedFile, -) -> Result<(), Box> -where - P: AsRef, -{ - let big_endian = unsafe { - from_raw_parts( - (&serialized_file.m_Header as *const _) as *const u8, - size_of_val(&serialized_file.m_Header), - ) - }[0x20] - > 0; - - match big_endian { - true => _extract_acb::<_, BigEndian>(data, output_dir, args), - false => _extract_acb::<_, LittleEndian>(data, output_dir, args), - } -} diff --git a/extract/src/class/mod.rs b/extract/src/class/mod.rs index 2fd575b..e9b2d98 100644 --- a/extract/src/class/mod.rs +++ b/extract/src/class/mod.rs @@ -1,8 +1,8 @@ -//! This module contains methods for extracting Unity objects, because +//! This module contains methods for extracting Unity objects, which //! rabex doesn't provide any yet. -pub mod acb; pub mod asset_bundle; pub mod mesh; pub mod sprite; +pub mod text_asset; pub mod texture_2d; diff --git a/extract/src/class/text_asset.rs b/extract/src/class/text_asset.rs new file mode 100644 index 0000000..9b680a0 --- /dev/null +++ b/extract/src/class/text_asset.rs @@ -0,0 +1,82 @@ +use std::error::Error; +use std::fs::write; +use std::io::Cursor; +use std::mem::size_of_val; +use std::path::Path; +use std::slice::from_raw_parts; +use std::str::FromStr; + +use byteorder::BigEndian; +use byteorder::ByteOrder; +use byteorder::LittleEndian; +use rabex::files::SerializedFile; +use rabex::objects::classes::TextAsset; +use rabex::read_ext::ReadUrexExt; + +use crate::utils::ffmpeg; +use crate::utils::ReadAlignedExt; +use crate::version::*; +use crate::ExtractorArgs; + +pub fn _construct_text_asset( + data: &[u8], + serialized_file: &SerializedFile, +) -> Result> +where + E: ByteOrder, +{ + let mut reader = Cursor::new(data); + let unity_version = Version::from_str(serialized_file.m_UnityVersion.as_ref().unwrap())?; + + Ok(TextAsset { + m_Name: reader.read_aligned_string::()?, + m_PathName: match UNITY_VERSION_3_4_0 <= unity_version + && unity_version <= UNITY_VERSION_2017_1_0_B1 + { + true => Some(reader.read_aligned_string::()?), + false => None, + }, + m_Script: unsafe { String::from_utf8_unchecked(reader.read_bytes::()?) }, + }) +} + +pub fn construct_text_asset( + data: &[u8], + serialized_file: &SerializedFile, +) -> Result> { + let big_endian = unsafe { + from_raw_parts( + (&serialized_file.m_Header as *const _) as *const u8, + size_of_val(&serialized_file.m_Header), + ) + }[0x20] + > 0; + + match big_endian { + true => _construct_text_asset::(data, serialized_file), + false => _construct_text_asset::(data, serialized_file), + } +} + +pub fn extract_acb

( + data: &[u8], + output_dir: P, + args: &ExtractorArgs, + serialized_file: &SerializedFile, +) -> Result<(), Box> +where + P: AsRef, +{ + let text_asset = construct_text_asset(data, serialized_file)?; + let wav = acb::to_tracks(text_asset.m_Script.as_bytes())?.swap_remove(0); + let output_path = output_dir.as_ref().join(text_asset.m_Name).with_extension(&args.audio_ext); + + log::info!("writing audio to: {}", output_path.display()); + + if args.audio_ext == "wav" && args.audio_args.is_empty() { + write(&output_path, wav.data)?; + return Ok(()); + } + + ffmpeg(&wav.data, num_cpus::get() / args.parallel, &args.audio_args, output_path) +} diff --git a/extract/src/class/texture_2d.rs b/extract/src/class/texture_2d.rs index 0db2460..32aafb0 100644 --- a/extract/src/class/texture_2d.rs +++ b/extract/src/class/texture_2d.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::error::Error; +use std::fs::File; use std::io::Cursor; use std::mem::size_of_val; use std::path::Path; @@ -7,7 +8,9 @@ use std::slice::from_raw_parts; use std::str::FromStr; use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt}; +use image::codecs::png::PngEncoder; use image::{DynamicImage, GrayImage, RgbaImage}; +use num_derive::FromPrimitive; use num_traits::FromPrimitive; use rabex::files::SerializedFile; use rabex::objects::classes::{GLTextureSettings, StreamingInfo, Texture2D}; @@ -16,7 +19,7 @@ use rabex::read_ext::{ReadSeekUrexExt, ReadUrexExt}; use crate::class::sprite::construct_sprite; use crate::environment::Environment; -use crate::utils::{solve_puzzle, write_buffer_with_format, ReadAlignedExt}; +use crate::utils::{ffmpeg, solve_puzzle, ReadAlignedExt}; use crate::{version::*, ExtractorArgs}; fn _construct_texture_2d( @@ -218,7 +221,7 @@ pub fn construct_texture_2d( } /// Format used when creating textures from scripts. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, num_derive::FromPrimitive)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromPrimitive)] pub enum TextureFormat { /// Alpha-only texture format, 8 bit integer. /// @@ -752,6 +755,7 @@ where if resource.is_none() { return Err("Texture2D stream data not found in resources".into()); } + let resource = resource.unwrap(); let img = decode_texture( resource, @@ -788,9 +792,19 @@ where true => texture.m_Name.to_owned(), false => format!("{}_{}", texture.m_Name, i), }) - .with_extension(args.image_format.extensions_str()[0]); + .with_extension(&args.image_ext); + + log::info!("writing image to {}", output_path.display()); + + if args.image_ext == "png" && args.image_args.is_empty() { + img.write_with_encoder(PngEncoder::new(File::create(output_path)?))?; + return Ok(()); + } + + let mut buf = Vec::new(); + img.write_with_encoder(PngEncoder::new(Cursor::new(&mut buf)))?; - write_buffer_with_format(img, &output_path, &args.image_format, args.image_quality)?; + ffmpeg(&buf, num_cpus::get() / args.parallel, &args.image_args, output_path)?; } Ok(()) } diff --git a/extract/src/lib.rs b/extract/src/lib.rs index be28df6..af5b0f6 100644 --- a/extract/src/lib.rs +++ b/extract/src/lib.rs @@ -9,19 +9,18 @@ use std::io::{Cursor, Seek, SeekFrom}; use std::path::{Path, PathBuf}; use std::process::exit; +use clap::Args; use environment::Environment; -use image::ImageFormat; use rabex::config::ExtractionConfig; use rabex::files::{BundleFile, SerializedFile}; use rabex::objects::map; -use utils::MyImageFormat; -use crate::class::acb::extract_acb; use crate::class::asset_bundle::construct_asset_bundle; +use crate::class::text_asset::extract_acb; use crate::class::texture_2d::extract_texture_2d; use crate::environment::{check_file_type, FileType}; -#[derive(Debug, clap::Args)] +#[derive(Debug, Args)] #[command(author, version, about, arg_required_else_help(true))] pub struct ExtractorArgs { /// The input directory or file @@ -29,30 +28,35 @@ pub struct ExtractorArgs { input: PathBuf, /// The output directory - #[arg(short, long, value_name = "DIR", default_value_os_t = [".", "output"].iter().collect())] + #[arg(short, long, value_name = "DIR", display_order = 1)] + #[arg(default_value_os_t = [".", "output"].iter().collect())] output: PathBuf, - /// The number of threads to use - #[arg(short = 'P', long, value_name = "CPUS", default_value_t = num_cpus::get())] - parallel: usize, + /// Extension for audio output + #[arg(long, value_name = "EXT", display_order = 2)] + #[arg(default_value_t = String::from("wav"))] + audio_ext: String, - /// image output format - #[arg(long, value_name = "FORMAT", value_enum, default_value_t = MyImageFormat(ImageFormat::WebP))] - image_format: MyImageFormat, + /// Arguments to pass to ffmpeg for audio output + #[arg(long, value_name = "ARGS", display_order = 2, hide_default_value = true)] + #[arg(default_value_t = String::from(""))] + audio_args: String, - /// image output quality - #[arg(long, value_name = "QUALITY", default_value_t = 100, value_parser = number_range)] - image_quality: u8, - // TODO: Add option to extract only specific files -} + /// Extension for image output + #[arg(long, value_name = "EXT", display_order = 2)] + #[arg(default_value_t = String::from("png"))] + image_ext: String, -fn number_range(s: &str) -> Result { - let n = s.parse::().map_err(|e| e.to_string())?; - if !(0..=100).contains(&n) { - return Err(format!("{} is out of range [0, 100]", n)); - } + /// Arguments to pass to ffmpeg for image output + #[arg(long, value_name = "ARGS", display_order = 2, hide_default_value = true)] + #[arg(default_value_t = String::from(""))] + image_args: String, - Ok(n as u8) + /// The number of threads to use + #[arg(short = 'P', long, value_name = "CPUS", display_order = 2)] + #[arg(default_value_t = num_cpus::get())] + parallel: usize, + // TODO: Add option to extract only specific files } pub fn extract_media(args: &ExtractorArgs) -> Result<(), Box> { @@ -104,7 +108,7 @@ where let data = env.get_cab(&dir_info.path).unwrap(); let file_type = check_file_type(&mut Cursor::new(data))?; - log::debug!("file type: {:?}, size: {}", file_type, data.len()); + log::debug!("file type: {:?}, size: {}", file_type, data.len()); if file_type != FileType::AssetsFile { continue; @@ -159,20 +163,11 @@ fn extract_object( for (i, object_info) in serialized_file.m_Objects.iter().enumerate() { log::debug!("extracting object: {} ({})", i, map::CLASS_ID_NAME[&object_info.m_ClassID]); + let data = env.get_object(object_info.m_PathID).unwrap(); + match object_info.m_ClassID { - map::TextAsset => extract_acb( - env.get_object(object_info.m_PathID).unwrap(), - &output_dir, - args, - serialized_file, - )?, - map::Texture2D => extract_texture_2d( - env.get_object(object_info.m_PathID).unwrap(), - &output_dir, - args, - serialized_file, - env, - )?, + map::TextAsset => extract_acb(data, &output_dir, args, serialized_file)?, + map::Texture2D => extract_texture_2d(data, &output_dir, args, serialized_file, env)?, map::AssetBundle => { // this class contains some information about the bundle } diff --git a/extract/src/utils/image.rs b/extract/src/utils/image.rs deleted file mode 100644 index 5e9089c..0000000 --- a/extract/src/utils/image.rs +++ /dev/null @@ -1,109 +0,0 @@ -use std::error::Error; -use std::fs::File; -use std::ops::Deref; -use std::path::Path; -use std::str::FromStr; - -use clap::builder::PossibleValue; -use clap::ValueEnum; -use image::codecs::avif::{AvifEncoder, ColorSpace}; -use image::codecs::bmp::BmpEncoder; -use image::codecs::jpeg::JpegEncoder; -use image::codecs::png::{CompressionType, FilterType, PngEncoder}; -use image::codecs::tiff::TiffEncoder; -use image::codecs::webp::{WebPEncoder, WebPQuality}; -use image::{DynamicImage, ImageFormat}; - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub struct MyImageFormat(pub ImageFormat); - -impl FromStr for MyImageFormat { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(Self( - ImageFormat::from_extension(s).ok_or(format!("unsupported image format: {}", s))?, - )) - } -} - -impl Deref for MyImageFormat { - type Target = ImageFormat; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl ValueEnum for MyImageFormat { - fn from_str(input: &str, ignore_case: bool) -> Result::Err> { - match ignore_case { - true => FromStr::from_str(input.to_ascii_lowercase().as_str()), - false => FromStr::from_str(input), - } - } - - fn value_variants<'a>() -> &'a [Self] { - &[ - Self(ImageFormat::Avif), - Self(ImageFormat::Bmp), - Self(ImageFormat::Jpeg), - Self(ImageFormat::Png), - Self(ImageFormat::Tiff), - Self(ImageFormat::WebP), - ] - } - - fn to_possible_value(&self) -> Option { - match self.0 { - ImageFormat::Avif => Some(PossibleValue::new("avif")), - ImageFormat::Bmp => Some(PossibleValue::new("bmp")), - ImageFormat::Jpeg => Some(PossibleValue::new("jpeg")), - ImageFormat::Png => Some(PossibleValue::new("png")), - ImageFormat::Tiff => Some(PossibleValue::new("tiff")), - ImageFormat::WebP => Some(PossibleValue::new("webp")), - _ => None, - } - } -} - -pub fn write_buffer_with_format

( - image: &DynamicImage, - path: P, - format: &ImageFormat, - quality: u8, -) -> Result<(), Box> -where - P: AsRef, -{ - let mut f = File::create(&path)?; - log::info!("writing image to {}", path.as_ref().display()); - - match format { - ImageFormat::Avif => { - image.write_with_encoder( - AvifEncoder::new_with_speed_quality(f, 5, quality) - .with_colorspace(ColorSpace::Srgb) - .with_num_threads(Some(1)), - )?; - } - ImageFormat::Bmp => image.write_with_encoder(BmpEncoder::new(&mut f))?, - ImageFormat::Jpeg => image.write_with_encoder(JpegEncoder::new_with_quality(f, quality))?, - ImageFormat::Png => image.write_with_encoder(PngEncoder::new_with_quality( - f, - CompressionType::Best, - FilterType::Adaptive, - ))?, - ImageFormat::Tiff => image.write_with_encoder(TiffEncoder::new(f))?, - ImageFormat::WebP => image.write_with_encoder(WebPEncoder::new_with_quality( - f, - match quality { - 100 => WebPQuality::lossless(), - _ => WebPQuality::lossy(quality), - }, - ))?, - _ => return Err(format!("unsupported image format: {:?}", format).into()), - }; - - Ok(()) -} diff --git a/extract/src/utils/mod.rs b/extract/src/utils/mod.rs index eca44b1..c930685 100644 --- a/extract/src/utils/mod.rs +++ b/extract/src/utils/mod.rs @@ -1,7 +1,47 @@ -mod image; mod puzzle; mod read_ext; -pub use self::image::*; +use std::error::Error; +use std::io::Write; +use std::path::Path; +use std::process::Command; +use std::process::Stdio; + pub use self::puzzle::*; pub use self::read_ext::*; + +pub fn ffmpeg

( + input: &[u8], + threads: usize, + args: &str, + output_path: P, +) -> Result<(), Box> +where + P: AsRef, +{ + #[rustfmt::skip] + let ffmpeg_args = [ + "-hide_banner", + "-threads", &threads.to_string(), + "-i", "-", + "-y", + ]; + + let ffmpeg_args = ffmpeg_args.into_iter().chain(args.split_ascii_whitespace()); + + let mut ffmpeg = Command::new("ffmpeg") + .args(ffmpeg_args) + .arg(output_path.as_ref()) + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn()?; + + let mut stdin = ffmpeg.stdin.take().unwrap(); + stdin.write_all(input)?; + drop(stdin); + + ffmpeg.wait()?; + + Ok(()) +}