Commit: patch 9.2.0637: sixel: anti-aliased RGBA images render with visible outline

0 views
Skip to first unread message

Christian Brabandt

unread,
Jun 13, 2026, 3:15:16 PM (2 days ago) Jun 13
to vim...@googlegroups.com
patch 9.2.0637: sixel: anti-aliased RGBA images render with visible outline

Commit: https://github.com/vim/vim/commit/66bec4bd8a421461d75a8b04619d63e2cd0b0b40
Author: Yasuhiro Matsumoto <matt...@gmail.com>
Date: Sat Jun 13 19:07:06 2026 +0000

patch 9.2.0637: sixel: anti-aliased RGBA images render with visible outline

Problem: Only alpha == 0 was treated as transparent, so partly-
transparent edge pixels rendered opaque and outlined the
image.
Solution: Treat alpha < 128 as transparent.

Emit pixels with alpha < 128 as the transparent palette index.
Rendering them opaque showed the anti-aliased fringe of an RGBA
image as bright dots.

closes: #20477

Signed-off-by: Yasuhiro Matsumoto <matt...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/sixel.c b/src/sixel.c
index 4d7ef53c2..5245af663 100644
--- a/src/sixel.c
+++ b/src/sixel.c
@@ -306,11 +306,14 @@ sixel_resize_rgb(char_u *src, int sw, int sh, int dw, int dh)
* (indices 1..npal; 0 is reserved as transparent).
*
* Handles both RGB (3 bytes/pixel, has_alpha == FALSE) and RGBA (4 bytes/
- * pixel, has_alpha == TRUE). For RGBA, alpha == 0 pixels are mapped to
- * palette index 0 -- which the sixel emitter never writes to the bitmask,
- * leaving the cell's underlying terminal contents visible (transparency).
- * Pixels with alpha != 0 are deduplicated by their R,G,B triple, ignoring
- * the alpha value (sixel cannot represent partial transparency anyway).
+ * pixel, has_alpha == TRUE). Sixel cannot represent partial transparency,
+ * so RGBA pixels are split at half coverage: alpha < 128 pixels are mapped
+ * to palette index 0 -- which the sixel emitter never writes to the
+ * bitmask, leaving the cell's underlying terminal contents visible
+ * (transparency). Rendering them opaque instead would show the image's
+ * anti-aliased edge fringe (mostly-transparent, often light-colored
+ * pixels) as bright dots around the image. Pixels with alpha >= 128 are
+ * deduplicated by their R,G,B triple, ignoring the alpha value.
*
* Returns OK on success, FAIL when colors exceed max_colors (caller may
* fall back to a fixed palette) or on OOM.
@@ -354,7 +357,7 @@ rgb_to_paletted_fast(
unsigned int h;
int slot;

- if (has_alpha && p[3] == 0)
+ if (has_alpha && p[3] < 128)
{
idx[i] = 0; // transparent -- terminal leaves cell as-is
continue;
@@ -403,9 +406,10 @@ too_many:
* Always succeeds; produces 240 palette entries.
*
* Handles both RGB (3 bytes/pixel, has_alpha == FALSE) and RGBA (4 bytes/
- * pixel, has_alpha == TRUE). For RGBA, alpha == 0 pixels are mapped to
+ * pixel, has_alpha == TRUE). For RGBA, alpha < 128 pixels are mapped to
* palette index 0 -- which the sixel emitter never writes to the bitmask,
- * leaving the cell's underlying terminal contents visible (transparency).
+ * leaving the cell's underlying terminal contents visible (transparency);
+ * see rgb_to_paletted_fast() for why the cut is at half coverage.
*/
static int
rgb_to_paletted_fixed(
@@ -433,7 +437,7 @@ rgb_to_paletted_fixed(
char_u *p = pixels + (size_t)n * bpp;
int ri, gi, bi;

- if (has_alpha && p[3] == 0)
+ if (has_alpha && p[3] < 128)
{
idx[n] = 0;
continue;
@@ -518,9 +522,9 @@ sixel_encode(image_rgb_T *img)
// P2=1 means pixel positions left unspecified by any colour register
// keep their previous on-screen contents instead of being painted with
// colour register 0. That gives true transparency for RGBA images:
- // alpha==0 pixels are emitted as palette index 0 (which we never write
- // to the bitmask), so the terminal leaves the popup's underlying cell
- // colour visible there -- no flatten, no colour-match drift.
+ // alpha < 128 pixels are emitted as palette index 0 (which we never
+ // write to the bitmask), so the terminal leaves the popup's underlying
+ // cell colour visible there -- no flatten, no colour-match drift.
if (ga_concat_bytes(&ga, " P0;1;8q\"1;1;", 13) == FAIL
|| ga_concat_int(&ga, width) == FAIL
|| ga_append(&ga, ';') == FAIL
diff --git a/src/version.c b/src/version.c
index d2dcaafb5..619d899b2 100644
--- a/src/version.c
+++ b/src/version.c
@@ -759,6 +759,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 637,
/**/
636,
/**/
Reply all
Reply to author
Forward
0 new messages