├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── gifs ├── 1.gif ├── 2.gif ├── 3.gif ├── 4.gif └── 5.gif ├── imgs ├── 1.png └── 2.png ├── rascii ├── readme ├── 1.png ├── 2.png ├── 3.png ├── 4.png └── 5.gif └── src ├── cli.yml ├── converter.rs ├── generic_renderer.rs ├── gif.rs ├── gif_renderer.rs ├── img_renderer.rs ├── main.rs ├── renderer.rs ├── settings.rs └── types.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "adler32" 3 | version = "1.0.3" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | 6 | [[package]] 7 | name = "aho-corasick" 8 | version = "0.6.10" 9 | source = "registry+https://github.com/rust-lang/crates.io-index" 10 | dependencies = [ 11 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 12 | ] 13 | 14 | [[package]] 15 | name = "ansi_term" 16 | version = "0.11.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | dependencies = [ 19 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 20 | ] 21 | 22 | [[package]] 23 | name = "arrayvec" 24 | version = "0.4.10" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | dependencies = [ 27 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 28 | ] 29 | 30 | [[package]] 31 | name = "atty" 32 | version = "0.2.11" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | dependencies = [ 35 | "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 37 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 38 | ] 39 | 40 | [[package]] 41 | name = "bitflags" 42 | version = "1.0.4" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | 45 | [[package]] 46 | name = "byteorder" 47 | version = "1.3.1" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | 50 | [[package]] 51 | name = "cfg-if" 52 | version = "0.1.6" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | 55 | [[package]] 56 | name = "clap" 57 | version = "2.32.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | dependencies = [ 60 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 61 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 62 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 63 | "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 64 | "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 65 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 66 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 68 | ] 69 | 70 | [[package]] 71 | name = "color_quant" 72 | version = "1.0.1" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | 75 | [[package]] 76 | name = "crossbeam-deque" 77 | version = "0.2.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | dependencies = [ 80 | "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 81 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 82 | ] 83 | 84 | [[package]] 85 | name = "crossbeam-epoch" 86 | version = "0.3.1" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | dependencies = [ 89 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 90 | "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 91 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 92 | "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 93 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 96 | ] 97 | 98 | [[package]] 99 | name = "crossbeam-utils" 100 | version = "0.2.2" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | dependencies = [ 103 | "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 104 | ] 105 | 106 | [[package]] 107 | name = "deflate" 108 | version = "0.7.19" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | dependencies = [ 111 | "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 113 | ] 114 | 115 | [[package]] 116 | name = "either" 117 | version = "1.5.1" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | 120 | [[package]] 121 | name = "gif" 122 | version = "0.10.1" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | dependencies = [ 125 | "color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 126 | "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 127 | ] 128 | 129 | [[package]] 130 | name = "image" 131 | version = "0.21.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | dependencies = [ 134 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 135 | "gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 136 | "jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", 137 | "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 138 | "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", 139 | "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 140 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 141 | "png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 143 | "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 145 | ] 146 | 147 | [[package]] 148 | name = "inflate" 149 | version = "0.4.5" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | dependencies = [ 152 | "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 153 | ] 154 | 155 | [[package]] 156 | name = "jpeg-decoder" 157 | version = "0.1.15" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | dependencies = [ 160 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 161 | "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 162 | ] 163 | 164 | [[package]] 165 | name = "lazy_static" 166 | version = "1.2.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | 169 | [[package]] 170 | name = "libc" 171 | version = "0.2.49" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | 174 | [[package]] 175 | name = "lzw" 176 | version = "0.10.0" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | 179 | [[package]] 180 | name = "memchr" 181 | version = "2.2.0" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | 184 | [[package]] 185 | name = "memoffset" 186 | version = "0.2.1" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | 189 | [[package]] 190 | name = "nodrop" 191 | version = "0.1.13" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | 194 | [[package]] 195 | name = "num-derive" 196 | version = "0.2.4" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | dependencies = [ 199 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 200 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 201 | "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", 202 | ] 203 | 204 | [[package]] 205 | name = "num-integer" 206 | version = "0.1.39" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | dependencies = [ 209 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 210 | ] 211 | 212 | [[package]] 213 | name = "num-iter" 214 | version = "0.1.37" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | dependencies = [ 217 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 218 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 219 | ] 220 | 221 | [[package]] 222 | name = "num-rational" 223 | version = "0.2.1" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | dependencies = [ 226 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 227 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 228 | ] 229 | 230 | [[package]] 231 | name = "num-traits" 232 | version = "0.2.6" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | 235 | [[package]] 236 | name = "num_cpus" 237 | version = "1.10.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | dependencies = [ 240 | "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", 241 | ] 242 | 243 | [[package]] 244 | name = "png" 245 | version = "0.14.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | dependencies = [ 248 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 249 | "deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)", 250 | "inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 251 | "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", 252 | ] 253 | 254 | [[package]] 255 | name = "proc-macro2" 256 | version = "0.4.27" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | dependencies = [ 259 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 260 | ] 261 | 262 | [[package]] 263 | name = "quote" 264 | version = "0.6.11" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | dependencies = [ 267 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 268 | ] 269 | 270 | [[package]] 271 | name = "rascii" 272 | version = "0.3.0" 273 | dependencies = [ 274 | "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", 275 | "gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 276 | "image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", 277 | "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 278 | "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 279 | ] 280 | 281 | [[package]] 282 | name = "rayon" 283 | version = "1.0.3" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | dependencies = [ 286 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 287 | "either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 288 | "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 289 | ] 290 | 291 | [[package]] 292 | name = "rayon-core" 293 | version = "1.4.1" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | dependencies = [ 296 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 297 | "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 298 | "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", 299 | "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 300 | ] 301 | 302 | [[package]] 303 | name = "redox_syscall" 304 | version = "0.1.51" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | 307 | [[package]] 308 | name = "redox_termios" 309 | version = "0.1.1" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | dependencies = [ 312 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 313 | ] 314 | 315 | [[package]] 316 | name = "regex" 317 | version = "1.1.0" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | dependencies = [ 320 | "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 321 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 322 | "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 323 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 324 | "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 325 | ] 326 | 327 | [[package]] 328 | name = "regex-syntax" 329 | version = "0.6.5" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | dependencies = [ 332 | "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 333 | ] 334 | 335 | [[package]] 336 | name = "safe-transmute" 337 | version = "0.10.1" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | 340 | [[package]] 341 | name = "scoped_threadpool" 342 | version = "0.1.9" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | 345 | [[package]] 346 | name = "scopeguard" 347 | version = "0.3.3" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | 350 | [[package]] 351 | name = "strsim" 352 | version = "0.7.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | 355 | [[package]] 356 | name = "syn" 357 | version = "0.15.26" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | dependencies = [ 360 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 361 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 362 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 363 | ] 364 | 365 | [[package]] 366 | name = "termcolor" 367 | version = "1.0.4" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | dependencies = [ 370 | "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 371 | ] 372 | 373 | [[package]] 374 | name = "termion" 375 | version = "1.5.1" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | dependencies = [ 378 | "libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)", 379 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 380 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 381 | ] 382 | 383 | [[package]] 384 | name = "textwrap" 385 | version = "0.10.0" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | dependencies = [ 388 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 389 | ] 390 | 391 | [[package]] 392 | name = "thread_local" 393 | version = "0.3.6" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | dependencies = [ 396 | "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 397 | ] 398 | 399 | [[package]] 400 | name = "tiff" 401 | version = "0.2.2" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | dependencies = [ 404 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 405 | "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 406 | "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 407 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 408 | ] 409 | 410 | [[package]] 411 | name = "ucd-util" 412 | version = "0.1.3" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | 415 | [[package]] 416 | name = "unicode-width" 417 | version = "0.1.5" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | 420 | [[package]] 421 | name = "unicode-xid" 422 | version = "0.1.0" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | 425 | [[package]] 426 | name = "utf8-ranges" 427 | version = "1.0.2" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | 430 | [[package]] 431 | name = "vec_map" 432 | version = "0.8.1" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | 435 | [[package]] 436 | name = "winapi" 437 | version = "0.3.6" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | dependencies = [ 440 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 441 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 442 | ] 443 | 444 | [[package]] 445 | name = "winapi-i686-pc-windows-gnu" 446 | version = "0.4.0" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | 449 | [[package]] 450 | name = "winapi-util" 451 | version = "0.1.2" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | dependencies = [ 454 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 455 | ] 456 | 457 | [[package]] 458 | name = "winapi-x86_64-pc-windows-gnu" 459 | version = "0.4.0" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | 462 | [[package]] 463 | name = "wincolor" 464 | version = "1.0.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | dependencies = [ 467 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 468 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 469 | ] 470 | 471 | [[package]] 472 | name = "yaml-rust" 473 | version = "0.3.5" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | 476 | [metadata] 477 | "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" 478 | "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" 479 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 480 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" 481 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 482 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 483 | "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" 484 | "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" 485 | "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" 486 | "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" 487 | "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" 488 | "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" 489 | "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" 490 | "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" 491 | "checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" 492 | "checksum gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4bca55ac1f213920ce3527ccd62386f1f15fa3f1714aeee1cf93f2c416903f" 493 | "checksum image 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "52fb0666a1273dac46f9725aa4859bcd5595fc3554cf3495051b4de8db745e7d" 494 | "checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" 495 | "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" 496 | "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" 497 | "checksum libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)" = "413f3dfc802c5dc91dc570b05125b6cda9855edfaa9825c9849807876376e70e" 498 | "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" 499 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" 500 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 501 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 502 | "checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d" 503 | "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 504 | "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" 505 | "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" 506 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 507 | "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" 508 | "checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9" 509 | "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 510 | "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 511 | "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" 512 | "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" 513 | "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" 514 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 515 | "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" 516 | "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" 517 | "checksum safe-transmute 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9604873ffe1980bc1f179103704a65c8aca141c248d9e52b7af95ff10578166e" 518 | "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" 519 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 520 | "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 521 | "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" 522 | "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" 523 | "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" 524 | "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" 525 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 526 | "checksum tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4834f28a0330cb9f3f2c87d2649dca723cb33802e2bdcf18da32759fbec7ce" 527 | "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" 528 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 529 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 530 | "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" 531 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 532 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 533 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 534 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" 535 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 536 | "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" 537 | "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" 538 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rascii" 3 | version = "0.3.0" 4 | authors = ["Stepan Khodzhaian "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | termcolor = "1.0.4" 9 | image = "0.21.0" 10 | gif = "0.10.1" 11 | regex = "1" 12 | clap = {version = "~2.32.0", features = ["yaml"]} 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RASCII 2 | ### ASCII image renderer written in Rust 3 | 4 | Rascii allows you to preview image files in terminal. 5 | By default it shows the image in very low resolution. 6 | 7 | ```./rascii imgs/1.png``` 8 | 9 | ![](https://raw.githubusercontent.com/mightykho/rascii/master/readme/1.png) 10 | 11 | 12 | By tweaking some values you can get much better results. 13 | 14 | ```./rascii imgs/1.png -w 260``` 15 | 16 | ![](https://raw.githubusercontent.com/mightykho/rascii/master/readme/2.png) 17 | 18 | 19 | To get colourful results pass `-c` argument (Currently doesn't work in Mac OS 20 | terminal.) 21 | 22 | ```./rascii imgs/1.png -w 260 -c``` 23 | 24 | ![](https://raw.githubusercontent.com/mightykho/rascii/master/readme/3.png) 25 | 26 | 27 | Rascii also allows you to play GIF animations (only 256 colour gifs are supported) 28 | 29 | ```./rascii gifs/5.gif -w 460 -f 6 -p 3``` 30 | 31 | [![Watch the video](https://raw.githubusercontent.com/mightykho/rascii/master/readme/4.png)](https://youtu.be/RAfJnAe2HhA) 32 | 33 | 34 | Gif animations could be also previewed in colour but it is much less performant 35 | than ASCII version. 36 | 37 | ![](https://raw.githubusercontent.com/mightykho/rascii/master/readme/5.gif) 38 | 39 | 40 | ## Usage 41 | ``` 42 | USAGE: 43 | rascii [FLAGS] [OPTIONS] 44 | 45 | FLAGS: 46 | -c, --color Use colors instead of symbols. Less performant when used with GIFs 47 | -h, --help Prints help information 48 | -i, --invert Inverts image. Useful for light-themed terminals 49 | -V, --version Prints version information 50 | 51 | OPTIONS: 52 | -f, --fps Sets frames per second. Default: 2 53 | -p Sets aspect ratio of a symbol-pixel. Might need tweaking depending on line height. 54 | Default: 3.0 55 | -w Sets image width in symbols. Default: 100 56 | 57 | ARGS: 58 | Image path to preview 59 | ``` 60 | -------------------------------------------------------------------------------- /gifs/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/gifs/1.gif -------------------------------------------------------------------------------- /gifs/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/gifs/2.gif -------------------------------------------------------------------------------- /gifs/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/gifs/3.gif -------------------------------------------------------------------------------- /gifs/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/gifs/4.gif -------------------------------------------------------------------------------- /gifs/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/gifs/5.gif -------------------------------------------------------------------------------- /imgs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/imgs/1.png -------------------------------------------------------------------------------- /imgs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/imgs/2.png -------------------------------------------------------------------------------- /rascii: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/rascii -------------------------------------------------------------------------------- /readme/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/readme/1.png -------------------------------------------------------------------------------- /readme/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/readme/2.png -------------------------------------------------------------------------------- /readme/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/readme/3.png -------------------------------------------------------------------------------- /readme/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/readme/4.png -------------------------------------------------------------------------------- /readme/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightykho/rascii/6232475cd6a47ee47a0ae861458a507ebd433d16/readme/5.gif -------------------------------------------------------------------------------- /src/cli.yml: -------------------------------------------------------------------------------- 1 | name: RASCII 2 | version: "0.3" 3 | author: Stepan K. 4 | about: ASCII image preview on Rust 5 | args: 6 | - image: 7 | index: 1 8 | value_name: IMAGE 9 | help: "Image path to preview" 10 | required: true 11 | - width: 12 | short: w 13 | value_name: IMAGE WIDTH 14 | help: "Sets image width in symbols. Default: 100" 15 | required: false 16 | - pixel_aspect_ratio: 17 | short: p 18 | value_name: PIXEL ASPECT RATIO 19 | help: "Sets aspect ratio of a symbol-pixel. Might need tweaking depending on line height. Default: 3.0" 20 | required: false 21 | - invert: 22 | short: i 23 | long: invert 24 | takes_value: false 25 | help: "Inverts image. Useful for light-themed terminals" 26 | required: false 27 | - color: 28 | short: c 29 | long: color 30 | takes_value: false 31 | help: "Use colors instead of symbols. Less performant when used with GIFs" 32 | required: false 33 | - fps: 34 | short: f 35 | long: fps 36 | value_name: FPS 37 | help: "Sets frames per second. Default: 2" 38 | -------------------------------------------------------------------------------- /src/converter.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; 4 | use image::{GenericImageView, Rgba, DynamicImage}; 5 | 6 | use crate::{Settings, RgbaBuffer}; 7 | 8 | const CHARS: [char; 10] = [' ','.',':','-','=','+','*','#','%','@']; 9 | const CHARS_LEN: usize = 10; 10 | 11 | pub struct Converter<'a> { 12 | settings: &'a Settings, 13 | bufwtr: BufferWriter 14 | } 15 | 16 | impl<'a> Converter<'a> { 17 | pub fn new(settings: &'a Settings) -> Self { 18 | let bufwtr = BufferWriter::stdout(ColorChoice::Always); 19 | 20 | Self { settings, bufwtr } 21 | } 22 | 23 | pub fn convert_to_string(&self, img: DynamicImage) -> String { 24 | let mut buffer = self.bufwtr.buffer(); 25 | 26 | let img = self.prepare_img_for_conversion(img); 27 | 28 | let mut cur_y = 0; 29 | 30 | for (_x, y, pixel) in img.enumerate_pixels() { 31 | if y != cur_y { 32 | cur_y = y; 33 | write!(&mut buffer, "\n").ok(); 34 | } 35 | 36 | self.write_px_to_buffer(pixel, &mut buffer); 37 | } 38 | write!(&mut buffer, "\n").ok(); 39 | 40 | String::from_utf8(buffer.into_inner()).unwrap() 41 | } 42 | 43 | fn prepare_img_for_conversion(&self, img: DynamicImage) -> RgbaBuffer { 44 | let original_dimensions = img.dimensions(); 45 | let height = (original_dimensions.1 as f64 / (original_dimensions.0 as f64 * self.settings.pixel_aspect_ratio) * self.settings.width as f64) as u32; 46 | 47 | let img = img.thumbnail_exact(self.settings.width, height); 48 | 49 | let img = if self.settings.color { 50 | img.to_rgba() 51 | } else { 52 | img.grayscale().to_rgba() 53 | }; 54 | 55 | img 56 | } 57 | 58 | fn write_px_to_buffer(&self, pixel: &Rgba, buffer: &mut Buffer) { 59 | if self.settings.color { 60 | let color = Color::Rgb(pixel[0], pixel[1], pixel[2]); 61 | 62 | buffer.set_color(ColorSpec::new().set_bg(Some(color))).ok(); 63 | write!(buffer, " ").ok(); 64 | buffer.set_color(ColorSpec::new().set_bg(None)).ok(); 65 | } else { 66 | let char_index = (pixel[0] as f64 / 255.0) * (CHARS_LEN - 1) as f64; 67 | 68 | if self.settings.invert { 69 | write!(buffer, "{}", CHARS[CHARS_LEN - 1 - char_index as usize]).ok(); 70 | } else { 71 | write!(buffer, "{}", CHARS[char_index as usize]).ok(); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/generic_renderer.rs: -------------------------------------------------------------------------------- 1 | pub trait GenericRenderer { 2 | fn new(settings: crate::Settings) -> Self; 3 | fn render(&self); 4 | } 5 | -------------------------------------------------------------------------------- /src/gif.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use gif::SetParameter; 3 | use std::io::Write; 4 | use image::{Rgba, Pixel, GenericImage}; 5 | 6 | use crate::renderer::Renderer; 7 | use crate::settings::Settings; 8 | use crate::generic_renderer::GenericRenderer; 9 | 10 | pub struct GifRenderer { 11 | settings: Settings 12 | } 13 | 14 | impl GenericRenderer for GifRenderer { 15 | fn new(settings: Settings) -> Self { 16 | Self { settings } 17 | } 18 | 19 | fn render(&self) { 20 | let mut decoder = gif::Decoder::new(File::open(image_path).unwrap()); 21 | decoder.set(gif::ColorOutput::RGBA); 22 | let mut decoder = decoder.read_info().unwrap(); 23 | 24 | let mut stringified_frames: Vec = vec![]; 25 | 26 | let frame = decoder.read_next_frame().unwrap().unwrap(); 27 | let mut img = image::DynamicImage::new_rgba8(frame.width as u32, frame.height as u32); 28 | write_frame_to_image(frame, &mut img); 29 | 30 | let original_img = img.to_rgba(); 31 | let original_dimensions = original_img.dimensions(); 32 | 33 | stringified_frames.push(renderer.render_to_string(img)); 34 | 35 | while let Some(frame) = decoder.read_next_frame().unwrap() { 36 | let mut img = image::DynamicImage::new_rgba8(original_dimensions.0, original_dimensions.1); 37 | img.copy_from(&original_img, 0, 0); 38 | 39 | write_frame_to_image(frame, &mut img); 40 | 41 | stringified_frames.push(renderer.render_to_string(img)); 42 | } 43 | 44 | let stdout = std::io::stdout(); 45 | let mut stdout = stdout.lock(); 46 | 47 | for frame in stringified_frames.iter().cycle() { 48 | std::thread::sleep(std::time::Duration::from_millis(1000 / fps as u64)); 49 | write!(stdout, "{}[2J{}", 27 as char, frame); 50 | } 51 | } 52 | 53 | 54 | impl GifRenderer { 55 | 56 | fn write_frame_to_image(frame: &gif::Frame, img: &mut image::DynamicImage) { 57 | for y in 0..(frame.height as u32) { 58 | for x in 0..(frame.width as u32) { 59 | let pixel_index = ((y * frame.width as u32 + x) * 4) as usize; 60 | 61 | if frame.buffer[pixel_index + 3] != 0 { 62 | img.put_pixel(x + frame.left as u32, y + frame.top as u32, Rgba::from_channels( 63 | frame.buffer[pixel_index], 64 | frame.buffer[pixel_index + 1], 65 | frame.buffer[pixel_index + 2], 66 | frame.buffer[pixel_index + 3] 67 | )); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/gif_renderer.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Write; 3 | 4 | use gif::{SetParameter, Frame}; 5 | use image::{Rgba, Pixel, GenericImage, DynamicImage}; 6 | 7 | use crate::{RgbaBuffer, Settings}; 8 | use crate::converter::Converter; 9 | use crate::generic_renderer::GenericRenderer; 10 | 11 | pub struct GifRenderer { 12 | settings: Settings 13 | } 14 | 15 | impl GenericRenderer for GifRenderer { 16 | fn new(settings: Settings) -> Self { 17 | Self { settings } 18 | } 19 | 20 | fn render(&self) { 21 | let mut decoder = self.build_gif_decoder(); 22 | let converter = Converter::new(&self.settings); 23 | let mut stringified_frames: Vec = vec![]; 24 | 25 | let frame = decoder.read_next_frame().unwrap().unwrap(); 26 | let img = Self::build_image_from_frame(frame, None); 27 | let first_frame_img = img.to_rgba(); 28 | 29 | stringified_frames.push(converter.convert_to_string(img)); 30 | 31 | while let Some(frame) = decoder.read_next_frame().unwrap() { 32 | let img = Self::build_image_from_frame(frame, Some(&first_frame_img)); 33 | 34 | stringified_frames.push(converter.convert_to_string(img)); 35 | } 36 | 37 | self.output_to_stdout(stringified_frames); 38 | } 39 | } 40 | 41 | impl GifRenderer { 42 | fn output_to_stdout(&self, frames: Vec) { 43 | let stdout = std::io::stdout(); 44 | let mut stdout = stdout.lock(); 45 | 46 | for frame in frames.iter().cycle() { 47 | std::thread::sleep(std::time::Duration::from_millis(1000 / self.settings.fps as u64)); 48 | write!(stdout, "{}[2J{}", 27 as char, frame).ok(); 49 | } 50 | } 51 | 52 | fn build_gif_decoder(&self) -> gif::Reader { 53 | let mut decoder = gif::Decoder::new(File::open(&self.settings.image_path).unwrap()); 54 | decoder.set(gif::ColorOutput::RGBA); 55 | 56 | decoder.read_info().unwrap() 57 | } 58 | 59 | fn build_image_from_frame(frame: &Frame, maybe_first_frame_img: Option<&RgbaBuffer>) -> DynamicImage { 60 | let mut img: DynamicImage; 61 | 62 | if let Some(first_frame_img) = maybe_first_frame_img { 63 | let (width, height) = first_frame_img.dimensions(); 64 | 65 | img = DynamicImage::new_rgba8(width, height); 66 | img.copy_from(first_frame_img, 0, 0); 67 | } else { 68 | img = DynamicImage::new_rgba8(frame.width as u32, frame.height as u32); 69 | } 70 | 71 | Self::write_frame_to_image(frame, img) 72 | } 73 | 74 | fn write_frame_to_image(frame: &Frame, mut img: DynamicImage) -> DynamicImage { 75 | for y in 0..(frame.height as u32) { 76 | for x in 0..(frame.width as u32) { 77 | let pixel_index = ((y * frame.width as u32 + x) * 4) as usize; 78 | 79 | if frame.buffer[pixel_index + 3] != 0 { 80 | img.put_pixel(x + frame.left as u32, y + frame.top as u32, Rgba::from_channels( 81 | frame.buffer[pixel_index], 82 | frame.buffer[pixel_index + 1], 83 | frame.buffer[pixel_index + 2], 84 | frame.buffer[pixel_index + 3] 85 | )); 86 | } 87 | } 88 | } 89 | 90 | img 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/img_renderer.rs: -------------------------------------------------------------------------------- 1 | use crate::converter::Converter; 2 | use crate::Settings; 3 | 4 | pub struct ImgRenderer { 5 | settings: Settings 6 | } 7 | 8 | impl crate::GenericRenderer for ImgRenderer { 9 | fn new(settings: Settings) -> Self { 10 | Self { settings } 11 | } 12 | 13 | fn render(&self) { 14 | let img = image::open(&self.settings.image_path).unwrap(); 15 | let converter = Converter::new(&self.settings); 16 | 17 | print!("{}", converter.convert_to_string(img)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate clap; 3 | 4 | mod types; 5 | mod renderer; 6 | mod settings; 7 | mod gif_renderer; 8 | mod generic_renderer; 9 | mod img_renderer; 10 | mod converter; 11 | 12 | pub use self::settings::Settings; 13 | pub use self::types::*; 14 | pub use self::generic_renderer::GenericRenderer; 15 | pub use self::img_renderer::ImgRenderer; 16 | pub use self::gif_renderer::GifRenderer; 17 | 18 | fn main() { 19 | let yaml = load_yaml!("cli.yml"); 20 | let matches = clap::App::from_yaml(yaml).get_matches(); 21 | 22 | let settings = Settings::new(matches); 23 | let renderer = renderer::build_renderer(settings); 24 | 25 | renderer.render(); 26 | } 27 | -------------------------------------------------------------------------------- /src/renderer.rs: -------------------------------------------------------------------------------- 1 | use crate::{GenericRenderer, GifRenderer, ImgRenderer}; 2 | 3 | pub enum Renderer { 4 | Gif(GifRenderer), 5 | Img(ImgRenderer) 6 | } 7 | 8 | impl Renderer { 9 | pub fn render(&self) { 10 | match *self { 11 | Renderer::Img(ref renderer) => renderer.render(), 12 | Renderer::Gif(ref renderer) => renderer.render() 13 | } 14 | } 15 | } 16 | 17 | pub fn build_renderer(settings: crate::Settings) -> Renderer { 18 | let gif_regex = regex::Regex::new(r"\.gif$").unwrap(); 19 | 20 | if gif_regex.is_match(&settings.image_path) { 21 | Renderer::Gif(GifRenderer::new(settings)) 22 | } else { 23 | Renderer::Img(ImgRenderer::new(settings)) 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/settings.rs: -------------------------------------------------------------------------------- 1 | pub struct Settings { 2 | pub width: u32, 3 | pub pixel_aspect_ratio: f64, 4 | pub invert: bool, 5 | pub color: bool, 6 | pub fps: u8, 7 | pub image_path: String 8 | } 9 | 10 | impl Settings { 11 | pub fn new(matches: clap::ArgMatches) -> Self { 12 | let image_path = matches.value_of("image").unwrap().to_string(); 13 | 14 | let width_param = matches.value_of("width").unwrap_or(""); 15 | let width = width_param.parse::().unwrap_or(100); 16 | 17 | let par_param = matches.value_of("pixel_aspect_ratio").unwrap_or(""); 18 | let pixel_aspect_ratio = par_param.parse::().unwrap_or(3.0); 19 | 20 | let fps_param = matches.value_of("fps").unwrap_or(""); 21 | let fps = fps_param.parse::().unwrap_or(2); 22 | 23 | let invert = matches.is_present("invert"); 24 | let color = matches.is_present("color"); 25 | 26 | 27 | Self { 28 | image_path, 29 | width, 30 | pixel_aspect_ratio, 31 | invert, 32 | color, 33 | fps 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | pub type RgbaBuffer = image::ImageBuffer, Vec>; 2 | --------------------------------------------------------------------------------