├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-MIT ├── README.md ├── img ├── bfa ├── bfa.jpg ├── curldemo.gif ├── demo.gif ├── explode.gif ├── flaky.gif ├── gifdemo.gif ├── giphy.gif ├── iterm.png ├── kittydemo.gif ├── lights.jpg ├── snake.png └── trip.gif └── src ├── app.rs ├── config.rs └── main.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | check-and-test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: hecrj/setup-rust-action@master 10 | with: 11 | rust-version: stable 12 | components: clippy, rustfmt 13 | - uses: actions/checkout@v3 14 | - name: Format 15 | run: cargo fmt --all -- --check 16 | - name: Lint 17 | run: cargo clippy -- -D warnings 18 | - name: Build 19 | run: cargo build --verbose 20 | - name: Run tests 21 | run: cargo test --verbose 22 | 23 | build-and-deploy: 24 | needs: [check-and-test] 25 | runs-on: ${{ matrix.os }} 26 | strategy: 27 | matrix: 28 | include: 29 | - os: macos-latest 30 | TARGET: x86_64-apple-darwin 31 | 32 | - os: ubuntu-latest 33 | TARGET: arm-unknown-linux-musleabihf 34 | 35 | - os: ubuntu-latest 36 | TARGET: armv7-unknown-linux-musleabihf 37 | 38 | - os: ubuntu-latest 39 | TARGET: aarch64-unknown-linux-musl 40 | 41 | - os: ubuntu-latest 42 | TARGET: x86_64-unknown-linux-musl 43 | 44 | - os: windows-latest 45 | TARGET: x86_64-pc-windows-msvc 46 | EXTENSION: .exe 47 | 48 | steps: 49 | - name: Building ${{ matrix.TARGET }} 50 | run: echo "${{ matrix.TARGET }}" 51 | 52 | - uses: actions/checkout@master 53 | - uses: actions-rs/toolchain@v1 54 | with: 55 | toolchain: stable 56 | target: ${{ matrix.TARGET }} 57 | override: true 58 | 59 | - uses: actions-rs/cargo@v1 60 | with: 61 | use-cross: true 62 | command: build 63 | args: --verbose --release --target=${{ matrix.TARGET }} 64 | 65 | - name: Rename 66 | run: cp target/${{ matrix.TARGET }}/release/viu${{ matrix.EXTENSION }} viu-${{ matrix.TARGET }}${{ matrix.EXTENSION }} 67 | 68 | - uses: actions/upload-artifact@v3 69 | with: 70 | name: viu-${{ matrix.TARGET }}${{ matrix.EXTENSION }} 71 | path: viu-${{ matrix.TARGET }}${{ matrix.EXTENSION }} 72 | 73 | - uses: softprops/action-gh-release@v1 74 | name: Upload binaries to release 75 | if: startsWith(github.ref, 'refs/tags/') 76 | with: 77 | files: viu-${{ matrix.TARGET }}${{ matrix.EXTENSION }} 78 | prerelease: ${{ !startsWith(github.ref, 'refs/tags/') }} 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Generated by WAPM 6 | /wapm_packages/ 7 | wapm.lock 8 | 9 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 10 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 11 | #Cargo.lock 12 | 13 | # These are backup files generated by rustfmt 14 | **/*.rs.bk 15 | 16 | .vscode 17 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler" 7 | version = "1.0.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 10 | 11 | [[package]] 12 | name = "adler2" 13 | version = "2.0.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 16 | 17 | [[package]] 18 | name = "aligned-vec" 19 | version = "0.5.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" 22 | 23 | [[package]] 24 | name = "ansi_colours" 25 | version = "1.2.3" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "14eec43e0298190790f41679fe69ef7a829d2a2ddd78c8c00339e84710e435fe" 28 | dependencies = [ 29 | "rgb", 30 | ] 31 | 32 | [[package]] 33 | name = "anstream" 34 | version = "0.6.15" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" 37 | dependencies = [ 38 | "anstyle", 39 | "anstyle-parse", 40 | "anstyle-query", 41 | "anstyle-wincon", 42 | "colorchoice", 43 | "is_terminal_polyfill", 44 | "utf8parse", 45 | ] 46 | 47 | [[package]] 48 | name = "anstyle" 49 | version = "1.0.8" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" 52 | 53 | [[package]] 54 | name = "anstyle-parse" 55 | version = "0.2.5" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" 58 | dependencies = [ 59 | "utf8parse", 60 | ] 61 | 62 | [[package]] 63 | name = "anstyle-query" 64 | version = "1.1.1" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" 67 | dependencies = [ 68 | "windows-sys 0.52.0", 69 | ] 70 | 71 | [[package]] 72 | name = "anstyle-wincon" 73 | version = "3.0.4" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" 76 | dependencies = [ 77 | "anstyle", 78 | "windows-sys 0.52.0", 79 | ] 80 | 81 | [[package]] 82 | name = "anyhow" 83 | version = "1.0.90" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" 86 | 87 | [[package]] 88 | name = "arbitrary" 89 | version = "1.3.2" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" 92 | 93 | [[package]] 94 | name = "arg_enum_proc_macro" 95 | version = "0.3.4" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" 98 | dependencies = [ 99 | "proc-macro2", 100 | "quote", 101 | "syn", 102 | ] 103 | 104 | [[package]] 105 | name = "arrayvec" 106 | version = "0.7.6" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 109 | 110 | [[package]] 111 | name = "autocfg" 112 | version = "1.4.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 115 | 116 | [[package]] 117 | name = "av1-grain" 118 | version = "0.2.3" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" 121 | dependencies = [ 122 | "anyhow", 123 | "arrayvec", 124 | "log", 125 | "nom", 126 | "num-rational", 127 | "v_frame", 128 | ] 129 | 130 | [[package]] 131 | name = "avif-serialize" 132 | version = "0.8.2" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" 135 | dependencies = [ 136 | "arrayvec", 137 | ] 138 | 139 | [[package]] 140 | name = "base64" 141 | version = "0.22.1" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 144 | 145 | [[package]] 146 | name = "bit_field" 147 | version = "0.10.2" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" 150 | 151 | [[package]] 152 | name = "bitflags" 153 | version = "1.3.2" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 156 | 157 | [[package]] 158 | name = "bitflags" 159 | version = "2.6.0" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 162 | 163 | [[package]] 164 | name = "bitstream-io" 165 | version = "2.5.3" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "b81e1519b0d82120d2fd469d5bfb2919a9361c48b02d82d04befc1cdd2002452" 168 | 169 | [[package]] 170 | name = "built" 171 | version = "0.7.5" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" 174 | 175 | [[package]] 176 | name = "bumpalo" 177 | version = "3.16.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 180 | 181 | [[package]] 182 | name = "bytemuck" 183 | version = "1.19.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" 186 | 187 | [[package]] 188 | name = "byteorder" 189 | version = "1.5.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 192 | 193 | [[package]] 194 | name = "byteorder-lite" 195 | version = "0.1.0" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" 198 | 199 | [[package]] 200 | name = "cc" 201 | version = "1.1.31" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" 204 | dependencies = [ 205 | "jobserver", 206 | "libc", 207 | "shlex", 208 | ] 209 | 210 | [[package]] 211 | name = "cfg-expr" 212 | version = "0.15.8" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" 215 | dependencies = [ 216 | "smallvec", 217 | "target-lexicon", 218 | ] 219 | 220 | [[package]] 221 | name = "cfg-if" 222 | version = "1.0.0" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 225 | 226 | [[package]] 227 | name = "cfg_aliases" 228 | version = "0.2.1" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 231 | 232 | [[package]] 233 | name = "clap" 234 | version = "4.5.20" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" 237 | dependencies = [ 238 | "clap_builder", 239 | ] 240 | 241 | [[package]] 242 | name = "clap_builder" 243 | version = "4.5.20" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" 246 | dependencies = [ 247 | "anstream", 248 | "anstyle", 249 | "clap_lex", 250 | "strsim", 251 | ] 252 | 253 | [[package]] 254 | name = "clap_lex" 255 | version = "0.7.2" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" 258 | 259 | [[package]] 260 | name = "color_quant" 261 | version = "1.1.0" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" 264 | 265 | [[package]] 266 | name = "colorchoice" 267 | version = "1.0.2" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" 270 | 271 | [[package]] 272 | name = "console" 273 | version = "0.15.8" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 276 | dependencies = [ 277 | "encode_unicode", 278 | "lazy_static", 279 | "libc", 280 | "windows-sys 0.52.0", 281 | ] 282 | 283 | [[package]] 284 | name = "crc32fast" 285 | version = "1.4.2" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 288 | dependencies = [ 289 | "cfg-if", 290 | ] 291 | 292 | [[package]] 293 | name = "crossbeam-deque" 294 | version = "0.8.5" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 297 | dependencies = [ 298 | "crossbeam-epoch", 299 | "crossbeam-utils", 300 | ] 301 | 302 | [[package]] 303 | name = "crossbeam-epoch" 304 | version = "0.9.18" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 307 | dependencies = [ 308 | "crossbeam-utils", 309 | ] 310 | 311 | [[package]] 312 | name = "crossbeam-utils" 313 | version = "0.8.20" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 316 | 317 | [[package]] 318 | name = "crossterm" 319 | version = "0.28.1" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" 322 | dependencies = [ 323 | "bitflags 2.6.0", 324 | "crossterm_winapi", 325 | "parking_lot", 326 | "rustix", 327 | "winapi", 328 | ] 329 | 330 | [[package]] 331 | name = "crossterm_winapi" 332 | version = "0.9.1" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 335 | dependencies = [ 336 | "winapi", 337 | ] 338 | 339 | [[package]] 340 | name = "crunchy" 341 | version = "0.2.2" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 344 | 345 | [[package]] 346 | name = "ctrlc" 347 | version = "3.4.5" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" 350 | dependencies = [ 351 | "nix", 352 | "windows-sys 0.59.0", 353 | ] 354 | 355 | [[package]] 356 | name = "either" 357 | version = "1.13.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 360 | 361 | [[package]] 362 | name = "encode_unicode" 363 | version = "0.3.6" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 366 | 367 | [[package]] 368 | name = "equivalent" 369 | version = "1.0.1" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 372 | 373 | [[package]] 374 | name = "errno" 375 | version = "0.3.9" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 378 | dependencies = [ 379 | "libc", 380 | "windows-sys 0.52.0", 381 | ] 382 | 383 | [[package]] 384 | name = "exr" 385 | version = "1.72.0" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" 388 | dependencies = [ 389 | "bit_field", 390 | "flume", 391 | "half", 392 | "lebe", 393 | "miniz_oxide 0.7.4", 394 | "rayon-core", 395 | "smallvec", 396 | "zune-inflate", 397 | ] 398 | 399 | [[package]] 400 | name = "fastrand" 401 | version = "2.1.1" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" 404 | 405 | [[package]] 406 | name = "fdeflate" 407 | version = "0.3.5" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" 410 | dependencies = [ 411 | "simd-adler32", 412 | ] 413 | 414 | [[package]] 415 | name = "flate2" 416 | version = "1.0.34" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" 419 | dependencies = [ 420 | "crc32fast", 421 | "miniz_oxide 0.8.0", 422 | ] 423 | 424 | [[package]] 425 | name = "flume" 426 | version = "0.11.1" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" 429 | dependencies = [ 430 | "spin", 431 | ] 432 | 433 | [[package]] 434 | name = "getrandom" 435 | version = "0.2.15" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 438 | dependencies = [ 439 | "cfg-if", 440 | "libc", 441 | "wasi", 442 | ] 443 | 444 | [[package]] 445 | name = "gif" 446 | version = "0.13.1" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" 449 | dependencies = [ 450 | "color_quant", 451 | "weezl", 452 | ] 453 | 454 | [[package]] 455 | name = "half" 456 | version = "2.4.1" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 459 | dependencies = [ 460 | "cfg-if", 461 | "crunchy", 462 | ] 463 | 464 | [[package]] 465 | name = "hashbrown" 466 | version = "0.15.0" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" 469 | 470 | [[package]] 471 | name = "heck" 472 | version = "0.5.0" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 475 | 476 | [[package]] 477 | name = "image" 478 | version = "0.25.4" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" 481 | dependencies = [ 482 | "bytemuck", 483 | "byteorder-lite", 484 | "color_quant", 485 | "exr", 486 | "gif", 487 | "image-webp", 488 | "num-traits", 489 | "png", 490 | "qoi", 491 | "ravif", 492 | "rayon", 493 | "rgb", 494 | "tiff", 495 | "zune-core", 496 | "zune-jpeg", 497 | ] 498 | 499 | [[package]] 500 | name = "image-webp" 501 | version = "0.2.0" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" 504 | dependencies = [ 505 | "byteorder-lite", 506 | "quick-error", 507 | ] 508 | 509 | [[package]] 510 | name = "imgref" 511 | version = "1.11.0" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" 514 | 515 | [[package]] 516 | name = "indexmap" 517 | version = "2.6.0" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 520 | dependencies = [ 521 | "equivalent", 522 | "hashbrown", 523 | ] 524 | 525 | [[package]] 526 | name = "interpolate_name" 527 | version = "0.2.4" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" 530 | dependencies = [ 531 | "proc-macro2", 532 | "quote", 533 | "syn", 534 | ] 535 | 536 | [[package]] 537 | name = "is_terminal_polyfill" 538 | version = "1.70.1" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 541 | 542 | [[package]] 543 | name = "itertools" 544 | version = "0.12.1" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 547 | dependencies = [ 548 | "either", 549 | ] 550 | 551 | [[package]] 552 | name = "jobserver" 553 | version = "0.1.32" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" 556 | dependencies = [ 557 | "libc", 558 | ] 559 | 560 | [[package]] 561 | name = "jpeg-decoder" 562 | version = "0.3.1" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" 565 | 566 | [[package]] 567 | name = "lazy_static" 568 | version = "1.5.0" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 571 | 572 | [[package]] 573 | name = "lebe" 574 | version = "0.5.2" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" 577 | 578 | [[package]] 579 | name = "libc" 580 | version = "0.2.161" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" 583 | 584 | [[package]] 585 | name = "libfuzzer-sys" 586 | version = "0.4.7" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" 589 | dependencies = [ 590 | "arbitrary", 591 | "cc", 592 | "once_cell", 593 | ] 594 | 595 | [[package]] 596 | name = "linux-raw-sys" 597 | version = "0.4.14" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 600 | 601 | [[package]] 602 | name = "lock_api" 603 | version = "0.4.12" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 606 | dependencies = [ 607 | "autocfg", 608 | "scopeguard", 609 | ] 610 | 611 | [[package]] 612 | name = "log" 613 | version = "0.4.22" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 616 | 617 | [[package]] 618 | name = "loop9" 619 | version = "0.1.5" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" 622 | dependencies = [ 623 | "imgref", 624 | ] 625 | 626 | [[package]] 627 | name = "make-cmd" 628 | version = "0.1.0" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "a8ca8afbe8af1785e09636acb5a41e08a765f5f0340568716c18a8700ba3c0d3" 631 | 632 | [[package]] 633 | name = "maybe-rayon" 634 | version = "0.1.1" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" 637 | dependencies = [ 638 | "cfg-if", 639 | ] 640 | 641 | [[package]] 642 | name = "memchr" 643 | version = "2.7.4" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 646 | 647 | [[package]] 648 | name = "minimal-lexical" 649 | version = "0.2.1" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 652 | 653 | [[package]] 654 | name = "miniz_oxide" 655 | version = "0.7.4" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 658 | dependencies = [ 659 | "adler", 660 | ] 661 | 662 | [[package]] 663 | name = "miniz_oxide" 664 | version = "0.8.0" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 667 | dependencies = [ 668 | "adler2", 669 | "simd-adler32", 670 | ] 671 | 672 | [[package]] 673 | name = "new_debug_unreachable" 674 | version = "1.0.6" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 677 | 678 | [[package]] 679 | name = "nix" 680 | version = "0.29.0" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" 683 | dependencies = [ 684 | "bitflags 2.6.0", 685 | "cfg-if", 686 | "cfg_aliases", 687 | "libc", 688 | ] 689 | 690 | [[package]] 691 | name = "nom" 692 | version = "7.1.3" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 695 | dependencies = [ 696 | "memchr", 697 | "minimal-lexical", 698 | ] 699 | 700 | [[package]] 701 | name = "noop_proc_macro" 702 | version = "0.3.0" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" 705 | 706 | [[package]] 707 | name = "num-bigint" 708 | version = "0.4.6" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 711 | dependencies = [ 712 | "num-integer", 713 | "num-traits", 714 | ] 715 | 716 | [[package]] 717 | name = "num-derive" 718 | version = "0.4.2" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" 721 | dependencies = [ 722 | "proc-macro2", 723 | "quote", 724 | "syn", 725 | ] 726 | 727 | [[package]] 728 | name = "num-integer" 729 | version = "0.1.46" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 732 | dependencies = [ 733 | "num-traits", 734 | ] 735 | 736 | [[package]] 737 | name = "num-rational" 738 | version = "0.4.2" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" 741 | dependencies = [ 742 | "num-bigint", 743 | "num-integer", 744 | "num-traits", 745 | ] 746 | 747 | [[package]] 748 | name = "num-traits" 749 | version = "0.2.19" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 752 | dependencies = [ 753 | "autocfg", 754 | ] 755 | 756 | [[package]] 757 | name = "once_cell" 758 | version = "1.20.2" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 761 | 762 | [[package]] 763 | name = "parking_lot" 764 | version = "0.12.3" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 767 | dependencies = [ 768 | "lock_api", 769 | "parking_lot_core", 770 | ] 771 | 772 | [[package]] 773 | name = "parking_lot_core" 774 | version = "0.9.10" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 777 | dependencies = [ 778 | "cfg-if", 779 | "libc", 780 | "redox_syscall", 781 | "smallvec", 782 | "windows-targets", 783 | ] 784 | 785 | [[package]] 786 | name = "paste" 787 | version = "1.0.15" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 790 | 791 | [[package]] 792 | name = "pkg-config" 793 | version = "0.3.31" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 796 | 797 | [[package]] 798 | name = "png" 799 | version = "0.17.14" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" 802 | dependencies = [ 803 | "bitflags 1.3.2", 804 | "crc32fast", 805 | "fdeflate", 806 | "flate2", 807 | "miniz_oxide 0.8.0", 808 | ] 809 | 810 | [[package]] 811 | name = "ppv-lite86" 812 | version = "0.2.20" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 815 | dependencies = [ 816 | "zerocopy", 817 | ] 818 | 819 | [[package]] 820 | name = "proc-macro2" 821 | version = "1.0.88" 822 | source = "registry+https://github.com/rust-lang/crates.io-index" 823 | checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" 824 | dependencies = [ 825 | "unicode-ident", 826 | ] 827 | 828 | [[package]] 829 | name = "profiling" 830 | version = "1.0.16" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" 833 | dependencies = [ 834 | "profiling-procmacros", 835 | ] 836 | 837 | [[package]] 838 | name = "profiling-procmacros" 839 | version = "1.0.16" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" 842 | dependencies = [ 843 | "quote", 844 | "syn", 845 | ] 846 | 847 | [[package]] 848 | name = "qoi" 849 | version = "0.4.1" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" 852 | dependencies = [ 853 | "bytemuck", 854 | ] 855 | 856 | [[package]] 857 | name = "quick-error" 858 | version = "2.0.1" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" 861 | 862 | [[package]] 863 | name = "quote" 864 | version = "1.0.37" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 867 | dependencies = [ 868 | "proc-macro2", 869 | ] 870 | 871 | [[package]] 872 | name = "rand" 873 | version = "0.8.5" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 876 | dependencies = [ 877 | "libc", 878 | "rand_chacha", 879 | "rand_core", 880 | ] 881 | 882 | [[package]] 883 | name = "rand_chacha" 884 | version = "0.3.1" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 887 | dependencies = [ 888 | "ppv-lite86", 889 | "rand_core", 890 | ] 891 | 892 | [[package]] 893 | name = "rand_core" 894 | version = "0.6.4" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 897 | dependencies = [ 898 | "getrandom", 899 | ] 900 | 901 | [[package]] 902 | name = "rav1e" 903 | version = "0.7.1" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" 906 | dependencies = [ 907 | "arbitrary", 908 | "arg_enum_proc_macro", 909 | "arrayvec", 910 | "av1-grain", 911 | "bitstream-io", 912 | "built", 913 | "cfg-if", 914 | "interpolate_name", 915 | "itertools", 916 | "libc", 917 | "libfuzzer-sys", 918 | "log", 919 | "maybe-rayon", 920 | "new_debug_unreachable", 921 | "noop_proc_macro", 922 | "num-derive", 923 | "num-traits", 924 | "once_cell", 925 | "paste", 926 | "profiling", 927 | "rand", 928 | "rand_chacha", 929 | "simd_helpers", 930 | "system-deps", 931 | "thiserror", 932 | "v_frame", 933 | "wasm-bindgen", 934 | ] 935 | 936 | [[package]] 937 | name = "ravif" 938 | version = "0.11.11" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" 941 | dependencies = [ 942 | "avif-serialize", 943 | "imgref", 944 | "loop9", 945 | "quick-error", 946 | "rav1e", 947 | "rgb", 948 | ] 949 | 950 | [[package]] 951 | name = "rayon" 952 | version = "1.10.0" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 955 | dependencies = [ 956 | "either", 957 | "rayon-core", 958 | ] 959 | 960 | [[package]] 961 | name = "rayon-core" 962 | version = "1.12.1" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 965 | dependencies = [ 966 | "crossbeam-deque", 967 | "crossbeam-utils", 968 | ] 969 | 970 | [[package]] 971 | name = "redox_syscall" 972 | version = "0.5.7" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" 975 | dependencies = [ 976 | "bitflags 2.6.0", 977 | ] 978 | 979 | [[package]] 980 | name = "rgb" 981 | version = "0.8.50" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" 984 | dependencies = [ 985 | "bytemuck", 986 | ] 987 | 988 | [[package]] 989 | name = "rustix" 990 | version = "0.38.37" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" 993 | dependencies = [ 994 | "bitflags 2.6.0", 995 | "errno", 996 | "libc", 997 | "linux-raw-sys", 998 | "windows-sys 0.52.0", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "scopeguard" 1003 | version = "1.2.0" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1006 | 1007 | [[package]] 1008 | name = "serde" 1009 | version = "1.0.210" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" 1012 | dependencies = [ 1013 | "serde_derive", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "serde_derive" 1018 | version = "1.0.210" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" 1021 | dependencies = [ 1022 | "proc-macro2", 1023 | "quote", 1024 | "syn", 1025 | ] 1026 | 1027 | [[package]] 1028 | name = "serde_spanned" 1029 | version = "0.6.8" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1032 | dependencies = [ 1033 | "serde", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "shlex" 1038 | version = "1.3.0" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1041 | 1042 | [[package]] 1043 | name = "simd-adler32" 1044 | version = "0.3.7" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1047 | 1048 | [[package]] 1049 | name = "simd_helpers" 1050 | version = "0.1.0" 1051 | source = "registry+https://github.com/rust-lang/crates.io-index" 1052 | checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" 1053 | dependencies = [ 1054 | "quote", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "sixel-rs" 1059 | version = "0.3.3" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "cfa95c014543113a192d906e5971d0c8d1e8b4cc1e61026539687a7016644ce5" 1062 | dependencies = [ 1063 | "sixel-sys", 1064 | ] 1065 | 1066 | [[package]] 1067 | name = "sixel-sys" 1068 | version = "0.3.1" 1069 | source = "registry+https://github.com/rust-lang/crates.io-index" 1070 | checksum = "fb46e0cd5569bf910390844174a5a99d52dd40681fff92228d221d9f8bf87dea" 1071 | dependencies = [ 1072 | "make-cmd", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "smallvec" 1077 | version = "1.13.2" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1080 | 1081 | [[package]] 1082 | name = "spin" 1083 | version = "0.9.8" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1086 | dependencies = [ 1087 | "lock_api", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "strsim" 1092 | version = "0.11.1" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1095 | 1096 | [[package]] 1097 | name = "syn" 1098 | version = "2.0.82" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" 1101 | dependencies = [ 1102 | "proc-macro2", 1103 | "quote", 1104 | "unicode-ident", 1105 | ] 1106 | 1107 | [[package]] 1108 | name = "system-deps" 1109 | version = "6.2.2" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" 1112 | dependencies = [ 1113 | "cfg-expr", 1114 | "heck", 1115 | "pkg-config", 1116 | "toml", 1117 | "version-compare", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "target-lexicon" 1122 | version = "0.12.16" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" 1125 | 1126 | [[package]] 1127 | name = "tempfile" 1128 | version = "3.13.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" 1131 | dependencies = [ 1132 | "cfg-if", 1133 | "fastrand", 1134 | "once_cell", 1135 | "rustix", 1136 | "windows-sys 0.59.0", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "termcolor" 1141 | version = "1.4.1" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1144 | dependencies = [ 1145 | "winapi-util", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "thiserror" 1150 | version = "1.0.64" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" 1153 | dependencies = [ 1154 | "thiserror-impl", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "thiserror-impl" 1159 | version = "1.0.64" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" 1162 | dependencies = [ 1163 | "proc-macro2", 1164 | "quote", 1165 | "syn", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "tiff" 1170 | version = "0.9.1" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" 1173 | dependencies = [ 1174 | "flate2", 1175 | "jpeg-decoder", 1176 | "weezl", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "toml" 1181 | version = "0.8.19" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 1184 | dependencies = [ 1185 | "serde", 1186 | "serde_spanned", 1187 | "toml_datetime", 1188 | "toml_edit", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "toml_datetime" 1193 | version = "0.6.8" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 1196 | dependencies = [ 1197 | "serde", 1198 | ] 1199 | 1200 | [[package]] 1201 | name = "toml_edit" 1202 | version = "0.22.22" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 1205 | dependencies = [ 1206 | "indexmap", 1207 | "serde", 1208 | "serde_spanned", 1209 | "toml_datetime", 1210 | "winnow", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "unicode-ident" 1215 | version = "1.0.13" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 1218 | 1219 | [[package]] 1220 | name = "utf8parse" 1221 | version = "0.2.2" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1224 | 1225 | [[package]] 1226 | name = "v_frame" 1227 | version = "0.3.8" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" 1230 | dependencies = [ 1231 | "aligned-vec", 1232 | "num-traits", 1233 | "wasm-bindgen", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "version-compare" 1238 | version = "0.2.0" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" 1241 | 1242 | [[package]] 1243 | name = "viu" 1244 | version = "1.5.1" 1245 | dependencies = [ 1246 | "clap", 1247 | "crossterm", 1248 | "ctrlc", 1249 | "image", 1250 | "viuer", 1251 | ] 1252 | 1253 | [[package]] 1254 | name = "viuer" 1255 | version = "0.9.0" 1256 | source = "registry+https://github.com/rust-lang/crates.io-index" 1257 | checksum = "7e3e4a9a9e48f7b812c56241edceb5e3d3db067b53cc34fa907abdf1784b4071" 1258 | dependencies = [ 1259 | "ansi_colours", 1260 | "base64", 1261 | "console", 1262 | "crossterm", 1263 | "image", 1264 | "lazy_static", 1265 | "sixel-rs", 1266 | "tempfile", 1267 | "termcolor", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "wasi" 1272 | version = "0.11.0+wasi-snapshot-preview1" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1275 | 1276 | [[package]] 1277 | name = "wasm-bindgen" 1278 | version = "0.2.95" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" 1281 | dependencies = [ 1282 | "cfg-if", 1283 | "once_cell", 1284 | "wasm-bindgen-macro", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "wasm-bindgen-backend" 1289 | version = "0.2.95" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" 1292 | dependencies = [ 1293 | "bumpalo", 1294 | "log", 1295 | "once_cell", 1296 | "proc-macro2", 1297 | "quote", 1298 | "syn", 1299 | "wasm-bindgen-shared", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "wasm-bindgen-macro" 1304 | version = "0.2.95" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" 1307 | dependencies = [ 1308 | "quote", 1309 | "wasm-bindgen-macro-support", 1310 | ] 1311 | 1312 | [[package]] 1313 | name = "wasm-bindgen-macro-support" 1314 | version = "0.2.95" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" 1317 | dependencies = [ 1318 | "proc-macro2", 1319 | "quote", 1320 | "syn", 1321 | "wasm-bindgen-backend", 1322 | "wasm-bindgen-shared", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "wasm-bindgen-shared" 1327 | version = "0.2.95" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" 1330 | 1331 | [[package]] 1332 | name = "weezl" 1333 | version = "0.1.8" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" 1336 | 1337 | [[package]] 1338 | name = "winapi" 1339 | version = "0.3.9" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1342 | dependencies = [ 1343 | "winapi-i686-pc-windows-gnu", 1344 | "winapi-x86_64-pc-windows-gnu", 1345 | ] 1346 | 1347 | [[package]] 1348 | name = "winapi-i686-pc-windows-gnu" 1349 | version = "0.4.0" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1352 | 1353 | [[package]] 1354 | name = "winapi-util" 1355 | version = "0.1.9" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1358 | dependencies = [ 1359 | "windows-sys 0.59.0", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "winapi-x86_64-pc-windows-gnu" 1364 | version = "0.4.0" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1367 | 1368 | [[package]] 1369 | name = "windows-sys" 1370 | version = "0.52.0" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1373 | dependencies = [ 1374 | "windows-targets", 1375 | ] 1376 | 1377 | [[package]] 1378 | name = "windows-sys" 1379 | version = "0.59.0" 1380 | source = "registry+https://github.com/rust-lang/crates.io-index" 1381 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1382 | dependencies = [ 1383 | "windows-targets", 1384 | ] 1385 | 1386 | [[package]] 1387 | name = "windows-targets" 1388 | version = "0.52.6" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1391 | dependencies = [ 1392 | "windows_aarch64_gnullvm", 1393 | "windows_aarch64_msvc", 1394 | "windows_i686_gnu", 1395 | "windows_i686_gnullvm", 1396 | "windows_i686_msvc", 1397 | "windows_x86_64_gnu", 1398 | "windows_x86_64_gnullvm", 1399 | "windows_x86_64_msvc", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "windows_aarch64_gnullvm" 1404 | version = "0.52.6" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1407 | 1408 | [[package]] 1409 | name = "windows_aarch64_msvc" 1410 | version = "0.52.6" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1413 | 1414 | [[package]] 1415 | name = "windows_i686_gnu" 1416 | version = "0.52.6" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1419 | 1420 | [[package]] 1421 | name = "windows_i686_gnullvm" 1422 | version = "0.52.6" 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" 1424 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1425 | 1426 | [[package]] 1427 | name = "windows_i686_msvc" 1428 | version = "0.52.6" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1431 | 1432 | [[package]] 1433 | name = "windows_x86_64_gnu" 1434 | version = "0.52.6" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1437 | 1438 | [[package]] 1439 | name = "windows_x86_64_gnullvm" 1440 | version = "0.52.6" 1441 | source = "registry+https://github.com/rust-lang/crates.io-index" 1442 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1443 | 1444 | [[package]] 1445 | name = "windows_x86_64_msvc" 1446 | version = "0.52.6" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1449 | 1450 | [[package]] 1451 | name = "winnow" 1452 | version = "0.6.20" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 1455 | dependencies = [ 1456 | "memchr", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "zerocopy" 1461 | version = "0.7.35" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1464 | dependencies = [ 1465 | "byteorder", 1466 | "zerocopy-derive", 1467 | ] 1468 | 1469 | [[package]] 1470 | name = "zerocopy-derive" 1471 | version = "0.7.35" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1474 | dependencies = [ 1475 | "proc-macro2", 1476 | "quote", 1477 | "syn", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "zune-core" 1482 | version = "0.4.12" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" 1485 | 1486 | [[package]] 1487 | name = "zune-inflate" 1488 | version = "0.2.54" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" 1491 | dependencies = [ 1492 | "simd-adler32", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "zune-jpeg" 1497 | version = "0.4.13" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768" 1500 | dependencies = [ 1501 | "zune-core", 1502 | ] 1503 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "viu" 3 | version = "1.5.1" 4 | authors = ["Atanas Yankov "] 5 | edition = "2021" 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/atanunq/viu" 9 | description = "View images right from the terminal." 10 | categories = ["command-line-utilities"] 11 | keywords = ["terminal", "image", "gif"] 12 | exclude = ["/img", "/.github"] 13 | 14 | [dependencies] 15 | clap = { version = "4.4", features = ["cargo"] } 16 | crossterm = { version = "0.28", default-features = false } 17 | viuer = { version = "0.9", features = ["print-file"] } 18 | ctrlc = { version = "3.4", features = ["termination"] } 19 | image = "0.25" 20 | 21 | [features] 22 | default = [] 23 | sixel = ["viuer/sixel"] 24 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Atanas Yankov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - [Description](#description) 2 | - [Features](#features) 3 | - [Installation](#installation) 4 | - [From source (recommended)](#from-source-recommended) 5 | - [Binary](#binary) 6 | - [Packages](#packages) 7 | - [MacOS](#macos) 8 | - [Arch Linux](#arch-linux) 9 | - [NetBSD](#netbsd) 10 | - [Usage](#usage) 11 | - [Examples](#examples) 12 | - [iTerm note](#iterm-note) 13 | - [Aspect Ratio](#aspect-ratio) 14 | - [Command line options](#command-line-options) 15 | 16 | ## Description 17 | A small command-line application to view images from the terminal written in Rust. It is basically the 18 | front-end of [`viuer`](https://github.com/atanunq/viuer). It uses either [iTerm](https://iterm2.com/documentation-images.html) 19 | or [Kitty](https://sw.kovidgoyal.net/kitty/graphics-protocol.html) graphics protocol, if supported. 20 | If not, lower half blocks (▄ or \u2584) are displayed instead. 21 | 22 | Based on the value of `$TERM`, `viuer` decides which protocol to use. For half 23 | blocks, `$COLORTERM` is inspected. If it contains either `truecolor` or `24bit`, 24 | truecolor (16 million colors) will be used. If not, it will fallback to using only ansi256. A nice 25 | explanation can be found in this [gist](https://gist.github.com/XVilka/8346728). 26 | 27 | 28 | ## Features 29 | - Native iTerm and Kitty support 30 | - Animated GIF support 31 | - Accept media through stdin 32 | - Custom dimensions 33 | - Transparency 34 | - Experimental Sixel support (behind the `sixel` feature flag) 35 | 36 | ## Installation 37 | 38 | ### From source (recommended) 39 | 40 | Installation from source requires a local [Rust environment](https://www.rust-lang.org/tools/install). 41 | 42 | ```bash 43 | git clone https://github.com/atanunq/viu.git 44 | 45 | # Build & Install 46 | cd viu/ 47 | cargo install --path . 48 | 49 | # Use 50 | viu img/giphy.gif 51 | ``` 52 | Or without cloning: 53 | ```bash 54 | cargo install viu 55 | ``` 56 | 57 | ### Binary 58 | A precompiled binary can be downloaded from the [release 59 | page](https://www.github.com/atanunq/viu/releases/latest). 60 | GPG fingerprint is B195BADA40BEF20E4907A5AC628280A0217A7B0F. 61 | 62 | ### Packages 63 | 64 | #### MacOS 65 | Available in [`brew`](https://formulae.brew.sh/formula/viu). 66 | ```bash 67 | brew install viu 68 | ``` 69 | 70 | #### Arch Linux 71 | Available in [`extra/viu`](https://archlinux.org/packages/extra/x86_64/viu/). 72 | ```bash 73 | pacman -S viu 74 | ``` 75 | 76 | #### NetBSD 77 | Available in [`graphics/viu`](http://cdn.netbsd.org/pub/pkgsrc/current/pkgsrc/graphics/viu/README.html). 78 | 79 | ## Usage 80 | 81 | ### Examples 82 | On a [Kitty](https://github.com/kovidgoyal/kitty) terminal: 83 | 84 | ![Kitty](img/kittydemo.gif) 85 | 86 | On a Mac with iTerm: 87 | 88 | ![iTerm](img/iterm.png) 89 | 90 | 91 | Using half blocks (Kitty protocol and `tmux` do not get along): 92 | 93 | ![Demo](img/demo.gif) 94 | 95 | 96 | ![Demo](img/gifdemo.gif) 97 | 98 | 99 | ![Demo](img/curldemo.gif) 100 | 101 | 102 | Ctrl-C was pressed to stop the GIFs. 103 | 104 | 105 | When `viu` receives only one file and it is GIF, it will be displayed over and over until Ctrl-C is 106 | pressed. However, when couple of files are up for display the GIF will be displayed only once. 107 | 108 | ### iTerm note 109 | iTerm can handle GIFs by itself with better performance, but configuration through `--once` 110 | and `--frame-rate` will have no effect there. 111 | 112 | ### Aspect Ratio 113 | If no flags are supplied to `viu` it will try to get the size of the terminal where it was invoked. 114 | If it succeeds it will fit the image and preserve the aspect ratio. The aspect ratio will be changed 115 | only if both options **-w** and **-h** are used together. 116 | 117 | ### Command line options 118 | ``` 119 | View images right from the terminal. 120 | 121 | Usage: viu [OPTIONS] [file]... 122 | 123 | Arguments: 124 | [file]... The images to be displayed. Set to - for standard input. 125 | 126 | Options: 127 | -w, --width 128 | Resize the image to a provided width 129 | -h, --height 130 | Resize the image to a provided height 131 | -x 132 | X offset [default: 0] 133 | -y 134 | Y offset [default: 0] 135 | -a, --absolute-offset 136 | Make the x and y offset be relative to the top left terminal corner. If not set, they are relative to the cursor's position. 137 | -r, --recursive 138 | Recurse down directories if passed one 139 | -b, --blocks 140 | Force block output 141 | -n, --name 142 | Output the name of the file before displaying 143 | -t, --transparent 144 | Display transparent images with transparent background 145 | -f, --frame-rate 146 | Play the gif at a given frame rate 147 | -1, --once 148 | Loop only once through the gif 149 | -s, --static 150 | Show only the first frame of the gif 151 | -H, --help 152 | Print help information 153 | -V, --version 154 | Print version information 155 | ``` 156 | -------------------------------------------------------------------------------- /img/bfa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/bfa -------------------------------------------------------------------------------- /img/bfa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/bfa.jpg -------------------------------------------------------------------------------- /img/curldemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/curldemo.gif -------------------------------------------------------------------------------- /img/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/demo.gif -------------------------------------------------------------------------------- /img/explode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/explode.gif -------------------------------------------------------------------------------- /img/flaky.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/flaky.gif -------------------------------------------------------------------------------- /img/gifdemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/gifdemo.gif -------------------------------------------------------------------------------- /img/giphy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/giphy.gif -------------------------------------------------------------------------------- /img/iterm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/iterm.png -------------------------------------------------------------------------------- /img/kittydemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/kittydemo.gif -------------------------------------------------------------------------------- /img/lights.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/lights.jpg -------------------------------------------------------------------------------- /img/snake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/snake.png -------------------------------------------------------------------------------- /img/trip.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atanunq/viu/f821ee9cbd9ff4840bce74b7b076f7d6c9fc290c/img/trip.gif -------------------------------------------------------------------------------- /src/app.rs: -------------------------------------------------------------------------------- 1 | use crate::config::Config; 2 | use crossterm::terminal::{Clear, ClearType}; 3 | use crossterm::{cursor, execute}; 4 | use image::{codecs::gif::GifDecoder, AnimationDecoder, DynamicImage}; 5 | use std::fs; 6 | use std::io::{stdin, stdout, BufRead, BufReader, Cursor, Error, ErrorKind, Read, Seek}; 7 | use std::sync::mpsc; 8 | use std::{thread, time::Duration}; 9 | use viuer::ViuResult; 10 | 11 | type TxRx<'a> = (&'a mpsc::Sender, &'a mpsc::Receiver); 12 | 13 | // TODO: Create a viu-specific result and error types, do not reuse viuer's 14 | pub fn run(mut conf: Config) -> ViuResult { 15 | //create two channels so that ctrlc-handler and the main thread can pass messages in order to 16 | // communicate when printing must be stopped without distorting the current frame 17 | let (tx_ctrlc, rx_print) = mpsc::channel(); 18 | let (tx_print, rx_ctrlc) = mpsc::channel(); 19 | 20 | //handle Ctrl-C in order to clean up after ourselves 21 | ctrlc::set_handler(move || { 22 | //if ctrlc is received tell the infinite gif loop to stop drawing 23 | // or stop the next file from being drawn 24 | tx_ctrlc 25 | .send(true) 26 | .expect("Could not send signal to stop drawing."); 27 | //a message will be received when that has happened so we can clear leftover symbols 28 | let _ = rx_ctrlc 29 | .recv() 30 | .expect("Could not receive signal to clean up terminal."); 31 | 32 | if let Err(e) = execute!(stdout(), Clear(ClearType::FromCursorDown)) { 33 | if e.kind() == ErrorKind::BrokenPipe { 34 | //Do nothing. Output is probably piped to `head` or a similar tool 35 | } else { 36 | panic!("{}", e); 37 | } 38 | } 39 | std::process::exit(0); 40 | }) 41 | .map_err(|_| Error::new(ErrorKind::Other, "Could not setup Ctrl-C handler."))?; 42 | 43 | //TODO: handle multiple files 44 | //read stdin if only one parameter is passed and it is "-" 45 | if conf.files.len() == 1 && conf.files[0] == "-" { 46 | let stdin = stdin(); 47 | let mut handle = stdin.lock(); 48 | 49 | let mut buf: Vec = Vec::new(); 50 | let _ = handle.read_to_end(&mut buf)?; 51 | let cursor = Cursor::new(&buf); 52 | 53 | //TODO: print_from_file if data is a gif and terminal is iTerm 54 | if try_print_gif(&conf, cursor, (&tx_print, &rx_print)).is_err() { 55 | //If stdin data is not a gif, treat it as a regular image 56 | 57 | let img = image::load_from_memory(&buf)?; 58 | viuer::print(&img, &conf.viuer_config)?; 59 | }; 60 | 61 | Ok(()) 62 | } else { 63 | view_passed_files(&mut conf, (&tx_print, &rx_print)) 64 | } 65 | } 66 | 67 | fn view_passed_files(conf: &mut Config, (tx, rx): TxRx) -> ViuResult { 68 | //loop throught all files passed 69 | for filename in &conf.files { 70 | //check if Ctrl-C has been received. If yes, stop iterating 71 | if rx.try_recv().is_ok() { 72 | return tx.send(true).map_err(|_| { 73 | Error::new(ErrorKind::Other, "Could not send signal to clean up.").into() 74 | }); 75 | }; 76 | //if it's a directory, stop gif looping because there will probably be more files 77 | if fs::metadata(filename)?.is_dir() { 78 | conf.loop_gif = false; 79 | view_directory(conf, filename, (tx, rx))?; 80 | } 81 | //if a file has been passed individually and fails, propagate the error 82 | else { 83 | view_file(conf, filename, (tx, rx))?; 84 | } 85 | } 86 | Ok(()) 87 | } 88 | 89 | fn view_directory(conf: &Config, dirname: &str, (tx, rx): TxRx) -> ViuResult { 90 | for dir_entry_result in fs::read_dir(dirname)? { 91 | //check if Ctrl-C has been received. If yes, stop iterating 92 | if rx.try_recv().is_ok() { 93 | return tx.send(true).map_err(|_| { 94 | Error::new(ErrorKind::Other, "Could not send signal to clean up.").into() 95 | }); 96 | }; 97 | let dir_entry = dir_entry_result?; 98 | 99 | //check if the given file is a directory 100 | if let Some(path_name) = dir_entry.path().to_str() { 101 | //if -r is passed, continue down 102 | if conf.recursive && dir_entry.metadata()?.is_dir() { 103 | view_directory(conf, path_name, (tx, rx))?; 104 | } 105 | //if it is a regular file, viu it, but do not exit on error 106 | else { 107 | let _ = view_file(conf, path_name, (tx, rx)); 108 | } 109 | } else { 110 | eprintln!("Could not get path name, skipping..."); 111 | continue; 112 | } 113 | } 114 | 115 | Ok(()) 116 | } 117 | 118 | fn view_file(conf: &Config, filename: &str, (tx, rx): TxRx) -> ViuResult { 119 | if conf.name { 120 | println!("{}:", filename); 121 | } 122 | let mut file_in = fs::File::open(filename)?; 123 | 124 | // Read some of the first bytes to guess the image format 125 | let mut format_guess_buf: [u8; 20] = [0; 20]; 126 | let _ = file_in.read(&mut format_guess_buf)?; 127 | // Reset the cursor 128 | file_in.seek(std::io::SeekFrom::Start(0))?; 129 | 130 | // If the file is a gif, let iTerm handle it natively 131 | if conf.viuer_config.use_iterm 132 | && viuer::is_iterm_supported() 133 | && (image::guess_format(&format_guess_buf[..])?) == image::ImageFormat::Gif 134 | { 135 | viuer::print_from_file(filename, &conf.viuer_config)?; 136 | } else { 137 | let result = try_print_gif(conf, BufReader::new(file_in), (tx, rx)); 138 | //the provided image is not a gif so try to view it 139 | if result.is_err() { 140 | viuer::print_from_file(filename, &conf.viuer_config)?; 141 | } 142 | } 143 | 144 | Ok(()) 145 | } 146 | 147 | fn try_print_gif(conf: &Config, input_stream: R, (tx, rx): TxRx) -> ViuResult 148 | where 149 | R: Read + BufRead + Seek, 150 | { 151 | //read all frames of the gif and resize them all at once before starting to print them 152 | let resized_frames: Vec<(Duration, DynamicImage)> = GifDecoder::new(input_stream)? 153 | .into_frames() 154 | .collect_frames()? 155 | .into_iter() 156 | .map(|f| { 157 | let delay = Duration::from(f.delay()); 158 | // Keep the image as it is for Kitty and iTerm, it will be printed in full resolution there 159 | if (conf.viuer_config.use_iterm && viuer::is_iterm_supported()) 160 | || (conf.viuer_config.use_kitty 161 | && viuer::get_kitty_support() != viuer::KittySupport::None) 162 | { 163 | (delay, DynamicImage::ImageRgba8(f.into_buffer())) 164 | } else { 165 | ( 166 | delay, 167 | viuer::resize( 168 | &DynamicImage::ImageRgba8(f.into_buffer()), 169 | conf.viuer_config.width, 170 | conf.viuer_config.height, 171 | ), 172 | ) 173 | } 174 | }) 175 | .collect(); 176 | 177 | 'infinite: loop { 178 | let mut iter = resized_frames.iter().peekable(); 179 | while let Some((delay, frame)) = iter.next() { 180 | let (_print_width, print_height) = viuer::print(frame, &conf.viuer_config)?; 181 | 182 | if conf.static_gif { 183 | break 'infinite; 184 | } 185 | 186 | thread::sleep(match conf.frame_duration { 187 | None => *delay, 188 | Some(duration) => duration, 189 | }); 190 | 191 | //if ctrlc is received then respond so the handler can clear the 192 | // terminal from leftover colors 193 | if rx.try_recv().is_ok() { 194 | return tx.send(true).map_err(|_| { 195 | Error::new(ErrorKind::Other, "Could not send signal to clean up.").into() 196 | }); 197 | }; 198 | 199 | //keep replacing old pixels as the gif goes on so that scrollback 200 | // buffer is not filled (do not do that if it is the last frame of the gif 201 | // or a couple of files are being processed) 202 | if iter.peek().is_some() || conf.loop_gif { 203 | //since picture height is in pixel, we divide by 2 to get the height in 204 | // terminal cells 205 | if let Err(e) = execute!(stdout(), cursor::MoveUp(print_height as u16)) { 206 | if e.kind() == ErrorKind::BrokenPipe { 207 | //Stop printing. Output is probably piped to `head` or a similar tool 208 | break 'infinite; 209 | } else { 210 | return Err(e.into()); 211 | } 212 | } 213 | } 214 | } 215 | if !conf.loop_gif { 216 | break 'infinite; 217 | } 218 | } 219 | Ok(()) 220 | } 221 | 222 | #[cfg(test)] 223 | mod test { 224 | use super::*; 225 | 226 | #[test] 227 | fn test_view_without_extension() { 228 | let conf = Config::test_config(); 229 | let (tx, rx) = mpsc::channel(); 230 | view_file(&conf, "img/bfa", (&tx, &rx)).unwrap(); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use clap::ArgMatches; 2 | use std::time::Duration; 3 | use viuer::Config as ViuerConfig; 4 | 5 | pub struct Config<'a> { 6 | pub files: Vec<&'a str>, 7 | pub loop_gif: bool, 8 | pub name: bool, 9 | pub recursive: bool, 10 | pub static_gif: bool, 11 | pub viuer_config: ViuerConfig, 12 | pub frame_duration: Option, 13 | } 14 | 15 | impl<'a> Config<'a> { 16 | pub fn new(matches: &'a ArgMatches) -> Config<'a> { 17 | let width = matches.get_one("width").cloned(); 18 | let height = matches.get_one("height").cloned(); 19 | 20 | let files: Vec<&str> = matches 21 | .get_many::("file") 22 | .unwrap_or_default() 23 | .map(|s| s.as_str()) 24 | .collect(); 25 | 26 | let absolute_offset = matches.get_flag("absolute-offset"); 27 | let x: u16 = matches 28 | .get_one("x") 29 | .cloned() 30 | .expect("X offset must be present"); 31 | let y: i16 = matches 32 | .get_one("y") 33 | .cloned() 34 | .expect("Y offset must be present"); 35 | 36 | let use_blocks = matches.get_flag("blocks"); 37 | let transparent = matches.get_flag("transparent"); 38 | 39 | let viuer_config = ViuerConfig { 40 | width, 41 | height, 42 | x, 43 | y, 44 | transparent, 45 | absolute_offset, 46 | use_kitty: !use_blocks, 47 | use_iterm: !use_blocks, 48 | #[cfg(feature = "sixel")] 49 | use_sixel: !use_blocks, 50 | ..Default::default() 51 | }; 52 | 53 | let frame_duration: Option = matches 54 | .get_one::("frames-per-second") 55 | .cloned() 56 | .map(|f| Duration::from_secs_f32(1.0 / f as f32)); 57 | 58 | let once = matches.get_flag("once"); 59 | let static_gif = matches.get_flag("static"); 60 | let loop_gif = files.len() <= 1 && !once; 61 | 62 | Config { 63 | files, 64 | loop_gif, 65 | name: matches.get_flag("name"), 66 | recursive: matches.get_flag("recursive"), 67 | static_gif, 68 | viuer_config, 69 | frame_duration, 70 | } 71 | } 72 | #[cfg(test)] 73 | pub fn test_config() -> Config<'a> { 74 | Config { 75 | files: vec![], 76 | loop_gif: true, 77 | name: false, 78 | recursive: false, 79 | static_gif: false, 80 | viuer_config: ViuerConfig { 81 | absolute_offset: false, 82 | use_kitty: false, 83 | ..Default::default() 84 | }, 85 | frame_duration: None, 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{ 2 | crate_description, crate_name, crate_version, value_parser, Arg, 3 | ArgAction::{Append, Help, SetTrue}, 4 | Command, 5 | }; 6 | 7 | mod app; 8 | mod config; 9 | 10 | use config::Config; 11 | 12 | fn main() { 13 | let matches = Command::new(crate_name!()) 14 | .version(crate_version!()) 15 | .about(crate_description!()) 16 | .arg_required_else_help(true) 17 | .arg( 18 | Arg::new("file") 19 | .help("The images to be displayed. Set to - for standard input.") 20 | .action(Append), 21 | ) 22 | .arg( 23 | Arg::new("width") 24 | .short('w') 25 | .long("width") 26 | .value_parser(value_parser!(u32)) 27 | .help("Resize the image to a provided width"), 28 | ) 29 | .arg( 30 | Arg::new("height") 31 | .short('h') 32 | .long("height") 33 | .value_parser(value_parser!(u32)) 34 | .help("Resize the image to a provided height"), 35 | ) 36 | .arg( 37 | Arg::new("x") 38 | .short('x') 39 | .default_value("0") 40 | .value_parser(value_parser!(u16)) 41 | .help("X offset"), 42 | ) 43 | .arg( 44 | Arg::new("y") 45 | .short('y') 46 | .default_value("0") 47 | .value_parser(value_parser!(i16)) 48 | .help("Y offset"), 49 | ) 50 | .arg( 51 | Arg::new("absolute-offset") 52 | .short('a') 53 | .long("absolute-offset") 54 | .action(SetTrue) 55 | .help("Make the x and y offset be relative to the top left terminal corner. If not set, they are relative to the cursor's position."), 56 | ) 57 | .arg( 58 | Arg::new("recursive") 59 | .short('r') 60 | .long("recursive") 61 | .action(SetTrue) 62 | .help("Recurse down directories if passed one"), 63 | ) 64 | .arg( 65 | Arg::new("blocks") 66 | .short('b') 67 | .long("blocks") 68 | .action(SetTrue) 69 | .help("Force block output"), 70 | ) 71 | .arg( 72 | Arg::new("name") 73 | .short('n') 74 | .long("name") 75 | .action(SetTrue) 76 | .help("Output the name of the file before displaying"), 77 | ) 78 | .arg( 79 | Arg::new("transparent") 80 | .short('t') 81 | .long("transparent") 82 | .action(SetTrue) 83 | .help("Display transparent images with transparent background"), 84 | ) 85 | .arg( 86 | Arg::new("frames-per-second") 87 | .short('f') 88 | .long("frame-rate") 89 | .value_parser(value_parser!(u8)) 90 | .help("Play the gif at a given frame rate"), 91 | ) 92 | .arg( 93 | Arg::new("once") 94 | .short('1') 95 | .long("once") 96 | .action(SetTrue) 97 | .help("Loop only once through the gif"), 98 | ) 99 | .arg( 100 | Arg::new("static") 101 | .short('s') 102 | .long("static") 103 | .action(SetTrue) 104 | .help("Show only the first frame of the gif"), 105 | ) 106 | .disable_help_flag(true) 107 | .arg( 108 | Arg::new("help") 109 | .short('H') 110 | .long("help") 111 | .action(Help) 112 | .help("Print help information"), 113 | ) 114 | .get_matches(); 115 | 116 | let conf = Config::new(&matches); 117 | 118 | if let Err(e) = app::run(conf) { 119 | eprintln!("{:?}", e); 120 | std::process::exit(1); 121 | } 122 | } 123 | --------------------------------------------------------------------------------