diff --git a/image-sixel.c b/image-sixel.c index 15d5c07c6..7b8bdd7ea 100644 --- a/image-sixel.c +++ b/image-sixel.c @@ -1033,10 +1033,10 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, const u_char *pixel; uint16_t *cache; int *current, *next, *tmp; - int red_error, green_error, blue_error; + int red_error, green_error, blue_error, alpha_error; u_int x, y, sx, sy, index, error_index; u_int sourcex0, sourcey0, sourcewidth, sourceheight; - u_int red, green, blue, colour, i, ncolours; + u_int red, green, blue, alpha, colour, i, ncolours; uint64_t destination_width, destination_height; uint64_t content_width, content_height, x0, x1, y0, y1; @@ -1078,7 +1078,7 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, for (x = 0; x < sx; x++) { pixel = sixel_from_image_pixel(&source, sourcex0, sourcey0, sourcewidth, sourceheight, sx, sy, x, y); - if (pixel[3] < 128) + if (pixel[3] == 0) continue; index = ((pixel[0] >> 3) << 10)| ((pixel[1] >> 3) << 5)|(pixel[2] >> 3); @@ -1112,46 +1112,55 @@ sixel_from_image(struct image *im, u_int ox, u_int oy, u_int cells_x, cache = xmalloc(SIXEL_HISTOGRAM_SIZE * sizeof *cache); memset(cache, 0xff, SIXEL_HISTOGRAM_SIZE * sizeof *cache); - current = xcalloc(((size_t)sx + 2) * 3, sizeof *current); - next = xcalloc(((size_t)sx + 2) * 3, sizeof *next); + current = xcalloc(((size_t)sx + 2) * 4, sizeof *current); + next = xcalloc(((size_t)sx + 2) * 4, sizeof *next); for (y = 0; y < sy; y++) { for (x = 0; x < sx; x++) { pixel = sixel_from_image_pixel(&source, sourcex0, sourcey0, sourcewidth, sourceheight, sx, sy, x, y); - if (pixel[3] < 128) - continue; - error_index = (x + 1) * 3; - red = sixel_clamp_colour((int)pixel[0] + - current[error_index] / 16); - green = sixel_clamp_colour((int)pixel[1] + - current[error_index + 1] / 16); - blue = sixel_clamp_colour((int)pixel[2] + - current[error_index + 2] / 16); - colour = sixel_nearest_colour(palette, ncolours, cache, - red, green, blue); - if (sixel_set_pixel(si, x, y, colour + 1) != 0) - goto fail; + error_index = (x + 1) * 4; + /* SIXEL pixels are binary, so dither alpha separately. */ + alpha = sixel_clamp_colour((int)pixel[3] + + current[error_index + 3] / 16); + alpha_error = (int)alpha; + if (alpha >= 128) { + alpha_error -= 255; + red = sixel_clamp_colour((int)pixel[0] + + current[error_index] / 16); + green = sixel_clamp_colour((int)pixel[1] + + current[error_index + 1] / 16); + blue = sixel_clamp_colour((int)pixel[2] + + current[error_index + 2] / 16); + colour = sixel_nearest_colour(palette, ncolours, cache, + red, green, blue); + if (sixel_set_pixel(si, x, y, colour + 1) != 0) + goto fail; - red_error = (int)red - palette[colour].red; - green_error = (int)green - palette[colour].green; - blue_error = (int)blue - palette[colour].blue; - current[error_index + 3] += red_error * 7; - current[error_index + 4] += green_error * 7; - current[error_index + 5] += blue_error * 7; - next[error_index - 3] += red_error * 3; - next[error_index - 2] += green_error * 3; - next[error_index - 1] += blue_error * 3; - next[error_index] += red_error * 5; - next[error_index + 1] += green_error * 5; - next[error_index + 2] += blue_error * 5; - next[error_index + 3] += red_error; - next[error_index + 4] += green_error; - next[error_index + 5] += blue_error; + red_error = (int)red - palette[colour].red; + green_error = (int)green - palette[colour].green; + blue_error = (int)blue - palette[colour].blue; + current[error_index + 4] += red_error * 7; + current[error_index + 5] += green_error * 7; + current[error_index + 6] += blue_error * 7; + next[error_index - 4] += red_error * 3; + next[error_index - 3] += green_error * 3; + next[error_index - 2] += blue_error * 3; + next[error_index] += red_error * 5; + next[error_index + 1] += green_error * 5; + next[error_index + 2] += blue_error * 5; + next[error_index + 4] += red_error; + next[error_index + 5] += green_error; + next[error_index + 6] += blue_error; + } + current[error_index + 7] += alpha_error * 7; + next[error_index - 1] += alpha_error * 3; + next[error_index + 3] += alpha_error * 5; + next[error_index + 7] += alpha_error; } tmp = current; current = next; next = tmp; - memset(next, 0, ((size_t)sx + 2) * 3 * sizeof *next); + memset(next, 0, ((size_t)sx + 2) * 4 * sizeof *next); } free(current); free(next);