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