├── LICENSE ├── Makefile ├── README.md └── img2xterm.c /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 Lin, Ke-fei (kfei). http://kfei.net 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX = /usr/local 2 | INSTALL = install 3 | LN = ln -fs 4 | 5 | ifeq ($(shell sh -c 'which gcc>/dev/null 2>/dev/null && echo y'), y) 6 | CC = gcc 7 | CFLAGS = -O2 -Wall 8 | LDFLAGS = -s 9 | endif 10 | 11 | ifeq ($(shell sh -c 'uname'), Darwin) 12 | CC = clang 13 | CFLAGS = -O2 -Wall 14 | LDFLAGS = 15 | endif 16 | 17 | ifeq ($(shell sh -c 'which ncurses5-config>/dev/null 2>/dev/null && echo y'), y) 18 | DEFS = 19 | CFLAGS += $(shell ncurses5-config --cflags) 20 | LIBS = -lm $(shell ncurses5-config --libs) 21 | else 22 | ifeq ($(shell sh -c 'which ncursesw5-config>/dev/null 2>/dev/null && echo y'), y) 23 | DEFS = 24 | CFLAGS += $(shell ncursesw5-config --cflags) 25 | LIBS = -lm $(shell ncursesw5-config --libs) 26 | else 27 | DEFS = -DNO_CURSES 28 | LIBS = -lm 29 | endif 30 | endif 31 | 32 | ifeq ($(shell sh -c 'which MagickWand-config>/dev/null 2>/dev/null && echo y'), y) 33 | WANDCONFIG = MagickWand-config 34 | else 35 | WANDCONFIG = Wand-config 36 | endif 37 | 38 | CFLAGS := $(CFLAGS) $(shell $(WANDCONFIG) --cflags) 39 | CPPFLAGS := $(CPPFLAGS) $(DEFS) $(shell $(WANDCONFIG) --cppflags) 40 | LDFLAGS := $(LDFLAGS) $(shell $(WANDCONFIG) --ldflags) 41 | LIBS := $(LIBS) $(shell $(WANDCONFIG) --libs) 42 | 43 | all: img2xterm 44 | 45 | img2xterm: img2xterm.c 46 | $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(LDFLAGS) $(LIBS) 47 | 48 | .PHONY: all install clean 49 | 50 | clean: 51 | -$(RM) img2xterm 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # img2xterm 2 | 3 | [Demo](#demo) 4 | 5 | This project was originally a fork from [rossy/img2xterm][1] with: 6 | 7 | - Image auto fit to terminal 8 | - Support for displaying in B/W mode 9 | - Cowfile-related code deleted 10 | 11 | You may also be interested in the [Golang version][5]. 12 | 13 | ## Dependencies 14 | 15 | Before compilation, make sure you have the development packages of 16 | [ImageMagick][2] and [Ncurses][3] (for *terminfo* support). 17 | 18 | - *Arch Linux*: `pacman -S imagemagick-doc ncurses` 19 | - *Debian*/*Ubuntu*: `apt-get install libmagickwand4 libncurses5-dev` 20 | 21 | ## Getting img2xterm 22 | 23 | The GNU Autotools are not required. To compile and install from source, simply 24 | run: 25 | 26 | ```bash 27 | make 28 | make install 29 | ``` 30 | 31 | ## Usage 32 | 33 | To display an image on a 256-color compatible terminal: 34 | 35 | ```bash 36 | img2xterm image.jpg 37 | ``` 38 | 39 | Use [CIE94][4] for color difference algorithm: 40 | 41 | ```bash 42 | img2xterm -p image.jpg 43 | ``` 44 | 45 | Save image to file in grayscale: 46 | 47 | ```bash 48 | img2xterm -b image.jpg outfile 49 | cat outfile 50 | ``` 51 | 52 | More usage: 53 | 54 | ```bash 55 | img2xterm -h 56 | ``` 57 | 58 | ## License 59 | 60 | The MIT License (MIT) 61 | 62 | ## Demo 63 | 64 | ![IMAGE](http://i.imgur.com/YfakxHd.png) 65 | 66 | [1]: https://github.com/rossy/img2xterm 67 | [2]: http://www.imagemagick.org 68 | [3]: http://www.gnu.org/software/ncurses/ncurses.html 69 | [4]: http://en.wikipedia.org/wiki/Color_difference#CIE94 70 | [5]: https://github.com/kfei/sshcam/tree/master/img2xterm 71 | -------------------------------------------------------------------------------- /img2xterm.c: -------------------------------------------------------------------------------- 1 | /* format: astyle --style=linux -t8 */ 2 | 3 | #define _GNU_SOURCE 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifndef NO_CURSES 14 | #include 15 | #endif 16 | 17 | #ifndef INFINITY 18 | #include 19 | #define INFINITY DBL_MAX 20 | #endif 21 | 22 | enum { 23 | color_undef, 24 | color_transparent, 25 | }; 26 | 27 | unsigned char* colortable; 28 | double* labtable; 29 | 30 | const unsigned char valuerange[] = { 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff }; 31 | unsigned long oldfg = color_undef; 32 | unsigned long oldbg = color_undef; 33 | int perceptive = 0; 34 | double chroma_weight = 1.0; 35 | struct winsize w; 36 | 37 | #ifndef NO_CURSES 38 | int use_terminfo = 0; 39 | char* ti_setb; 40 | char* ti_setf; 41 | char* ti_op; 42 | #endif 43 | 44 | void srgb2lab(unsigned char red, unsigned char green, unsigned char blue, double* lightness, double* aa, double* bb) 45 | { 46 | double r = (double)red / 255.0; 47 | double g = (double)green / 255.0; 48 | double b = (double)blue / 255.0; 49 | 50 | double rl = r <= 0.4045 ? r / 12.92 : pow((r + 0.055) / 1.055, 2.4); 51 | double gl = g <= 0.4045 ? g / 12.92 : pow((g + 0.055) / 1.055, 2.4); 52 | double bl = b <= 0.4045 ? b / 12.92 : pow((b + 0.055) / 1.055, 2.4); 53 | 54 | double x = 0.4124564 * rl + 0.3575761 * gl + 0.1804375 * bl; 55 | double y = 0.2126729 * rl + 0.7151522 * gl + 0.0721750 * bl; 56 | double z = 0.0193339 * rl + 0.1191920 * gl + 0.9503041 * bl; 57 | 58 | double xn = x / 0.95047; 59 | double yn = y; 60 | double zn = z / 1.08883; 61 | 62 | double fxn = xn > (216.0 / 24389.0) ? pow(xn, 1.0 / 3.0) 63 | : (841.0 / 108.0) * xn + (4.0 / 29.0); 64 | double fyn = yn > (216.0 / 24389.0) ? pow(yn, 1.0 / 3.0) 65 | : (841.0 / 108.0) * yn + (4.0 / 29.0); 66 | double fzn = zn > (216.0 / 24389.0) ? pow(zn, 1.0 / 3.0) 67 | : (841.0 / 108.0) * zn + (4.0 / 29.0); 68 | 69 | *lightness = 116.0 * fyn - 16.0; 70 | *aa = (500.0 * (fxn - fyn)) * chroma_weight; 71 | *bb = (200.0 * (fyn - fzn)) * chroma_weight; 72 | } 73 | 74 | void srgb2yiq(unsigned char red, unsigned char green, unsigned char blue, double* y, double* i, double* q) 75 | { 76 | double r = (double)red / 255.0; 77 | double g = (double)green / 255.0; 78 | double b = (double)blue / 255.0; 79 | 80 | *y = 0.299 * r + 0.587 * g + 0.144 * b; 81 | *i = (0.595716 * r + -0.274453 * g + -0.321263 * b) * chroma_weight; 82 | *q = (0.211456 * r + -0.522591 * g + 0.311135 * b) * chroma_weight; 83 | } 84 | 85 | double cie94(double l1, double a1, double b1, double l2, double a2, double b2) 86 | { 87 | const double kl = 1; 88 | const double k1 = 0.045; 89 | const double k2 = 0.015; 90 | 91 | double c1 = sqrt(a1 * a1 + b1 * b1); 92 | double c2 = sqrt(a2 * a2 + b2 * b2); 93 | double dl = l1 - l2; 94 | double dc = c1 - c2; 95 | double da = a1 - a2; 96 | double db = b1 - b2; 97 | double dh = sqrt(da * da + db * db - dc * dc); 98 | 99 | double t1 = dl / kl; 100 | double t2 = dc / (1 + k1 * c1); 101 | double t3 = dh / (1 + k2 * c1); 102 | 103 | return sqrt(t1 * t1 + t2 * t2 + t3 * t3); 104 | } 105 | 106 | void xterm2rgb(unsigned char color, unsigned char* rgb) 107 | { 108 | if (color < 232) { 109 | color -= 16; 110 | rgb[0] = valuerange[(color / 36) % 6]; 111 | rgb[1] = valuerange[(color / 6) % 6]; 112 | rgb[2] = valuerange[color % 6]; 113 | } else 114 | rgb[0] = rgb[1] = rgb[2] = 8 + (color - 232) * 10; 115 | } 116 | 117 | unsigned long rgb2xterm_cie94(unsigned char r, unsigned char g, unsigned char b) 118 | { 119 | unsigned long i = 16, ret = 0; 120 | double d, smallest_distance = INFINITY; 121 | double l, aa, bb; 122 | 123 | srgb2lab(r, g, b, &l, &aa, &bb); 124 | 125 | for (; i < 256; i++) { 126 | d = cie94(l, aa, bb, labtable[i * 3], labtable[i * 3 + 1], labtable[i * 3 + 2]); 127 | if (d < smallest_distance) { 128 | smallest_distance = d; 129 | ret = i; 130 | } 131 | } 132 | 133 | return ret; 134 | } 135 | 136 | unsigned long rgb2xterm_yiq(unsigned char r, unsigned char g, unsigned char b) 137 | { 138 | unsigned long i = 16, ret = 0; 139 | double d, smallest_distance = INFINITY; 140 | double y, ii, q; 141 | 142 | srgb2yiq(r, g, b, &y, &ii, &q); 143 | 144 | for (; i < 256; i++) { 145 | d = (y - labtable[i * 3]) * (y - labtable[i * 3]) + 146 | (ii - labtable[i * 3 + 1]) * (ii - labtable[i * 3 + 1]) + 147 | (q - labtable[i * 3 + 2]) * (q - labtable[i * 3 + 2]); 148 | if (d < smallest_distance) { 149 | smallest_distance = d; 150 | ret = i; 151 | } 152 | } 153 | 154 | return ret; 155 | } 156 | 157 | unsigned long rgb2xterm(unsigned char r, unsigned char g, unsigned char b) 158 | { 159 | unsigned long i = 16, d, ret = 0, smallest_distance = UINT_MAX; 160 | 161 | for (; i < 256; i++) { 162 | d = (colortable[i * 3] - r) * (colortable[i * 3] - r) + 163 | (colortable[i * 3 + 1] - g) * (colortable[i * 3 + 1] - g) + 164 | (colortable[i * 3 + 2] - b) * (colortable[i * 3 + 2] - b); 165 | if (d < smallest_distance) { 166 | smallest_distance = d; 167 | ret = i; 168 | } 169 | } 170 | 171 | return ret; 172 | } 173 | 174 | void bifurcate(FILE* file, unsigned long color1, unsigned long color2) 175 | { 176 | unsigned long fg = oldfg; 177 | unsigned long bg = oldbg; 178 | char* str = "\xe2\x96\x84"; 179 | 180 | if (color1 == color2) { 181 | bg = color1; 182 | str = " "; 183 | } else if (color2 == color_transparent) { 184 | str = "\xe2\x96\x80"; 185 | bg = color2; 186 | fg = color1; 187 | } else { 188 | bg = color1; 189 | fg = color2; 190 | } 191 | 192 | #ifndef NO_CURSES 193 | if (use_terminfo) { 194 | if (bg != oldbg) { 195 | if (bg == color_transparent) { 196 | fputs(ti_op, file); 197 | oldfg = color_undef; 198 | } else 199 | fputs(tparm(ti_setb, bg), file); 200 | } 201 | 202 | if (fg != oldfg) 203 | fputs(tparm(ti_setf, fg), file); 204 | } else 205 | #endif 206 | if (bg != oldbg) { 207 | if (bg == color_transparent) 208 | fputs("\e[49m", file); 209 | else 210 | fprintf(file, "\e[48;5;%lum", bg); 211 | } 212 | 213 | if (fg != oldfg) { 214 | if (fg == color_undef) 215 | fputs("\e[39m", file); 216 | else 217 | fprintf(file, "\e[38;5;%lum", fg); 218 | } 219 | 220 | oldbg = bg; 221 | oldfg = fg; 222 | 223 | fputs(str, file); 224 | } 225 | 226 | unsigned long fillrow(PixelWand** pixels, unsigned long* row, unsigned long width) 227 | { 228 | unsigned long i = 0, lastpx = 0; 229 | 230 | switch (perceptive) { 231 | case 0: 232 | for (; i < width; i ++) { 233 | if (PixelGetAlpha(pixels[i]) < 0.5) 234 | row[i] = color_transparent; 235 | else { 236 | row[i] = rgb2xterm( 237 | (unsigned long)(PixelGetRed(pixels[i]) * 255.0), 238 | (unsigned long)(PixelGetGreen(pixels[i]) * 255.0), 239 | (unsigned long)(PixelGetBlue(pixels[i]) * 255.0)); 240 | lastpx = i; 241 | } 242 | } 243 | break; 244 | case 1: 245 | for (; i < width; i ++) { 246 | if (PixelGetAlpha(pixels[i]) < 0.5) 247 | row[i] = color_transparent; 248 | else { 249 | row[i] = rgb2xterm_cie94( 250 | (unsigned long)(PixelGetRed(pixels[i]) * 255.0), 251 | (unsigned long)(PixelGetGreen(pixels[i]) * 255.0), 252 | (unsigned long)(PixelGetBlue(pixels[i]) * 255.0)); 253 | lastpx = i; 254 | } 255 | } 256 | break; 257 | case 2: 258 | for (; i < width; i ++) { 259 | if (PixelGetAlpha(pixels[i]) < 0.5) 260 | row[i] = color_transparent; 261 | else { 262 | row[i] = rgb2xterm_yiq( 263 | (unsigned long)(PixelGetRed(pixels[i]) * 255.0), 264 | (unsigned long)(PixelGetGreen(pixels[i]) * 255.0), 265 | (unsigned long)(PixelGetBlue(pixels[i]) * 255.0)); 266 | lastpx = i; 267 | } 268 | } 269 | break; 270 | } 271 | 272 | return lastpx + 1; 273 | } 274 | 275 | void xtermfit(MagickWand* wand) 276 | { 277 | struct winsize w; 278 | ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 279 | 280 | double wi = (double)MagickGetImageWidth(wand); 281 | double hi = (double)MagickGetImageHeight(wand); 282 | double ri = wi / hi; 283 | 284 | double ws = (double)w.ws_col; 285 | double hs = (double)w.ws_row * 2; 286 | double rs = ws / hs; 287 | 288 | int scaled_width = (int)floor(rs > ri ? wi * hs / hi : ws); 289 | int scaled_height = (int)floor(rs > ri ? hs : hi * ws / wi); 290 | 291 | MagickResizeImage(wand, scaled_width, scaled_height, LanczosFilter, 1); 292 | } 293 | 294 | void usage(int ret, const char* binname) 295 | { 296 | fprintf(ret ? stderr: stdout, 297 | "\ 298 | Usage: %s [ options ] [ infile ] [ outfile ]\n\n\ 299 | Convert bitmap images to 256 color block elements suitable for display in xterm\n\ 300 | and similar terminal emulators.\n\n\ 301 | Options:\n\ 302 | -h, --help display this message\n" 303 | #ifndef NO_CURSES 304 | "\ 305 | -i, --terminfo use terminfo to set the colors of each block\n\ 306 | " 307 | #endif 308 | "\ 309 | -m, --margin [width] add a margin to the left of the image\n\ 310 | -b, --bw display image in black/white mode\n\ 311 | -p, --perceptive use the CIE94 color difference formula for color\n\ 312 | conversion instead of simple RGB linear distance\n\ 313 | -w, --chroma-weight [mult] weighting for chroma in --perceptive and --yiq\n\ 314 | modes (default: 1)\n\ 315 | -y, --yiq use linear distance in the YIQ color space\n\ 316 | instead of RGB for color conversion\n\ 317 | \n\ 318 | If the output file name is omitted the image is written to stdout. If both the\n\ 319 | input file name and the output file name are missing, img2xterm will act as a\n\ 320 | filter.\n\ 321 | \n\ 322 | Examples:\n\ 323 | img2xterm -yw 2 image.png display a bitmap image on the terminal using the\n\ 324 | YIQ color space for conversion with weighted\n\ 325 | chroma\n\ 326 | img2xterm banner.png motd save a bitmap image as a text file to display\n\ 327 | later\n\ 328 | " 329 | , binname); 330 | exit(ret); 331 | } 332 | 333 | const char* basename2(const char* string) 334 | { 335 | const char* ret = string; 336 | for (; *string; string++) 337 | #if defined(WIN32) || defined(_WIN32) 338 | if (*string == '/' || *string == '\\') 339 | #endif 340 | if (*string == '/') 341 | ret = string + 1; 342 | return ret; 343 | } 344 | 345 | int main(int argc, char** argv) 346 | { 347 | const char stdin_str[] = "-", * infile = stdin_str, * outfile_str = NULL, * binname = *argv; 348 | char c; 349 | FILE* outfile = stdout; 350 | 351 | size_t width1, width2; 352 | unsigned long i, * row1, * row2, color1, color2, lastpx1, lastpx2, margin = 0; 353 | 354 | int bw = 0; 355 | 356 | MagickWand* science; 357 | PixelIterator* iterator; 358 | PixelWand** pixels; 359 | 360 | while (*++argv) 361 | if (**argv == '-') { 362 | while ((c = *++*argv)) 363 | switch (c) { 364 | case '-': 365 | if (!strcmp("help", ++*argv)) 366 | usage(0, binname); 367 | else if (!strcmp("perceptive", *argv)) 368 | perceptive = 1; 369 | else if (!strcmp("margin", *argv)) { 370 | if (!*++argv || !sscanf(*argv, "%lu", &margin)) 371 | usage(1, binname); 372 | } 373 | #ifndef NO_CURSES 374 | else if (!strcmp("terminfo", *argv)) 375 | use_terminfo = 1; 376 | #endif 377 | else if (!strcmp("chroma-weight", *argv)) { 378 | if (!*++argv || !sscanf(*argv, "%lf", &chroma_weight)) 379 | usage(1, binname); 380 | } else if (!strcmp("yiq", *argv)) 381 | perceptive = 2; 382 | else if (!strcmp("bw", *argv)) 383 | bw = 1; 384 | else { 385 | fprintf(stderr, "%s: unrecognised long option --%s\n", binname, *argv); 386 | usage(1, binname); 387 | } 388 | goto nextarg; 389 | case 'h': 390 | usage(0, binname); 391 | break; 392 | #ifndef NO_CURSES 393 | case 'i': 394 | use_terminfo = 1; 395 | break; 396 | #endif 397 | case 'm': 398 | if (*++*argv || !*++argv || !sscanf(*argv, "%lu", &margin)) 399 | usage(1, binname); 400 | goto nextarg; 401 | case 'p': 402 | perceptive = 1; 403 | break; 404 | case 'w': 405 | if (*++*argv || !*++argv || !sscanf(*argv, "%lf", &chroma_weight)) 406 | usage(1, binname); 407 | goto nextarg; 408 | case 'y': 409 | perceptive = 2; 410 | break; 411 | case 'b': 412 | bw = 1; 413 | break; 414 | default: 415 | fprintf(stderr, "%s: unrecognised option -%c", binname, *--*argv); 416 | usage(1, binname); 417 | } 418 | nextarg: 419 | continue; 420 | } else if (infile == stdin_str) 421 | infile = *argv; 422 | else if (!outfile_str) 423 | outfile_str = *argv; 424 | else 425 | usage(1, binname); 426 | 427 | #ifndef NO_CURSES 428 | if (use_terminfo) { 429 | if (setupterm(NULL, fileno(stdout), NULL)) 430 | return 5; 431 | if (((ti_op = tigetstr("op")) == (void*)-1 && 432 | (ti_op = tigetstr("sgr0")) == (void*)-1) || 433 | (ti_setb = tigetstr("setb")) == (void*)-1 || 434 | (ti_setf = tigetstr("setf")) == (void*)-1 || 435 | !tparm(ti_setb, 255) || 436 | !tparm(ti_setf, 255)) { 437 | fprintf(stderr, 438 | "%s: terminal doesn't support required features\n", binname); 439 | return 5; 440 | } 441 | } 442 | #endif 443 | 444 | MagickWandGenesis(); 445 | atexit(MagickWandTerminus); 446 | science = NewMagickWand(); 447 | 448 | if (!MagickReadImage(science, infile)) { 449 | DestroyMagickWand(science); 450 | fprintf(stderr, "%s: couldn't open input file %s\n", binname, infile == stdin_str ? "" : infile); 451 | return 3; 452 | } 453 | 454 | if (bw) { 455 | MagickTransformImageColorspace(science, GRAYColorspace); 456 | } 457 | 458 | xtermfit(science); 459 | 460 | if (!(iterator = NewPixelIterator(science))) { 461 | DestroyMagickWand(science); 462 | fprintf(stderr, "%s: out of memory\n", binname); 463 | return 4; 464 | } 465 | 466 | if (outfile_str && !(outfile = fopen(outfile_str, "w"))) { 467 | fprintf(stderr, "%s: couldn't open output file %s\n", binname, outfile_str); 468 | return 2; 469 | } 470 | 471 | if (perceptive) { 472 | unsigned char rgb[3]; 473 | double l, a, b; 474 | 475 | labtable = malloc(256 * 3 * sizeof(double)); 476 | for (i = 16; i < 256; i ++) { 477 | xterm2rgb(i, rgb); 478 | if (perceptive == 1) 479 | srgb2lab(rgb[0], rgb[1], rgb[2], &l, &a, &b); 480 | else 481 | srgb2yiq(rgb[0], rgb[1], rgb[2], &l, &a, &b); 482 | labtable[i * 3] = l; 483 | labtable[i * 3 + 1] = a; 484 | labtable[i * 3 + 2] = b; 485 | } 486 | } else { 487 | colortable = malloc(256 * 3 * sizeof(unsigned char)); 488 | for (i = 16; i < 256; i ++) 489 | xterm2rgb(i, colortable + i * 3); 490 | } 491 | 492 | pixels = PixelGetNextIteratorRow(iterator, &width1); 493 | while (pixels) { 494 | row1 = malloc(width1 * sizeof(unsigned long)); 495 | lastpx1 = fillrow(pixels, row1, width1); 496 | 497 | if ((pixels = PixelGetNextIteratorRow(iterator, &width2))) { 498 | row2 = malloc(width2 * sizeof(unsigned long)); 499 | lastpx2 = fillrow(pixels, row2, width2); 500 | if (lastpx2 > lastpx1) 501 | lastpx1 = lastpx2; 502 | } else 503 | row2 = NULL; 504 | 505 | for (i = 0; i < margin; i ++) 506 | fputc(' ', outfile); 507 | 508 | for (i = 0; i < lastpx1; i ++) { 509 | color1 = i < width1 ? row1[i] : color_transparent; 510 | color2 = i < width2 ? row2 ? row2[i] : color_transparent : color_transparent; 511 | bifurcate(outfile, color1, color2); 512 | } 513 | 514 | free(row1); 515 | if (row2) 516 | free(row2); 517 | 518 | if ((pixels = PixelGetNextIteratorRow(iterator, &width1))) 519 | #ifndef NO_CURSES 520 | if (use_terminfo) { 521 | fprintf(outfile, "%s\n", ti_op); 522 | oldbg = color_transparent; 523 | oldfg = color_undef; 524 | } else 525 | #endif 526 | if (oldbg != color_transparent) { 527 | fputs("\e[49m\n", outfile); 528 | oldbg = color_transparent; 529 | } else 530 | fputc('\n', outfile); 531 | #ifndef NO_CURSES 532 | else if (use_terminfo) 533 | fprintf(outfile, "%s\n", ti_op); 534 | #endif 535 | else if (oldbg == color_transparent) 536 | fputs("\e[39m\n", outfile); 537 | else 538 | fputs("\e[39;49m\n", outfile); 539 | } 540 | 541 | DestroyPixelIterator(iterator); 542 | DestroyMagickWand(science); 543 | free(colortable); 544 | if (outfile != stdout) 545 | fclose(outfile); 546 | 547 | return 0; 548 | } 549 | --------------------------------------------------------------------------------