| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
Was looking for kitty support in tmux and saw this PR. Not sure if i'm doing something wrong, but getting: ❯ ./configure --with-image-support ... ❯ make make: *** No rule to make target `image-kitty.c', needed by `image-kitty.o'. Stop. |
Sorry, something went wrong.
|
Oops sorry, forgot to add the new files. Added now. Please try again. |
Sorry, something went wrong.
|
@senthil-instrumentl found another missing .h file which is now fixed (included inside image-kitty.h). Please give it a try. Feedback welcome. Thanks! |
Sorry, something went wrong.
|
I am using it inside Windows Terminal for development. I tried it briefly in kitty term. I fixed a flashing issue but that was already pushed yesterday. I can try it in wezterm probably tomorrow. Can you attach the png file or tell me where to get it? Hopefully we can fix the flashing everywhere. We will get this to work. Thanks for your help testing it! |
Sorry, something went wrong.
Sorry, something went wrong.
|
I reproduced this in wezterm locally. I've added a fix for this to this branch, please pull it and recompile. IMPORTANT: you should remove this from your .tmux.conf set -ga terminal-features ',*:RGB:sixel:sync:kitty' Then fully restart the tmux server. tmux will detect each attached terminal separately:
If you have a separate reason to force sync, it should be configured only for the appropriate terminal pattern, not with *. The global line incorrectly claims every client supports both image protocols, which defeats per-client backend selection. |
Sorry, something went wrong.
|
I like the initiative, but there are a few bugs. diff --git a/image-sixel.c b/image-sixel.c
index 577ba51a..595c3836 100644
--- a/image-sixel.c
+++ b/image-sixel.c
@@ -429,9 +429,9 @@ sixel_colour_to_rgb(u_int colour, u_char *r, u_char *g, u_char *b)
double h, l, s, p, q;
if (type == 2) {
- *r = ((colour >> 16) & 0x1ff) * 255 / 100;
- *g = ((colour >> 8) & 0xff) * 255 / 100;
- *b = (colour & 0xff) * 255 / 100;
+ *r = (((colour >> 16) & 0xff) * 255 + 50) / 100;
+ *g = (((colour >> 8) & 0xff) * 255 + 50) / 100;
+ *b = ((colour & 0xff) * 255 + 50) / 100;
return;
}
if (type != 1) {
@@ -448,9 +448,9 @@ sixel_colour_to_rgb(u_int colour, u_char *r, u_char *g, u_char *b)
}
q = l < 0.5 ? l * (1 + s) : l + s - l * s;
p = 2 * l - q;
- *r = sixel_hue(p, q, h + 1.0 / 3) * 255;
- *g = sixel_hue(p, q, h) * 255;
- *b = sixel_hue(p, q, h - 1.0 / 3) * 255;
+ *r = sixel_hue(p, q, h) * 255 + 0.5;
+ *g = sixel_hue(p, q, h - 1.0 / 3) * 255 + 0.5;
+ *b = sixel_hue(p, q, h + 1.0 / 3) * 255 + 0.5;
}
/* Convert decoded SIXEL data into the protocol-neutral immutable image. */Second, sixel_from_image is... not pretty. The way you'd normally go about this is some kind of image quantization algorithm (I've had luck with octrees), with the current nearest neighbor approach the output looks awful, as demonstrated by your own screenshot. Or at the very least you should apply some error diffusion, ref. Third, sizing is broken. For example, printf '\033P0;1q"1;1;26;26#0;2;50;50;50#1;2;0;0;0#2;2;49;49;49#3;2;33;33;33#4;2;47;47;47#5;2;44;44;44#6;2;48;48;48#2?O?C!5?S!4?__?_?__$#0?_wW!5KGwo_-#0?~~!8?!10@BB}w$#2!12?a_A?A?A?A??@E-#0?~~!7?KK~~KK!7?~~$#2!9?K!6?K-#0?F^[owowowowowowowowooS^F$#2?G!10?@@!7?G??G-\033\' should print a 26x26 image, but it gets scaled up to the cell size, so if I have 20x10 pixel cells then it blows up to 40x30. From a quick look at the code, draw_rectangle only gets sizes in cells, so perhaps that's related. Finally, maybe I'm wrong but it looks like the cropping Kitty parameters (X/Y/w/h (edit: sorry, I meant x/y, although I use X/Y too but it's less important)) aren't respected? Those are kind of necessary for efficient TUIs, e.g. I use them extensively in chawan so that I don't have to re-send images on scroll. |
Sorry, something went wrong.
@bptato, Did this address all your concerns? The sixel image definitely looks better to me now, thanks! |
Sorry, something went wrong.
|
It's better, thanks. Some issues left:
Also, even with the error diffusion there are some pretty bad artifacts (image, up: kitty -> tmux -> sixel on this branch, bottom: sixel passed through tmux master):
Apples to oranges of course, as the palettizer algorithm is different. But you can see the stripes per line, which I think happens because the palette & dither is recomputed for each line. At least the latter must be kept. |
Sorry, something went wrong.
|
Wow but it's really close! I see it gets dithery above his head and up his arm. What do you think is causing that? I can try to figure it out but if you have some ideas that would be super helpful. Have a look in image-sixel.c and see if it makes sense. This is the first step to get this to paint the image in stripes because that's the way the current screen-redraw works. It splits the screen up into a "scene" of "spans". When each span is output, the sub-rectangle of the image is output in that stripe. This way, we treat the image just exactly like characters on the screen. They can be scrolled up into the copy buffer, moved around on the screen in floating panes, and partially obscured by floating panes or popups, everything just works. In a near future revision of this, I hope to be able to join up ajoining spans into larger rectangles. Still though, an image may be painted with multiple sub-rectangles if it is partly obscured by one or more floating panes. But it should improve the efficiency of sending these images to the terminal. But I don't think this is the solution to this image aberation. It looks like either an encoder or decoder issue and it well could be the encoding into these stripes that is causing this. Can you show me some of the other examples of images flowing into one another? It sounds like the sub-rectangles are not properly scaled for the terminal or something like that. By the way, this idea of using small rectangles is based on how Kitty does images. Each of those special unicode characters carries with it which piece of which puzzle belongs on top of that character. |
Sorry, something went wrong.
|
Without the set line in .tmux.conf, can you confirm the Wezterm issue is fixed?
I'll have a look at the kitty image issue.
…On 3 August 2026 14:50:19 BST, paranoidi ***@***.***> wrote:
paranoidi left a comment (tmux/tmux#5445)
Rendering is pretty broken atm. Example:
<img width="256" alt="image" src="https://github.com/user-attachments/assets/b9933811-c1b8-48e3-84d9-124219644e49" />
Original:
<img width="256" height="256" alt="ChatGPT Image Apr 3, 2026, 09_26_54 PM" src="https://github.com/user-attachments/assets/57a6ca15-cdef-4565-9ce4-cc56f60a60ce" />
I still can not get kitty images to show within tmux even after correcting my .tmux.conf per instructions. I tried with default config and no dice with that either.
--
Reply to this email directly or view it on GitHub:
#5445 (comment)
You are receiving this because you authored the thread.
Message ID: ***@***.***>
|
Sorry, something went wrong.
Sorry, something went wrong.
|
@bptato let me know if this last push fixes the sixel issues. |
Sorry, something went wrong.
|
Well, it fixes it for Sixel input. But quantization is still broken for kitty -> tmux -> sixel (image):
What is the algorithm based off of, anyway? By the way, I've found the source of my Kitty cursor positioning issue: the patch doesn't respect 'C=1', which is supposed to keep the cursor where it was. I suppose it should set a flag and suppress cursor movement in image_write. Apropos image_write, I've noticed this: sx = im->sx;
if (sx > screen_size_x(s) - cx)
sx = screen_size_x(s) - cx;
sy = im->sy;
if (sy > screen_size_y(s) - 1)
sy = screen_size_y(s) - 1; // <-- ??
if (sx == 0 || sy == 0)
return;
if (screen_size_y(s) - cy <= sy) {
lines = sy - (screen_size_y(s) - cy) + 1;
screen_write_scrollup(ctx, lines, bg);
if (lines > cy)
screen_write_cursormove(ctx, -1, 0, 0);
else
screen_write_cursormove(ctx, -1, cy - lines, 0);
cy = s->cy;
}Surely we don't want to crop the image to the screen height when moving the cursor? I believe what should happen here is that if the image overflows the screen, it should first scroll down by lines, and then the image should be cropped from the top so it fits into the screen (i.e. set some kind of "y origin" variable). |
Sorry, something went wrong.
|
@bptato Ok I made progress on the kitty images and the kitty->tmux->sixel support. Can you please restest this branch. I can't seem to reproduce this issue: "scrolling, eventually the entire layout collapses into a mess". If it's still messing up when you scroll up and down, please can you provide me with a list of instructions how to reproduce that? I have the 1.wepb image you used. If you used a different image, please provide me a link. I tested in kitty with this: kitty +kitten icat --scale-up --fit=both 1.webp to make the image fit full width. |
Sorry, something went wrong.
C=1 indeed works now, thanks.
From what I can see, you removed the dither, which I find puzzling because that's the only part that worked. Now the image looks like:
The part that is broken is the quantization, i.e., your (?) median cut routine. In other words, the colors are being selected incorrectly.
The bug(s) I was talking about manifested when viewing the webp gallery in chawan as described above. By "scroll" I referred to scrolling inside the TUI, which in the background both scrolls the text and moves the placements. (This is necessary because every terminal I tested handled scroll + Kitty placements differently.)
I'm pretty sure icat discriminates against tmux, so this would use the passthrough sequence by default, i.e., this doesn't really test anything. (I've tried passing --transfer-mode=stream --passthrough=none but then it doesn't print anything for some reason.) |
Sorry, something went wrong.
#!/bin/sh
printf '\033_GC=1,s=26,v=26,p=1,q=2,i=1,a=T,f=100,m=0;iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAACmUlEQVR4XmOgF2CEWVRfX8/w//9/BkZGRgy7YeKNjY1kuwtsam1tLQMTE5MG0MBsoEWW6KYBxf8DxScD6UVNTU1kWcZYU1MD0qjLzMx8EmgYJy5TgJb8/ffvn+2vX7+Od3Z2kmwZC9AnIE0FIEuAhl0H4ulA9k9kk4Bi4UB1TkA8H2iRYXl5+Xd2dna8loGCG2Q2LLgZQXED1PEIaLjs379/g4Ds9VDLwQYBxRiAPpFmZWW9DFQjCDRgLxDfJeQloJpdQHPWA9X9A1kGs+gZ0BBJoKQtUOIIeqSDgheoKR6IF5ASZkAH3gKaCzLzFQsxGltaWhjq6uoWguIJ6hi82oCG8wIV+AEdpga0LBfIrmUh1oWg1AYM5iVA9UuI1JMGVDcTiCNIsghkOChIQ0NDwfasXr0ap33QeL8GUgD0HTeIZmIgAUAtYQZqYYZZSKx2oi2CWaKpqbkIhEm1jOg40tLSAjleEBgUUSAGkJ8PpN8Q6yOCFoF8AvQBTvOAqZHh+vXrDPjijGAcIcXJUqBPQOXda5iNQP5rkBiQv5SYYMTrIxUVFZC5IkDCCk8QWQHVgdS8xBeMeBNDe3s7A7CwfQl0uSmwKDIBYhdQGQbCIDZIDCQHUgNSS7ZFII2gUgEU6UADzwJz+kUgDa6zoOyzIDmoGgaKLAJpBheKkArxC7BIeQDCQPEvIEuJrQyJzkdQA38ADbcHYaBFP0ipcVGqCWDYBwPxOkYs1TkDCeA/pEkQBDRnLZD9GKhVjgUkCGTsBgomAekWIJYG4p8MlAFQrZgJMgJo/m4QzQJ1fT9QIBLI1gTiSRRaAm/gAM38DjSvH2QeuHECLW1xNk7IsRhoyXGgJVOBem+AExPMEHzNLTItYiAlVTJQCwAAJxkMkgbHo2UAAAAASUVORK5CYII=\033\\\n'
sleep 1
printf '\033_GC=1,s=26,v=26,p=1,q=2,i=1,a=p;\033\\\n'The first printf should draw the icon, then the second one should move it to the next line. |
Sorry, something went wrong.
|
I've reverted ab591ae and hopefully now I have fixed the quantization, sorry about that misunderstanding. Hopefully the quantization bug is fixed. I tested both using icat in kitty and displaying the image in tmux in ms terminal which output using sixel and visa versa I cat'ed out a sixel image in ms term and it displayed in kitty. scrolling the tmux window works but that isn't quite what you were doing. I will see if i can reproduce what you describe tomorrow. Meanwhile, tell me if I got the quantization bug this time. I feel we're getting closer. Thanks for help testing, very helpful! |
Sorry, something went wrong.
|
@bptato I ran your shell script: |
Sorry, something went wrong.
|
@bptato Theicat test was useful for the new Kitty→tmux→SIXEL interoperability because we now deliberately intercept that wrapped placeholder form and convert it into shared tmux image cells. I pushed another fix to hopefully fix or improve the scrolling in chawan, pleases let me know if it's any better or worse. |
Sorry, something went wrong.
|
After my last fix, your script indeed makes the little icon folder move down (I see only one icon now).
|
Sorry, something went wrong.
Sorry, something went wrong.
Ok, i see what you mean, let me reverse that. What do you think should happen on a simultaneously connected sixel compatible terminal (not kitty)? Should we try to passively look at the passthrough image and if possible try to create a sixel shadow image of it for the sixel capable terminal (for example Microsoft Windows Terminal)? Because otherwise, those other terminals will just see a gaping hole. This won't support everything you could throw at kitty like animations but it would support the majority of the static images which seems useful. Not the easiest thing to do but it should be possible. What's your suggestion in this case? |
Sorry, something went wrong.
I'd say "nothing". We shouldn't incentivize apps to stick to an obsolete hack by adding another hack on top of it. The right way to fix this is to patch terminal libraries (that don't already do so) to query for kitty support without passthrough as well. Then, if they get a regular response, they can just send the image as normal, and optionally fall back to passthrough for older tmux versions as long as that's relevant. |
Sorry, something went wrong.
…ne later overwritten by text. On a SIXEL terminal, damaged cells are omitted from image output; on Kitty they remain ordinary positional placements.
…d first in the cell.
Replace the per-cell image marker with sparse placement spans attached to grid lines. A placement owns all of its spans and records the input protocol, application image and placement IDs, z-index, and creation order. This retains overlapping image layers without storing a list in every grid cell. Grid operations move, split, clip, and remove only the affected spans. Use the input protocol to determine image/text interaction: later text damages SIXEL spans, while Kitty placements remain and are ordered by their z-index. Rendering then adapts that one logical scene for each client, rather than changing its semantics according to whether the outer terminal uses Kitty or SIXEL.
Scale SIXEL rasters uniformly when clients have different cell dimensions, while retaining the original logical cell canvas as blank padding. Map crops using real cell boundaries so partial final cells are not stretched or compressed.
image_redraw_start() was called with a pane's full nominal geometry rather than the cells it actually owns in the current scene. When a floating pane occluded part of that rectangle, the erase blanked the floating pane's on-screen content, and the following text redraw correctly skipped those cells (not owned by this pane), leaving them blank with nothing to restore them.
…ort.sh Three adjacent blocks shared one 'set -as terminal-features' setting with contradictory requirements - fallback text, then real SIXEL, then fallback text again in a single client attach. terminal-features is only detected at client attach, not live, so this needs detach/reattach between blocks rather than toggling the option in place.
window_make_pane_status() gates physical redraw of border-status text on a logical content diff, not physical damage - if something else disturbs those cells, the text stays blank because tmux believes nothing changed. This test currently fails and is expected to keep failing until the general damage-tracking redraw work lands (see IMAGE-REDRAW-PLAN.md).
…redraw image_redraw_area() used to unconditionally flag the whole pane (PANE_REDRAW) whenever any part of it needed an image recomposited - a pane can be much taller than the area actually disturbed (a small scroll region, or a single line insert/delete far from where an image sits), so this erased and retransmitted every image anywhere in the pane regardless of proximity to the affected area. Report damage for just the area via redraw_damage_window() instead. image_redraw_scroll() similarly now scopes to the current scroll region rather than redrawing the whole pane via image_redraw_all().
image_write() only ever creates spans for as much of an image as fit in the pane at the time it was placed - the rest of the image's pixels are still retained (struct image is immutable and kept for as long as any placement references it), but nothing revisited that clipping decision, so a pane that was too narrow when an image was displayed stayed clipped forever, even after growing wide enough to fit the rest. Unlike height, which recovers via ordinary scrollback, there is no equivalent "scroll right" - this is the only way the extra width is ever recovered. image_grid_resize_width() finds every placement referenced in a grid's rows, works out how far its spans already reach and its origin column, and extends them (via a new image_extend_row(), factored out of image_write()'s own span-building loop) up to whichever is smaller: the image's own full width or the new pane width. window_pane_resize() calls it after a pane grows wider.
…opy-mode redraws window_copy_write_one() used to write text/highlight styling directly over image-covered cells via the normal path, which - since a character write typically clears whatever pixel content a terminal was showing there - erased the image with nothing to redraw it back in. Image-covered cells now bypass styling and go straight into the grid instead (a non-graphical client's ASCII fallback for the image still depends on this same write, so it can't just be skipped). window_copy_write_line()'s call to image_redraw_area() used to fire unconditionally on every redraw, needlessly recompositing (and briefly flashing) the image on every single cursor step even after the erasure above was fixed, even though nothing about the image had changed. It now only fires when window_copy_update_image_refresh() (new) determines the view's underlying history position actually moved since the last redraw. Also adds window_copy_visible_has_images(), used by a later commit's scroll-region fix as a bypass to a full redraw when the visible range carries image data - line insert/delete only shifts character cells, not already-sent image pixels, so scroll's normal fast path leaves stale or missing image content behind.
…ding it image_write() handles an image taller than the pane by scrolling the screen up to make room, but only ever created spans for the rows that ended up on screen afterwards - the rows immediately scrolled off (up to origin_y of them) were pushed into history as blank, spanless rows and that part of the image was permanently discarded. Unlike width, which has no "scroll right" to recover a permanent clip, height already has ordinary scrollback, so this was pure waste: scrolling back up just showed empty space where part of the image used to be. image_write() now also calls image_extend_row() for those origin_y rows, capped to however many real history rows screen_write_scrollup() actually created (it clamps its own request to one scroll-region height per call, so a single call may not push everywhere origin_y implies - looping it until the full amount is pushed, done here too, makes that gap rare, but the cap keeps the fill-in safe even if it isn't).
|
@bptato some major changes in the 4902-image-support branch. Would you mind retesting your application and let me know if everything still works? Basically this branch is based on the redraw-damage-rectangles branch which tracks damage to the screen and redraws only the necessary spans. It should substantially reduce the amount of flashing of images. |
Sorry, something went wrong.
|
It seems to work fine, thank you. (Although if the goal was to eliminate flashing, that still happens with Sixel, except when Sync hides it - in xterm it's visible even when I just dump an image to the shell with img2sixel and scroll by repeatedly hitting return.) |
Sorry, something went wrong.
|
How can I compile this correctly, seems like --with-image-support no longer works: "configure: WARNING: unrecognized options: --with-image-support" Currently when I test this PR sixel graphics do not show up at all. Based on logs the --enable-sixel is deprecated as well. |
Sorry, something went wrong.
|
Use --enable-images. Option changed for consistency.
…On 27 August 2026 05:30:33 GMT-07:00, paranoidi ***@***.***> wrote:
paranoidi left a comment (tmux/tmux#5445)
How can I compile this correctly, seems like --with-image-support no longer works:
`"configure: WARNING: unrecognized options: --with-image-support"`
Currently when I test this PR sixel graphics do not show up at all.
Based on logs the `--enable-sixel` is deprecated as well.
--
Reply to this email directly or view it on GitHub:
#5445 (comment)
You are receiving this because you authored the thread.
Message ID: ***@***.***>
|
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
This PR adds generalised support for both kitty and sixel images. Basically it breaks up images into grid size rectangles. If the terminal is kitty then it sends kitty the image using the special unicode character encoding and kitty displays it locally. If the terminal supports sixel images, the image is sent to the terminal using sixel escape codes. This uses the new screen-redraw scene and span drawing, so it works in and around floating panes. Images can be scrolled into the copy buffer without issue.