From 3925f0370ff638174fcb500e9c358f9bed6d669a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mikrut?= <41945903+qarmin@users.noreply.github.com> Date: Sat, 5 Oct 2024 10:17:48 +0200 Subject: [PATCH] Avif + Jxl support, using native pixbuf loader vs rust to load gui preview, fast exit (#1358) --- .github/workflows/linux_cli.yml | 2 +- .github/workflows/linux_gui.yml | 4 +- .github/workflows/mac.yml | 2 +- .github/workflows/quality.yml | 4 +- .rustfmt.toml | 3 +- Cargo.lock | 477 +++++++++++++----- Cargo.toml | 5 + Changelog.md | 20 + ci_tester/src/main.rs | 11 + czkawka_cli/Cargo.toml | 1 + czkawka_cli/README.md | 12 +- czkawka_cli/src/main.rs | 5 +- czkawka_cli/src/progress.rs | 3 +- czkawka_core/Cargo.toml | 8 +- czkawka_core/src/bad_extensions.rs | 4 + czkawka_core/src/big_file.rs | 11 +- czkawka_core/src/broken_files.rs | 23 +- czkawka_core/src/common.rs | 130 ++--- czkawka_core/src/common_cache.rs | 18 +- czkawka_core/src/common_dir_traversal.rs | 8 +- czkawka_core/src/common_image.rs | 173 +++++++ czkawka_core/src/duplicate.rs | 60 ++- czkawka_core/src/lib.rs | 1 + czkawka_core/src/same_music.rs | 78 +-- czkawka_core/src/similar_images.rs | 105 +--- czkawka_core/src/similar_videos.rs | 6 +- czkawka_gui/Cargo.toml | 5 +- czkawka_gui/README.md | 29 +- czkawka_gui/i18n/en/czkawka_gui.ftl | 14 + czkawka_gui/src/compute_results.rs | 11 +- .../connect_things/connect_button_compare.rs | 52 +- .../connect_things/connect_button_hardlink.rs | 3 +- .../src/connect_things/connect_button_save.rs | 3 +- .../connect_things/connect_button_search.rs | 7 +- .../connect_duplicate_buttons.rs | 3 +- .../connect_things/connect_popovers_select.rs | 5 +- .../connect_things/connect_progress_window.rs | 4 +- .../connect_same_music_mode_changed.rs | 3 +- .../connect_selection_of_directories.rs | 5 +- .../src/connect_things/connect_settings.rs | 11 +- .../connect_similar_image_size_change.rs | 3 +- .../src/gui_structs/gui_bottom_buttons.rs | 3 +- czkawka_gui/src/gui_structs/gui_data.rs | 7 +- .../src/gui_structs/gui_main_notebook.rs | 9 +- czkawka_gui/src/gui_structs/gui_settings.rs | 6 + czkawka_gui/src/help_combo_box.rs | 3 +- czkawka_gui/src/help_functions.rs | 14 +- czkawka_gui/src/initialize_gui.rs | 54 +- czkawka_gui/src/main.rs | 11 +- czkawka_gui/src/saving_loading.rs | 31 +- czkawka_gui/ui/about_dialog.ui | 2 +- czkawka_gui/ui/compare_images.ui | 2 +- czkawka_gui/ui/czkawka.cmb | 326 ++++++------ czkawka_gui/ui/main_window.ui | 2 +- czkawka_gui/ui/popover_right_click.ui | 2 +- czkawka_gui/ui/popover_select.ui | 2 +- czkawka_gui/ui/popover_sort.ui | 2 +- czkawka_gui/ui/progress.ui | 2 +- czkawka_gui/ui/settings.ui | 9 +- justfile | 46 +- krokiet/Cargo.toml | 3 +- krokiet/src/common.rs | 3 +- krokiet/src/connect_delete.rs | 5 +- krokiet/src/connect_move.rs | 11 +- krokiet/src/connect_progress_receiver.rs | 4 +- krokiet/src/connect_scan.rs | 7 +- krokiet/src/connect_select.rs | 3 +- krokiet/src/connect_show_preview.rs | 40 +- krokiet/src/main.rs | 3 +- krokiet/src/model_operations.rs | 6 +- krokiet/src/set_initial_gui_info.rs | 3 +- krokiet/src/settings.rs | 9 +- 72 files changed, 1169 insertions(+), 793 deletions(-) create mode 100644 czkawka_core/src/common_image.rs diff --git a/.github/workflows/linux_cli.yml b/.github/workflows/linux_cli.yml index 3360f2847..2a60a4611 100644 --- a/.github/workflows/linux_cli.yml +++ b/.github/workflows/linux_cli.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v4 - name: Install basic libraries - run: sudo apt update || true; sudo apt install libheif-dev ffmpeg -y + run: sudo apt update || true; sudo apt install libheif-dev libraw-dev ffmpeg -y - name: Setup rust version run: rustup default ${{ matrix.toolchain }} diff --git a/.github/workflows/linux_gui.yml b/.github/workflows/linux_gui.yml index 89a228909..025cec24b 100644 --- a/.github/workflows/linux_gui.yml +++ b/.github/workflows/linux_gui.yml @@ -118,7 +118,7 @@ jobs: - uses: actions/checkout@v4 - name: Install Dependencies - run: sudo apt update || true; sudo apt install libgtk-4-dev libheif-dev librsvg2-dev wget fuse libfuse2 desktop-file-utils -y + run: sudo apt update || true; sudo apt install libgtk-4-dev libheif-dev libraw-dev librsvg2-dev wget fuse libfuse2 desktop-file-utils -y - name: Setup rust version run: rustup default ${{ matrix.toolchain }} @@ -186,7 +186,7 @@ jobs: - uses: actions/checkout@v4 - name: Install Dependencies - run: sudo apt update || true; sudo apt install libgtk-4-dev libheif-dev librsvg2-dev wget fuse libfuse2 -y xvfb + run: sudo apt update || true; sudo apt install libgtk-4-dev libheif-dev libraw-dev librsvg2-dev wget fuse libfuse2 -y xvfb - name: Setup rust version run: rustup default ${{ matrix.toolchain }} diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 90093c435..8858ca275 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -59,7 +59,7 @@ jobs: path: target/release/krokiet if: ${{ matrix.type == 'release' }} -# TODO - compilation is broken, not sure why +# # TODO - compilation is broken, not sure why # - name: Build Release Heif # run: cargo build --release --features heif # if: ${{ matrix.type == 'release'}} diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index c864a3afc..a18c80edf 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -10,12 +10,12 @@ env: jobs: quality: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Install Gtk 4 - run: sudo apt update || true; sudo apt install -y libgtk-4-dev libraw-dev libheif-dev -y + run: sudo apt update || true; sudo apt install -y libgtk-4-dev libraw-dev libheif-dev libavif-dev libdav1d-dev -y - name: Check the format run: cargo fmt --all -- --check diff --git a/.rustfmt.toml b/.rustfmt.toml index 62a8e231b..de1cf8c1e 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -3,4 +3,5 @@ max_width = 180 remove_nested_parens = true # Enable only with nightly channel via - cargo +nightly fmt -imports_granularity = "Module" \ No newline at end of file +imports_granularity = "Module" +group_imports = "StdExternalCrate" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d74acdbf5..4ad3752fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,7 +201,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -369,7 +369,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -404,7 +404,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -431,14 +431,28 @@ dependencies = [ "derive_utils", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "av-data" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "124ae24335161b3d2226594640a67903da0866e2591312591fc8ddad64c1b38c" +dependencies = [ + "byte-slice-cast", + "bytes", + "num-derive", + "num-rational", + "num-traits", + "thiserror", +] [[package]] name = "av1-grain" @@ -506,7 +520,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.77", + "syn 2.0.79", "which", ] @@ -528,6 +542,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitreader" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd859c9d97f7c468252795b35aeccc412bdbb1e90ee6969c4fa6328272eaeff" +dependencies = [ + "cfg-if", +] + [[package]] name = "bitstream-io" version = "2.5.3" @@ -630,6 +653,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "bytemuck" version = "1.18.0" @@ -647,7 +676,7 @@ checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -762,9 +791,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.21" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", @@ -875,9 +904,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -885,9 +914,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -904,7 +933,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1037,7 +1066,7 @@ checksum = "5387f5bbc9e9e6c96436ea125afa12614cebf8ac67f49abc08c1e7a891466c90" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1319,6 +1348,7 @@ dependencies = [ "imagepipe", "infer", "itertools 0.13.0", + "jxl-oxide", "libheif-rs", "libheif-sys", "libraw-rs", @@ -1460,6 +1490,38 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dav1d" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4b54a40baf633a71c6f0fb49494a7e4ee7bc26f3e727212b6cb915aa1ea1e1" +dependencies = [ + "av-data", + "bitflags 2.6.0", + "dav1d-sys", + "static_assertions", +] + +[[package]] +name = "dav1d-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ecb1c5e8f4dc438eedc1b534a54672fb0e0a56035dae6b50162787bd2c50e95" +dependencies = [ + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "dcv-color-primitives" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ad62edfed069700a5b33af6babd29c498d7e33eb01d96ffa8841ee1841634c" +dependencies = [ + "paste", + "wasm-bindgen", +] + [[package]] name = "deflate" version = "1.0.0" @@ -1486,7 +1548,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1499,7 +1561,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1510,7 +1572,7 @@ checksum = "65f152f4b8559c4da5d574bafc7af85454d706b4c5fe8b530d508cacbb6807ea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1559,7 +1621,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1687,7 +1749,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1698,7 +1760,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1769,6 +1831,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" +[[package]] +name = "fallible_collections" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88c69768c0a15262df21899142bc6df9b9b823546d4b4b9a7bc2d6c448ec6fd" +dependencies = [ + "hashbrown 0.13.2", +] + [[package]] name = "fastrand" version = "2.1.1" @@ -1882,9 +1953,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -2007,7 +2078,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2113,7 +2184,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2160,9 +2231,9 @@ dependencies = [ [[package]] name = "gbm-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd2d6bf7c0143b38beece05f9a5c4c851a49a8434f62bf58ff28da92b0ddc58" +checksum = "a9cc2f64de9fa707b5c6b2d2f10d7a7e49e845018a9f5685891eb40d3bab2538" dependencies = [ "libc", ] @@ -2194,9 +2265,9 @@ dependencies = [ [[package]] name = "gdk4" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b7d7237c1487ed4b300aac7744efcbf1319e12d60d7afcd6f505414bd5b5dea" +checksum = "c121aeeb0cf7545877ae615dac6bfd088b739d8abee4d55e7143b06927d16a31" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -2209,9 +2280,9 @@ dependencies = [ [[package]] name = "gdk4-sys" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67576c8ec012156d7f680e201a807b4432a77babb3157e0555e990ab6bcd878" +checksum = "7d3c03d1ea9d5199f14f060890fde68a3b5ec5699144773d1fa6abf337bfbc9c" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -2350,7 +2421,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2494,9 +2565,9 @@ dependencies = [ [[package]] name = "gsk4" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3cf2091e1af185b347b3450817d93dea6fe435df7abd4c2cd7fb5bcb4cfda8" +checksum = "aa21a2f7c51ee1c6cc1242c2faf3aae2b7566138f182696759987bde8219e922" dependencies = [ "cairo-rs", "gdk4", @@ -2509,9 +2580,9 @@ dependencies = [ [[package]] name = "gsk4-sys" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa69614a26d8760c186c3690f1b0fbb917572ca23ef83137445770ceddf8cde" +checksum = "0f9fb607554f9f4e8829eb7ea301b0fde051e1dbfd5d16b143a8a9c2fac6c01b" dependencies = [ "cairo-sys-rs", "gdk4-sys", @@ -2525,9 +2596,9 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fe572bf318e5dbc6f5a2f8a25d853f1ae3f42768c0b08af6ca20a18f4057e1" +checksum = "31e2d105ce672f5cdcb5af2602e91c2901e91c72da15ab76f613ad57ecf04c6d" dependencies = [ "cairo-rs", "field-offset", @@ -2553,14 +2624,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "gtk4-sys" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1114a207af8ada02cf4658a76692f4190f06f093380d5be07e3ca8b43aa7c666" +checksum = "cbe4325908b1c1642dbb48e9f49c07a73185babf43e8b2065b0f881a589f55b8" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -2610,6 +2681,15 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -2621,6 +2701,12 @@ dependencies = [ "rayon", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "heck" version = "0.4.1" @@ -2844,7 +2930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17c4f06e2ccbf6e7381abd64e8716767e97b5fdf15280decf8f08f8d58cde25c" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2968,7 +3054,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.77", + "syn 2.0.79", "unic-langid", ] @@ -2982,7 +3068,7 @@ dependencies = [ "i18n-config", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3051,9 +3137,12 @@ dependencies = [ "bytemuck", "byteorder-lite", "color_quant", + "dav1d", + "dcv-color-primitives", "exr", "gif", "image-webp", + "mp4parse", "num-traits", "png", "qoi", @@ -3132,12 +3221,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -3174,13 +3263,12 @@ dependencies = [ [[package]] name = "input" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7911ce3db9c10c5ab4a35c49af778a5f9a827bd0f7371d9be56175d8dd2740d0" +checksum = "fbdc09524a91f9cacd26f16734ff63d7dc650daffadd2b6f84d17a285bd875a9" dependencies = [ "bitflags 2.6.0", "input-sys", - "io-lifetimes", "libc", "log", "udev", @@ -3218,7 +3306,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3367,6 +3455,145 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jxl-bitstream" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5855ff16398ffbcf81fee52c41ca65326499c8764b21bb9952c367ace98995fb" +dependencies = [ + "tracing", +] + +[[package]] +name = "jxl-coding" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da5b5093904e940bc11ef50e872c7bdf7b6e88653f012b925f8479daf212b5c9" +dependencies = [ + "jxl-bitstream", + "tracing", +] + +[[package]] +name = "jxl-color" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97f0dd548fabf9c094f9f2304059c86764f606b9040c0bfcfac55f155f423b55" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-threadpool", + "tracing", +] + +[[package]] +name = "jxl-frame" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4719f285ebfff5e64f352d0ef149a5244aef4f8e6b5aa666ba6241e90b50632f" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-image", + "jxl-modular", + "jxl-threadpool", + "jxl-vardct", + "tracing", +] + +[[package]] +name = "jxl-grid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e941628e8de1dc6ba1d2bba8ebc68a69f8ff50cc7ddce5bc821658d1f4ea6e59" +dependencies = [ + "tracing", +] + +[[package]] +name = "jxl-image" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3824c81613c05c19a9e4329d569145d3f460c0fcadb3965bd8418162d43f7f4" +dependencies = [ + "jxl-bitstream", + "jxl-color", + "jxl-grid", + "tracing", +] + +[[package]] +name = "jxl-modular" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f48a5d003627f380004c29d35e51672da06ae343a2e6fe8d9c84295b9a3e843" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-threadpool", + "tracing", +] + +[[package]] +name = "jxl-oxide" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c209f66ef0fe72df77b44ee6aae98eb87bc2dd236d6981e44e143cc37f33f6e" +dependencies = [ + "jxl-bitstream", + "jxl-color", + "jxl-frame", + "jxl-grid", + "jxl-image", + "jxl-render", + "jxl-threadpool", + "tracing", +] + +[[package]] +name = "jxl-render" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aec53c004c9171e89f15ad1f029d6b638cbd70d3a70276746bb8c75f9393bb64" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-color", + "jxl-frame", + "jxl-grid", + "jxl-image", + "jxl-modular", + "jxl-threadpool", + "jxl-vardct", + "tracing", +] + +[[package]] +name = "jxl-threadpool" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2860c68899a3c6266044fc26c6a0041e9f27145f58cc69b6eedc1b77f5ee13" +dependencies = [ + "tracing", +] + +[[package]] +name = "jxl-vardct" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15da4b49b832b3d8a67329f47e2a1732e0847667938bb9b4a37d99a4668775c2" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-modular", + "jxl-threadpool", + "tracing", +] + [[package]] name = "khronos_api" version = "3.1.0" @@ -3562,7 +3789,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.6", + "redox_syscall 0.5.7", ] [[package]] @@ -3654,7 +3881,7 @@ checksum = "28bd4b9d8a5af74808932492521cdd272019b056f75fcc70056bd2c09fceb550" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3835,7 +4062,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", - "simd-adler32", ] [[package]] @@ -3845,6 +4071,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", + "simd-adler32", +] + +[[package]] +name = "mp4parse" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63a35203d3c6ce92d5251c77520acb2e57108c88728695aa883f70023624c570" +dependencies = [ + "bitreader", + "byteorder", + "fallible_collections", + "log", + "num-traits", + "static_assertions", ] [[package]] @@ -3973,7 +4214,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4024,7 +4265,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4295,9 +4536,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" dependencies = [ "critical-section", "portable-atomic", @@ -4406,7 +4647,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.6", + "redox_syscall 0.5.7", "smallvec", "windows-targets 0.52.6", ] @@ -4446,7 +4687,7 @@ dependencies = [ "deflate", "fax", "globalcache", - "indexmap 2.5.0", + "indexmap 2.6.0", "istring", "itertools 0.10.5", "jpeg-decoder", @@ -4501,7 +4742,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4541,15 +4782,15 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "png" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.4", + "miniz_oxide 0.8.0", ] [[package]] @@ -4575,9 +4816,9 @@ checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" [[package]] name = "portable-atomic" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" dependencies = [ "critical-section", ] @@ -4604,7 +4845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4674,7 +4915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4849,9 +5090,9 @@ dependencies = [ [[package]] name = "realfft" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953d9f7e5cdd80963547b456251296efc2626ed4e3cbf36c869d9564e0220571" +checksum = "390252372b7f2aac8360fc5e72eba10136b166d6faeed97e6d0c8324eb99b2b1" dependencies = [ "rustfft 6.2.0", ] @@ -4867,9 +5108,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -4887,14 +5128,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -4908,13 +5149,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4925,9 +5166,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "resvg" @@ -5030,7 +5271,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.77", + "syn 2.0.79", "walkdir", ] @@ -5235,7 +5476,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5258,7 +5499,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5360,9 +5601,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "skia-bindings" -version = "0.78.0" +version = "0.78.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ac1da945f92ee2c5ae7999bc679d682fd976ef524b09cc80b5aae971d3e557" +checksum = "29880a81b088de322e9c5306236c70761a61b5fa4df3c15c93bad3ce890ce34c" dependencies = [ "bindgen", "cc", @@ -5377,9 +5618,9 @@ dependencies = [ [[package]] name = "skia-safe" -version = "0.78.0" +version = "0.78.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80a2993ab98e8f01c874fc35cfec9a8d216d968b80f7e9b1cb9ac1bf4f6a2f3a" +checksum = "4f15700ac678c06649077495acbba07e7ae01e5ca46b7dc18213f2c3477ada71" dependencies = [ "bitflags 2.6.0", "lazy_static", @@ -5549,7 +5790,7 @@ dependencies = [ "objc2-foundation", "objc2-quartz-core", "raw-window-handle 0.6.2", - "redox_syscall 0.5.6", + "redox_syscall 0.5.7", "rustix", "tiny-xlib", "wasm-bindgen", @@ -5657,7 +5898,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5884,9 +6125,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -5938,9 +6179,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -5981,7 +6222,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6137,7 +6378,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -6164,7 +6405,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6287,9 +6528,9 @@ dependencies = [ [[package]] name = "udev" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50051c6e22be28ee6f217d50014f3bc29e81c20dc66ff7ca0d5c5226e1dcc5a1" +checksum = "8ba005bcd5b1158ae3cd815905990e8b6ee4ba9ee7adbab6d7b58d389ad09c93" dependencies = [ "io-lifetimes", "libc", @@ -6338,9 +6579,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-bidi-mirroring" @@ -6377,9 +6618,9 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-script" @@ -6537,7 +6778,7 @@ checksum = "68c1b85ec843d3bc60e9d65fa7e00ce6549416a25c267b5ea93e6c81e3aa66e5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6553,7 +6794,7 @@ dependencies = [ "crossbeam-queue", "half", "heck 0.4.1", - "indexmap 2.5.0", + "indexmap 2.6.0", "libloading 0.8.5", "objc", "once_cell", @@ -6607,7 +6848,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -6641,7 +6882,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6901,7 +7142,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6912,7 +7153,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6923,7 +7164,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6934,7 +7175,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -7422,7 +7663,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "zvariant_utils", ] @@ -7455,7 +7696,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -7475,7 +7716,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -7493,7 +7734,7 @@ dependencies = [ "displaydoc", "flate2", "hmac", - "indexmap 2.5.0", + "indexmap 2.6.0", "memchr", "pbkdf2", "rand", @@ -7565,7 +7806,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "zvariant_utils", ] @@ -7577,5 +7818,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] diff --git a/Cargo.toml b/Cargo.toml index 8cfa2d0b0..0184c4abd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,11 @@ resolver = "2" # until you are ready to occasional crashes panic = "unwind" +# Should find more panics, that now are hidden from user +# There is one big disadvantage - in case of overflow/underflow entire app crashes and panic cannot be catched and app aborts +# So feel free to disable it, if you want +overflow-checks = true + # LTO setting is disabled by default, because release mode is usually needed to develop app and compilation with LTO would take a lot of time # But it is used to optimize release builds(and probably also in CI, where time is not so important as in local development) #lto = "thin" diff --git a/Changelog.md b/Changelog.md index f3ff8ee2a..c8a698589 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,10 @@ ## Version 8.0.0 - ? +### Breaking changes + +- Due removing image_type from image struct, old cache files are incompatible with new version and should be regenerated + from scratch(it uses new name) + ### Core - Removed some unnecessary panics - [#1354](https://github.com/qarmin/czkawka/pull/1354) @@ -14,18 +19,33 @@ - Printing to file/console no longer uses two backslashes in windows paths - [#1354](https://github.com/qarmin/czkawka/pull/1354) - Fixed panic when failed to decode raw picture - [#1355](https://github.com/qarmin/czkawka/pull/1355) +- Remove useless saving/loading cache when there is no files to + check - [#1358](https://github.com/qarmin/czkawka/pull/1358) +- Filtering hard links on windows - [#1316](https://github.com/qarmin/czkawka/pull/1316) +- Added jxl support - [#1358](https://github.com/qarmin/czkawka/pull/1358) +- Added avif support(via external C library, not enabled by + default) - [#1358](https://github.com/qarmin/czkawka/pull/1358) +- Integer overflow are enabled by default(prepare for reporting bugs, slower performance and + unstability) - [#1358](https://github.com/qarmin/czkawka/pull/1358) +- Fixed crash when loading invalid image cache - [#1230](https://github.com/qarmin/czkawka/pull/1230) ### Krokiet - Fixed invalid default hash size in similar images - [#1354](https://github.com/qarmin/czkawka/pull/1354) - Fixed and added more input parameters to the application - [#1354](https://github.com/qarmin/czkawka/pull/1354) +- Fixed problem with loading invalid preset - [#1226](https://github.com/qarmin/czkawka/pull/1226) ### GTK GUI - Fixed and added more input parameters to the application - [#1355](https://github.com/qarmin/czkawka/pull/1355) +- Added option to use external libraries instead gtk pixbuf loader for + previews - [#1358](https://github.com/qarmin/czkawka/pull/1358) +- Using static runtime with zstd compression in appimage - [#1350](https://github.com/qarmin/czkawka/pull/1355) +- [External] Mac homebrew version of app - https://formulae.brew.sh/formula/czkawka ### CLI +- Added options to find/remove images by size - [#1255](https://github.com/qarmin/czkawka/pull/1255) - Fixed and added more input parameters to the application - [#1354](https://github.com/qarmin/czkawka/pull/1354) - Fixed crash when stopping scan mutliple times - [#1355](https://github.com/qarmin/czkawka/pull/1355) - Print results also in debug build - [#1355](https://github.com/qarmin/czkawka/pull/1355) diff --git a/ci_tester/src/main.rs b/ci_tester/src/main.rs index b0959d95f..04e473111 100644 --- a/ci_tester/src/main.rs +++ b/ci_tester/src/main.rs @@ -480,6 +480,17 @@ fn collect_all_files_and_dirs(dir: &str) -> std::io::Result { } } + for dir in &folders_to_check { + println!("Folder \"{}\"", dir) + } + for symlink in &symlinks { + println!("Symlink \"{}\"", symlink) + } + for file in &files { + let metadata = fs::metadata(file)?; + println!("File \"{}\" with size {} bytes", file, metadata.len()); + } + folders.remove(dir); // println!("Found {} files, {} folders and {} symlinks", files.len(), folders.len(), symlinks.len()); Ok(CollectedFiles { files, folders, symlinks }) diff --git a/czkawka_cli/Cargo.toml b/czkawka_cli/Cargo.toml index 58884fc82..40337cdbd 100644 --- a/czkawka_cli/Cargo.toml +++ b/czkawka_cli/Cargo.toml @@ -27,3 +27,4 @@ ctrlc = { version = "3.4", features = ["termination"] } default = [] heif = ["czkawka_core/heif"] libraw = ["czkawka_core/libraw"] +libavif = ["czkawka_core/libavif"] diff --git a/czkawka_cli/README.md b/czkawka_cli/README.md index 4e8c156d2..e5a5cd120 100644 --- a/czkawka_cli/README.md +++ b/czkawka_cli/README.md @@ -12,11 +12,12 @@ Windows 7. On linux it is even possible with eyra to avoid entirely libc and using fully static rust binary. -If you want to use similar videos tool, you need to install ffmpeg(runtime dependency) or use heif/libraw(build/runtime -dependency) you need to install required packages. +If you want to use similar videos tool, you need to install ffmpeg(runtime dependency). +If you want to use heif/libraw/libavif(build/runtime dependency) you need to install required packages(may require +bigger os version than czkawka). -- mac - `brew install ffmpeg libraw libheif` - https://formulae.brew.sh/formula/ffmpeg -- linux - `sudo apt install ffmpeg libraw-dev libheif-dev` +- mac - `brew install ffmpeg libraw libheif libavif` - https://formulae.brew.sh/formula/ffmpeg +- linux - `sudo apt install ffmpeg libraw-dev libheif-dev libavif-dev libdav1d-dev` - windows - `choco install ffmpeg` - or if not working, download from https://ffmpeg.org/download.html#build-windows and unpack to location with `czkawka_cli.exe`, heif and libraw are not supported on windows @@ -31,7 +32,7 @@ cargo run --release --bin czkawka_cli you can enable additional features via ```shell -cargo run --release --bin czkawka_cli --features "heif,libraw" +cargo run --release --bin czkawka_cli --features "heif,libraw,libavif" ``` on linux to build fully static binary with eyra you need to use (this is only for crazy people, so just use command @@ -53,7 +54,6 @@ Not all available features in core are available in CLI. List of not available features: - Ability to use/choose referenced directories -- See progress of scanning ## LICENSE diff --git a/czkawka_cli/src/main.rs b/czkawka_cli/src/main.rs index 39320d9ff..8a580ef6d 100644 --- a/czkawka_cli/src/main.rs +++ b/czkawka_cli/src/main.rs @@ -4,10 +4,8 @@ use std::thread; use clap::Parser; -use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; -use log::error; - use commands::Commands; +use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; use czkawka_core::bad_extensions::{BadExtensions, BadExtensionsParameters}; use czkawka_core::big_file::{BigFile, BigFileParameters, SearchMode}; use czkawka_core::broken_files::{BrokenFiles, BrokenFilesParameters, CheckedTypes}; @@ -24,6 +22,7 @@ use czkawka_core::same_music::{SameMusic, SameMusicParameters}; use czkawka_core::similar_images::{return_similarity_from_similarity_preset, test_image_conversion_speed, SimilarImages, SimilarImagesParameters}; use czkawka_core::similar_videos::{SimilarVideos, SimilarVideosParameters}; use czkawka_core::temporary::Temporary; +use log::error; use crate::commands::{ Args, BadExtensionsArgs, BiggestFilesArgs, BrokenFilesArgs, CommonCliItems, DuplicatesArgs, EmptyFilesArgs, EmptyFoldersArgs, InvalidSymlinksArgs, SameMusicArgs, diff --git a/czkawka_cli/src/progress.rs b/czkawka_cli/src/progress.rs index 526014b2e..1377d0b92 100644 --- a/czkawka_cli/src/progress.rs +++ b/czkawka_cli/src/progress.rs @@ -1,10 +1,9 @@ use std::time::Duration; use crossbeam_channel::Receiver; -use indicatif::{ProgressBar, ProgressStyle}; - use czkawka_core::common_dir_traversal::ToolType; use czkawka_core::progress_data::{CurrentStage, ProgressData}; +use indicatif::{ProgressBar, ProgressStyle}; pub fn connect_progress(progress_receiver: &Receiver) { let mut pb = ProgressBar::new(1); diff --git a/czkawka_core/Cargo.toml b/czkawka_core/Cargo.toml index eeb0c9617..e5ca18007 100644 --- a/czkawka_core/Cargo.toml +++ b/czkawka_core/Cargo.toml @@ -21,7 +21,7 @@ directories-next = "2.0" # Needed by similar images image_hasher = "2.0" bk-tree = "0.5" -image = { version = "0.25", default-features = false, features = ["gif", "jpeg", "ico", "png", "pnm", "tga", "tiff", "webp", "bmp", "hdr", "dds", "qoi"] } +image = { version = "0.25", default-features = false, features = ["bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp"] } hamming = "0.1" # Needed by same music @@ -42,7 +42,7 @@ blake3 = "1.5" crc32fast = "1.4" xxhash-rust = { version = "0.8", features = ["xxh3"] } -tempfile = "3.12" +tempfile = "3.13" # Video Duplicates vid_dup_finder_lib = "0.1" @@ -57,12 +57,13 @@ serde_json = "1.0" i18n-embed = { version = "0.15", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.9" rust-embed = { version = "8.5", features = ["debug-embed"] } -once_cell = "1.19" +once_cell = "1.20" # Raw image files rawloader = "0.37" imagepipe = "0.5" libraw-rs = { version = "0.0.4", optional = true } +jxl-oxide = { version = "0.9.0", default-features = false } # Checking for invalid extensions mime_guess = "2.0" @@ -95,3 +96,4 @@ rustc_version = "0.4" default = [] heif = ["dep:libheif-rs", "dep:libheif-sys"] libraw = ["dep:libraw-rs"] +libavif = ["image/avif-native", "image/avif"] diff --git a/czkawka_core/src/bad_extensions.rs b/czkawka_core/src/bad_extensions.rs index 1ead2f571..124417a8d 100644 --- a/czkawka_core/src/bad_extensions.rs +++ b/czkawka_core/src/bad_extensions.rs @@ -263,6 +263,10 @@ impl BadExtensions { #[fun_time(message = "look_for_bad_extensions_files", level = "debug")] fn look_for_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { + if self.files_to_check.is_empty() { + return true; + } + let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = prepare_thread_handler_common(progress_sender, CurrentStage::BadExtensionsChecking, self.files_to_check.len(), self.get_test_type()); diff --git a/czkawka_core/src/big_file.rs b/czkawka_core/src/big_file.rs index addbaf4d3..b5e9fa34a 100644 --- a/czkawka_core/src/big_file.rs +++ b/czkawka_core/src/big_file.rs @@ -1,16 +1,17 @@ use std::fs; use std::io::Write; -use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ToolType}; -use crate::common_tool::{CommonData, CommonToolData, DeleteMethod}; -use crate::common_traits::{DebugPrint, PrintResults}; -use crate::progress_data::ProgressData; use crossbeam_channel::{Receiver, Sender}; use fun_time::fun_time; use humansize::{format_size, BINARY}; use log::debug; use rayon::prelude::*; +use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ToolType}; +use crate::common_tool::{CommonData, CommonToolData, DeleteMethod}; +use crate::common_traits::{DebugPrint, PrintResults}; +use crate::progress_data::ProgressData; + #[derive(Copy, Clone, Eq, PartialEq)] pub enum SearchMode { BiggestFiles, @@ -65,7 +66,7 @@ impl BigFile { self.debug_print(); } - // #[fun_time(message = "look_for_big_files", level = "debug")] + #[fun_time(message = "look_for_big_files", level = "debug")] fn look_for_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { let result = DirTraversalBuilder::new() .group_by(|_fe| ()) diff --git a/czkawka_core/src/broken_files.rs b/czkawka_core/src/broken_files.rs index 72cd15266..b493c2fe5 100644 --- a/czkawka_core/src/broken_files.rs +++ b/czkawka_core/src/broken_files.rs @@ -5,15 +5,6 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::Ordering; use std::{fs, mem, panic}; -use crate::common::{ - check_if_stop_received, create_crash_message, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, AUDIO_FILES_EXTENSIONS, - IMAGE_RS_BROKEN_FILES_EXTENSIONS, PDF_FILES_EXTENSIONS, ZIP_FILES_EXTENSIONS, -}; -use crate::common_cache::{extract_loaded_cache, get_broken_files_cache_file, load_cache_from_file_generalized_by_path, save_cache_to_file_generalized}; -use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ToolType}; -use crate::common_tool::{CommonData, CommonToolData, DeleteMethod}; -use crate::common_traits::*; -use crate::progress_data::{CurrentStage, ProgressData}; use crossbeam_channel::{Receiver, Sender}; use fun_time::fun_time; use log::debug; @@ -24,6 +15,16 @@ use pdf::PdfError::Try; use rayon::prelude::*; use serde::{Deserialize, Serialize}; +use crate::common::{ + check_if_stop_received, create_crash_message, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, AUDIO_FILES_EXTENSIONS, + IMAGE_RS_BROKEN_FILES_EXTENSIONS, PDF_FILES_EXTENSIONS, ZIP_FILES_EXTENSIONS, +}; +use crate::common_cache::{extract_loaded_cache, get_broken_files_cache_file, load_cache_from_file_generalized_by_path, save_cache_to_file_generalized}; +use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ToolType}; +use crate::common_tool::{CommonData, CommonToolData, DeleteMethod}; +use crate::common_traits::*; +use crate::progress_data::{CurrentStage, ProgressData}; + #[derive(Clone, Serialize, Deserialize, Debug)] pub struct BrokenEntry { pub path: PathBuf, @@ -294,6 +295,10 @@ impl BrokenFiles { #[fun_time(message = "look_for_broken_files", level = "debug")] fn look_for_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { + if self.files_to_check.is_empty() { + return true; + } + let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache(); let (progress_thread_handle, progress_thread_run, atomic_counter, _check_was_stopped) = diff --git a/czkawka_core/src/common.rs b/czkawka_core/src/common.rs index 807265238..0d8ea1a92 100644 --- a/czkawka_core/src/common.rs +++ b/czkawka_core/src/common.rs @@ -1,6 +1,3 @@ -#![allow(unused_imports)] -// I don't wanna fight with unused(heif) imports in this file, so simply ignore it to avoid too much complexity - use std::cmp::Ordering; use std::ffi::OsString; use std::fs::{DirEntry, File, OpenOptions}; @@ -8,24 +5,14 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::{atomic, Arc}; use std::thread::{sleep, JoinHandle}; -use std::time::{Duration, Instant, SystemTime}; +use std::time::{Duration, SystemTime}; use std::{fs, thread}; -#[cfg(feature = "heif")] -use anyhow::Result; use crossbeam_channel::Sender; use directories_next::ProjectDirs; use fun_time::fun_time; use handsome_logger::{ColorChoice, ConfigBuilder, TerminalMode}; -use image::{DynamicImage, ImageBuffer, Rgb}; -use imagepipe::{ImageSource, Pipeline}; -#[cfg(feature = "heif")] -use libheif_rs::{ColorSpace, HeifContext, RgbChroma}; -#[cfg(feature = "libraw")] -use libraw::Processor; -use log::{debug, error, info, warn, LevelFilter, Record}; -use rawloader::RawLoader; -use symphonia::core::conv::IntoSample; +use log::{debug, info, warn, LevelFilter, Record}; // #[cfg(feature = "heif")] // use libheif_rs::LibHeif; @@ -33,7 +20,7 @@ use crate::common_dir_traversal::{CheckingMethod, ToolType}; use crate::common_directory::Directories; use crate::common_items::{ExcludedItems, SingleExcludedItem}; use crate::common_messages::Messages; -use crate::common_tool::{CommonData, DeleteMethod}; +use crate::common_tool::DeleteMethod; use crate::common_traits::ResultEntry; use crate::duplicate::make_hard_link; use crate::progress_data::{CurrentStage, ProgressData}; @@ -76,6 +63,7 @@ pub fn get_all_available_threads() -> usize { }) } +#[allow(clippy::vec_init_then_push)] pub fn print_version_mode() { let rust_version = env!("RUST_VERSION_INTERNAL"); let debug_release = if cfg!(debug_assertions) { "debug" } else { "release" }; @@ -83,12 +71,24 @@ pub fn print_version_mode() { let processors = get_all_available_threads(); let info = os_info::get(); + + #[allow(unused_mut)] + let mut features: Vec<&str> = vec![]; + #[cfg(feature = "heif")] + features.push("heif"); + #[cfg(feature = "libavif")] + features.push("libavif"); + #[cfg(feature = "libraw")] + features.push("libraw"); + info!( - "App version: {CZKAWKA_VERSION}, {debug_release} mode, rust {rust_version}, os {} {} [{} {}], {processors} cpu/threads", + "App version: {CZKAWKA_VERSION}, {debug_release} mode, rust {rust_version}, os {} {} [{} {}], {processors} cpu/threads, features({}): [{}]", info.os_type(), info.version(), std::env::consts::ARCH, info.bitness(), + features.len(), + features.join(", ") ); if cfg!(debug_assertions) { warn!("You are running debug version of app which is a lot of slower than release version."); @@ -123,14 +123,31 @@ pub fn set_number_of_threads(thread_number: usize) { pub const RAW_IMAGE_EXTENSIONS: &[&str] = &[ "mrw", "arw", "srf", "sr2", "mef", "orf", "srw", "erf", "kdc", "kdc", "dcs", "rw2", "raf", "dcr", "dng", "pef", "crw", "iiq", "3fr", "nrw", "nef", "mos", "cr2", "ari", ]; + +pub const JXL_IMAGE_EXTENSIONS: &[&str] = &["jxl"]; + +#[cfg(feature = "libavif")] +pub const IMAGE_RS_EXTENSIONS: &[&str] = &[ + "jpg", "jpeg", "png", "bmp", "tiff", "tif", "tga", "ff", "jif", "jfi", "webp", "gif", "ico", "exr", "qoi", "avif", +]; +#[cfg(not(feature = "libavif"))] pub const IMAGE_RS_EXTENSIONS: &[&str] = &["jpg", "jpeg", "png", "bmp", "tiff", "tif", "tga", "ff", "jif", "jfi", "webp", "gif", "ico", "exr", "qoi"]; +#[cfg(feature = "libavif")] +pub const IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS: &[&str] = &["jpg", "jpeg", "png", "tiff", "tif", "tga", "ff", "jif", "jfi", "bmp", "webp", "exr", "qoi", "avif"]; +#[cfg(not(feature = "libavif"))] pub const IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS: &[&str] = &["jpg", "jpeg", "png", "tiff", "tif", "tga", "ff", "jif", "jfi", "bmp", "webp", "exr", "qoi"]; +#[cfg(feature = "libavif")] +pub const IMAGE_RS_BROKEN_FILES_EXTENSIONS: &[&str] = &[ + "jpg", "jpeg", "png", "tiff", "tif", "tga", "ff", "jif", "jfi", "gif", "bmp", "ico", "jfif", "jpe", "pnz", "dib", "webp", "exr", "avif", +]; +#[cfg(not(feature = "libavif"))] pub const IMAGE_RS_BROKEN_FILES_EXTENSIONS: &[&str] = &[ "jpg", "jpeg", "png", "tiff", "tif", "tga", "ff", "jif", "jfi", "gif", "bmp", "ico", "jfif", "jpe", "pnz", "dib", "webp", "exr", ]; -pub const HEIC_EXTENSIONS: &[&str] = &["heif", "heifs", "heic", "heics", "avci", "avcs", "avifs"]; + +pub const HEIC_EXTENSIONS: &[&str] = &["heif", "heifs", "heic", "heics", "avci", "avcs"]; pub const ZIP_FILES_EXTENSIONS: &[&str] = &["zip", "jar"]; @@ -259,83 +276,6 @@ pub fn open_cache_folder(cache_file_name: &str, save_to_cache: bool, use_json: b None } -#[cfg(feature = "heif")] -pub fn get_dynamic_image_from_heic(path: &str) -> Result { - // let libheif = LibHeif::new(); - let im = HeifContext::read_from_file(path)?; - let handle = im.primary_image_handle()?; - // let image = libheif.decode(&handle, ColorSpace::Rgb(RgbChroma::Rgb), None)?; // Enable when using libheif 0.19 - let image = handle.decode(ColorSpace::Rgb(RgbChroma::Rgb), None)?; - let width = image.width(); - let height = image.height(); - let planes = image.planes(); - let interleaved_plane = planes.interleaved.ok_or_else(|| anyhow::anyhow!("Failed to get interleaved plane"))?; - ImageBuffer::from_raw(width, height, interleaved_plane.data.to_owned()) - .map(DynamicImage::ImageRgb8) - .ok_or_else(|| anyhow::anyhow!("Failed to create image buffer")) -} - -#[cfg(feature = "libraw")] -pub fn get_dynamic_image_from_raw_image(path: impl AsRef) -> Result { - let buf = fs::read(path.as_ref())?; - - let processor = Processor::new(); - let start_timer = Instant::now(); - let processed = processor.process_8bit(&buf)?; - println!("Processing took {:?}", start_timer.elapsed()); - - let width = processed.width(); - let height = processed.height(); - - let data = processed.to_vec(); - let data_len = data.len(); - - let buffer = ImageBuffer::from_raw(width, height, data).ok_or(anyhow::anyhow!(format!( - "Cannot create ImageBuffer from raw image with width: {width} and height: {height} and data length: {data_len}", - )))?; - - Ok(DynamicImage::ImageRgb8(buffer)) -} - -#[cfg(not(feature = "libraw"))] -pub fn get_dynamic_image_from_raw_image(path: impl AsRef + std::fmt::Debug) -> Result { - let mut start_timer = Instant::now(); - let mut times = Vec::new(); - - let loader = RawLoader::new(); - let raw = loader.decode_file(path.as_ref()).map_err(|e| format!("Error decoding file: {e:?}"))?; - - times.push(("After decoding", start_timer.elapsed())); - start_timer = Instant::now(); - - let source = ImageSource::Raw(raw); - - times.push(("After creating source", start_timer.elapsed())); - start_timer = Instant::now(); - - let mut pipeline = Pipeline::new_from_source(source).map_err(|e| format!("Error creating pipeline: {e:?}"))?; - - times.push(("After creating pipeline", start_timer.elapsed())); - start_timer = Instant::now(); - - pipeline.run(None); - let image = pipeline.output_8bit(None).map_err(|e| format!("Error running pipeline: {e:?}"))?; - - times.push(("After creating image", start_timer.elapsed())); - start_timer = Instant::now(); - - let image = ImageBuffer::, Vec>::from_raw(image.width as u32, image.height as u32, image.data).ok_or_else(|| "Failed to create image buffer".to_string())?; - - times.push(("After creating image buffer", start_timer.elapsed())); - start_timer = Instant::now(); - let res = DynamicImage::ImageRgb8(image); - times.push(("After creating dynamic image", start_timer.elapsed())); - - let str_timer = times.into_iter().map(|(name, time)| format!("{name}: {time:?}")).collect::>().join(", "); - debug!("Loading raw image --- {str_timer}"); - Ok(res) -} - pub fn split_path(path: &Path) -> (String, String) { match (path.parent(), path.file_name()) { (Some(dir), Some(file)) => (dir.to_string_lossy().to_string(), file.to_string_lossy().into_owned()), diff --git a/czkawka_core/src/common_cache.rs b/czkawka_core/src/common_cache.rs index d4367d57b..77b80c4c9 100644 --- a/czkawka_core/src/common_cache.rs +++ b/czkawka_core/src/common_cache.rs @@ -4,7 +4,7 @@ use std::io::{BufReader, BufWriter}; use fun_time::fun_time; use image::imageops::FilterType; use image_hasher::HashAlg; -use log::debug; +use log::{debug, error}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; @@ -15,6 +15,7 @@ use crate::duplicate::HashType; use crate::similar_images::{convert_algorithm_to_string, convert_filters_to_string}; const CACHE_VERSION: &str = "70"; +const CACHE_IMAGE_VERSION: &str = "80"; pub fn get_broken_files_cache_file() -> String { format!("cache_broken_files_{CACHE_VERSION}.bin") @@ -22,7 +23,7 @@ pub fn get_broken_files_cache_file() -> String { pub fn get_similar_images_cache_file(hash_size: &u8, hash_alg: &HashAlg, image_filter: &FilterType) -> String { format!( - "cache_similar_images_{hash_size}_{}_{}_{CACHE_VERSION}.bin", + "cache_similar_images_{hash_size}_{}_{}_{CACHE_IMAGE_VERSION}.bin", convert_algorithm_to_string(hash_alg), convert_filters_to_string(image_filter), ) @@ -195,11 +196,18 @@ where if let Some(file_handler) = file_handler { let reader = BufReader::new(file_handler); + // TODO cannot use limits + // Probably also save function needs to be updated + // Without it loading not working + + // let options = bincode::DefaultOptions::new().with_limit(4 * 1024 * 1024 * 1024); + // vec_loaded_entries = match options.deserialize_from(reader) { + vec_loaded_entries = match bincode::deserialize_from(reader) { Ok(t) => t, Err(e) => { text_messages.warnings.push(format!("Failed to load data from cache file {cache_file:?}, reason {e}")); - debug!("Failed to load cache from file {cache_file:?}"); + error!("Failed to load cache from file {cache_file:?}"); return (text_messages, None); } }; @@ -208,7 +216,9 @@ where vec_loaded_entries = match serde_json::from_reader(reader) { Ok(t) => t, Err(e) => { - text_messages.warnings.push(format!("Failed to load data from cache file {cache_file_json:?}, reason {e}")); + text_messages + .warnings + .push(format!("Failed to load data from json cache file {cache_file_json:?}, reason {e}")); debug!("Failed to load cache from file {cache_file:?}"); return (text_messages, None); } diff --git a/czkawka_core/src/common_dir_traversal.rs b/czkawka_core/src/common_dir_traversal.rs index b07f16001..3ebceaaec 100644 --- a/czkawka_core/src/common_dir_traversal.rs +++ b/czkawka_core/src/common_dir_traversal.rs @@ -645,16 +645,18 @@ pub fn take_1_per_inode((k, mut v): (Option, Vec)) -> Vec &CommonToolData { self diff --git a/czkawka_core/src/common_image.rs b/czkawka_core/src/common_image.rs new file mode 100644 index 000000000..d0fdbc482 --- /dev/null +++ b/czkawka_core/src/common_image.rs @@ -0,0 +1,173 @@ +#![allow(unused_imports)] +// I don't wanna fight with unused(heif) imports in this file, so simply ignore it to avoid too much complexity + +use std::cmp::Ordering; +use std::ffi::OsString; +use std::fs::{DirEntry, File, OpenOptions}; +use std::path::{Path, PathBuf}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::sync::{atomic, Arc}; +use std::thread::{sleep, JoinHandle}; +use std::time::{Duration, Instant, SystemTime}; +use std::{fs, panic, thread}; + +use anyhow::anyhow; +use crossbeam_channel::Sender; +use directories_next::ProjectDirs; +use fun_time::fun_time; +use handsome_logger::{ColorChoice, ConfigBuilder, TerminalMode}; +use image::{DynamicImage, ImageBuffer, Rgb, Rgba}; +use imagepipe::{ImageSource, Pipeline}; +use jxl_oxide::image::BitDepth; +use jxl_oxide::{JxlImage, PixelFormat}; +#[cfg(feature = "heif")] +use libheif_rs::{ColorSpace, HeifContext, RgbChroma}; +#[cfg(feature = "libraw")] +use libraw::Processor; +use log::{debug, error, info, warn, LevelFilter, Record}; +use rawloader::RawLoader; +use symphonia::core::conv::IntoSample; + +use crate::common; +use crate::common::{create_crash_message, HEIC_EXTENSIONS, JXL_IMAGE_EXTENSIONS, RAW_IMAGE_EXTENSIONS}; +// #[cfg(feature = "heif")] +// use libheif_rs::LibHeif; + +// TODO this code is ugly - this should exists in image-rs or be taken from official example of jxl-oxide +// Its presence offends everything good in this world +pub fn get_jxl_image(path: &str) -> anyhow::Result { + let buf_reader = std::io::BufReader::new(File::open(path)?); + + let decoder = JxlImage::builder().read(buf_reader).map_err(|e| anyhow::anyhow!("Failed to read jxl file {e}"))?; + let width = decoder.width(); + let height = decoder.height(); + let frame = decoder.render_frame(0).map_err(|e| anyhow::anyhow!("Failed to render jxl frame {e}"))?; + let planar = &frame.image_planar(); + let pixfmt = decoder.pixel_format(); + let bits_per_sample = decoder.image_header().metadata.bit_depth; + + if bits_per_sample.bits_per_sample() == 8 && pixfmt == PixelFormat::Rgb && planar.len() == 3 { + let zips = planar[0].buf().iter().zip(planar[1].buf().iter()).zip(planar[2].buf().iter()); + let pixels = zips.flat_map(|((r, g), b)| [(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8]).collect::>(); + let data = ImageBuffer::, Vec>::from_vec(width, height, pixels).ok_or_else(|| anyhow::anyhow!("Failed to create rgb image buffer from jxl data"))?; + Ok(DynamicImage::ImageRgb8(data)) + } else if bits_per_sample.bits_per_sample() == 8 && pixfmt == PixelFormat::Rgba && planar.len() == 4 { + let zips = planar[0].buf().iter().zip(planar[1].buf().iter()).zip(planar[2].buf().iter()).zip(planar[3].buf().iter()); + let pixels = zips + .flat_map(|(((r, g), b), a)| [(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8, (a * 255.0) as u8]) + .collect::>(); + let data = ImageBuffer::, Vec>::from_vec(width, height, pixels).ok_or_else(|| anyhow::anyhow!("Failed to create rgba image buffer from jxl data"))?; + Ok(DynamicImage::ImageRgba8(data)) + } else { + return Err(anyhow::anyhow!("Unsupported number of planes: {}", planar.len())); + } +} + +pub fn get_dynamic_image_from_path(path: &str) -> Result { + let path_lower = Path::new(path).extension().unwrap_or_default().to_string_lossy().to_lowercase(); + + let res = panic::catch_unwind(|| { + if HEIC_EXTENSIONS.iter().any(|ext| path_lower.ends_with(ext)) { + #[cfg(feature = "heif")] + { + get_dynamic_image_from_heic(path).map_err(|e| format!("Cannot open heic file \"{path}\": {e}")) + } + #[cfg(not(feature = "heif"))] + { + image::open(path).map_err(|e| format!("Cannot open image file \"{path}\": {e}")) + } + } else if JXL_IMAGE_EXTENSIONS.iter().any(|ext| path_lower.ends_with(ext)) { + get_jxl_image(path).map_err(|e| format!("Cannot open jxl image file \"{path}\": {e}")) + } else if RAW_IMAGE_EXTENSIONS.iter().any(|ext| path_lower.ends_with(ext)) { + get_raw_image(path).map_err(|e| format!("Cannot open raw image file \"{path}\": {e}")) + } else { + image::open(path).map_err(|e| format!("Cannot open image file \"{path}\": {e}")) + } + }); + + if let Ok(res) = res { + match res { + Ok(t) => Ok(t), + Err(e) => Err(format!("Cannot open image file \"{path}\": {e}")), + } + } else { + let message = create_crash_message("Image-rs or libraw-rs or jxl-oxide", path, "https://github.com/image-rs/image/issues"); + println!("{message}"); + Err(message) + } +} + +#[cfg(feature = "heif")] +pub fn get_dynamic_image_from_heic(path: &str) -> anyhow::Result { + // let libheif = LibHeif::new(); + let im = HeifContext::read_from_file(path)?; + let handle = im.primary_image_handle()?; + // let image = libheif.decode(&handle, ColorSpace::Rgb(RgbChroma::Rgb), None)?; // Enable when using libheif 0.19 + let image = handle.decode(ColorSpace::Rgb(RgbChroma::Rgb), None)?; + let width = image.width(); + let height = image.height(); + let planes = image.planes(); + let interleaved_plane = planes.interleaved.ok_or_else(|| anyhow::anyhow!("Failed to get interleaved plane"))?; + ImageBuffer::from_raw(width, height, interleaved_plane.data.to_owned()) + .map(DynamicImage::ImageRgb8) + .ok_or_else(|| anyhow::anyhow!("Failed to create image buffer")) +} + +#[cfg(feature = "libraw")] +pub fn get_raw_image(path: impl AsRef) -> anyhow::Result { + let buf = fs::read(path.as_ref())?; + + let processor = Processor::new(); + let processed = processor.process_8bit(&buf)?; + + let width = processed.width(); + let height = processed.height(); + + let data = processed.to_vec(); + let data_len = data.len(); + + let buffer = ImageBuffer::from_raw(width, height, data).ok_or(anyhow::anyhow!(format!( + "Cannot create ImageBuffer from raw image with width: {width} and height: {height} and data length: {data_len}", + )))?; + + Ok(DynamicImage::ImageRgb8(buffer)) +} + +#[cfg(not(feature = "libraw"))] +pub fn get_raw_image(path: impl AsRef + std::fmt::Debug) -> Result { + let mut start_timer = Instant::now(); + let mut times = Vec::new(); + + let loader = RawLoader::new(); + let raw = loader.decode_file(path.as_ref()).map_err(|e| format!("Error decoding file: {e:?}"))?; + + times.push(("After decoding", start_timer.elapsed())); + start_timer = Instant::now(); + + let source = ImageSource::Raw(raw); + + times.push(("After creating source", start_timer.elapsed())); + start_timer = Instant::now(); + + let mut pipeline = Pipeline::new_from_source(source).map_err(|e| format!("Error creating pipeline: {e:?}"))?; + + times.push(("After creating pipeline", start_timer.elapsed())); + start_timer = Instant::now(); + + pipeline.run(None); + let image = pipeline.output_8bit(None).map_err(|e| format!("Error running pipeline: {e:?}"))?; + + times.push(("After creating image", start_timer.elapsed())); + start_timer = Instant::now(); + + let image = ImageBuffer::, Vec>::from_raw(image.width as u32, image.height as u32, image.data).ok_or_else(|| "Failed to create image buffer".to_string())?; + + times.push(("After creating image buffer", start_timer.elapsed())); + start_timer = Instant::now(); + let res = DynamicImage::ImageRgb8(image); + times.push(("After creating dynamic image", start_timer.elapsed())); + + let str_timer = times.into_iter().map(|(name, time)| format!("{name}: {time:?}")).collect::>().join(", "); + debug!("Loading raw image --- {str_timer}"); + Ok(res) +} diff --git a/czkawka_core/src/duplicate.rs b/czkawka_core/src/duplicate.rs index bc755ac51..c5fb70e75 100644 --- a/czkawka_core/src/duplicate.rs +++ b/czkawka_core/src/duplicate.rs @@ -10,12 +10,6 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::Ordering; use std::{fs, mem}; -use crate::common::{check_if_stop_received, delete_files_custom, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; -use crate::common_cache::{get_duplicate_cache_file, load_cache_from_file_generalized_by_size, save_cache_to_file_generalized}; -use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ToolType}; -use crate::common_tool::{CommonData, CommonToolData, DeleteMethod}; -use crate::common_traits::*; -use crate::progress_data::{CurrentStage, ProgressData}; use crossbeam_channel::{Receiver, Sender}; use fun_time::fun_time; use humansize::{format_size, BINARY}; @@ -24,6 +18,13 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; use xxhash_rust::xxh3::Xxh3; +use crate::common::{check_if_stop_received, delete_files_custom, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; +use crate::common_cache::{get_duplicate_cache_file, load_cache_from_file_generalized_by_size, save_cache_to_file_generalized}; +use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ToolType}; +use crate::common_tool::{CommonData, CommonToolData, DeleteMethod}; +use crate::common_traits::*; +use crate::progress_data::{CurrentStage, ProgressData}; + const TEMP_HARDLINK_FILE: &str = "rzeczek.rxrxrxl"; #[derive(PartialEq, Eq, Clone, Debug, Copy, Default)] @@ -544,7 +545,11 @@ impl DuplicateFinder { stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>, pre_checked_map: &mut BTreeMap>, - ) -> Option<()> { + ) -> bool { + if self.files_with_identical_size.is_empty() { + return true; + } + let check_type = self.get_params().hash_type; let (progress_thread_handle, progress_thread_run, _atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, CurrentStage::DuplicatePreHashCacheLoading, 0, self.get_test_type()); @@ -553,7 +558,7 @@ impl DuplicateFinder { send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle); if check_if_stop_received(stop_receiver) { - return None; + return false; } let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = prepare_thread_handler_common( progress_sender, @@ -618,10 +623,10 @@ impl DuplicateFinder { send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle); if check_was_stopped.load(Ordering::Relaxed) || check_if_stop_received(stop_receiver) { - return None; + return false; } - Some(()) + true } fn diff_loaded_and_prechecked_files( @@ -747,12 +752,11 @@ impl DuplicateFinder { } #[fun_time(message = "full_hashing", level = "debug")] - fn full_hashing( - &mut self, - stop_receiver: Option<&Receiver<()>>, - progress_sender: Option<&Sender>, - pre_checked_map: BTreeMap>, - ) -> Option<()> { + fn full_hashing(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>, pre_checked_map: BTreeMap>) -> bool { + if pre_checked_map.is_empty() { + return true; + } + let (progress_thread_handle, progress_thread_run, _atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, CurrentStage::DuplicateCacheLoading, 0, self.get_test_type()); @@ -760,7 +764,7 @@ impl DuplicateFinder { send_info_and_wait_for_ending_all_threads(&progress_thread_run, progress_thread_handle); if check_if_stop_received(stop_receiver) { - return None; + return false; } let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = prepare_thread_handler_common( @@ -818,7 +822,7 @@ impl DuplicateFinder { } } - Some(()) + true } #[fun_time(message = "hash_reference_folders", level = "debug")] @@ -877,13 +881,11 @@ impl DuplicateFinder { assert_eq!(self.get_params().check_method, CheckingMethod::Hash); let mut pre_checked_map: BTreeMap> = Default::default(); - let ret = self.prehashing(stop_receiver, progress_sender, &mut pre_checked_map); - if ret.is_none() { + if !self.prehashing(stop_receiver, progress_sender, &mut pre_checked_map) { return false; } - let ret = self.full_hashing(stop_receiver, progress_sender, pre_checked_map); - if ret.is_none() { + if !self.full_hashing(stop_receiver, progress_sender, pre_checked_map) { return false; } @@ -977,9 +979,9 @@ impl DuplicateFinder { impl DebugPrint for DuplicateFinder { fn debug_print(&self) { - if !cfg!(debug_assertions) { - return; - } + // if !cfg!(debug_assertions) { + // return; + // } println!("---------------DEBUG PRINT---------------"); println!( "Number of duplicated files by size(in groups) - {} ({})", @@ -1008,6 +1010,12 @@ impl DebugPrint for DuplicateFinder { println!("Files list size - {}", self.files_with_identical_size.len()); println!("Hashed Files list size - {}", self.files_with_identical_hashes.len()); + println!("Files with identical names - {}", self.files_with_identical_names.len()); + println!("Files with identical size names - {}", self.files_with_identical_size_names.len()); + println!("Files with identical names referenced - {}", self.files_with_identical_names_referenced.len()); + println!("Files with identical size names referenced - {}", self.files_with_identical_size_names_referenced.len()); + println!("Files with identical size referenced - {}", self.files_with_identical_size_referenced.len()); + println!("Files with identical hashes referenced - {}", self.files_with_identical_hashes_referenced.len()); println!("Checking Method - {:?}", self.get_params().check_method); self.debug_print_common(); println!("-----------------------------------------"); @@ -1183,7 +1191,7 @@ impl PrintResults for DuplicateFinder { for (size, vectors_vector) in self.files_with_identical_hashes_referenced.iter().rev() { for (file_entry, vector) in vectors_vector { writeln!(writer, "\n---- Size {} ({}) - {} files", format_size(*size, BINARY), size, vector.len())?; - writeln!(writer, "Reference file - {:?}", file_entry.path)?; + writeln!(writer, "Reference file - \"{}\"", file_entry.path.to_string_lossy())?; for file_entry in vector { writeln!(writer, "\"{}\"", file_entry.path.to_string_lossy())?; } diff --git a/czkawka_core/src/lib.rs b/czkawka_core/src/lib.rs index 5d4479ade..c4007e662 100644 --- a/czkawka_core/src/lib.rs +++ b/czkawka_core/src/lib.rs @@ -24,6 +24,7 @@ pub mod common_cache; pub mod common_dir_traversal; pub mod common_directory; pub mod common_extensions; +pub mod common_image; pub mod common_items; pub mod common_messages; pub mod common_tool; diff --git a/czkawka_core/src/same_music.rs b/czkawka_core/src/same_music.rs index 599fc9ba5..ab5f24802 100644 --- a/czkawka_core/src/same_music.rs +++ b/czkawka_core/src/same_music.rs @@ -284,6 +284,10 @@ impl SameMusic { #[fun_time(message = "calculate_fingerprint", level = "debug")] fn calculate_fingerprint(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { + if self.music_entries.is_empty() { + return true; + } + // We only calculate fingerprints, for files with similar titles // This saves a lot of time, because we don't need to calculate and later compare fingerprints for files with different titles @@ -360,6 +364,10 @@ impl SameMusic { #[fun_time(message = "read_tags", level = "debug")] fn read_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { + if self.music_to_check.is_empty() { + return true; + } + let (progress_thread_handle, progress_thread_run, _atomic_counter, _check_was_stopped) = prepare_thread_handler_common(progress_sender, CurrentStage::SameMusicCacheLoadingTags, 0, self.get_test_type()); @@ -383,7 +391,7 @@ impl SameMusic { check_was_stopped.store(true, Ordering::Relaxed); return None; } - if read_single_file_tag(&path, &mut music_entry) { + if read_single_file_tags(&path, &mut music_entry) { Some(Some(music_entry)) } else { Some(None) @@ -529,6 +537,10 @@ impl SameMusic { let mut entries_grouped_by_title: BTreeMap> = BTreeMap::new(); for entry in music_data { let simplified_track_title = get_simplified_name(&entry.track_title); + // TODO maybe add as option to check for empty titles? + if simplified_track_title.is_empty() { + continue; + } entries_grouped_by_title.entry(simplified_track_title).or_default().push(entry); } entries_grouped_by_title @@ -543,7 +555,13 @@ impl SameMusic { .filter_map(|(_title, entries)| { let (base_files, files_to_compare) = self.split_fingerprints_to_base_and_files_to_compare(entries); - if base_files.is_empty() || files_to_compare.is_empty() { + // When there is 0 files in base files or files to compare there will be no comparison, so removing it from the list + // Also when there is only one file in base files and files to compare and they are the same file, there will be no comparison + + if base_files.is_empty() + || files_to_compare.is_empty() + || (base_files.len() == 1 && files_to_compare.len() == 1 && (base_files[0].path == files_to_compare[0].path)) + { return None; } @@ -628,6 +646,10 @@ impl SameMusic { #[fun_time(message = "check_for_duplicate_fingerprints", level = "debug")] fn check_for_duplicate_fingerprints(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { + if self.music_entries.is_empty() { + return true; + } + let grouped_files_to_check = self.split_fingerprints_to_check(); let base_files_number = grouped_files_to_check.iter().map(|g| g.base_files.len()).sum::(); @@ -811,7 +833,7 @@ fn calc_fingerprint_helper(path: impl AsRef, config: &Configuration) -> an Ok(printer.fingerprint().to_vec()) } -fn read_single_file_tag(path: &str, music_entry: &mut MusicEntry) -> bool { +fn read_single_file_tags(path: &str, music_entry: &mut MusicEntry) -> bool { let Ok(mut file) = File::open(path) else { return false; }; @@ -920,17 +942,7 @@ impl PrintResults for SameMusic { for vec_file_entry in &self.duplicated_music_entries { writeln!(writer, "Found {} music files which have similar friends", vec_file_entry.len())?; for file_entry in vec_file_entry { - writeln!( - writer, - "TT: {} - TA: {} - Y: {} - L: {} - G: {} - B: {} - P: \"{}\"", - file_entry.track_title, - file_entry.track_artist, - file_entry.year, - file_entry.length, - file_entry.genre, - file_entry.bitrate, - file_entry.path.to_string_lossy() - )?; + write_music_entry(writer, file_entry)?; } writeln!(writer)?; } @@ -939,29 +951,9 @@ impl PrintResults for SameMusic { for (file_entry, vec_file_entry) in &self.duplicated_music_entries_referenced { writeln!(writer, "Found {} music files which have similar friends", vec_file_entry.len())?; writeln!(writer)?; - writeln!( - writer, - "TT: {} - TA: {} - Y: {} - L: {} - G: {} - B: {} - P: \"{}\"", - file_entry.track_title, - file_entry.track_artist, - file_entry.year, - file_entry.length, - file_entry.genre, - file_entry.bitrate, - file_entry.path.to_string_lossy() - )?; + write_music_entry(writer, file_entry)?; for file_entry in vec_file_entry { - writeln!( - writer, - "TT: {} - TA: {} - Y: {} - L: {} - G: {} - B: {} - P: \"{}\"", - file_entry.track_title, - file_entry.track_artist, - file_entry.year, - file_entry.length, - file_entry.genre, - file_entry.bitrate, - file_entry.path.to_string_lossy() - )?; + write_music_entry(writer, file_entry)?; } writeln!(writer)?; } @@ -981,6 +973,20 @@ impl PrintResults for SameMusic { } } +fn write_music_entry(writer: &mut T, file_entry: &MusicEntry) -> std::io::Result<()> { + writeln!( + writer, + "TT: {} - TA: {} - Y: {} - L: {} - G: {} - B: {} - P: \"{}\"", + file_entry.track_title, + file_entry.track_artist, + file_entry.year, + file_entry.length, + file_entry.genre, + file_entry.bitrate, + file_entry.path.to_string_lossy() + ) +} + fn get_simplified_name(what: &str) -> String { let mut new_what = String::with_capacity(what.len()); let mut tab_number = 0; diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index 6aeaa3c62..77c8a1143 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -9,20 +9,19 @@ use bk_tree::BKTree; use crossbeam_channel::{Receiver, Sender}; use fun_time::fun_time; use humansize::{format_size, BINARY}; -use image::{DynamicImage, GenericImageView}; +use image::GenericImageView; use image_hasher::{FilterType, HashAlg, HasherConfig}; use log::debug; use rayon::prelude::*; use serde::{Deserialize, Serialize}; -#[cfg(feature = "heif")] -use crate::common::get_dynamic_image_from_heic; use crate::common::{ - check_if_stop_received, create_crash_message, delete_files_custom, get_dynamic_image_from_raw_image, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, - HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, + check_if_stop_received, delete_files_custom, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, + JXL_IMAGE_EXTENSIONS, RAW_IMAGE_EXTENSIONS, }; use crate::common_cache::{extract_loaded_cache, get_similar_images_cache_file, load_cache_from_file_generalized_by_path, save_cache_to_file_generalized}; use crate::common_dir_traversal::{inode, take_1_per_inode, DirTraversalBuilder, DirTraversalResult, FileEntry, ToolType}; +use crate::common_image::get_dynamic_image_from_path; use crate::common_tool::{CommonData, CommonToolData, DeleteMethod}; use crate::common_traits::{DebugPrint, PrintResults, ResultEntry}; use crate::flc; @@ -46,7 +45,6 @@ pub struct ImagesEntry { pub modified_date: u64, pub hash: ImHash, pub similarity: u32, - pub image_type: ImageType, } impl ResultEntry for ImagesEntry { @@ -71,19 +69,10 @@ impl FileEntry { height: 0, hash: Vec::new(), similarity: 0, - image_type: ImageType::Unknown, } } } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] -pub enum ImageType { - Normal, - Raw, - Heic, - Unknown, -} - #[derive(Clone, Debug, Copy)] pub enum SimilarityPreset { Original, @@ -183,25 +172,22 @@ impl SimilarImages { self.debug_print(); } - // #[fun_time(message = "check_for_similar_images", level = "debug")] + #[fun_time(message = "check_for_similar_images", level = "debug")] fn check_for_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { if cfg!(feature = "heif") { self.common_data .extensions - .set_and_validate_allowed_extensions(&[IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, HEIC_EXTENSIONS].concat()); + .set_and_validate_allowed_extensions(&[IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, JXL_IMAGE_EXTENSIONS, HEIC_EXTENSIONS].concat()); } else { self.common_data .extensions - .set_and_validate_allowed_extensions(&[IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS].concat()); + .set_and_validate_allowed_extensions(&[IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, JXL_IMAGE_EXTENSIONS].concat()); } + if !self.common_data.extensions.set_any_extensions() { return true; } - let normal_image_extensions = IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS.iter().collect::>(); - let raw_image_extensions = RAW_IMAGE_EXTENSIONS.iter().collect::>(); - let heic_extensions = HEIC_EXTENSIONS.iter().collect::>(); - let result = DirTraversalBuilder::new() .group_by(inode) .stop_receiver(stop_receiver) @@ -217,17 +203,8 @@ impl SimilarImages { .flat_map(if self.get_params().ignore_hard_links { |(_, fes)| fes } else { take_1_per_inode }) .map(|fe| { let fe_str = fe.path.to_string_lossy().to_string(); - let extension_lowercase = fe.path.extension().unwrap_or_default().to_string_lossy().to_lowercase(); - let mut image_entry = fe.into_images_entry(); - if normal_image_extensions.contains(&extension_lowercase.as_str()) { - image_entry.image_type = ImageType::Normal; - } else if raw_image_extensions.contains(&extension_lowercase.as_str()) { - image_entry.image_type = ImageType::Raw; - } else if heic_extensions.contains(&extension_lowercase.as_str()) { - image_entry.image_type = ImageType::Heic; - } else { - panic!("Unrecognized extension") - } + let image_entry = fe.into_images_entry(); + (fe_str, image_entry) }) .collect(); @@ -286,6 +263,10 @@ impl SimilarImages { #[fun_time(message = "hash_images", level = "debug")] fn hash_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { + if self.images_to_check.is_empty() { + return true; + } + let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.hash_images_load_cache(); let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = prepare_thread_handler_common( @@ -295,12 +276,6 @@ impl SimilarImages { self.get_test_type(), ); - // Throw out images with not proper type - TODO why this happens, only broken cache? - let non_cached_files_to_check = non_cached_files_to_check - .into_iter() - .filter(|(_, file_entry)| file_entry.image_type != ImageType::Unknown) - .collect::>(); - debug!("hash_images - start hashing images"); let (mut vec_file_entry, errors): (Vec, Vec) = non_cached_files_to_check .into_par_iter() @@ -370,38 +345,7 @@ impl SimilarImages { } fn collect_image_file_entry(&self, file_entry: &mut ImagesEntry) -> Result<(), String> { - let img; - - if file_entry.image_type == ImageType::Heic { - #[cfg(feature = "heif")] - { - img = match get_dynamic_image_from_heic(&file_entry.path.to_string_lossy()) { - Ok(t) => t, - Err(e) => { - return Err(format!("Cannot open HEIC file \"{}\": {}", file_entry.path.to_string_lossy(), e)); - } - }; - } - #[cfg(not(feature = "heif"))] - { - img = Self::get_normal_heif_image(file_entry)?; - } - } else { - match file_entry.image_type { - ImageType::Normal | ImageType::Heic => { - img = Self::get_normal_heif_image(file_entry)?; - } - ImageType::Raw => { - img = match get_dynamic_image_from_raw_image(&file_entry.path) { - Ok(t) => t, - Err(e) => return Err(format!("Cannot open RAW file \"{}\": {}", file_entry.path.to_string_lossy(), e)), - }; - } - _ => { - unreachable!(); - } - } - } + let img = get_dynamic_image_from_path(&file_entry.path.to_string_lossy())?; let dimensions = img.dimensions(); @@ -420,19 +364,6 @@ impl SimilarImages { Ok(()) } - fn get_normal_heif_image(file_entry: &ImagesEntry) -> Result { - if let Ok(image_result) = panic::catch_unwind(|| image::open(&file_entry.path)) { - match image_result { - Ok(image) => Ok(image), - Err(e) => Err(format!("Cannot open image file \"{}\": {}", file_entry.path.to_string_lossy(), e)), - } - } else { - let message = create_crash_message("Image-rs", &file_entry.path.to_string_lossy(), "https://github.com/image-rs/image/issues"); - println!("{message}"); - Err(message) - } - } - // Split hashes at 2 parts, base hashes and hashes to compare, 3 argument is set of hashes with multiple images #[fun_time(message = "split_hashes", level = "debug")] fn split_hashes(&mut self, all_hashed_images: &HashMap>) -> (Vec, HashSet) { @@ -1087,12 +1018,13 @@ mod tests { use std::collections::HashMap; use std::path::PathBuf; - use crate::common_tool::CommonData; - use crate::similar_images::{Hamming, ImHash, ImageType, ImagesEntry, SimilarImages, SimilarImagesParameters}; use bk_tree::BKTree; use image::imageops::FilterType; use image_hasher::HashAlg; + use crate::common_tool::CommonData; + use crate::similar_images::{Hamming, ImHash, ImagesEntry, SimilarImages, SimilarImagesParameters}; + fn get_default_parameters() -> SimilarImagesParameters { SimilarImagesParameters { hash_alg: HashAlg::Gradient, @@ -1463,7 +1395,6 @@ mod tests { modified_date: 0, hash, similarity: 0, - image_type: ImageType::Normal, } } } diff --git a/czkawka_core/src/similar_videos.rs b/czkawka_core/src/similar_videos.rs index e366ecf66..c8773f696 100644 --- a/czkawka_core/src/similar_videos.rs +++ b/czkawka_core/src/similar_videos.rs @@ -140,7 +140,7 @@ impl SimilarVideos { self.debug_print(); } - // #[fun_time(message = "check_for_similar_videos", level = "debug")] + #[fun_time(message = "check_for_similar_videos", level = "debug")] fn check_for_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { self.common_data.extensions.set_and_validate_allowed_extensions(VIDEO_FILES_EXTENSIONS); if !self.common_data.extensions.set_any_extensions() { @@ -198,6 +198,10 @@ impl SimilarVideos { #[fun_time(message = "sort_videos", level = "debug")] fn sort_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&Sender>) -> bool { + if self.videos_to_check.is_empty() { + return true; + } + let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache_at_start(); let (progress_thread_handle, progress_thread_run, atomic_counter, check_was_stopped) = prepare_thread_handler_common( diff --git a/czkawka_gui/Cargo.toml b/czkawka_gui/Cargo.toml index db0262357..6ffce9a87 100644 --- a/czkawka_gui/Cargo.toml +++ b/czkawka_gui/Cargo.toml @@ -30,7 +30,7 @@ open = "5.3" image = "0.25" # To be able to use custom select -regex = "1.10" +regex = "1.11" # To get image_hasher types image_hasher = "2.0" @@ -45,7 +45,7 @@ fs_extra = "1.3" i18n-embed = { version = "0.15", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.9" rust-embed = { version = "8.5", features = ["debug-embed"] } -once_cell = "1.19" +once_cell = "1.20" log = "0.4.22" handsome_logger = "0.8" @@ -61,3 +61,4 @@ winapi = { version = "0.3.9", features = ["combaseapi", "objbase", "shobjidl_cor default = [] heif = ["czkawka_core/heif"] libraw = ["czkawka_core/libraw"] +libavif = ["czkawka_core/libavif"] diff --git a/czkawka_gui/README.md b/czkawka_gui/README.md index 5db5f1487..90e8d486c 100644 --- a/czkawka_gui/README.md +++ b/czkawka_gui/README.md @@ -10,6 +10,8 @@ Requirements depend on your platform. Prebuilt binaries are available here - https://github.com/qarmin/czkawka/releases/ +Additional features like heif, libraw, libavif require additional libraries to be installed, and may increase + ### Linux #### Prebuild binaries @@ -27,9 +29,21 @@ none - all needed libraries are bundled - https://flathub.org/apps/com.github.qa ### Mac +### Homebrew + +Czkawka gui is available in homebrew - https://formulae.brew.sh/formula/czkawka and can be installed via + ``` +brew install czkawka +``` + +### Manual installation requirements + +``` + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" brew install gtk4 adwaita-icon-theme ffmpeg librsvg libheif libraw + ``` ### Windows @@ -41,7 +55,9 @@ You can also install the app via msys2 (webp and heif should work here) - https: package - https://packages.msys2.org/base/mingw-w64-czkawka) ``` + pacman -S mingw-w64-x86_64-czkawka-gui + ``` and you can create a shortcut to `C:\msys64\mingw64\bin\czkawka_gui.exe` @@ -61,10 +77,11 @@ lot build and runtime dependencies. ### Linux (Ubuntu, but on other OS should work similar) ```shell -sudo apt install libgtk-4-dev libheif-dev libraw-dev -y +sudo apt install libgtk-4-dev -y # Base +sudo apt install libgtk-4-dev libheif-dev libraw-dev libavif-dev libdav1d-dev -y # With features cargo run --release --bin czkawka_gui -# Or with support for heif and libraw -cargo run --release --bin czkawka_gui --features "heif,libraw" +# Or with support for heif, libraw, libavif +cargo run --release --bin czkawka_gui --features "heif,libraw,libavif" ``` ### Mac @@ -74,8 +91,8 @@ cargo run --release --bin czkawka_gui --features "heif,libraw" brew install rustup gtk4 adwaita-icon-theme ffmpeg librsvg libheif libraw pkg-config rustup-init cargo run --release --bin czkawka_gui -# Or with support for heif and libraw -cargo run --release --bin czkawka_gui --features "heif,libraw" +# Or with support for heif, libraw, libavif +cargo run --release --bin czkawka_gui --features "heif,libraw,libavif" ``` ### Windows @@ -91,7 +108,7 @@ purposes - https://github.com/msys2/MINGW-packages/blob/master/mingw-w64-czkawka Not all available features and/or components implemented here, this is the list of limitations: - Snap versions does not allow to use the similar videos feature -- Windows version does not support heif and webp files with prebuilt binaries +- Windows version does not support heif and webp files with prebuilt binaries(msys2 version support them) - Prebuilt binaries for mac arm do not exist - On Windows, text may appear very small on high resolution displays, a solution is to manually change DPI scaling for this app, see : diff --git a/czkawka_gui/i18n/en/czkawka_gui.ftl b/czkawka_gui/i18n/en/czkawka_gui.ftl index 6d6ec9576..121fe51f0 100644 --- a/czkawka_gui/i18n/en/czkawka_gui.ftl +++ b/czkawka_gui/i18n/en/czkawka_gui.ftl @@ -21,6 +21,12 @@ music_checking_by_content = Content same_music_seconds_label = Minimal fragment second duration same_music_similarity_label = Maximum difference +music_compare_only_in_title_group = Compare only in title +music_compare_only_in_title_group_tooltip = + When enabled, files are grouped by title and then compared to each other. + + With 10000 files, instead almost 100 million comparisons usually there will be around 20000 comparisons. + same_music_tooltip = Searching for similar music files by its content can be configured by setting: @@ -332,6 +338,14 @@ header_about_button_tooltip = Opens dialog with info about app. settings_number_of_threads = Number of used threads settings_number_of_threads_tooltip = Number of used threads, 0 means that all available threads will be used. +settings_use_rust_preview = Use external libraries instead gtk to load previews +settings_use_rust_preview_tooltip = + Using gtk previews will sometimes be faster and support more formats, but sometimes this could be exactly the opposite. + + If you have problems with loading previews, you may can to try to change this setting. + + On non-linux systems, it is recommended to use this option, because gtk-pixbuf are not always available there so disabling this option will not load previews of some images. + settings_label_restart = You need to restart app to apply settings! settings_ignore_other_filesystems = Ignore other filesystems (only Linux) diff --git a/czkawka_gui/src/compute_results.rs b/czkawka_gui/src/compute_results.rs index 4ff2205aa..ae60b5246 100644 --- a/czkawka_gui/src/compute_results.rs +++ b/czkawka_gui/src/compute_results.rs @@ -5,12 +5,6 @@ use std::time::Duration; use chrono::DateTime; use crossbeam_channel::Receiver; -use fun_time::fun_time; -use gtk4::prelude::*; -use gtk4::{Entry, ListStore, TextView, TreeView, Widget}; -use humansize::{format_size, BINARY}; -use rayon::prelude::*; - use czkawka_core::bad_extensions::BadExtensions; use czkawka_core::big_file::BigFile; use czkawka_core::broken_files::BrokenFiles; @@ -27,6 +21,11 @@ use czkawka_core::similar_images; use czkawka_core::similar_images::{ImagesEntry, SimilarImages}; use czkawka_core::similar_videos::SimilarVideos; use czkawka_core::temporary::Temporary; +use fun_time::fun_time; +use gtk4::prelude::*; +use gtk4::{Entry, ListStore, TextView, TreeView, Widget}; +use humansize::{format_size, BINARY}; +use rayon::prelude::*; use crate::flg; use crate::gui_structs::gui_data::GuiData; diff --git a/czkawka_gui/src/connect_things/connect_button_compare.rs b/czkawka_gui/src/connect_things/connect_button_compare.rs index d1c8fb976..7985574d7 100644 --- a/czkawka_gui/src/connect_things/connect_button_compare.rs +++ b/czkawka_gui/src/connect_things/connect_button_compare.rs @@ -1,15 +1,12 @@ use std::cell::RefCell; use std::rc::Rc; +use czkawka_core::common_image::get_dynamic_image_from_path; use gdk4::gdk_pixbuf::{InterpType, Pixbuf}; use gtk4::prelude::*; use gtk4::{Align, CheckButton, Image, ListStore, Orientation, ScrolledWindow, TreeIter, TreeModel, TreePath, TreeSelection, Widget}; use image::DynamicImage; -#[cfg(feature = "heif")] -use czkawka_core::common::get_dynamic_image_from_heic; -use czkawka_core::common::HEIC_EXTENSIONS; - use crate::flg; use crate::gui_structs::gui_data::GuiData; use crate::help_functions::{ @@ -44,6 +41,8 @@ pub fn connect_button_compare(gui_data: &GuiData) { let image_compare_left = gui_data.compare_images.image_compare_left.clone(); let image_compare_right = gui_data.compare_images.image_compare_right.clone(); + let check_button_settings_use_rust_preview = gui_data.settings.check_button_settings_use_rust_preview.clone(); + window_compare.set_default_size(700, 700); button_compare.connect_clicked(move |_| { @@ -81,6 +80,7 @@ pub fn connect_button_compare(gui_data: &GuiData) { &shared_using_for_preview, &button_go_previous_compare_group, &button_go_next_compare_group, + &check_button_settings_use_rust_preview, ); window_compare.show(); @@ -125,6 +125,8 @@ pub fn connect_button_compare(gui_data: &GuiData) { let image_compare_left = gui_data.compare_images.image_compare_left.clone(); let image_compare_right = gui_data.compare_images.image_compare_right.clone(); + let check_button_settings_use_rust_preview = gui_data.settings.check_button_settings_use_rust_preview.clone(); + button_go_previous_compare_group.connect_clicked(move |button_go_previous_compare_group| { let nb_number = notebook_main.current_page().expect("Current page not set"); let tree_view = &main_tree_views[nb_number as usize]; @@ -160,6 +162,7 @@ pub fn connect_button_compare(gui_data: &GuiData) { &shared_using_for_preview, button_go_previous_compare_group, &button_go_next_compare_group, + &check_button_settings_use_rust_preview, ); }); @@ -182,6 +185,8 @@ pub fn connect_button_compare(gui_data: &GuiData) { let image_compare_left = gui_data.compare_images.image_compare_left.clone(); let image_compare_right = gui_data.compare_images.image_compare_right.clone(); + let check_button_settings_use_rust_preview = gui_data.settings.check_button_settings_use_rust_preview.clone(); + button_go_next_compare_group.connect_clicked(move |button_go_next_compare_group| { let nb_number = notebook_main.current_page().expect("Current page not set"); let tree_view = &main_tree_views[nb_number as usize]; @@ -217,6 +222,7 @@ pub fn connect_button_compare(gui_data: &GuiData) { &shared_using_for_preview, &button_go_previous_compare_group, button_go_next_compare_group, + &check_button_settings_use_rust_preview, ); }); @@ -299,6 +305,7 @@ fn populate_groups_at_start( shared_using_for_preview: &Rc, Option)>>, button_go_previous_compare_group: >k4::Button, button_go_next_compare_group: >k4::Button, + check_button_settings_use_rust_preview: &CheckButton, ) { if current_group == 1 { button_go_previous_compare_group.set_sensitive(false); @@ -320,7 +327,7 @@ fn populate_groups_at_start( ); *shared_current_path.borrow_mut() = Some(tree_path); - let cache_all_images = generate_cache_for_results(all_vec); + let cache_all_images = generate_cache_for_results(all_vec, check_button_settings_use_rust_preview.is_active()); // This is safe, because cache have at least 2 results image_compare_left.set_paintable(cache_all_images[0].2.paintable().as_ref()); @@ -379,7 +386,7 @@ fn populate_groups_at_start( check_button_right_preview_text.set_active(is_active); } -fn generate_cache_for_results(vector_with_path: Vec<(String, String, TreePath)>) -> Vec<(String, String, Image, Image, TreePath)> { +fn generate_cache_for_results(vector_with_path: Vec<(String, String, TreePath)>, use_rust_loader: bool) -> Vec<(String, String, Image, Image, TreePath)> { // TODO use here threads, // For now threads cannot be used because Image and TreeIter cannot be used in threads let mut cache_all_images = Vec::new(); @@ -388,36 +395,23 @@ fn generate_cache_for_results(vector_with_path: Vec<(String, String, TreePath)>) let big_img = Image::new(); let mut pixbuf = get_pixbuf_from_dynamic_image(&DynamicImage::new_rgb8(1, 1)).expect("Failed to create pixbuf"); - let extension_lowercase = full_path.split('.').last().map(str::to_lowercase); - let is_heic = match extension_lowercase { - Some(extension) => HEIC_EXTENSIONS.iter().any(|e| e == &extension), - None => false, - }; - - if is_heic { - #[allow(clippy::never_loop)] - 'czystka: loop { - #[cfg(feature = "heif")] - if is_heic { - match get_dynamic_image_from_heic(&full_path) { + + if use_rust_loader { + match get_dynamic_image_from_path(&full_path) { + Ok(t) => { + match get_pixbuf_from_dynamic_image(&t) { Ok(t) => { - match get_pixbuf_from_dynamic_image(&t) { - Ok(t) => { - pixbuf = t; - } - Err(e) => { - println!("Failed to open image {full_path}, reason {e}"); - } - }; + pixbuf = t; } Err(e) => { println!("Failed to open image {full_path}, reason {e}"); } }; - break 'czystka; } - break 'czystka; - } + Err(e) => { + println!("Failed to open image {full_path}, reason {e}"); + } + }; } else { match Pixbuf::from_file(&full_path) { Ok(t) => { diff --git a/czkawka_gui/src/connect_things/connect_button_hardlink.rs b/czkawka_gui/src/connect_things/connect_button_hardlink.rs index 12007e5ad..2cba3af66 100644 --- a/czkawka_gui/src/connect_things/connect_button_hardlink.rs +++ b/czkawka_gui/src/connect_things/connect_button_hardlink.rs @@ -1,11 +1,10 @@ use std::fs; use std::path::PathBuf; +use czkawka_core::duplicate::make_hard_link; use gtk4::prelude::*; use gtk4::{Align, CheckButton, Dialog, Orientation, ResponseType, TextView, TreeIter, TreePath}; -use czkawka_core::duplicate::make_hard_link; - use crate::flg; use crate::gui_structs::gui_data::GuiData; use crate::help_functions::*; diff --git a/czkawka_gui/src/connect_things/connect_button_save.rs b/czkawka_gui/src/connect_things/connect_button_save.rs index 7fbc7b961..552d84b0a 100644 --- a/czkawka_gui/src/connect_things/connect_button_save.rs +++ b/czkawka_gui/src/connect_things/connect_button_save.rs @@ -3,11 +3,10 @@ use std::collections::HashMap; use std::env; use std::rc::Rc; +use czkawka_core::common_traits::PrintResults; use gtk4::prelude::*; use gtk4::{Button, Entry}; -use czkawka_core::common_traits::PrintResults; - use crate::flg; use crate::gui_structs::gui_data::GuiData; use crate::help_functions::BottomButtonsEnum; diff --git a/czkawka_gui/src/connect_things/connect_button_search.rs b/czkawka_gui/src/connect_things/connect_button_search.rs index ef30c445f..3ff8831f4 100644 --- a/czkawka_gui/src/connect_things/connect_button_search.rs +++ b/czkawka_gui/src/connect_things/connect_button_search.rs @@ -4,10 +4,6 @@ use std::sync::Arc; use std::thread; use crossbeam_channel::{Receiver, Sender}; -use fun_time::fun_time; -use gtk4::prelude::*; -use gtk4::Grid; - use czkawka_core::bad_extensions::{BadExtensions, BadExtensionsParameters}; use czkawka_core::big_file::{BigFile, BigFileParameters}; use czkawka_core::broken_files::{BrokenFiles, BrokenFilesParameters, CheckedTypes}; @@ -23,6 +19,9 @@ use czkawka_core::same_music::{MusicSimilarity, SameMusic, SameMusicParameters}; use czkawka_core::similar_images::{SimilarImages, SimilarImagesParameters}; use czkawka_core::similar_videos::{SimilarVideos, SimilarVideosParameters}; use czkawka_core::temporary::Temporary; +use fun_time::fun_time; +use gtk4::prelude::*; +use gtk4::Grid; use crate::gui_structs::gui_data::GuiData; use crate::help_combo_box::{ diff --git a/czkawka_gui/src/connect_things/connect_duplicate_buttons.rs b/czkawka_gui/src/connect_things/connect_duplicate_buttons.rs index 4b88d15a1..f5e7775ac 100644 --- a/czkawka_gui/src/connect_things/connect_duplicate_buttons.rs +++ b/czkawka_gui/src/connect_things/connect_duplicate_buttons.rs @@ -1,6 +1,5 @@ -use gtk4::prelude::*; - use czkawka_core::common_dir_traversal::CheckingMethod; +use gtk4::prelude::*; use crate::gui_structs::gui_data::GuiData; use crate::help_combo_box::DUPLICATES_CHECK_METHOD_COMBO_BOX; diff --git a/czkawka_gui/src/connect_things/connect_popovers_select.rs b/czkawka_gui/src/connect_things/connect_popovers_select.rs index fd173d115..26f225ccd 100644 --- a/czkawka_gui/src/connect_things/connect_popovers_select.rs +++ b/czkawka_gui/src/connect_things/connect_popovers_select.rs @@ -1,10 +1,9 @@ +use czkawka_core::common::regex_check; +use czkawka_core::common_items::new_excluded_item; use gtk4::prelude::*; use gtk4::{ResponseType, TreeIter, Window}; use regex::Regex; -use czkawka_core::common::regex_check; -use czkawka_core::common_items::new_excluded_item; - use crate::flg; use crate::gui_structs::gui_data::GuiData; use crate::help_functions::*; diff --git a/czkawka_gui/src/connect_things/connect_progress_window.rs b/czkawka_gui/src/connect_things/connect_progress_window.rs index 474e10274..63a0d99e1 100644 --- a/czkawka_gui/src/connect_things/connect_progress_window.rs +++ b/czkawka_gui/src/connect_things/connect_progress_window.rs @@ -4,6 +4,8 @@ use std::rc::Rc; use std::time::Duration; use crossbeam_channel::Receiver; +use czkawka_core::common_dir_traversal::ToolType; +use czkawka_core::progress_data::{CurrentStage, ProgressData}; use glib::MainContext; use gtk4::prelude::*; use gtk4::ProgressBar; @@ -13,8 +15,6 @@ use crate::gui_structs::gui_data::GuiData; use crate::localizer_core::generate_translation_hashmap; use crate::taskbar_progress::tbp_flags::TBPF_INDETERMINATE; use crate::taskbar_progress::TaskbarProgress; -use czkawka_core::common_dir_traversal::ToolType; -use czkawka_core::progress_data::{CurrentStage, ProgressData}; #[allow(clippy::too_many_arguments)] pub fn connect_progress_window(gui_data: &GuiData, progress_receiver: Receiver) { diff --git a/czkawka_gui/src/connect_things/connect_same_music_mode_changed.rs b/czkawka_gui/src/connect_things/connect_same_music_mode_changed.rs index 2d8747aff..40ba7326e 100644 --- a/czkawka_gui/src/connect_things/connect_same_music_mode_changed.rs +++ b/czkawka_gui/src/connect_things/connect_same_music_mode_changed.rs @@ -1,8 +1,7 @@ +use czkawka_core::common_dir_traversal::CheckingMethod; use gtk4::prelude::*; use gtk4::{CheckButton, Widget}; -use czkawka_core::common_dir_traversal::CheckingMethod; - use crate::gui_structs::gui_data::GuiData; use crate::help_combo_box::AUDIO_TYPE_CHECK_METHOD_COMBO_BOX; use crate::help_functions::scale_set_min_max_values; diff --git a/czkawka_gui/src/connect_things/connect_selection_of_directories.rs b/czkawka_gui/src/connect_things/connect_selection_of_directories.rs index 8bc3b1ebf..e710848d7 100644 --- a/czkawka_gui/src/connect_things/connect_selection_of_directories.rs +++ b/czkawka_gui/src/connect_things/connect_selection_of_directories.rs @@ -1,13 +1,12 @@ use std::collections::HashSet; use std::path::PathBuf; +#[cfg(target_family = "windows")] +use czkawka_core::common::normalize_windows_path; use gdk4::{DragAction, FileList}; use gtk4::prelude::*; use gtk4::{DropTarget, FileChooserNative, Notebook, Orientation, ResponseType, TreeView, Window}; -#[cfg(target_family = "windows")] -use czkawka_core::common::normalize_windows_path; - use crate::flg; use crate::gui_structs::gui_data::GuiData; use crate::help_functions::{check_if_value_is_in_list_store, get_list_store, ColumnsExcludedDirectory, ColumnsIncludedDirectory}; diff --git a/czkawka_gui/src/connect_things/connect_settings.rs b/czkawka_gui/src/connect_things/connect_settings.rs index e6e361c32..4c511cdbd 100644 --- a/czkawka_gui/src/connect_things/connect_settings.rs +++ b/czkawka_gui/src/connect_things/connect_settings.rs @@ -1,18 +1,17 @@ use std::collections::BTreeMap; use std::default::Default; -use directories_next::ProjectDirs; -use gtk4::prelude::*; -use gtk4::{Label, ResponseType, Window}; -use image::imageops::FilterType; -use image_hasher::HashAlg; - use czkawka_core::common_cache::{ get_duplicate_cache_file, get_similar_images_cache_file, get_similar_videos_cache_file, load_cache_from_file_generalized_by_path, load_cache_from_file_generalized_by_size, save_cache_to_file_generalized, }; use czkawka_core::common_messages::Messages; use czkawka_core::duplicate::HashType; +use directories_next::ProjectDirs; +use gtk4::prelude::*; +use gtk4::{Label, ResponseType, Window}; +use image::imageops::FilterType; +use image_hasher::HashAlg; use crate::flg; use crate::gui_structs::gui_data::GuiData; diff --git a/czkawka_gui/src/connect_things/connect_similar_image_size_change.rs b/czkawka_gui/src/connect_things/connect_similar_image_size_change.rs index a5c209b2d..64258ea38 100644 --- a/czkawka_gui/src/connect_things/connect_similar_image_size_change.rs +++ b/czkawka_gui/src/connect_things/connect_similar_image_size_change.rs @@ -1,6 +1,5 @@ -use gtk4::prelude::*; - use czkawka_core::similar_images::{get_string_from_similarity, SIMILAR_VALUES}; +use gtk4::prelude::*; use crate::gui_structs::gui_data::GuiData; use crate::help_combo_box::IMAGES_HASH_SIZE_COMBO_BOX; diff --git a/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs b/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs index 7389985d5..f391afe74 100644 --- a/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs +++ b/czkawka_gui/src/gui_structs/gui_bottom_buttons.rs @@ -147,11 +147,12 @@ impl GuiBottomButtons { #[cfg(target_family = "windows")] fn test_hardlinks() -> bool { - use directories_next::ProjectDirs; use std::fs; use std::io::Write; use std::path::Path; + use directories_next::ProjectDirs; + let mut hardlinked = false; if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") { diff --git a/czkawka_gui/src/gui_structs/gui_data.rs b/czkawka_gui/src/gui_structs/gui_data.rs index 64d5966db..90a553e89 100644 --- a/czkawka_gui/src/gui_structs/gui_data.rs +++ b/czkawka_gui/src/gui_structs/gui_data.rs @@ -4,10 +4,6 @@ use std::io::BufReader; use std::rc::Rc; use crossbeam_channel::bounded; -use gdk4::gdk_pixbuf::Pixbuf; -use gtk4::prelude::*; -use gtk4::{Builder, FileChooserNative}; - use czkawka_core::bad_extensions::BadExtensions; use czkawka_core::big_file::BigFile; use czkawka_core::broken_files::BrokenFiles; @@ -19,6 +15,9 @@ use czkawka_core::same_music::SameMusic; use czkawka_core::similar_images::SimilarImages; use czkawka_core::similar_videos::SimilarVideos; use czkawka_core::temporary::Temporary; +use gdk4::gdk_pixbuf::Pixbuf; +use gtk4::prelude::*; +use gtk4::{Builder, FileChooserNative}; use crate::flg; use crate::gui_structs::gui_about::GuiAbout; diff --git a/czkawka_gui/src/gui_structs/gui_main_notebook.rs b/czkawka_gui/src/gui_structs/gui_main_notebook.rs index 89bdea1e4..2b89637ba 100644 --- a/czkawka_gui/src/gui_structs/gui_main_notebook.rs +++ b/czkawka_gui/src/gui_structs/gui_main_notebook.rs @@ -1,10 +1,9 @@ -use gtk4::prelude::*; -use gtk4::{Builder, CheckButton, ComboBoxText, Entry, EventControllerKey, GestureClick, Image, Label, Notebook, Scale, ScrolledWindow, TreeView, Widget}; - use czkawka_core::big_file::SearchMode; use czkawka_core::common_dir_traversal::CheckingMethod; use czkawka_core::localizer_core::{fnc_get_similarity_minimal, fnc_get_similarity_very_high}; use czkawka_core::similar_images::{get_string_from_similarity, SIMILAR_VALUES}; +use gtk4::prelude::*; +use gtk4::{Builder, CheckButton, ComboBoxText, Entry, EventControllerKey, GestureClick, Image, Label, Notebook, Scale, ScrolledWindow, TreeView, Widget}; use crate::flg; use crate::help_combo_box::{AUDIO_TYPE_CHECK_METHOD_COMBO_BOX, BIG_FILES_CHECK_METHOD_COMBO_BOX, DUPLICATES_CHECK_METHOD_COMBO_BOX, IMAGES_HASH_SIZE_COMBO_BOX}; @@ -382,6 +381,8 @@ impl GuiMainNotebook { self.check_button_music_genre.set_label(Some(&flg!("music_genre_checkbox"))); self.check_button_music_length.set_label(Some(&flg!("music_length_checkbox"))); self.check_button_music_approximate_comparison.set_label(Some(&flg!("music_comparison_checkbox"))); + self.check_button_music_compare_only_in_title_group + .set_label(Some(&flg!("music_compare_only_in_title_group"))); self.check_button_music_approximate_comparison .set_tooltip_text(Some(&flg!("music_comparison_checkbox_tooltip"))); @@ -404,6 +405,8 @@ impl GuiMainNotebook { self.combo_box_duplicate_hash_type.set_tooltip_text(Some(&flg!("duplicate_hash_type_tooltip"))); self.check_button_duplicate_case_sensitive_name .set_tooltip_text(Some(&flg!("duplicate_case_sensitive_name_tooltip"))); + self.check_button_music_compare_only_in_title_group + .set_tooltip_text(Some(&flg!("music_compare_only_in_title_group_tooltip"))); self.combo_box_image_hash_size.set_tooltip_text(Some(&flg!("image_hash_size_tooltip"))); self.label_image_hash_size.set_tooltip_text(Some(&flg!("image_hash_size_tooltip"))); diff --git a/czkawka_gui/src/gui_structs/gui_settings.rs b/czkawka_gui/src/gui_structs/gui_settings.rs index 95795625b..67dcf82ae 100644 --- a/czkawka_gui/src/gui_structs/gui_settings.rs +++ b/czkawka_gui/src/gui_structs/gui_settings.rs @@ -26,6 +26,7 @@ pub struct GuiSettings { pub label_settings_number_of_threads: gtk4::Label, pub scale_settings_number_of_threads: gtk4::Scale, pub label_restart_needed: gtk4::Label, + pub check_button_settings_use_rust_preview: gtk4::CheckButton, // Duplicates pub check_button_settings_hide_hard_links: gtk4::CheckButton, @@ -84,6 +85,7 @@ impl GuiSettings { let label_settings_number_of_threads: gtk4::Label = builder.object("label_settings_number_of_threads").expect("Cambalache"); let scale_settings_number_of_threads: gtk4::Scale = builder.object("scale_settings_number_of_threads").expect("Cambalache"); let label_restart_needed: gtk4::Label = builder.object("label_restart_needed").expect("Cambalache"); + let check_button_settings_use_rust_preview: gtk4::CheckButton = builder.object("check_button_settings_use_rust_preview").expect("Cambalache"); // Duplicates let check_button_settings_hide_hard_links: gtk4::CheckButton = builder.object("check_button_settings_hide_hard_links").expect("Cambalache"); @@ -134,6 +136,7 @@ impl GuiSettings { label_settings_number_of_threads, scale_settings_number_of_threads, label_restart_needed, + check_button_settings_use_rust_preview, check_button_settings_hide_hard_links, entry_settings_cache_file_minimal_size, entry_settings_prehash_cache_file_minimal_size, @@ -176,6 +179,7 @@ impl GuiSettings { self.label_settings_general_language.set_label(&flg!("settings_language_label")); self.check_button_settings_one_filesystem.set_label(Some(&flg!("settings_ignore_other_filesystems"))); self.label_settings_number_of_threads.set_label(&flg!("settings_number_of_threads")); + self.check_button_settings_use_rust_preview.set_label(Some(&flg!("settings_use_rust_preview"))); self.check_button_settings_save_at_exit .set_tooltip_text(Some(&flg!("settings_save_at_exit_button_tooltip"))); @@ -197,6 +201,8 @@ impl GuiSettings { self.check_button_settings_one_filesystem .set_tooltip_text(Some(&flg!("settings_ignore_other_filesystems_tooltip"))); self.scale_settings_number_of_threads.set_tooltip_text(Some(&flg!("settings_number_of_threads_tooltip"))); + self.check_button_settings_use_rust_preview + .set_tooltip_text(Some(&flg!("settings_use_rust_preview_tooltip"))); self.check_button_settings_hide_hard_links .set_label(Some(&flg!("settings_duplicates_hide_hard_link_button"))); diff --git a/czkawka_gui/src/help_combo_box.rs b/czkawka_gui/src/help_combo_box.rs index 17ba2c6c8..ddecc4a8f 100644 --- a/czkawka_gui/src/help_combo_box.rs +++ b/czkawka_gui/src/help_combo_box.rs @@ -1,8 +1,7 @@ -use image_hasher::{FilterType, HashAlg}; - use czkawka_core::big_file::SearchMode; use czkawka_core::common_dir_traversal::CheckingMethod; use czkawka_core::duplicate::HashType; +use image_hasher::{FilterType, HashAlg}; pub struct HashTypeStruct { pub eng_name: &'static str, diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index 60009468b..0fa7a0ac1 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -1,10 +1,3 @@ -use gdk4::gdk_pixbuf::{InterpType, Pixbuf}; -use glib::Error; -use gtk4::prelude::*; -use gtk4::{ListStore, Scale, ScrollType, TextView, TreeView, Widget}; -use image::codecs::jpeg::JpegEncoder; -use image::{DynamicImage, EncodableLayout}; -use once_cell::sync::OnceCell; use std::cell::RefCell; use std::cmp::Ordering; use std::collections::HashMap; @@ -25,6 +18,13 @@ use czkawka_core::same_music::SameMusic; use czkawka_core::similar_images::SimilarImages; use czkawka_core::similar_videos::SimilarVideos; use czkawka_core::temporary::Temporary; +use gdk4::gdk_pixbuf::{InterpType, Pixbuf}; +use glib::Error; +use gtk4::prelude::*; +use gtk4::{ListStore, Scale, ScrollType, TextView, TreeView, Widget}; +use image::codecs::jpeg::JpegEncoder; +use image::{DynamicImage, EncodableLayout}; +use once_cell::sync::OnceCell; use crate::flg; use crate::notebook_enums::{NotebookMainEnum, NotebookUpperEnum}; diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index cd96a58d9..2e39d0287 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -1,19 +1,15 @@ use std::cell::RefCell; -use std::path::Path; use std::rc::Rc; +use czkawka_core::common_image::get_dynamic_image_from_path; +use czkawka_core::similar_images::SIMILAR_VALUES; +use czkawka_core::similar_videos::MAX_TOLERANCE; use gdk4::gdk_pixbuf::Pixbuf; use glib::types::Type; use gtk4::gdk_pixbuf::InterpType; use gtk4::prelude::*; use gtk4::{CheckButton, Image, ScrolledWindow, SelectionMode, TextView, TreeModel, TreePath, TreeSelection, TreeView}; -#[cfg(feature = "heif")] -use czkawka_core::common::get_dynamic_image_from_heic; -use czkawka_core::common::{HEIC_EXTENSIONS, IMAGE_RS_EXTENSIONS, RAW_IMAGE_EXTENSIONS}; -use czkawka_core::similar_images::SIMILAR_VALUES; -use czkawka_core::similar_videos::MAX_TOLERANCE; - use crate::create_tree_view::*; use crate::gui_structs::gui_data::*; use crate::help_combo_box::{ @@ -335,6 +331,7 @@ fn connect_event_mouse(gui_data: &GuiData) { let image_preview = gui_data.main_notebook.image_preview_duplicates.clone(); let preview_path = gui_data.preview_path.clone(); let tree_view = gui_data.main_notebook.tree_view_duplicate_finder.clone(); + let check_button_settings_use_rust_preview = gui_data.settings.check_button_settings_use_rust_preview.clone(); tree_view.set_property("activate-on-single-click", true); @@ -351,6 +348,7 @@ fn connect_event_mouse(gui_data: &GuiData) { &preview_path, nb_object.column_path, nb_object.column_name, + check_button_settings_use_rust_preview.is_active(), ); }); } @@ -361,6 +359,7 @@ fn connect_event_mouse(gui_data: &GuiData) { let preview_path = gui_data.preview_path.clone(); let image_preview = gui_data.main_notebook.image_preview_similar_images.clone(); let tree_view = gui_data.main_notebook.tree_view_similar_images_finder.clone(); + let check_button_settings_use_rust_preview = gui_data.settings.check_button_settings_use_rust_preview.clone(); tree_view.set_property("activate-on-single-click", true); @@ -376,6 +375,7 @@ fn connect_event_mouse(gui_data: &GuiData) { &preview_path, nb_object.column_path, nb_object.column_name, + check_button_settings_use_rust_preview.is_active(), ); }); } @@ -412,6 +412,7 @@ fn connect_event_buttons(gui_data: &GuiData) { let image_preview = gui_data.main_notebook.image_preview_duplicates.clone(); let preview_path = gui_data.preview_path.clone(); let evk = gui_data.main_notebook.evk_tree_view_duplicate_finder.clone(); + let check_button_settings_use_rust_preview = gui_data.settings.check_button_settings_use_rust_preview.clone(); evk.connect_key_pressed(opening_enter_function_ported); @@ -433,6 +434,7 @@ fn connect_event_buttons(gui_data: &GuiData) { &preview_path, nb_object.column_path, nb_object.column_name, + check_button_settings_use_rust_preview.is_active(), ); }); } @@ -444,6 +446,7 @@ fn connect_event_buttons(gui_data: &GuiData) { let gui_data_clone = gui_data.clone(); let preview_path = gui_data.preview_path.clone(); let evk = gui_data.main_notebook.evk_tree_view_similar_images_finder.clone(); + let check_button_settings_use_rust_preview = gui_data.settings.check_button_settings_use_rust_preview.clone(); evk.connect_key_pressed(opening_enter_function_ported); @@ -465,6 +468,7 @@ fn connect_event_buttons(gui_data: &GuiData) { &preview_path, nb_object.column_path, nb_object.column_name, + check_button_settings_use_rust_preview.is_active(), ); }); } @@ -478,6 +482,7 @@ fn show_preview( preview_path: &Rc>, column_path: i32, column_name: i32, + use_rust_preview: bool, ) { let (selected_rows, tree_model) = tree_view.selection().selected_rows(); @@ -493,29 +498,13 @@ fn show_preview( let name = tree_model.get::(&tree_model.iter(&tree_path).expect("Invalid tree_path"), column_name); let file_name = get_full_name_from_path_name(&path, &name); - let file_name = file_name.as_str(); - { - let preview_path = preview_path.borrow(); - let preview_path = &*preview_path; - if file_name == preview_path { - return; // Preview is already created, no need to recreate it - } + if file_name == preview_path.borrow().as_str() { + return; // Preview is already created, no need to recreate it } - let is_heic; - if let Some(extension) = Path::new(&name).extension() { - let extension_lowercase = extension.to_string_lossy().to_lowercase(); - is_heic = HEIC_EXTENSIONS.contains(&extension_lowercase.as_str()); - if !RAW_IMAGE_EXTENSIONS.contains(&extension_lowercase.as_str()) && !IMAGE_RS_EXTENSIONS.contains(&extension_lowercase.as_str()) && !is_heic { - break 'dir; - } - } else { - break 'dir; - } - let mut pixbuf = if cfg!(feature = "heif") && is_heic { - #[cfg(feature = "heif")] - let image = match get_dynamic_image_from_heic(file_name) { + let mut pixbuf = if use_rust_preview { + let image = match get_dynamic_image_from_path(&file_name) { Ok(t) => t, Err(e) => { add_text_to_text_view(text_view_errors, flg!("preview_image_opening_failure", name = file_name, reason = e.to_string()).as_str()); @@ -523,7 +512,6 @@ fn show_preview( } }; - #[cfg(feature = "heif")] match get_pixbuf_from_dynamic_image(&image) { Ok(t) => t, Err(e) => { @@ -531,18 +519,15 @@ fn show_preview( break 'dir; } } - - #[cfg(not(feature = "heif"))] - unreachable!() } else { - match Pixbuf::from_file(file_name) { + match Pixbuf::from_file(&file_name) { Ok(pixbuf) => pixbuf, Err(e) => { add_text_to_text_view( text_view_errors, flg!( "preview_image_opening_failure", - generate_translation_hashmap(vec![("name", file_name.to_string()), ("reason", e.to_string())]) + generate_translation_hashmap(vec![("name", file_name), ("reason", e.to_string())]) ) .as_str(), ); @@ -550,7 +535,6 @@ fn show_preview( } } }; - pixbuf = match resize_pixbuf_dimension(&pixbuf, (800, 800), InterpType::Bilinear) { None => { add_text_to_text_view(text_view_errors, flg!("preview_image_resize_failure", name = file_name).as_str()); @@ -562,7 +546,7 @@ fn show_preview( image_preview.set_from_pixbuf(Some(&pixbuf)); { let mut preview_path = preview_path.borrow_mut(); - *preview_path = file_name.to_string(); + *preview_path = file_name; } created_image = true; diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index bdeeaffd1..551920e36 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -9,12 +9,6 @@ use std::env; use std::ffi::OsString; -use crossbeam_channel::{unbounded, Receiver, Sender}; -use gtk4::gio::ApplicationFlags; -use gtk4::prelude::*; -use gtk4::Application; -use log::info; - use connect_things::connect_about_buttons::*; use connect_things::connect_button_compare::*; use connect_things::connect_button_delete::*; @@ -33,10 +27,15 @@ use connect_things::connect_selection_of_directories::*; use connect_things::connect_settings::*; use connect_things::connect_show_hide_ui::*; use connect_things::connect_similar_image_size_change::*; +use crossbeam_channel::{unbounded, Receiver, Sender}; use czkawka_core::common::{get_number_of_threads, print_version_mode, set_number_of_threads, setup_logger}; use czkawka_core::progress_data::ProgressData; use czkawka_core::*; +use gtk4::gio::ApplicationFlags; +use gtk4::prelude::*; +use gtk4::Application; use gui_structs::gui_data::*; +use log::info; use crate::compute_results::*; use crate::connect_things::connect_button_sort::connect_button_sort; diff --git a/czkawka_gui/src/saving_loading.rs b/czkawka_gui/src/saving_loading.rs index 354998558..8fa27c350 100644 --- a/czkawka_gui/src/saving_loading.rs +++ b/czkawka_gui/src/saving_loading.rs @@ -5,14 +5,13 @@ use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::{env, fs}; -use directories_next::ProjectDirs; -use gtk4::prelude::*; -use gtk4::{ComboBoxText, ScrolledWindow, TextView, TreeView}; - use czkawka_core::common::get_all_available_threads; use czkawka_core::common_dir_traversal::CheckingMethod; use czkawka_core::common_items::DEFAULT_EXCLUDED_ITEMS; use czkawka_core::similar_images::SIMILAR_VALUES; +use directories_next::ProjectDirs; +use gtk4::prelude::*; +use gtk4::{ComboBoxText, ScrolledWindow, TextView, TreeView}; use crate::flg; use crate::gui_structs::gui_main_notebook::GuiMainNotebook; @@ -43,9 +42,10 @@ const DEFAULT_IMAGE_REMOVE_AUTO_OUTDATED_CACHE: bool = true; const DEFAULT_DUPLICATE_REMOVE_AUTO_OUTDATED_CACHE: bool = true; const DEFAULT_DUPLICATE_CASE_SENSITIVE_NAME_CHECKING: bool = false; const DEFAULT_GENERAL_IGNORE_OTHER_FILESYSTEMS: bool = false; +const DEFUALT_USING_RUST_LIBRARIES_TO_SHOW_PREVIEW: bool = true; const DEFAULT_MUSIC_APPROXIMATE_COMPARISON: bool = false; -const DEFAULT_MUSIC_COMPARE_BY_TITLE: bool = false; +const DEFAULT_MUSIC_GROUP_CONTENT_BY_TITLE: bool = false; const DEFAULT_BROKEN_FILES_PDF: bool = true; const DEFAULT_BROKEN_FILES_AUDIO: bool = true; @@ -391,6 +391,7 @@ enum LoadText { BrokenFilesImage, BrokenFilesArchive, ThreadNumber, + GeneralUseRustLibrariesToPreview, } fn create_hash_map() -> (HashMap, HashMap) { @@ -439,6 +440,7 @@ fn create_hash_map() -> (HashMap, HashMap) { (LoadText::GeneralIgnoreOtherFilesystems, "ignore_other_filesystems"), (LoadText::ThreadNumber, "thread_number"), (LoadText::MusicCompareByTitle, "music_compare_by_title"), + (LoadText::GeneralUseRustLibrariesToPreview, "use_rust_libraries_to_preview"), ]; let mut hashmap_ls: HashMap = Default::default(); let mut hashmap_sl: HashMap = Default::default(); @@ -529,6 +531,10 @@ pub fn save_configuration(manual_execution: bool, upper_notebook: &GuiUpperNoteb hashmap_ls[&LoadText::GeneralIgnoreOtherFilesystems].clone(), &settings.check_button_settings_one_filesystem.is_active(), ); + saving_struct.save_var( + hashmap_ls[&LoadText::GeneralUseRustLibrariesToPreview].clone(), + &settings.check_button_settings_use_rust_preview.is_active(), + ); saving_struct.save_var( hashmap_ls[&LoadText::BrokenFilesArchive].clone(), @@ -656,6 +662,11 @@ pub fn load_configuration( let use_json_cache: bool = loaded_entries.get_bool(hashmap_ls[&LoadText::UseJsonCacheFile].clone(), DEFAULT_SAVE_ALSO_AS_JSON); let use_trash: bool = loaded_entries.get_bool(hashmap_ls[&LoadText::DeleteToTrash].clone(), DEFAULT_USE_TRASH); let ignore_other_fs: bool = loaded_entries.get_bool(hashmap_ls[&LoadText::GeneralIgnoreOtherFilesystems].clone(), DEFAULT_GENERAL_IGNORE_OTHER_FILESYSTEMS); + let use_rust_libraries_to_preview: bool = loaded_entries.get_bool( + hashmap_ls[&LoadText::GeneralUseRustLibrariesToPreview].clone(), + DEFUALT_USING_RUST_LIBRARIES_TO_SHOW_PREVIEW, + ); + let delete_outdated_cache_duplicates: bool = loaded_entries.get_bool( hashmap_ls[&LoadText::DuplicateDeleteOutdatedCacheEntries].clone(), DEFAULT_DUPLICATE_REMOVE_AUTO_OUTDATED_CACHE, @@ -685,7 +696,7 @@ pub fn load_configuration( let similar_videos_ignore_same_size = loaded_entries.get_bool(hashmap_ls[&LoadText::SimilarVideosIgnoreSameSize].clone(), DEFAULT_SIMILAR_VIDEOS_IGNORE_SAME_SIZE); let check_button_case_sensitive_name = loaded_entries.get_object(hashmap_ls[&LoadText::DuplicateNameCaseSensitive].clone(), DEFAULT_DUPLICATE_CASE_SENSITIVE_NAME_CHECKING); let check_button_music_approximate_comparison = loaded_entries.get_object(hashmap_ls[&LoadText::MusicApproximateComparison].clone(), DEFAULT_MUSIC_APPROXIMATE_COMPARISON); - let check_button_music_compare_by_title = loaded_entries.get_object(hashmap_ls[&LoadText::MusicCompareByTitle].clone(), DEFAULT_MUSIC_COMPARE_BY_TITLE); + let check_button_music_compare_by_title = loaded_entries.get_object(hashmap_ls[&LoadText::MusicCompareByTitle].clone(), DEFAULT_MUSIC_GROUP_CONTENT_BY_TITLE); let check_button_broken_files_archive = loaded_entries.get_object(hashmap_ls[&LoadText::BrokenFilesArchive].clone(), DEFAULT_BROKEN_FILES_ARCHIVE); let check_button_broken_files_pdf = loaded_entries.get_object(hashmap_ls[&LoadText::BrokenFilesPdf].clone(), DEFAULT_BROKEN_FILES_PDF); @@ -800,6 +811,7 @@ pub fn load_configuration( settings.entry_settings_cache_file_minimal_size.set_text(&cache_minimal_size); settings.entry_settings_prehash_cache_file_minimal_size.set_text(&cache_prehash_minimal_size); settings.check_button_settings_one_filesystem.set_active(ignore_other_fs); + settings.check_button_settings_use_rust_preview.set_active(use_rust_libraries_to_preview); save_proper_value_to_combo_box(&main_notebook.combo_box_duplicate_hash_type, combo_box_duplicate_hash_type); save_proper_value_to_combo_box(&main_notebook.combo_box_duplicate_check_method, combo_box_duplicate_checking_method); @@ -966,6 +978,7 @@ pub fn reset_configuration(manual_clearing: bool, upper_notebook: &GuiUpperNoteb settings.entry_settings_prehash_cache_file_minimal_size.set_text(DEFAULT_PREHASH_MINIMAL_CACHE_SIZE); settings.combo_box_settings_language.set_active(Some(0)); settings.check_button_settings_one_filesystem.set_active(DEFAULT_GENERAL_IGNORE_OTHER_FILESYSTEMS); + settings.check_button_settings_use_rust_preview.set_active(DEFUALT_USING_RUST_LIBRARIES_TO_SHOW_PREVIEW); main_notebook.combo_box_duplicate_hash_type.set_active(Some(0)); main_notebook.combo_box_duplicate_check_method.set_active(Some(0)); @@ -982,6 +995,12 @@ pub fn reset_configuration(manual_clearing: bool, upper_notebook: &GuiUpperNoteb main_notebook.scale_similarity_similar_images.set_range(0_f64, SIMILAR_VALUES[0][5] as f64); // DEFAULT FOR MAX of 8 main_notebook.scale_similarity_similar_images.set_fill_level(SIMILAR_VALUES[0][5] as f64); + main_notebook + .check_button_music_compare_only_in_title_group + .set_active(DEFAULT_MUSIC_GROUP_CONTENT_BY_TITLE); + + main_notebook.check_button_music_approximate_comparison.set_active(DEFAULT_MUSIC_APPROXIMATE_COMPARISON); + main_notebook.entry_big_files_number.set_text(DEFAULT_NUMBER_OF_BIGGEST_FILES); main_notebook.scale_similarity_similar_images.set_value(DEFAULT_SIMILAR_IMAGES_SIMILARITY as f64); main_notebook.check_button_image_ignore_same_size.set_active(DEFAULT_SIMILAR_IMAGES_IGNORE_SAME_SIZE); diff --git a/czkawka_gui/ui/about_dialog.ui b/czkawka_gui/ui/about_dialog.ui index 5b3581f73..1f9320a35 100644 --- a/czkawka_gui/ui/about_dialog.ui +++ b/czkawka_gui/ui/about_dialog.ui @@ -1,5 +1,5 @@ - + diff --git a/czkawka_gui/ui/compare_images.ui b/czkawka_gui/ui/compare_images.ui index 210067924..f0edba028 100644 --- a/czkawka_gui/ui/compare_images.ui +++ b/czkawka_gui/ui/compare_images.ui @@ -1,5 +1,5 @@ - + diff --git a/czkawka_gui/ui/czkawka.cmb b/czkawka_gui/ui/czkawka.cmb index c3e58692a..abc1e69a0 100755 --- a/czkawka_gui/ui/czkawka.cmb +++ b/czkawka_gui/ui/czkawka.cmb @@ -1,6 +1,6 @@ - + (3,None,"about_dialog.ui","about_dialog.ui",None,None,None,None,None,None,None), (4,None,"compare_images.ui","compare_images.ui",None,None,None,None,None,None,None), @@ -22,139 +22,139 @@ (10,"gtk","4.6",None) - (3,1,"GtkAboutDialog","about_dialog",None,None,None,None,None,None,None), - (4,1,"GtkDialog","window_compare",None,None,None,None,None,None,None), - (4,2,"GtkBox",None,1,None,None,None,None,None,None), - (4,3,"GtkBox",None,2,None,None,None,None,None,None), + (3,1,"GtkAboutDialog","about_dialog",None,None,None,None,0,None,None), + (4,1,"GtkDialog","window_compare",None,None,None,None,0,None,None), + (4,2,"GtkBox",None,1,None,None,None,0,None,None), + (4,3,"GtkBox",None,2,None,None,None,0,None,None), (4,4,"GtkLabel","label_group_info",3,None,None,None,1,None,None), (4,5,"GtkButton","button_go_next_compare_group",3,None,None,None,2,None,None), - (4,6,"GtkImage",None,5,None,None,None,None,None,None), - (4,7,"GtkButton","button_go_previous_compare_group",3,None,None,None,None,None,None), - (4,8,"GtkImage",None,7,None,None,None,None,None,None), + (4,6,"GtkImage",None,5,None,None,None,0,None,None), + (4,7,"GtkButton","button_go_previous_compare_group",3,None,None,None,0,None,None), + (4,8,"GtkImage",None,7,None,None,None,0,None,None), (4,9,"GtkBox",None,2,None,None,None,1,None,None), - (4,10,"GtkCheckButton","check_button_left_preview_text",9,None,None,None,None,None,None), + (4,10,"GtkCheckButton","check_button_left_preview_text",9,None,None,None,0,None,None), (4,11,"GtkCheckButton","check_button_right_preview_text",9,None,None,None,1,None,None), (4,12,"GtkBox",None,2,None,None,None,2,None,None), - (4,13,"GtkImage","image_compare_left",12,None,None,None,None,None,None), + (4,13,"GtkImage","image_compare_left",12,None,None,None,0,None,None), (4,14,"GtkImage","image_compare_right",12,None,None,None,1,None,None), (4,15,"GtkScrolledWindow","scrolled_window_compare_choose_images",2,None,None,None,3,None,None), - (5,1,"GtkAdjustment","adjustment1",None,None,None,None,None,None,None), - (5,2,"GtkWindow","window_main",None,None,None,None,None,None,None), - (5,3,"GtkBox",None,2,None,None,None,None,None,None), - (5,4,"GtkPaned",None,3,None,None,None,None,None,None), - (5,5,"GtkNotebook","notebook_upper",4,None,None,None,None,None,None), - (5,6,"GtkNotebookPage",None,5,None,None,None,None,None,None), - (5,7,"GtkBox","notebook_upper_included_directories",6,None,None,None,None,None,None), - (5,8,"GtkBox",None,7,None,None,None,None,None,None), - (5,9,"GtkButton","buttons_add_included_directory",8,None,None,None,None,None,None), - (5,10,"GtkBox",None,9,None,None,None,None,None,None), - (5,11,"GtkImage",None,10,None,None,None,None,None,None), + (5,1,"GtkAdjustment","adjustment1",None,None,None,None,0,None,None), + (5,2,"GtkWindow","window_main",None,None,None,None,1,None,None), + (5,3,"GtkBox",None,2,None,None,None,0,None,None), + (5,4,"GtkPaned",None,3,None,None,None,0,None,None), + (5,5,"GtkNotebook","notebook_upper",4,None,None,None,0,None,None), + (5,6,"GtkNotebookPage",None,5,None,None,None,0,None,None), + (5,7,"GtkBox","notebook_upper_included_directories",6,None,None,None,0,None,None), + (5,8,"GtkBox",None,7,None,None,None,0,None,None), + (5,9,"GtkButton","buttons_add_included_directory",8,None,None,None,0,None,None), + (5,10,"GtkBox",None,9,None,None,None,0,None,None), + (5,11,"GtkImage",None,10,None,None,None,0,None,None), (5,12,"GtkLabel",None,10,None,None,None,1,None,None), (5,13,"GtkButton","buttons_remove_included_directory",8,None,None,None,1,None,None), - (5,14,"GtkBox",None,13,None,None,None,None,None,None), - (5,15,"GtkImage",None,14,None,None,None,None,None,None), + (5,14,"GtkBox",None,13,None,None,None,0,None,None), + (5,15,"GtkImage",None,14,None,None,None,0,None,None), (5,16,"GtkLabel",None,14,None,None,None,1,None,None), (5,17,"GtkButton","buttons_manual_add_included_directory",8,None,None,None,2,None,None), - (5,18,"GtkBox",None,17,None,None,None,None,None,None), - (5,19,"GtkImage",None,18,None,None,None,None,None,None), + (5,18,"GtkBox",None,17,None,None,None,0,None,None), + (5,19,"GtkImage",None,18,None,None,None,0,None,None), (5,20,"GtkLabel",None,18,None,None,None,1,None,None), (5,21,"GtkScrolledWindow","scrolled_window_included_directories",7,None,None,None,1,None,None), (5,22,"GtkCheckButton","check_button_recursive",7,None,None,None,2,None,None), - (5,23,"GtkLabel",None,6,None,None,None,None,None,None), + (5,23,"GtkLabel",None,6,None,None,None,1,None,None), (5,24,"GtkNotebookPage",None,5,None,None,None,1,None,None), - (5,25,"GtkBox","notebook_upper_excluded_directories",24,None,None,None,None,None,None), - (5,26,"GtkBox",None,25,None,None,None,None,None,None), - (5,27,"GtkButton","buttons_add_excluded_directory",26,None,None,None,None,None,None), - (5,28,"GtkBox",None,27,None,None,None,None,None,None), - (5,29,"GtkImage",None,28,None,None,None,None,None,None), + (5,25,"GtkBox","notebook_upper_excluded_directories",24,None,None,None,0,None,None), + (5,26,"GtkBox",None,25,None,None,None,0,None,None), + (5,27,"GtkButton","buttons_add_excluded_directory",26,None,None,None,0,None,None), + (5,28,"GtkBox",None,27,None,None,None,0,None,None), + (5,29,"GtkImage",None,28,None,None,None,0,None,None), (5,30,"GtkLabel",None,28,None,None,None,1,None,None), (5,31,"GtkButton","buttons_remove_excluded_directory",26,None,None,None,1,None,None), - (5,32,"GtkBox",None,31,None,None,None,None,None,None), - (5,33,"GtkImage",None,32,None,None,None,None,None,None), + (5,32,"GtkBox",None,31,None,None,None,0,None,None), + (5,33,"GtkImage",None,32,None,None,None,0,None,None), (5,34,"GtkLabel",None,32,None,None,None,1,None,None), (5,35,"GtkButton","buttons_manual_add_excluded_directory",26,None,None,None,2,None,None), - (5,36,"GtkBox",None,35,None,None,None,None,None,None), - (5,37,"GtkImage",None,36,None,None,None,None,None,None), + (5,36,"GtkBox",None,35,None,None,None,0,None,None), + (5,37,"GtkImage",None,36,None,None,None,0,None,None), (5,38,"GtkLabel",None,36,None,None,None,1,None,None), (5,39,"GtkScrolledWindow","scrolled_window_excluded_directories",25,None,None,None,1,None,None), - (5,40,"GtkLabel",None,24,None,None,None,None,None,None), + (5,40,"GtkLabel",None,24,None,None,None,1,None,None), (5,41,"GtkNotebookPage",None,5,None,None,None,2,None,None), - (5,42,"GtkBox","notebook_upper_excluded_items",41,None,None,None,None,None,None), - (5,43,"GtkBox",None,42,None,None,None,None,None,None), - (5,44,"GtkLabel","label_excluded_items",43,None,None,None,None,None,None), + (5,42,"GtkBox","notebook_upper_excluded_items",41,None,None,None,0,None,None), + (5,43,"GtkBox",None,42,None,None,None,0,None,None), + (5,44,"GtkLabel","label_excluded_items",43,None,None,None,0,None,None), (5,45,"GtkEntry","entry_excluded_items",43,None,None,None,1,None,None), (5,46,"GtkBox",None,42,None,None,None,1,None,None), - (5,47,"GtkLabel","label_allowed_extensions",46,None,None,None,None,None,None), + (5,47,"GtkLabel","label_allowed_extensions",46,None,None,None,0,None,None), (5,48,"GtkEntry","entry_allowed_extensions",46,None,None,None,1,None,None), (5,49,"GtkBox",None,42,None,None,None,2,None,None), - (5,50,"GtkLabel","label_general_size_bytes",49,None,None,None,None,None,None), + (5,50,"GtkLabel","label_general_size_bytes",49,None,None,None,0,None,None), (5,51,"GtkLabel","label_general_min_size",49,None,None,None,1,None,None), (5,52,"GtkEntry","entry_general_minimal_size",49,None,None,None,2,None,None), (5,53,"GtkLabel","label_general_max_size",49,None,None,None,3,None,None), (5,54,"GtkEntry","entry_general_maximal_size",49,None,None,None,4,None,None), - (5,55,"GtkLabel",None,41,None,None,None,None,None,None), + (5,55,"GtkLabel",None,41,None,None,None,1,None,None), (5,56,"GtkNotebook","notebook_main",4,None,None,None,1,None,None), - (5,57,"GtkNotebookPage",None,56,None,None,None,None,None,None), - (5,58,"GtkPaned",None,57,None,None,None,None,None,None), - (5,59,"GtkBox",None,58,None,None,None,None,None,None), - (5,60,"GtkBox",None,59,None,None,None,None,None,None), - (5,61,"GtkLabel","label_duplicate_check_method",60,None,None,None,None,None,None), + (5,57,"GtkNotebookPage",None,56,None,None,None,0,None,None), + (5,58,"GtkPaned",None,57,None,None,None,0,None,None), + (5,59,"GtkBox",None,58,None,None,None,0,None,None), + (5,60,"GtkBox",None,59,None,None,None,0,None,None), + (5,61,"GtkLabel","label_duplicate_check_method",60,None,None,None,0,None,None), (5,62,"GtkComboBoxText","combo_box_duplicate_check_method",60,None,None,None,1,None,None), (5,63,"GtkLabel","label_duplicate_hash_type",60,None,None,None,2,None,None), (5,64,"GtkComboBoxText","combo_box_duplicate_hash_type",60,None,None,None,3,None,None), (5,65,"GtkCheckButton","check_button_duplicate_case_sensitive_name",60,None,None,None,4,None,None), (5,66,"GtkScrolledWindow","scrolled_window_duplicate_finder",59,None,None,None,1,None,None), (5,67,"GtkImage","image_preview_duplicates",58,None,None,None,1,None,None), - (5,68,"GtkLabel",None,57,None,None,None,None,None,None), + (5,68,"GtkLabel",None,57,None,None,None,1,None,None), (5,69,"GtkNotebookPage",None,56,None,None,None,1,None,None), - (5,70,"GtkScrolledWindow","scrolled_window_empty_folder_finder",69,None,None,None,None,None,None), - (5,71,"GtkLabel",None,69,None,None,None,None,None,None), + (5,70,"GtkScrolledWindow","scrolled_window_empty_folder_finder",69,None,None,None,0,None,None), + (5,71,"GtkLabel",None,69,None,None,None,1,None,None), (5,72,"GtkNotebookPage",None,56,None,None,None,2,None,None), - (5,73,"GtkBox",None,72,None,None,None,None,None,None), - (5,74,"GtkBox",None,73,None,None,None,None,None,None), + (5,73,"GtkBox",None,72,None,None,None,0,None,None), + (5,74,"GtkBox",None,73,None,None,None,0,None,None), (5,75,"GtkLabel","label_big_shown_files",74,None,None,None,2,None,None), (5,76,"GtkEntry","entry_big_files_number",74,None,None,None,3,None,None), (5,77,"GtkScrolledWindow","scrolled_window_big_files_finder",73,None,None,None,1,None,None), - (5,78,"GtkLabel",None,72,None,None,None,None,None,None), + (5,78,"GtkLabel",None,72,None,None,None,1,None,None), (5,79,"GtkNotebookPage",None,56,None,None,None,3,None,None), - (5,80,"GtkScrolledWindow","scrolled_window_empty_files_finder",79,None,None,None,None,None,None), - (5,81,"GtkLabel",None,79,None,None,None,None,None,None), + (5,80,"GtkScrolledWindow","scrolled_window_empty_files_finder",79,None,None,None,0,None,None), + (5,81,"GtkLabel",None,79,None,None,None,1,None,None), (5,82,"GtkNotebookPage",None,56,None,None,None,4,None,None), - (5,83,"GtkScrolledWindow","scrolled_window_temporary_files_finder",82,None,None,None,None,None,None), - (5,84,"GtkLabel",None,82,None,None,None,None,None,None), + (5,83,"GtkScrolledWindow","scrolled_window_temporary_files_finder",82,None,None,None,0,None,None), + (5,84,"GtkLabel",None,82,None,None,None,1,None,None), (5,85,"GtkNotebookPage",None,56,None,None,None,5,None,None), - (5,86,"GtkPaned",None,85,None,None,None,None,None,None), - (5,87,"GtkBox",None,86,None,None,None,None,None,None), - (5,88,"GtkBox",None,87,None,None,None,None,None,None), - (5,89,"GtkLabel","label_image_resize_algorithm",88,None,None,None,None,None,None), + (5,86,"GtkPaned",None,85,None,None,None,0,None,None), + (5,87,"GtkBox",None,86,None,None,None,0,None,None), + (5,88,"GtkBox",None,87,None,None,None,0,None,None), + (5,89,"GtkLabel","label_image_resize_algorithm",88,None,None,None,0,None,None), (5,90,"GtkComboBoxText","combo_box_image_resize_algorithm",88,None,None,None,1,None,None), (5,91,"GtkLabel","label_image_hash_size",88,None,None,None,2,None,None), (5,92,"GtkComboBoxText","combo_box_image_hash_size",88,None,None,None,3,None,None), (5,93,"GtkLabel","label_image_hash_type",88,None,None,None,4,None,None), (5,94,"GtkComboBoxText","combo_box_image_hash_algorithm",88,None,None,None,5,None,None), (5,95,"GtkBox",None,87,None,None,None,1,None,None), - (5,96,"GtkLabel","label_image_similarity",95,None,None,None,None,None,None), + (5,96,"GtkLabel","label_image_similarity",95,None,None,None,0,None,None), (5,97,"GtkLabel","label_image_similarity_max",95,None,None,None,1,None,None), (5,98,"GtkScale","scale_similarity_similar_images",95,None,None,None,2,None,None), (5,99,"GtkLabel","label_similar_images_minimal_similarity",95,None,None,None,3,None,None), (5,100,"GtkCheckButton","check_button_image_ignore_same_size",95,None,None,None,4,None,None), (5,102,"GtkScrolledWindow","scrolled_window_similar_images_finder",87,None,None,None,2,None,None), (5,103,"GtkImage","image_preview_similar_images",86,None,None,None,1,None,None), - (5,104,"GtkLabel",None,85,None,None,None,None,None,None), + (5,104,"GtkLabel",None,85,None,None,None,1,None,None), (5,105,"GtkNotebookPage",None,56,None,None,None,6,None,None), - (5,106,"GtkBox",None,105,None,None,None,None,None,None), - (5,107,"GtkBox",None,106,None,None,None,None,None,None), - (5,108,"GtkLabel","label_video_similarity",107,None,None,None,None,None,None), + (5,106,"GtkBox",None,105,None,None,None,0,None,None), + (5,107,"GtkBox",None,106,None,None,None,0,None,None), + (5,108,"GtkLabel","label_video_similarity",107,None,None,None,0,None,None), (5,109,"GtkLabel","label_video_similarity_max",107,None,None,None,1,None,None), (5,110,"GtkScale","scale_similarity_similar_videos",107,None,None,None,2,None,None), (5,111,"GtkLabel","label_video_similarity_min",107,None,None,None,3,None,None), (5,112,"GtkCheckButton","check_button_video_ignore_same_size",107,None,None,None,4,None,None), (5,113,"GtkScrolledWindow","scrolled_window_similar_videos_finder",106,None,None,None,1,None,None), - (5,114,"GtkLabel",None,105,None,None,None,None,None,None), + (5,114,"GtkLabel",None,105,None,None,None,1,None,None), (5,115,"GtkNotebookPage",None,56,None,None,None,7,None,None), - (5,116,"GtkBox",None,115,None,None,None,None,None,None), - (5,117,"GtkBox",None,116,None,None,None,None,None,None), - (5,118,"GtkCheckButton","check_button_music_title",117,None,None,None,None,None,None), + (5,116,"GtkBox",None,115,None,None,None,0,None,None), + (5,117,"GtkBox",None,116,None,None,None,0,None,None), + (5,118,"GtkCheckButton","check_button_music_title",117,None,None,None,0,None,None), (5,119,"GtkCheckButton","check_button_music_artist",117,None,None,None,1,None,None), (5,120,"GtkCheckButton","check_button_music_year",117,None,None,None,2,None,None), (5,121,"GtkCheckButton","check_button_music_bitrate",117,None,None,None,3,None,None), @@ -163,80 +163,80 @@ (5,124,"GtkBox",None,116,None,None,None,1,None,None), (5,125,"GtkCheckButton","check_button_music_approximate_comparison",124,None,None,None,2,None,None), (5,126,"GtkScrolledWindow","scrolled_window_same_music_finder",116,None,None,None,2,None,None), - (5,127,"GtkLabel",None,115,None,None,None,None,None,None), + (5,127,"GtkLabel",None,115,None,None,None,1,None,None), (5,128,"GtkNotebookPage",None,56,None,None,None,8,None,None), - (5,129,"GtkScrolledWindow","scrolled_window_invalid_symlinks",128,None,None,None,None,None,None), - (5,130,"GtkLabel",None,128,None,None,None,None,None,None), + (5,129,"GtkScrolledWindow","scrolled_window_invalid_symlinks",128,None,None,None,0,None,None), + (5,130,"GtkLabel",None,128,None,None,None,1,None,None), (5,131,"GtkNotebookPage",None,56,None,None,None,9,None,None), - (5,132,"GtkBox",None,131,None,None,None,None,None,None), - (5,133,"GtkLabel",None,131,None,None,None,None,None,None), + (5,132,"GtkBox",None,131,None,None,None,0,None,None), + (5,133,"GtkLabel",None,131,None,None,None,1,None,None), (5,134,"GtkNotebookPage",None,56,None,None,None,10,None,None), - (5,135,"GtkScrolledWindow","scrolled_window_bad_extensions",134,None,None,None,None,None,None), - (5,136,"GtkLabel",None,134,None,None,None,None,None,None), + (5,135,"GtkScrolledWindow","scrolled_window_bad_extensions",134,None,None,None,0,None,None), + (5,136,"GtkLabel",None,134,None,None,None,1,None,None), (5,137,"GtkBox","buttons",3,None,None,None,1,None,None), - (5,138,"GtkBox",None,137,None,None,None,None,None,None), - (5,139,"GtkButton","buttons_search",138,None,None,None,None,None,None), - (5,140,"GtkBox",None,139,None,None,None,None,None,None), - (5,141,"GtkImage",None,140,None,None,None,None,None,None), + (5,138,"GtkBox",None,137,None,None,None,0,None,None), + (5,139,"GtkButton","buttons_search",138,None,None,None,0,None,None), + (5,140,"GtkBox",None,139,None,None,None,0,None,None), + (5,141,"GtkImage",None,140,None,None,None,0,None,None), (5,142,"GtkLabel",None,140,None,None,None,1,None,None), (5,176,"GtkBox",None,3,None,None,None,2,None,None), - (5,177,"GtkEntry","entry_info",176,None,None,None,None,None,None), + (5,177,"GtkEntry","entry_info",176,None,None,None,0,None,None), (5,178,"GtkEntry",None,176,None,None,None,1,None,None), (5,179,"GtkScrolledWindow","scrolled_window_errors",3,None,None,None,3,None,None), - (5,180,"GtkTextView","text_view_errors",179,None,None,None,None,None,None), - (5,181,"GtkHeaderBar",None,2,None,"titlebar",None,None,None,None), - (5,182,"GtkBox",None,181,None,"end",None,None,None,None), - (5,183,"GtkButton","button_settings",182,None,None,None,None,None,None), - (5,184,"GtkImage",None,183,None,None,None,None,None,None), + (5,180,"GtkTextView","text_view_errors",179,None,None,None,0,None,None), + (5,181,"GtkHeaderBar",None,2,None,"titlebar",None,1,None,None), + (5,182,"GtkBox",None,181,None,"end",None,0,None,None), + (5,183,"GtkButton","button_settings",182,None,None,None,0,None,None), + (5,184,"GtkImage",None,183,None,None,None,0,None,None), (5,185,"GtkButton","button_app_info",182,None,None,None,1,None,None), - (5,186,"GtkImage",None,185,None,None,None,None,None,None), - (5,187,"GtkBox",None,137,None,None,None,4,None,None), - (5,188,"GtkBox",None,187,None,None,None,1,None,None), - (5,189,"GtkMenuButton","buttons_select",188,None,None,None,None,None,None), - (5,190,"GtkBox",None,189,None,None,None,None,None,None), - (5,191,"GtkImage",None,190,None,None,None,None,None,None), + (5,186,"GtkImage",None,185,None,None,None,0,None,None), + (5,187,"GtkBox",None,137,None,None,None,1,None,None), + (5,188,"GtkBox",None,187,None,None,None,0,None,None), + (5,189,"GtkMenuButton","buttons_select",188,None,None,None,0,None,None), + (5,190,"GtkBox",None,189,None,None,None,0,None,None), + (5,191,"GtkImage",None,190,None,None,None,0,None,None), (5,192,"GtkLabel","label_buttons_select",190,None,None,None,1,None,None), (5,193,"GtkButton","buttons_compare",188,None,None,None,2,None,None), - (5,194,"GtkBox",None,193,None,None,None,None,None,None), - (5,195,"GtkImage",None,194,None,None,None,None,None,None), + (5,194,"GtkBox",None,193,None,None,None,0,None,None), + (5,195,"GtkImage",None,194,None,None,None,0,None,None), (5,196,"GtkLabel",None,194,None,None,None,1,None,None), (5,197,"GtkButton","buttons_delete",188,None,None,None,3,None,None), - (5,198,"GtkBox",None,197,None,None,None,None,None,None), - (5,199,"GtkImage",None,198,None,None,None,None,None,None), + (5,198,"GtkBox",None,197,None,None,None,0,None,None), + (5,199,"GtkImage",None,198,None,None,None,0,None,None), (5,200,"GtkLabel",None,198,None,None,None,1,None,None), (5,201,"GtkButton","buttons_move",188,None,None,None,4,None,None), - (5,202,"GtkBox",None,201,None,None,None,None,None,None), - (5,203,"GtkImage",None,202,None,None,None,None,None,None), + (5,202,"GtkBox",None,201,None,None,None,0,None,None), + (5,203,"GtkImage",None,202,None,None,None,0,None,None), (5,204,"GtkLabel",None,202,None,None,None,1,None,None), (5,205,"GtkButton","buttons_save",188,None,None,None,5,None,None), - (5,206,"GtkBox",None,205,None,None,None,None,None,None), - (5,207,"GtkImage",None,206,None,None,None,None,None,None), + (5,206,"GtkBox",None,205,None,None,None,0,None,None), + (5,207,"GtkImage",None,206,None,None,None,0,None,None), (5,208,"GtkLabel",None,206,None,None,None,1,None,None), (5,209,"GtkButton","buttons_symlink",188,None,None,None,6,None,None), - (5,210,"GtkBox",None,209,None,None,None,None,None,None), - (5,211,"GtkImage",None,210,None,None,None,None,None,None), + (5,210,"GtkBox",None,209,None,None,None,0,None,None), + (5,211,"GtkImage",None,210,None,None,None,0,None,None), (5,212,"GtkLabel",None,210,None,None,None,1,None,None), (5,213,"GtkButton","buttons_hardlink",188,None,None,None,7,None,None), - (5,214,"GtkBox",None,213,None,None,None,None,None,None), - (5,215,"GtkImage",None,214,None,None,None,None,None,None), + (5,214,"GtkBox",None,213,None,None,None,0,None,None), + (5,215,"GtkImage",None,214,None,None,None,0,None,None), (5,216,"GtkLabel",None,214,None,None,None,1,None,None), - (5,217,"GtkButton","buttons_show_errors",187,None,None,None,2,None,None), - (5,218,"GtkImage",None,217,None,None,None,None,None,None), - (5,219,"GtkButton","buttons_show_upper_notebook",187,None,None,None,3,None,None), - (5,220,"GtkImage",None,219,None,None,None,None,None,None), + (5,217,"GtkButton","buttons_show_errors",187,None,None,None,1,None,None), + (5,218,"GtkImage",None,217,None,None,None,0,None,None), + (5,219,"GtkButton","buttons_show_upper_notebook",187,None,None,None,2,None,None), + (5,220,"GtkImage",None,219,None,None,None,0,None,None), (5,221,"GtkComboBoxText","combo_box_big_files_mode",74,None,None,None,1,None,None), - (5,222,"GtkLabel","label_big_files_mode",74,None,None,None,None,None,None), + (5,222,"GtkLabel","label_big_files_mode",74,None,None,None,0,None,None), (5,223,"GtkScrolledWindow","scrolled_window_broken_files",132,None,None,None,1,None,None), - (5,224,"GtkBox",None,132,None,None,None,None,None,None), - (5,225,"GtkCheckButton","check_button_broken_files_audio",224,None,None,None,None,None,None), + (5,224,"GtkBox",None,132,None,None,None,0,None,None), + (5,225,"GtkCheckButton","check_button_broken_files_audio",224,None,None,None,0,None,None), (5,226,"GtkCheckButton","check_button_broken_files_pdf",224,None,None,None,1,None,None), (5,227,"GtkCheckButton","check_button_broken_files_archive",224,None,None,None,2,None,None), (5,228,"GtkCheckButton","check_button_broken_files_image",224,None,None,None,3,None,None), (5,229,"GtkMenuButton","buttons_sort",188,None,None,None,1,None,None), - (5,230,"GtkBox",None,229,None,None,None,None,None,None), - (5,231,"GtkImage",None,230,None,None,None,None,None,None), + (5,230,"GtkBox",None,229,None,None,None,0,None,None), + (5,231,"GtkImage",None,230,None,None,None,0,None,None), (5,232,"GtkLabel","label_buttons_sort",230,None,None,None,1,None,None), - (5,234,"GtkLabel","label_audio_check_type",124,None,None,None,None,None,None), + (5,234,"GtkLabel","label_audio_check_type",124,None,None,None,0,None,None), (5,235,"GtkComboBoxText","combo_box_audio_check_type",124,None,None,None,1,None,None), (5,236,"GtkScale","scale_seconds_same_music",117,None,None,None,7,None,None), (5,237,"GtkScale","scale_similarity_same_music",117,None,None,None,9,None,None), @@ -245,13 +245,13 @@ (5,240,"GtkLabel","label_excluded_extensions",46,None,None,None,2,None,None), (5,241,"GtkEntry","entry_excluded_extensions",46,None,None,None,3,None,None), (5,242,"GtkCheckButton","check_button_music_compare_only_in_title_group",124,None,None,None,3,None,None), - (6,1,"GtkPopover","popover_right_click",None,None,None,None,None,None,None), - (6,2,"GtkBox",None,1,None,None,None,None,None,None), - (6,3,"GtkButton","buttons_popover_right_click_open_file",2,None,None,None,None,None,None), + (6,1,"GtkPopover","popover_right_click",None,None,None,None,0,None,None), + (6,2,"GtkBox",None,1,None,None,None,0,None,None), + (6,3,"GtkButton","buttons_popover_right_click_open_file",2,None,None,None,0,None,None), (6,4,"GtkButton","buttons_popover_right_click_open_folder",2,None,None,None,1,None,None), - (7,1,"GtkPopover","popover_select",None,None,None,None,None,None,None), - (7,2,"GtkBox",None,1,None,None,None,None,None,None), - (7,3,"GtkButton","buttons_popover_select_custom",2,None,None,None,None,None,None), + (7,1,"GtkPopover","popover_select",None,None,None,None,0,None,None), + (7,2,"GtkBox",None,1,None,None,None,0,None,None), + (7,3,"GtkButton","buttons_popover_select_custom",2,None,None,None,0,None,None), (7,4,"GtkButton","buttons_popover_unselect_custom",2,None,None,None,1,None,None), (7,5,"GtkSeparator","separator_select_custom",2,None,None,None,2,None,None), (7,6,"GtkButton","buttons_popover_select_all_images_except_biggest",2,None,None,None,3,None,None), @@ -266,26 +266,26 @@ (7,15,"GtkSeparator","separator_select_reverse",2,None,None,None,12,None,None), (7,16,"GtkButton","buttons_popover_select_all",2,None,None,None,13,None,None), (7,17,"GtkButton","buttons_popover_unselect_all",2,None,None,None,14,None,None), - (8,15,"GtkDialog","window_progress",None,None,None,None,None,None,None), - (8,16,"GtkBox",None,15,None,None,None,None,None,None), - (8,17,"GtkGrid","grid_progress",16,None,None,None,None,None,None), - (8,18,"GtkLabel","label_progress_all_stages",17,None,None,None,None,None,None), + (8,15,"GtkDialog","window_progress",None,None,None,None,0,None,None), + (8,16,"GtkBox",None,15,None,None,None,0,None,None), + (8,17,"GtkGrid","grid_progress",16,None,None,None,0,None,None), + (8,18,"GtkLabel","label_progress_all_stages",17,None,None,None,0,None,None), (8,19,"GtkProgressBar","progress_bar_all_stages",17,None,None,None,1,None,None), (8,20,"GtkLabel","label_progress_current_stage",17,None,None,None,2,None,None), (8,21,"GtkProgressBar","progress_bar_current_stage",17,None,None,None,3,None,None), (8,22,"GtkLabel","label_stage",16,None,None,None,1,None,None), (8,23,"GtkButton","button_stop_in_dialog",16,None,None,None,2,None,None), - (8,24,"GtkBox",None,23,None,None,None,None,None,None), - (8,25,"GtkImage",None,24,None,None,None,None,None,None), + (8,24,"GtkBox",None,23,None,None,None,0,None,None), + (8,25,"GtkImage",None,24,None,None,None,0,None,None), (8,26,"GtkLabel",None,24,None,None,None,1,None,None), - (9,1,"GtkDialog","window_settings",None,None,None,None,None,None,None), - (9,3,"GtkBox","potatoo",1,None,None,None,None,None,None), - (9,6,"GtkNotebook","notebook_settings",3,None,None,None,1,None,None), - (9,7,"GtkNotebookPage",None,6,None,None,None,None,None,None), - (9,8,"GtkBox",None,7,None,None,None,None,None,None), - (9,9,"GtkBox",None,8,None,None,None,None,None,None), - (9,10,"GtkBox",None,9,None,None,None,None,None,None), - (9,11,"GtkLabel","label_settings_general_language",10,None,None,None,None,None,None), + (9,1,"GtkDialog","window_settings",None,None,None,None,0,None,None), + (9,3,"GtkBox","potatoo",1,None,None,None,0,None,None), + (9,6,"GtkNotebook","notebook_settings",3,None,None,None,0,None,None), + (9,7,"GtkNotebookPage",None,6,None,None,None,0,None,None), + (9,8,"GtkBox",None,7,None,None,None,0,None,None), + (9,9,"GtkBox",None,8,None,None,None,0,None,None), + (9,10,"GtkBox",None,9,None,None,None,0,None,None), + (9,11,"GtkLabel","label_settings_general_language",10,None,None,None,0,None,None), (9,12,"GtkComboBoxText","combo_box_settings_language",10,None,None,None,1,None,None), (9,13,"GtkCheckButton","check_button_settings_load_at_start",9,None,None,None,1,None,None), (9,14,"GtkCheckButton","check_button_settings_save_at_exit",9,None,None,None,2,None,None), @@ -297,46 +297,47 @@ (9,20,"GtkCheckButton","check_button_settings_save_also_json",9,None,None,None,8,None,None), (9,21,"GtkCheckButton","check_button_settings_use_trash",9,None,None,None,9,None,None), (9,22,"GtkBox",None,8,None,None,None,2,None,None), - (9,23,"GtkButton","button_settings_open_cache_folder",22,None,None,None,None,None,None), + (9,23,"GtkButton","button_settings_open_cache_folder",22,None,None,None,0,None,None), (9,24,"GtkButton","button_settings_open_settings_folder",22,None,None,None,1,None,None), - (9,25,"GtkLabel",None,7,None,None,None,None,None,None), + (9,25,"GtkLabel",None,7,None,None,None,1,None,None), (9,26,"GtkNotebookPage",None,6,None,None,None,1,None,None), - (9,27,"GtkBox",None,26,None,None,None,None,None,None), - (9,28,"GtkCheckButton","check_button_settings_hide_hard_links",27,None,None,None,None,None,None), + (9,27,"GtkBox",None,26,None,None,None,0,None,None), + (9,28,"GtkCheckButton","check_button_settings_hide_hard_links",27,None,None,None,0,None,None), (9,29,"GtkCheckButton","check_button_settings_show_preview_duplicates",27,None,None,None,1,None,None), - (9,30,"GtkCheckButton","check_button_settings_duplicates_delete_outdated_cache",27,None,None,None,8,None,None), - (9,31,"GtkBox",None,27,None,None,None,3,None,None), - (9,32,"GtkLabel","label_settings_duplicate_minimal_size_cache",31,None,None,None,None,None,None), + (9,30,"GtkCheckButton","check_button_settings_duplicates_delete_outdated_cache",27,None,None,None,5,None,None), + (9,31,"GtkBox",None,27,None,None,None,2,None,None), + (9,32,"GtkLabel","label_settings_duplicate_minimal_size_cache",31,None,None,None,0,None,None), (9,33,"GtkEntry","entry_settings_cache_file_minimal_size",31,None,None,None,1,None,None), - (9,34,"GtkCheckButton","check_button_duplicates_use_prehash_cache",27,None,None,None,4,None,None), - (9,35,"GtkButton","button_settings_duplicates_clear_cache",27,None,None,None,9,None,None), - (9,36,"GtkBox",None,27,None,None,None,6,None,None), - (9,37,"GtkLabel","label_settings_duplicate_minimal_size_cache_prehash",36,None,None,None,None,None,None), + (9,34,"GtkCheckButton","check_button_duplicates_use_prehash_cache",27,None,None,None,3,None,None), + (9,35,"GtkButton","button_settings_duplicates_clear_cache",27,None,None,None,6,None,None), + (9,36,"GtkBox",None,27,None,None,None,4,None,None), + (9,37,"GtkLabel","label_settings_duplicate_minimal_size_cache_prehash",36,None,None,None,0,None,None), (9,38,"GtkEntry","entry_settings_prehash_cache_file_minimal_size",36,None,None,None,1,None,None), - (9,39,"GtkLabel",None,26,None,None,None,None,None,None), + (9,39,"GtkLabel",None,26,None,None,None,1,None,None), (9,40,"GtkNotebookPage",None,6,None,None,None,2,None,None), - (9,41,"GtkBox",None,40,None,None,None,None,None,None), - (9,42,"GtkCheckButton","check_button_settings_show_preview_similar_images",41,None,None,None,None,None,None), + (9,41,"GtkBox",None,40,None,None,None,0,None,None), + (9,42,"GtkCheckButton","check_button_settings_show_preview_similar_images",41,None,None,None,0,None,None), (9,43,"GtkCheckButton","check_button_settings_similar_images_delete_outdated_cache",41,None,None,None,1,None,None), (9,44,"GtkButton","button_settings_similar_images_clear_cache",41,None,None,None,2,None,None), - (9,45,"GtkLabel",None,40,None,None,None,None,None,None), + (9,45,"GtkLabel",None,40,None,None,None,1,None,None), (9,46,"GtkNotebookPage",None,6,None,None,None,3,None,None), - (9,47,"GtkBox",None,46,None,None,None,None,None,None), - (9,48,"GtkButton","button_settings_similar_videos_clear_cache",47,None,None,None,3,None,None), - (9,49,"GtkCheckButton","check_button_settings_similar_videos_delete_outdated_cache",47,None,None,None,1,None,None), - (9,50,"GtkLabel",None,46,None,None,None,None,None,None), - (9,51,"GtkBox",None,3,None,None,None,2,None,None), - (9,52,"GtkButton","button_settings_load_configuration",51,None,None,None,None,None,None), + (9,47,"GtkBox",None,46,None,None,None,0,None,None), + (9,48,"GtkButton","button_settings_similar_videos_clear_cache",47,None,None,None,1,None,None), + (9,49,"GtkCheckButton","check_button_settings_similar_videos_delete_outdated_cache",47,None,None,None,0,None,None), + (9,50,"GtkLabel",None,46,None,None,None,1,None,None), + (9,51,"GtkBox",None,3,None,None,None,1,None,None), + (9,52,"GtkButton","button_settings_load_configuration",51,None,None,None,0,None,None), (9,53,"GtkButton","button_settings_reset_configuration",51,None,None,None,1,None,None), (9,54,"GtkButton","button_settings_save_configuration",51,None,None,None,2,None,None), (9,55,"GtkCheckButton","check_button_settings_one_filesystem",9,None,None,None,10,None,None), - (9,56,"GtkBox",None,9,None,None,None,11,None,None), - (9,57,"GtkLabel","label_settings_number_of_threads",56,None,None,None,None,None,None), + (9,56,"GtkBox",None,9,None,None,None,12,None,None), + (9,57,"GtkLabel","label_settings_number_of_threads",56,None,None,None,0,None,None), (9,58,"GtkScale","scale_settings_number_of_threads",56,None,None,None,1,None,None), (9,59,"GtkLabel","label_restart_needed",8,None,None,None,1,None,None), - (10,1,"GtkPopover","popover_sort",None,None,None,None,None,None,None), - (10,2,"GtkBox",None,1,None,None,None,None,None,None), - (10,3,"GtkButton","buttons_popover_sort_file_name",2,None,None,None,None,None,None), + (9,60,"GtkCheckButton","check_button_settings_use_rust_preview",9,None,None,None,11,None,None), + (10,1,"GtkPopover","popover_sort",None,None,None,None,0,None,None), + (10,2,"GtkBox",None,1,None,None,None,0,None,None), + (10,3,"GtkButton","buttons_popover_sort_file_name",2,None,None,None,0,None,None), (10,4,"GtkButton","buttons_popover_sort_folder_name",2,None,None,None,1,None,None), (10,5,"GtkButton","buttons_popover_sort_full_name",2,None,None,None,2,None,None), (10,6,"GtkButton","buttons_popover_sort_size",2,None,None,None,3,None,None), @@ -1027,6 +1028,9 @@ (9,59,"GtkLabel","label","Restart Required",None,None,None,None,None,None,None,None,None), (9,59,"GtkWidget","margin-bottom","4",None,None,None,None,None,None,None,None,None), (9,59,"GtkWidget","margin-top","5",None,None,None,None,None,None,None,None,None), + (9,60,"GtkCheckButton","active","1",0,None,None,None,None,None,None,None,None), + (9,60,"GtkCheckButton","label","Use external libraries instead gtk to load previews",None,None,None,None,None,None,None,None,None), + (9,60,"GtkWidget","focusable","1",0,None,None,None,None,None,None,None,None), (10,1,"GtkPopover","child",None,None,None,None,None,2,None,None,None,None), (10,1,"GtkPopover","position","top",None,None,None,None,None,None,None,None,None), (10,2,"GtkOrientable","orientation","vertical",None,None,None,None,None,None,None,None,None), diff --git a/czkawka_gui/ui/main_window.ui b/czkawka_gui/ui/main_window.ui index 04d3b8a12..a1492e865 100644 --- a/czkawka_gui/ui/main_window.ui +++ b/czkawka_gui/ui/main_window.ui @@ -1,5 +1,5 @@ - + diff --git a/czkawka_gui/ui/popover_right_click.ui b/czkawka_gui/ui/popover_right_click.ui index 2646c7301..2edc5345e 100644 --- a/czkawka_gui/ui/popover_right_click.ui +++ b/czkawka_gui/ui/popover_right_click.ui @@ -1,5 +1,5 @@ - + diff --git a/czkawka_gui/ui/popover_select.ui b/czkawka_gui/ui/popover_select.ui index d7d44b138..ff5f6f959 100644 --- a/czkawka_gui/ui/popover_select.ui +++ b/czkawka_gui/ui/popover_select.ui @@ -1,5 +1,5 @@ - + diff --git a/czkawka_gui/ui/popover_sort.ui b/czkawka_gui/ui/popover_sort.ui index 061865583..0958c4ba6 100644 --- a/czkawka_gui/ui/popover_sort.ui +++ b/czkawka_gui/ui/popover_sort.ui @@ -1,5 +1,5 @@ - + diff --git a/czkawka_gui/ui/progress.ui b/czkawka_gui/ui/progress.ui index c782b4896..af3a49a2d 100644 --- a/czkawka_gui/ui/progress.ui +++ b/czkawka_gui/ui/progress.ui @@ -1,5 +1,5 @@ - + diff --git a/czkawka_gui/ui/settings.ui b/czkawka_gui/ui/settings.ui index 75d2963bf..44d3d58f7 100644 --- a/czkawka_gui/ui/settings.ui +++ b/czkawka_gui/ui/settings.ui @@ -1,5 +1,5 @@ - + @@ -114,6 +114,13 @@ Exclude other filesystems(Linux) + + + 1 + 1 + Use external libraries instead gtk to load previews + + diff --git a/justfile b/justfile index 85730d149..d82ab850e 100644 --- a/justfile +++ b/justfile @@ -4,8 +4,28 @@ build_all: cargo clippy cargo test -run: - cargo run --bin czkawka_gui +## run + +czkawka: + RUST_BACKTRACE=1 cargo run --bin czkawka_gui +czkawka_r: + RUST_BACKTRACE=1 cargo run --bin czkawka_gui --release + +krokiet: + RUST_BACKTRACE=1 cargo run --bin krokiet +krokiet_r: + RUST_BACKTRACE=1 cargo run --bin krokiet --release +krokiet_dark: + RUST_BACKTRACE=1 SLINT_STYLE=fluent-dark cargo run --bin krokiet + +cli: + RUST_BACKTRACE=1 cargo run --bin czkawka_cli +cli_r: + RUST_BACKTRACE=1 cargo run --bin czkawka_cli --release +cli_help: + cargo run --bin czkawka_cli -- --help + +## Other build: cargo build --bin czkawka_gui @@ -16,26 +36,6 @@ check: check_all: cargo check -krokiet: - cargo run --bin krokiet - -czkawka: - cargo run --bin czkawka_gui - -krokiet_r: - cargo run --bin krokiet --release - -krokiet_dark: - SLINT_STYLE=fluent-dark cargo run --bin krokiet - -czkawka_r: - cargo run --bin czkawka_gui --release - -cli: - cargo run --bin czkawka_cli - -cli_help: - cargo run --bin czkawka_cli -- --help build_krokiet: cargo build --bin krokiet @@ -44,7 +44,7 @@ build_czkawka: cargo build --bin czkawka_gui upgrade: - cargo upgrade -i + cargo +nightly -Z unstable-options update --breaking cargo update fix: diff --git a/krokiet/Cargo.toml b/krokiet/Cargo.toml index ace99fa16..aae93f105 100644 --- a/krokiet/Cargo.toml +++ b/krokiet/Cargo.toml @@ -34,7 +34,7 @@ trash = "5.1" i18n-embed = { version = "0.15", features = ["fluent-system", "desktop-requester"] } i18n-embed-fl = "0.9" rust-embed = { version = "8.5", features = ["debug-embed"] } -once_cell = "1.19" +once_cell = "1.20" # Try to use only needed features from https://github.com/slint-ui/slint/blob/master/api/rs/slint/Cargo.toml#L23-L31 #slint = { path = "/home/rafal/test/slint/api/rs/slint/", default-features = false, features = ["std", @@ -62,3 +62,4 @@ winit_software = ["slint/renderer-winit-software"] heif = ["czkawka_core/heif"] libraw = ["czkawka_core/libraw"] +libavif = ["czkawka_core/libavif"] diff --git a/krokiet/src/common.rs b/krokiet/src/common.rs index e8b20a3c2..d6ece412d 100644 --- a/krokiet/src/common.rs +++ b/krokiet/src/common.rs @@ -1,9 +1,10 @@ #![allow(dead_code)] use std::path::PathBuf; -use crate::{CurrentTab, ExcludedDirectoriesModel, IncludedDirectoriesModel, MainListModel, MainWindow, Settings}; use slint::{ComponentHandle, Model, ModelRc, SharedString, VecModel}; +use crate::{CurrentTab, ExcludedDirectoriesModel, IncludedDirectoriesModel, MainListModel, MainWindow, Settings}; + // Int model is used to store data in unchanged(* except that we need to split u64 into two i32) form and is used to sort/select data // Str model is used to display data in gui diff --git a/krokiet/src/connect_delete.rs b/krokiet/src/connect_delete.rs index 428f411e3..db3a2ac46 100644 --- a/krokiet/src/connect_delete.rs +++ b/krokiet/src/connect_delete.rs @@ -1,8 +1,7 @@ -use rayon::prelude::*; -use slint::{ComponentHandle, ModelRc, VecModel}; - use czkawka_core::common::remove_folder_if_contains_only_empty_folders; use czkawka_core::common_messages::Messages; +use rayon::prelude::*; +use slint::{ComponentHandle, ModelRc, VecModel}; use crate::common::{get_is_header_mode, get_tool_model, set_tool_model}; use crate::model_operations::{collect_full_path_from_model, deselect_all_items, filter_out_checked_items}; diff --git a/krokiet/src/connect_move.rs b/krokiet/src/connect_move.rs index 528c7fed2..ff5e5d594 100644 --- a/krokiet/src/connect_move.rs +++ b/krokiet/src/connect_move.rs @@ -1,13 +1,14 @@ -use crate::common::{get_is_header_mode, get_tool_model, set_tool_model}; -use crate::model_operations::{collect_path_name_from_model, deselect_all_items, filter_out_checked_items}; -use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow}; +use std::path::{Path, PathBuf}; +use std::{fs, path}; use czkawka_core::common_messages::Messages; use rayon::prelude::*; use rfd::FileDialog; use slint::{ComponentHandle, ModelRc, VecModel}; -use std::path::{Path, PathBuf}; -use std::{fs, path}; + +use crate::common::{get_is_header_mode, get_tool_model, set_tool_model}; +use crate::model_operations::{collect_path_name_from_model, deselect_all_items, filter_out_checked_items}; +use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow}; pub fn connect_move(app: &MainWindow) { let a = app.as_weak(); diff --git a/krokiet/src/connect_progress_receiver.rs b/krokiet/src/connect_progress_receiver.rs index 14053db45..a3f9cdf2c 100644 --- a/krokiet/src/connect_progress_receiver.rs +++ b/krokiet/src/connect_progress_receiver.rs @@ -1,11 +1,11 @@ use std::thread; use crossbeam_channel::Receiver; +use czkawka_core::common_dir_traversal::ToolType; +use czkawka_core::progress_data::{CurrentStage, ProgressData}; use slint::ComponentHandle; use crate::{MainWindow, ProgressToSend}; -use czkawka_core::common_dir_traversal::ToolType; -use czkawka_core::progress_data::{CurrentStage, ProgressData}; pub fn connect_progress_gathering(app: &MainWindow, progress_receiver: Receiver) { let a = app.as_weak(); diff --git a/krokiet/src/connect_scan.rs b/krokiet/src/connect_scan.rs index 6d68dcf8f..05b63cefd 100644 --- a/krokiet/src/connect_scan.rs +++ b/krokiet/src/connect_scan.rs @@ -6,10 +6,6 @@ use crossbeam_channel::{Receiver, Sender}; use czkawka_core::bad_extensions::{BadExtensions, BadExtensionsParameters, BadFileEntry}; use czkawka_core::big_file::{BigFile, BigFileParameters, SearchMode}; use czkawka_core::broken_files::{BrokenEntry, BrokenFiles, BrokenFilesParameters, CheckedTypes}; -use humansize::{format_size, BINARY}; -use rayon::prelude::*; -use slint::{ComponentHandle, ModelRc, SharedString, VecModel, Weak}; - use czkawka_core::common::{split_path, split_path_compare, DEFAULT_THREAD_SIZE}; use czkawka_core::common_dir_traversal::{CheckingMethod, FileEntry}; use czkawka_core::common_tool::CommonData; @@ -24,6 +20,9 @@ use czkawka_core::similar_images; use czkawka_core::similar_images::{ImagesEntry, SimilarImages, SimilarImagesParameters}; use czkawka_core::similar_videos::{SimilarVideos, SimilarVideosParameters, VideosEntry}; use czkawka_core::temporary::{Temporary, TemporaryFileEntry}; +use humansize::{format_size, BINARY}; +use rayon::prelude::*; +use slint::{ComponentHandle, ModelRc, SharedString, VecModel, Weak}; use crate::common::{check_if_all_included_dirs_are_referenced, split_u64_into_i32s}; use crate::settings::{ diff --git a/krokiet/src/connect_select.rs b/krokiet/src/connect_select.rs index 0509bd61e..856b742ae 100644 --- a/krokiet/src/connect_select.rs +++ b/krokiet/src/connect_select.rs @@ -1,8 +1,9 @@ +use slint::{ComponentHandle, Model, ModelRc, VecModel}; + use crate::common::{ connect_i32_into_u64, get_int_height_idx, get_int_modification_date_idx, get_int_size_idx, get_int_width_idx, get_is_header_mode, get_tool_model, set_tool_model, }; use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow, SelectMode, SelectModel}; -use slint::{ComponentHandle, Model, ModelRc, VecModel}; // TODO optimize this, not sure if it is possible to not copy entire model to just select item // https://github.com/slint-ui/slint/discussions/4595 diff --git a/krokiet/src/connect_show_preview.rs b/krokiet/src/connect_show_preview.rs index b96b54fac..b7d00aab9 100644 --- a/krokiet/src/connect_show_preview.rs +++ b/krokiet/src/connect_show_preview.rs @@ -1,13 +1,11 @@ -use std::panic; use std::path::Path; use std::time::{Duration, Instant}; +use czkawka_core::common_image::get_dynamic_image_from_path; use image::DynamicImage; use log::{debug, error}; use slint::ComponentHandle; -use czkawka_core::common::{get_dynamic_image_from_raw_image, IMAGE_RS_EXTENSIONS, RAW_IMAGE_EXTENSIONS}; - use crate::{Callabler, CurrentTab, GuiState, MainWindow, Settings}; pub type ImageBufferRgba = image::ImageBuffer, Vec>; @@ -77,39 +75,15 @@ fn load_image(image_path: &Path) -> Option<(Duration, DynamicImage)> { if !image_path.is_file() { return None; } - let image_name = image_path.to_string_lossy().to_string(); - let image_extension = image_path.extension()?.to_string_lossy().to_lowercase(); - - let is_raw_image = RAW_IMAGE_EXTENSIONS.contains(&image_extension.as_str()); - let is_normal_image = IMAGE_RS_EXTENSIONS.contains(&image_extension.as_str()); let load_img_start_timer = Instant::now(); - let img = panic::catch_unwind(|| { - let int_img = if is_normal_image { - match image::open(image_name) { - Ok(img) => img, - Err(e) => { - error!("Error while loading image: {}", e); - return None; - } - } - } else if is_raw_image { - match get_dynamic_image_from_raw_image(image_name) { - Ok(img) => img, - Err(e) => { - error!("Error while loading raw image: {}", e); - return None; - } - } - } else { + let img = match get_dynamic_image_from_path(&image_path.to_string_lossy()) { + Ok(img) => img, + Err(e) => { + error!("{e}"); return None; - }; - Some(int_img) - }) - .unwrap_or_else(|e| { - error!("Error while loading image: {e:?}"); - None - })?; + } + }; Some((load_img_start_timer.elapsed(), img)) } diff --git a/krokiet/src/main.rs b/krokiet/src/main.rs index 78f7cdf9a..b0ffa6b5c 100644 --- a/krokiet/src/main.rs +++ b/krokiet/src/main.rs @@ -21,10 +21,9 @@ use std::rc::Rc; use crossbeam_channel::{unbounded, Receiver, Sender}; -use slint::VecModel; - use czkawka_core::common::{print_version_mode, setup_logger}; use czkawka_core::progress_data::ProgressData; +use slint::VecModel; use crate::connect_delete::connect_delete_button; use crate::connect_directories_changes::connect_add_remove_directories; diff --git a/krokiet/src/model_operations.rs b/krokiet/src/model_operations.rs index e48af7e18..c589a6f98 100644 --- a/krokiet/src/model_operations.rs +++ b/krokiet/src/model_operations.rs @@ -1,7 +1,9 @@ +use std::path::MAIN_SEPARATOR; + +use slint::{Model, ModelRc}; + use crate::common::{get_str_name_idx, get_str_path_idx}; use crate::{CurrentTab, MainListModel}; -use slint::{Model, ModelRc}; -use std::path::MAIN_SEPARATOR; pub fn deselect_all_items(items: &mut [MainListModel]) { for item in items { diff --git a/krokiet/src/set_initial_gui_info.rs b/krokiet/src/set_initial_gui_info.rs index acdc48155..635322181 100644 --- a/krokiet/src/set_initial_gui_info.rs +++ b/krokiet/src/set_initial_gui_info.rs @@ -1,6 +1,5 @@ -use slint::{ComponentHandle, SharedString, VecModel}; - use czkawka_core::common::get_all_available_threads; +use slint::{ComponentHandle, SharedString, VecModel}; use crate::settings::{ ALLOWED_BIG_FILE_SIZE_VALUES, ALLOWED_DUPLICATES_CHECK_METHOD_VALUES, ALLOWED_DUPLICATES_HASH_TYPE_VALUES, ALLOWED_HASH_SIZE_VALUES, ALLOWED_IMAGE_HASH_ALG_VALUES, diff --git a/krokiet/src/settings.rs b/krokiet/src/settings.rs index 73a2c8f29..c5cb2c202 100644 --- a/krokiet/src/settings.rs +++ b/krokiet/src/settings.rs @@ -3,6 +3,10 @@ use std::env; use std::path::PathBuf; use czkawka_core::big_file::SearchMode; +use czkawka_core::common::{get_all_available_threads, set_number_of_threads}; +use czkawka_core::common_dir_traversal::CheckingMethod; +use czkawka_core::common_items::{DEFAULT_EXCLUDED_DIRECTORIES, DEFAULT_EXCLUDED_ITEMS}; +use czkawka_core::duplicate::HashType; use directories_next::ProjectDirs; use home::home_dir; use image_hasher::{FilterType, HashAlg}; @@ -10,11 +14,6 @@ use log::{debug, error, info, warn}; use serde::{Deserialize, Serialize}; use slint::{ComponentHandle, Model, ModelRc, SharedString, VecModel}; -use czkawka_core::common::{get_all_available_threads, set_number_of_threads}; -use czkawka_core::common_dir_traversal::CheckingMethod; -use czkawka_core::common_items::{DEFAULT_EXCLUDED_DIRECTORIES, DEFAULT_EXCLUDED_ITEMS}; -use czkawka_core::duplicate::HashType; - use crate::common::{create_excluded_directories_model_from_pathbuf, create_included_directories_model_from_pathbuf, create_vec_model_from_vec_string}; use crate::{Callabler, GuiState, MainWindow, Settings};