static int hls_to_rgb(int hue, int lum, int sat) { int R, G, B; int Magic1, Magic2; const int RGBMAX = 255; const int HLSMAX = 100; if (sat == 0) { R = G = B = (lum * RGBMAX) / HLSMAX; } else { if (lum <= (HLSMAX / 2)) { Magic2 = (lum * (HLSMAX + sat) + (HLSMAX / 2)) / HLSMAX; } else { Magic2 = lum + sat - ((lum * sat) + (HLSMAX / 2)) / HLSMAX; } Magic1 = 2 * lum - Magic2; R = (hue_to_rgb(Magic1, Magic2, hue + (HLSMAX / 3)) * RGBMAX + (HLSMAX / 2)) / HLSMAX; G = (hue_to_rgb(Magic1, Magic2, hue) * RGBMAX + (HLSMAX / 2)) / HLSMAX; B = (hue_to_rgb(Magic1, Magic2, hue - (HLSMAX / 3)) * RGBMAX + (HLSMAX/2)) / HLSMAX; } return SIXEL_RGB(R, G, B); }
/* convert sixel data into indexed pixel bytes and palette data */ MagickBooleanType sixel_decode(unsigned char /* in */ *p, /* sixel bytes */ unsigned char /* out */ **pixels, /* decoded pixels */ size_t /* out */ *pwidth, /* image width */ size_t /* out */ *pheight, /* image height */ unsigned char /* out */ **palette, /* ARGB palette */ size_t /* out */ *ncolors /* palette size (<= 256) */) { int n, i, r, g, b, sixel_vertical_mask, c; int posision_x, posision_y; int max_x, max_y; int attributed_pan, attributed_pad; int attributed_ph, attributed_pv; int repeat_count, color_index, max_color_index = 2, background_color_index; int param[10]; int sixel_palet[SIXEL_PALETTE_MAX]; unsigned char *imbuf, *dmbuf; int imsx, imsy; int dmsx, dmsy; int y; posision_x = posision_y = 0; max_x = max_y = 0; attributed_pan = 2; attributed_pad = 1; attributed_ph = attributed_pv = 0; repeat_count = 1; color_index = 0; background_color_index = 0; imsx = 2048; imsy = 2048; imbuf = (unsigned char *) AcquireQuantumMemory(imsx * imsy,1); if (imbuf == NULL) { return(MagickFalse); } for (n = 0; n < 16; n++) { sixel_palet[n] = sixel_default_color_table[n]; } /* colors 16-231 are a 6x6x6 color cube */ for (r = 0; r < 6; r++) { for (g = 0; g < 6; g++) { for (b = 0; b < 6; b++) { sixel_palet[n++] = SIXEL_RGB(r * 51, g * 51, b * 51); } } } /* colors 232-255 are a grayscale ramp, intentionally leaving out */ for (i = 0; i < 24; i++) { sixel_palet[n++] = SIXEL_RGB(i * 11, i * 11, i * 11); } for (; n < SIXEL_PALETTE_MAX; n++) { sixel_palet[n] = SIXEL_RGB(255, 255, 255); } (void) ResetMagickMemory(imbuf, background_color_index, imsx * imsy); while (*p != '\0') { if ((p[0] == '\033' && p[1] == 'P') || *p == 0x90) { if (*p == '\033') { p++; } p = get_params(++p, param, &n); if (*p == 'q') { p++; if (n > 0) { /* Pn1 */ switch(param[0]) { case 0: case 1: attributed_pad = 2; break; case 2: attributed_pad = 5; break; case 3: attributed_pad = 4; break; case 4: attributed_pad = 4; break; case 5: attributed_pad = 3; break; case 6: attributed_pad = 3; break; case 7: attributed_pad = 2; break; case 8: attributed_pad = 2; break; case 9: attributed_pad = 1; break; } } if (n > 2) { /* Pn3 */ if (param[2] == 0) { param[2] = 10; } attributed_pan = attributed_pan * param[2] / 10; attributed_pad = attributed_pad * param[2] / 10; if (attributed_pan <= 0) attributed_pan = 1; if (attributed_pad <= 0) attributed_pad = 1; } } } else if ((p[0] == '\033' && p[1] == '\\') || *p == 0x9C) { break; } else if (*p == '"') { /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */ p = get_params(++p, param, &n); if (n > 0) attributed_pad = param[0]; if (n > 1) attributed_pan = param[1]; if (n > 2 && param[2] > 0) attributed_ph = param[2]; if (n > 3 && param[3] > 0) attributed_pv = param[3]; if (attributed_pan <= 0) attributed_pan = 1; if (attributed_pad <= 0) attributed_pad = 1; if (imsx < attributed_ph || imsy < attributed_pv) { dmsx = imsx > attributed_ph ? imsx : attributed_ph; dmsy = imsy > attributed_pv ? imsy : attributed_pv; dmbuf = (unsigned char *) AcquireQuantumMemory(dmsx * dmsy,1); if (dmbuf == (unsigned char *) NULL) { imbuf = (unsigned char *) RelinquishMagickMemory(imbuf); return (MagickFalse); } (void) ResetMagickMemory(dmbuf, background_color_index, dmsx * dmsy); for (y = 0; y < imsy; ++y) { (void) CopyMagickMemory(dmbuf + dmsx * y, imbuf + imsx * y, imsx); } imbuf = (unsigned char *) RelinquishMagickMemory(imbuf); imsx = dmsx; imsy = dmsy; imbuf = dmbuf; } } else if (*p == '!') { /* DECGRI Graphics Repeat Introducer ! Pn Ch */ p = get_params(++p, param, &n); if (n > 0) { repeat_count = param[0]; } } else if (*p == '#') { /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */ p = get_params(++p, param, &n); if (n > 0) { if ((color_index = param[0]) < 0) { color_index = 0; } else if (color_index >= SIXEL_PALETTE_MAX) { color_index = SIXEL_PALETTE_MAX - 1; } } if (n > 4) { if (param[1] == 1) { /* HLS */ if (param[2] > 360) param[2] = 360; if (param[3] > 100) param[3] = 100; if (param[4] > 100) param[4] = 100; sixel_palet[color_index] = hls_to_rgb(param[2] * 100 / 360, param[3], param[4]); } else if (param[1] == 2) { /* RGB */ if (param[2] > 100) param[2] = 100; if (param[3] > 100) param[3] = 100; if (param[4] > 100) param[4] = 100; sixel_palet[color_index] = SIXEL_XRGB(param[2], param[3], param[4]); } } } else if (*p == '$') { /* DECGCR Graphics Carriage Return */ p++; posision_x = 0; repeat_count = 1; } else if (*p == '-') { /* DECGNL Graphics Next Line */ p++; posision_x = 0; posision_y += 6; repeat_count = 1; } else if (*p >= '?' && *p <= '\177') { if (imsx < (posision_x + repeat_count) || imsy < (posision_y + 6)) { int nx = imsx * 2; int ny = imsy * 2; while (nx < (posision_x + repeat_count) || ny < (posision_y + 6)) { nx *= 2; ny *= 2; } dmsx = nx; dmsy = ny; dmbuf = (unsigned char *) AcquireQuantumMemory(dmsx * dmsy,1); if (dmbuf == (unsigned char *) NULL) { imbuf = (unsigned char *) RelinquishMagickMemory(imbuf); return (MagickFalse); } (void) ResetMagickMemory(dmbuf, background_color_index, dmsx * dmsy); for (y = 0; y < imsy; ++y) { (void) CopyMagickMemory(dmbuf + dmsx * y, imbuf + imsx * y, imsx); } imbuf = (unsigned char *) RelinquishMagickMemory(imbuf); imsx = dmsx; imsy = dmsy; imbuf = dmbuf; } if (color_index > max_color_index) { max_color_index = color_index; } if ((b = *(p++) - '?') == 0) { posision_x += repeat_count; } else { sixel_vertical_mask = 0x01; if (repeat_count <= 1) { for (i = 0; i < 6; i++) { if ((b & sixel_vertical_mask) != 0) { imbuf[imsx * (posision_y + i) + posision_x] = color_index; if (max_x < posision_x) { max_x = posision_x; } if (max_y < (posision_y + i)) { max_y = posision_y + i; } } sixel_vertical_mask <<= 1; } posision_x += 1; } else { /* repeat_count > 1 */ for (i = 0; i < 6; i++) { if ((b & sixel_vertical_mask) != 0) { c = sixel_vertical_mask << 1; for (n = 1; (i + n) < 6; n++) { if ((b & c) == 0) { break; } c <<= 1; } for (y = posision_y + i; y < posision_y + i + n; ++y) { (void) ResetMagickMemory(imbuf + imsx * y + posision_x, color_index, repeat_count); } if (max_x < (posision_x + repeat_count - 1)) { max_x = posision_x + repeat_count - 1; } if (max_y < (posision_y + i + n - 1)) { max_y = posision_y + i + n - 1; } i += (n - 1); sixel_vertical_mask <<= (n - 1); } sixel_vertical_mask <<= 1; } posision_x += repeat_count; } } repeat_count = 1; } else { p++; } } if (++max_x < attributed_ph) { max_x = attributed_ph; } if (++max_y < attributed_pv) { max_y = attributed_pv; } if (imsx > max_x || imsy > max_y) { dmsx = max_x; dmsy = max_y; if ((dmbuf = (unsigned char *) AcquireQuantumMemory(dmsx * dmsy,1)) == NULL) { imbuf = (unsigned char *) RelinquishMagickMemory(imbuf); return (MagickFalse); } for (y = 0; y < dmsy; ++y) { (void) CopyMagickMemory(dmbuf + dmsx * y, imbuf + imsx * y, dmsx); } imbuf = (unsigned char *) RelinquishMagickMemory(imbuf); imsx = dmsx; imsy = dmsy; imbuf = dmbuf; } *pixels = imbuf; *pwidth = imsx; *pheight = imsy; *ncolors = max_color_index + 1; *palette = (unsigned char *) AcquireQuantumMemory(*ncolors,4); for (n = 0; n < (ssize_t) *ncolors; ++n) { (*palette)[n * 4 + 0] = sixel_palet[n] >> 16 & 0xff; (*palette)[n * 4 + 1] = sixel_palet[n] >> 8 & 0xff; (*palette)[n * 4 + 2] = sixel_palet[n] & 0xff; (*palette)[n * 4 + 3] = 0xff; } return(MagickTrue); }
int hls_to_rgb(int hue, int lum, int sat) { double hs = (hue + 240) % 360; double hv = hs / 360.0; double lv = lum / 100.0; double sv = sat / 100.0; double c, x, m, c2; double r1, g1, b1; int r, g, b; int hpi; if (sat == 0) { r = g = b = lum * 255 / 100; return SIXEL_RGB(r, g, b); } if ((c2 = ((2.0 * lv) - 1.0)) < 0.0) { c2 = -c2; } c = (1.0 - c2) * sv; hpi = (int) (hv * 6.0); x = (hpi & 1) ? c : 0.0; m = lv - 0.5 * c; switch (hpi) { case 0: r1 = c; g1 = x; b1 = 0.0; break; case 1: r1 = x; g1 = c; b1 = 0.0; break; case 2: r1 = 0.0; g1 = c; b1 = x; break; case 3: r1 = 0.0; g1 = x; b1 = c; break; case 4: r1 = x; g1 = 0.0; b1 = c; break; case 5: r1 = c; g1 = 0.0; b1 = x; break; default: return SIXEL_RGB(255, 255, 255); } r = (int) ((r1 + m) * 100.0 + 0.5); g = (int) ((g1 + m) * 100.0 + 0.5); b = (int) ((b1 + m) * 100.0 + 0.5); if (r < 0) { r = 0; } else if (r > 100) { r = 100; } if (g < 0) { g = 0; } else if (g > 100) { g = 100; } if (b < 0) { b = 0; } else if (b > 100) { b = 100; } return SIXEL_RGB(r * 255 / 100, g * 255 / 100, b * 255 / 100); }