mirror of
https://gitlab.com/AutumnMeowMeow/jexer
synced 2024-09-19 11:50:19 -06:00
kitty image output
This commit is contained in:
parent
5939f1aa77
commit
aee27fdfb9
1 changed files with 158 additions and 4 deletions
|
@ -267,6 +267,11 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
*/
|
||||
private ImageCache jexerCache = null;
|
||||
|
||||
/**
|
||||
* If true, emit image data via Kitty image protocol.
|
||||
*/
|
||||
private boolean kittyImages = false;
|
||||
|
||||
/**
|
||||
* The number of threads for image rendering.
|
||||
*/
|
||||
|
@ -1104,6 +1109,17 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
iterm2Images = true;
|
||||
}
|
||||
}
|
||||
|
||||
str = System.getProperty("jexer.ECMA48.kittyImages");
|
||||
// Default to not supporting Kitty images.
|
||||
if (str != null) {
|
||||
if (str.equals("false")) {
|
||||
kittyImages = false;
|
||||
}
|
||||
if (str.equals("true")) {
|
||||
kittyImages = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default to using JPG Jexer images if terminal supports it.
|
||||
|
@ -1717,18 +1733,34 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
|
||||
/*
|
||||
* For images support, draw all of the image output first, and then
|
||||
* draw everything else afterwards. This works OK, but performance
|
||||
* is still a drag on larger pictures.
|
||||
* draw everything else afterwards.
|
||||
*/
|
||||
GlyphMaker glyphMaker = GlyphMaker.getInstance(getTextHeight());
|
||||
for (int y = 0; y < height; y++) {
|
||||
boolean unsetRow = false;
|
||||
boolean unsetKittyRow = false;
|
||||
for (int x = 0; x < width; x++) {
|
||||
// If physical had non-image data that is now image data, the
|
||||
// entire row must be redrawn.
|
||||
Cell lCell = logical[x][y];
|
||||
Cell pCell = physical[x][y];
|
||||
if (lCell.isImage() && !pCell.isImage()) {
|
||||
|
||||
// Check if we need to erase images for Kitty, since text
|
||||
// does not overwrite images.
|
||||
if (kittyImages
|
||||
&& ((lCell.isImage() != pCell.isImage())
|
||||
|| reallyCleared)
|
||||
) {
|
||||
// Alas, Kitty erases the entire image even if you ask
|
||||
// for a single cell to be erased, and I've no idea if it
|
||||
// will also alpha blend on repeats or not.
|
||||
//
|
||||
// It is a bit much to figure out which image was emitted
|
||||
// last frame and break it up on this frame, so just
|
||||
// redraw the entire row.
|
||||
unsetKittyRow = true;
|
||||
}
|
||||
if (!kittyImages && lCell.isImage() && !pCell.isImage()) {
|
||||
unsetRow = true;
|
||||
}
|
||||
int ch = lCell.getChar();
|
||||
|
@ -1743,8 +1775,17 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
getTextWidth(), getTextHeight(), getBackend());
|
||||
lCell.setImage(newImage);
|
||||
unsetRow = true;
|
||||
unsetKittyRow = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (unsetKittyRow) {
|
||||
// There are no images, or different images, on this row, so
|
||||
// erase whatever might have been here before.
|
||||
sb.append(String.format("\033_Ga=d,d=Y,y=%d\033\\", y + 1));
|
||||
unsetImageRow(y);
|
||||
}
|
||||
|
||||
if (unsetRow) {
|
||||
unsetImageRow(y);
|
||||
}
|
||||
|
@ -1787,6 +1828,7 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
) {
|
||||
right++;
|
||||
}
|
||||
|
||||
ArrayList<Cell> cellsToDraw = new ArrayList<Cell>();
|
||||
for (int i = 0; i < (right - x); i++) {
|
||||
assert (logical[x + i][y].isImage());
|
||||
|
@ -1818,7 +1860,8 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
if (cellsToDraw.size() > 0) {
|
||||
if (debugToStderr && reallyDebug) {
|
||||
System.err.println("images to render: iTerm2: " +
|
||||
iterm2Images + " Jexer: " + jexerImageOption);
|
||||
iterm2Images + " Jexer: " + jexerImageOption +
|
||||
" Kitty: " + kittyImages);
|
||||
}
|
||||
|
||||
if (iterm2Images) {
|
||||
|
@ -1841,6 +1884,8 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
sb.append(toIterm2Image(x, y, cellsToDraw));
|
||||
} else if (jexerImageOption != JexerImageOption.DISABLED) {
|
||||
sb.append(toJexerImage(x, y, cellsToDraw));
|
||||
} else if (kittyImages) {
|
||||
sb.append(toKittyImage(x, y, cellsToDraw));
|
||||
} else {
|
||||
sb.append(toSixel(x, y, cellsToDraw));
|
||||
}
|
||||
|
@ -1859,6 +1904,8 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
return toIterm2Image(callX, callY, callCells);
|
||||
} else if (jexerImageOption != JexerImageOption.DISABLED) {
|
||||
return toJexerImage(callX, callY, callCells);
|
||||
} else if (kittyImages) {
|
||||
return toKittyImage(callX, callY, callCells);
|
||||
} else {
|
||||
return toSixel(callX, callY, callCells);
|
||||
}
|
||||
|
@ -2484,6 +2531,26 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
iterm2BottomRow = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Kitty image support will be ASSUMED for the following terminals
|
||||
// if kittyImages is not explicitly false.
|
||||
if (text.contains("WezTerm")
|
||||
|| text.contains("kitty")
|
||||
) {
|
||||
String str = System.getProperty("jexer.ECMA48.kittyImages");
|
||||
if ((str != null) && (str.equals("false"))) {
|
||||
if (debugToStderr) {
|
||||
System.err.println(" -- terminal supports Kitty, but " +
|
||||
"explicitly disabled in config");
|
||||
}
|
||||
kittyImages = false;
|
||||
} else {
|
||||
if (debugToStderr) {
|
||||
System.err.println(" -- enable Kitty images");
|
||||
}
|
||||
kittyImages = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4150,6 +4217,93 @@ public class ECMA48Terminal extends LogicalScreen
|
|||
// End Jexer image output support -----------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Kitty image output support ---------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a Kitty images string representing a row of several cells
|
||||
* containing bitmap data.
|
||||
*
|
||||
* @param x column coordinate. 0 is the left-most column.
|
||||
* @param y row coordinate. 0 is the top-most row.
|
||||
* @param cells the cells containing the bitmap data
|
||||
* @return the string to emit to an ANSI / ECMA-style terminal
|
||||
*/
|
||||
private String toKittyImage(final int x, final int y,
|
||||
final ArrayList<Cell> cells) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
assert (cells != null);
|
||||
assert (cells.size() > 0);
|
||||
assert (cells.get(0).getImage() != null);
|
||||
|
||||
// We don't cache Kitty images at this time.
|
||||
|
||||
BufferedImage image = cellsToImage(cells);
|
||||
int fullHeight = image.getHeight();
|
||||
|
||||
// Always encode as PNG
|
||||
ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream(1024);
|
||||
try {
|
||||
if (!ImageIO.write(image.getSubimage(0, 0, image.getWidth(),
|
||||
Math.min(image.getHeight(), fullHeight)),
|
||||
"PNG", pngOutputStream)
|
||||
) {
|
||||
// We failed to render image, bail out.
|
||||
return "";
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// We failed to render image, bail out.
|
||||
return "";
|
||||
}
|
||||
|
||||
String data = StringUtils.toBase64(pngOutputStream.toByteArray());
|
||||
// Kitty bug: "base64 data must have a length that is a multiple of
|
||||
// 4".
|
||||
data = data.replace("\r", "");
|
||||
data = data.replace("\n", "");
|
||||
|
||||
sb.append("\033_Ga=T,f=100,C=1,");
|
||||
while (data.length() > 0) {
|
||||
// This chunking stuff is stupid.
|
||||
String chunk = data.substring(0, Math.min(4096, data.length()));
|
||||
boolean last = false;
|
||||
if (chunk.length() == data.length()) {
|
||||
last = true;
|
||||
data = "";
|
||||
} else {
|
||||
data = data.substring(chunk.length());
|
||||
}
|
||||
if (last) {
|
||||
sb.append("m=0;");
|
||||
} else {
|
||||
sb.append("m=1;");
|
||||
}
|
||||
sb.append(chunk);
|
||||
sb.append("\033\\");
|
||||
if (!last) {
|
||||
sb.append("\033_G");
|
||||
}
|
||||
}
|
||||
|
||||
return (gotoXY(x, y) + sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Kitty images support flag.
|
||||
*
|
||||
* @return true if this terminal is emitting Jexer images
|
||||
*/
|
||||
public boolean hasKittyImages() {
|
||||
return kittyImages;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// End Kitty image output support -----------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Setup system colors to match DOS color palette.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue