sixel.c (16625B)
1 // sixel.c (part of mintty) 2 // originally written by kmiya@cluti (https://github.com/saitoha/sixel/blob/master/fromsixel.c) 3 // Licensed under the terms of the GNU General Public License v3 or later. 4 5 #include <stdlib.h> 6 #include <string.h> /* memcpy */ 7 8 #include "st.h" 9 #include "win.h" 10 #include "sixel.h" 11 #include "sixel_hls.h" 12 13 #define SIXEL_RGB(r, g, b) ((255 << 24) + ((r) << 16) + ((g) << 8) + (b)) 14 #define SIXEL_PALVAL(n,a,m) (((n) * (a) + ((m) / 2)) / (m)) 15 #define SIXEL_XRGB(r,g,b) SIXEL_RGB(SIXEL_PALVAL(r, 255, 100), SIXEL_PALVAL(g, 255, 100), SIXEL_PALVAL(b, 255, 100)) 16 17 static sixel_color_t const sixel_default_color_table[] = { 18 SIXEL_XRGB( 0, 0, 0), /* 0 Black */ 19 SIXEL_XRGB(20, 20, 80), /* 1 Blue */ 20 SIXEL_XRGB(80, 13, 13), /* 2 Red */ 21 SIXEL_XRGB(20, 80, 20), /* 3 Green */ 22 SIXEL_XRGB(80, 20, 80), /* 4 Magenta */ 23 SIXEL_XRGB(20, 80, 80), /* 5 Cyan */ 24 SIXEL_XRGB(80, 80, 20), /* 6 Yellow */ 25 SIXEL_XRGB(53, 53, 53), /* 7 Gray 50% */ 26 SIXEL_XRGB(26, 26, 26), /* 8 Gray 25% */ 27 SIXEL_XRGB(33, 33, 60), /* 9 Blue* */ 28 SIXEL_XRGB(60, 26, 26), /* 10 Red* */ 29 SIXEL_XRGB(33, 60, 33), /* 11 Green* */ 30 SIXEL_XRGB(60, 33, 60), /* 12 Magenta* */ 31 SIXEL_XRGB(33, 60, 60), /* 13 Cyan* */ 32 SIXEL_XRGB(60, 60, 33), /* 14 Yellow* */ 33 SIXEL_XRGB(80, 80, 80), /* 15 Gray 75% */ 34 }; 35 36 void 37 scroll_images(int n) { 38 ImageList *im, *next; 39 #if SCROLLBACK_PATCH || REFLOW_PATCH 40 int top = tisaltscr() ? 0 : term.scr - HISTSIZE; 41 #else 42 int top = 0; 43 #endif // SCROLLBACK_PATCH 44 45 for (im = term.images; im; im = next) { 46 next = im->next; 47 im->y += n; 48 49 /* check if the current sixel has exceeded the maximum 50 * draw distance, and should therefore be deleted */ 51 if (im->y < top) { 52 //fprintf(stderr, "im@0x%08x exceeded maximum distance\n"); 53 delete_image(im); 54 } 55 } 56 } 57 58 void 59 delete_image(ImageList *im) 60 { 61 if (im->prev) 62 im->prev->next = im->next; 63 else 64 term.images = im->next; 65 if (im->next) 66 im->next->prev = im->prev; 67 if (im->pixmap) 68 XFreePixmap(xw.dpy, (Drawable)im->pixmap); 69 if (im->clipmask) 70 XFreePixmap(xw.dpy, (Drawable)im->clipmask); 71 free(im->pixels); 72 free(im); 73 } 74 75 static int 76 set_default_color(sixel_image_t *image) 77 { 78 int i; 79 int n; 80 int r; 81 int g; 82 int b; 83 84 /* palette initialization */ 85 for (n = 1; n < 17; n++) { 86 image->palette[n] = sixel_default_color_table[n - 1]; 87 } 88 89 /* colors 17-232 are a 6x6x6 color cube */ 90 for (r = 0; r < 6; r++) { 91 for (g = 0; g < 6; g++) { 92 for (b = 0; b < 6; b++) { 93 image->palette[n++] = SIXEL_RGB(r * 51, g * 51, b * 51); 94 } 95 } 96 } 97 98 /* colors 233-256 are a grayscale ramp, intentionally leaving out */ 99 for (i = 0; i < 24; i++) { 100 image->palette[n++] = SIXEL_RGB(i * 11, i * 11, i * 11); 101 } 102 103 /* sixels rarely use more than 256 colors and if they do, they use a custom 104 * palette, so we don't need to initialize these colors */ 105 /* 106 for (; n < DECSIXEL_PALETTE_MAX; n++) { 107 image->palette[n] = SIXEL_RGB(255, 255, 255); 108 } 109 */ 110 111 return (0); 112 } 113 114 static int 115 sixel_image_init( 116 sixel_image_t *image, 117 int width, 118 int height, 119 int fgcolor, 120 int bgcolor, 121 int use_private_register) 122 { 123 int status = (-1); 124 size_t size; 125 126 size = (size_t)(width * height) * sizeof(sixel_color_no_t); 127 image->width = width; 128 image->height = height; 129 image->data = (sixel_color_no_t *)malloc(size); 130 image->ncolors = 2; 131 image->use_private_register = use_private_register; 132 133 if (image->data == NULL) { 134 status = (-1); 135 goto end; 136 } 137 memset(image->data, 0, size); 138 139 image->palette[0] = bgcolor; 140 141 if (image->use_private_register) 142 image->palette[1] = fgcolor; 143 144 image->palette_modified = 0; 145 146 status = (0); 147 148 end: 149 return status; 150 } 151 152 153 static int 154 image_buffer_resize( 155 sixel_image_t *image, 156 int width, 157 int height) 158 { 159 int status = (-1); 160 size_t size; 161 sixel_color_no_t *alt_buffer; 162 int n; 163 int min_height; 164 165 size = (size_t)(width * height) * sizeof(sixel_color_no_t); 166 alt_buffer = (sixel_color_no_t *)malloc(size); 167 if (alt_buffer == NULL) { 168 /* free source image */ 169 free(image->data); 170 image->data = NULL; 171 status = (-1); 172 goto end; 173 } 174 175 min_height = height > image->height ? image->height: height; 176 if (width > image->width) { /* if width is extended */ 177 for (n = 0; n < min_height; ++n) { 178 /* copy from source image */ 179 memcpy(alt_buffer + width * n, 180 image->data + image->width * n, 181 (size_t)image->width * sizeof(sixel_color_no_t)); 182 /* fill extended area with background color */ 183 memset(alt_buffer + width * n + image->width, 184 0, 185 (size_t)(width - image->width) * sizeof(sixel_color_no_t)); 186 } 187 } else { 188 for (n = 0; n < min_height; ++n) { 189 /* copy from source image */ 190 memcpy(alt_buffer + width * n, 191 image->data + image->width * n, 192 (size_t)width * sizeof(sixel_color_no_t)); 193 } 194 } 195 196 if (height > image->height) { /* if height is extended */ 197 /* fill extended area with background color */ 198 memset(alt_buffer + width * image->height, 199 0, 200 (size_t)(width * (height - image->height)) * sizeof(sixel_color_no_t)); 201 } 202 203 /* free source image */ 204 free(image->data); 205 206 image->data = alt_buffer; 207 image->width = width; 208 image->height = height; 209 210 status = (0); 211 212 end: 213 return status; 214 } 215 216 static void 217 sixel_image_deinit(sixel_image_t *image) 218 { 219 if (image->data) 220 free(image->data); 221 image->data = NULL; 222 } 223 224 int 225 sixel_parser_init(sixel_state_t *st, 226 int transparent, 227 sixel_color_t fgcolor, sixel_color_t bgcolor, 228 unsigned char use_private_register, 229 int cell_width, int cell_height) 230 { 231 int status = (-1); 232 233 st->state = PS_DECSIXEL; 234 st->pos_x = 0; 235 st->pos_y = 0; 236 st->max_x = 0; 237 st->max_y = 0; 238 st->attributed_pan = 2; 239 st->attributed_pad = 1; 240 st->attributed_ph = 0; 241 st->attributed_pv = 0; 242 st->transparent = transparent; 243 st->repeat_count = 1; 244 st->color_index = 16; 245 st->grid_width = cell_width; 246 st->grid_height = cell_height; 247 st->nparams = 0; 248 st->param = 0; 249 250 /* buffer initialization */ 251 status = sixel_image_init(&st->image, 1, 1, fgcolor, transparent ? 0 : bgcolor, use_private_register); 252 253 return status; 254 } 255 256 int 257 sixel_parser_set_default_color(sixel_state_t *st) 258 { 259 return set_default_color(&st->image); 260 } 261 262 int 263 sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, int cw, int ch) 264 { 265 sixel_image_t *image = &st->image; 266 int x, y; 267 sixel_color_no_t *src; 268 sixel_color_t *dst, color; 269 int w, h; 270 int i, j, cols, numimages; 271 char trans; 272 ImageList *im, *next, *tail; 273 274 if (!image->data) 275 return -1; 276 277 if (++st->max_x < st->attributed_ph) 278 st->max_x = st->attributed_ph; 279 280 if (++st->max_y < st->attributed_pv) 281 st->max_y = st->attributed_pv; 282 283 if (image->use_private_register && image->ncolors > 2 && !image->palette_modified) { 284 if (set_default_color(image) < 0) 285 return -1; 286 } 287 288 w = MIN(st->max_x, image->width); 289 h = MIN(st->max_y, image->height); 290 291 if ((numimages = (h + ch-1) / ch) <= 0) 292 return -1; 293 294 cols = (w + cw-1) / cw; 295 296 *newimages = NULL, tail = NULL; 297 for (y = 0, i = 0; i < numimages; i++) { 298 if ((im = malloc(sizeof(ImageList)))) { 299 if (!tail) { 300 *newimages = tail = im; 301 im->prev = im->next = NULL; 302 } else { 303 tail->next = im; 304 im->prev = tail; 305 im->next = NULL; 306 tail = im; 307 } 308 im->x = cx; 309 im->y = cy + i; 310 im->cols = cols; 311 im->width = w; 312 im->height = MIN(h - ch * i, ch); 313 im->pixels = malloc(im->width * im->height * 4); 314 im->pixmap = NULL; 315 im->clipmask = NULL; 316 im->cw = cw; 317 im->ch = ch; 318 } 319 if (!im || !im->pixels) { 320 for (im = *newimages; im; im = next) { 321 next = im->next; 322 if (im->pixels) 323 free(im->pixels); 324 free(im); 325 } 326 *newimages = NULL; 327 return -1; 328 } 329 dst = (sixel_color_t *)im->pixels; 330 for (trans = 0, j = 0; j < im->height && y < h; j++, y++) { 331 src = st->image.data + image->width * y; 332 for (x = 0; x < w; x++) { 333 color = st->image.palette[*src++]; 334 trans |= (color == 0); 335 *dst++ = color; 336 } 337 } 338 im->transparent = (st->transparent && trans); 339 } 340 341 return numimages; 342 } 343 344 /* convert sixel data into indexed pixel bytes and palette data */ 345 int 346 sixel_parser_parse(sixel_state_t *st, const unsigned char *p, size_t len) 347 { 348 int n = 0; 349 int i; 350 int x; 351 int y; 352 int bits; 353 int sx; 354 int sy; 355 int c; 356 int pos; 357 int width; 358 const unsigned char *p0 = p, *p2 = p + len; 359 sixel_image_t *image = &st->image; 360 sixel_color_no_t *data, color_index; 361 362 if (!image->data) 363 st->state = PS_ERROR; 364 365 while (p < p2) { 366 switch (st->state) { 367 case PS_ESC: 368 goto end; 369 370 case PS_DECSIXEL: 371 switch (*p) { 372 case '\x1b': 373 st->state = PS_ESC; 374 break; 375 case '"': 376 st->param = 0; 377 st->nparams = 0; 378 st->state = PS_DECGRA; 379 p++; 380 break; 381 case '!': 382 st->param = 0; 383 st->nparams = 0; 384 st->state = PS_DECGRI; 385 p++; 386 break; 387 case '#': 388 st->param = 0; 389 st->nparams = 0; 390 st->state = PS_DECGCI; 391 p++; 392 break; 393 case '$': 394 /* DECGCR Graphics Carriage Return */ 395 st->pos_x = 0; 396 p++; 397 break; 398 case '-': 399 /* DECGNL Graphics Next Line */ 400 st->pos_x = 0; 401 if (st->pos_y < DECSIXEL_HEIGHT_MAX - 5 - 6) 402 st->pos_y += 6; 403 else 404 st->pos_y = DECSIXEL_HEIGHT_MAX + 1; 405 p++; 406 break; 407 default: 408 if (*p >= '?' && *p <= '~') { /* sixel characters */ 409 if ((image->width < (st->pos_x + st->repeat_count) || image->height < (st->pos_y + 6)) 410 && image->width < DECSIXEL_WIDTH_MAX && image->height < DECSIXEL_HEIGHT_MAX) { 411 sx = image->width * 2; 412 sy = image->height * 2; 413 while (sx < (st->pos_x + st->repeat_count) || sy < (st->pos_y + 6)) { 414 sx *= 2; 415 sy *= 2; 416 } 417 418 sx = MIN(sx, DECSIXEL_WIDTH_MAX); 419 sy = MIN(sy, DECSIXEL_HEIGHT_MAX); 420 421 if (image_buffer_resize(image, sx, sy) < 0) { 422 perror("sixel_parser_parse() failed"); 423 st->state = PS_ERROR; 424 p++; 425 break; 426 } 427 } 428 429 if (st->color_index > image->ncolors) 430 image->ncolors = st->color_index; 431 432 if (st->pos_x + st->repeat_count > image->width) 433 st->repeat_count = image->width - st->pos_x; 434 435 if (st->repeat_count > 0 && st->pos_y + 5 < image->height) { 436 bits = *p - '?'; 437 if (bits != 0) { 438 data = image->data + image->width * st->pos_y + st->pos_x; 439 width = image->width; 440 color_index = st->color_index; 441 if (st->repeat_count <= 1) { 442 if (bits & 0x01) 443 *data = color_index, n = 0; 444 data += width; 445 if (bits & 0x02) 446 *data = color_index, n = 1; 447 data += width; 448 if (bits & 0x04) 449 *data = color_index, n = 2; 450 data += width; 451 if (bits & 0x08) 452 *data = color_index, n = 3; 453 data += width; 454 if (bits & 0x10) 455 *data = color_index, n = 4; 456 if (bits & 0x20) 457 data[width] = color_index, n = 5; 458 if (st->max_x < st->pos_x) 459 st->max_x = st->pos_x; 460 } else { 461 /* st->repeat_count > 1 */ 462 for (i = 0; bits; bits >>= 1, i++, data += width) { 463 if (bits & 1) { 464 data[0] = color_index; 465 data[1] = color_index; 466 for (x = 2; x < st->repeat_count; x++) 467 data[x] = color_index; 468 n = i; 469 } 470 } 471 if (st->max_x < (st->pos_x + st->repeat_count - 1)) 472 st->max_x = st->pos_x + st->repeat_count - 1; 473 } 474 if (st->max_y < (st->pos_y + n)) 475 st->max_y = st->pos_y + n; 476 } 477 } 478 if (st->repeat_count > 0) 479 st->pos_x += st->repeat_count; 480 st->repeat_count = 1; 481 } 482 p++; 483 break; 484 } 485 break; 486 487 case PS_DECGRA: 488 /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */ 489 switch (*p) { 490 case '\x1b': 491 st->state = PS_ESC; 492 break; 493 case '0': 494 case '1': 495 case '2': 496 case '3': 497 case '4': 498 case '5': 499 case '6': 500 case '7': 501 case '8': 502 case '9': 503 st->param = st->param * 10 + *p - '0'; 504 st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX); 505 p++; 506 break; 507 case ';': 508 if (st->nparams < DECSIXEL_PARAMS_MAX) 509 st->params[st->nparams++] = st->param; 510 st->param = 0; 511 p++; 512 break; 513 default: 514 if (st->nparams < DECSIXEL_PARAMS_MAX) 515 st->params[st->nparams++] = st->param; 516 if (st->nparams > 0) 517 st->attributed_pad = st->params[0]; 518 if (st->nparams > 1) 519 st->attributed_pan = st->params[1]; 520 if (st->nparams > 2 && st->params[2] > 0) 521 st->attributed_ph = st->params[2]; 522 if (st->nparams > 3 && st->params[3] > 0) 523 st->attributed_pv = st->params[3]; 524 525 if (st->attributed_pan <= 0) 526 st->attributed_pan = 1; 527 if (st->attributed_pad <= 0) 528 st->attributed_pad = 1; 529 530 if (image->width < st->attributed_ph || 531 image->height < st->attributed_pv) { 532 sx = MAX(image->width, st->attributed_ph); 533 sy = MAX(image->height, st->attributed_pv); 534 535 /* the height of the image buffer must be divisible by 6 536 * to avoid unnecessary resizing of the image buffer when 537 * parsing the last sixel line */ 538 sy = (sy + 5) / 6 * 6; 539 540 sx = MIN(sx, DECSIXEL_WIDTH_MAX); 541 sy = MIN(sy, DECSIXEL_HEIGHT_MAX); 542 543 if (image_buffer_resize(image, sx, sy) < 0) { 544 perror("sixel_parser_parse() failed"); 545 st->state = PS_ERROR; 546 break; 547 } 548 } 549 st->state = PS_DECSIXEL; 550 st->param = 0; 551 st->nparams = 0; 552 } 553 break; 554 555 case PS_DECGRI: 556 /* DECGRI Graphics Repeat Introducer ! Pn Ch */ 557 switch (*p) { 558 case '\x1b': 559 st->state = PS_ESC; 560 break; 561 case '0': 562 case '1': 563 case '2': 564 case '3': 565 case '4': 566 case '5': 567 case '6': 568 case '7': 569 case '8': 570 case '9': 571 st->param = st->param * 10 + *p - '0'; 572 st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX); 573 p++; 574 break; 575 default: 576 st->repeat_count = MAX(st->param, 1); 577 st->state = PS_DECSIXEL; 578 st->param = 0; 579 st->nparams = 0; 580 break; 581 } 582 break; 583 584 case PS_DECGCI: 585 /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */ 586 switch (*p) { 587 case '\x1b': 588 st->state = PS_ESC; 589 break; 590 case '0': 591 case '1': 592 case '2': 593 case '3': 594 case '4': 595 case '5': 596 case '6': 597 case '7': 598 case '8': 599 case '9': 600 st->param = st->param * 10 + *p - '0'; 601 st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX); 602 p++; 603 break; 604 case ';': 605 if (st->nparams < DECSIXEL_PARAMS_MAX) 606 st->params[st->nparams++] = st->param; 607 st->param = 0; 608 p++; 609 break; 610 default: 611 st->state = PS_DECSIXEL; 612 if (st->nparams < DECSIXEL_PARAMS_MAX) 613 st->params[st->nparams++] = st->param; 614 st->param = 0; 615 616 if (st->nparams > 0) { 617 st->color_index = st->params[0]; 618 if (st->color_index < 0) 619 st->color_index = 0; 620 else if (st->color_index >= DECSIXEL_PALETTE_MAX) 621 st->color_index = DECSIXEL_PALETTE_MAX - 1; 622 st->color_index++; /* offset by 1 (background) */ 623 } 624 625 if (st->nparams > 4) { 626 st->image.palette_modified = 1; 627 if (st->params[1] == 1) { 628 /* HLS */ 629 st->params[2] = MIN(st->params[2], 360); 630 st->params[3] = MIN(st->params[3], 100); 631 st->params[4] = MIN(st->params[4], 100); 632 image->palette[st->color_index] 633 = hls_to_rgb(st->params[2], st->params[3], st->params[4]); 634 } else if (st->params[1] == 2) { 635 /* RGB */ 636 st->params[2] = MIN(st->params[2], 100); 637 st->params[3] = MIN(st->params[3], 100); 638 st->params[4] = MIN(st->params[4], 100); 639 image->palette[st->color_index] 640 = SIXEL_XRGB(st->params[2], st->params[3], st->params[4]); 641 } 642 } 643 break; 644 } 645 break; 646 647 case PS_ERROR: 648 if (*p == '\x1b') { 649 st->state = PS_ESC; 650 goto end; 651 } 652 p++; 653 break; 654 default: 655 break; 656 } 657 } 658 659 end: 660 return p - p0; 661 } 662 663 void 664 sixel_parser_deinit(sixel_state_t *st) 665 { 666 if (st) 667 sixel_image_deinit(&st->image); 668 } 669 670 Pixmap 671 sixel_create_clipmask(char *pixels, int width, int height) 672 { 673 char c, *clipdata, *dst; 674 int b, i, n, y, w; 675 int msb = (XBitmapBitOrder(xw.dpy) == MSBFirst); 676 sixel_color_t *src = (sixel_color_t *)pixels; 677 Pixmap clipmask; 678 679 clipdata = dst = malloc((width+7)/8 * height); 680 if (!clipdata) 681 return (Pixmap)None; 682 683 for (y = 0; y < height; y++) { 684 for (w = width; w > 0; w -= n) { 685 n = MIN(w, 8); 686 if (msb) { 687 for (b = 0x80, c = 0, i = 0; i < n; i++, b >>= 1) 688 c |= (*src++) ? b : 0; 689 } else { 690 for (b = 0x01, c = 0, i = 0; i < n; i++, b <<= 1) 691 c |= (*src++) ? b : 0; 692 } 693 *dst++ = c; 694 } 695 } 696 697 clipmask = XCreateBitmapFromData(xw.dpy, xw.win, clipdata, width, height); 698 free(clipdata); 699 return clipmask; 700 }