X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Fbackend%2FECMA48Terminal.java;h=613a3abd8f8f2feee14022645469019b6c597201;hb=83787cfb2eb1501a328f8c5f2416c2532e3fef1c;hp=e2997d2f6b17486356ddd9d902d114039258bdef;hpb=d7054034dfac705a1764770009554d1bfa2028d2;p=nikiroo-utils.git diff --git a/src/jexer/backend/ECMA48Terminal.java b/src/jexer/backend/ECMA48Terminal.java index e2997d2..613a3ab 100644 --- a/src/jexer/backend/ECMA48Terminal.java +++ b/src/jexer/backend/ECMA48Terminal.java @@ -83,6 +83,16 @@ public class ECMA48Terminal extends LogicalScreen MOUSE_SGR, } + /** + * Available Jexer images support. + */ + private enum JexerImageOption { + DISABLED, + JPG, + PNG, + RGB, + } + // ------------------------------------------------------------------------ // Variables -------------------------------------------------------------- // ------------------------------------------------------------------------ @@ -217,9 +227,10 @@ public class ECMA48Terminal extends LogicalScreen private ImageCache iterm2Cache = null; /** - * If true, emit image data via Jexer image protocol. + * If not DISABLED, emit image data via Jexer image protocol if the + * terminal supports it. */ - private boolean jexerImages = false; + private JexerImageOption jexerImageOption = JexerImageOption.JPG; /** * The Jexer post-rendered string cache. @@ -1479,7 +1490,7 @@ public class ECMA48Terminal extends LogicalScreen // SQUASH } - // Default to using images for full-width characters. + // Default to not supporting iTerm2 images. if (System.getProperty("jexer.ECMA48.iTerm2Images", "false").equals("true")) { iterm2Images = true; @@ -1487,6 +1498,19 @@ public class ECMA48Terminal extends LogicalScreen iterm2Images = false; } + // Default to using JPG Jexer images if terminal supports it. + String jexerImageStr = System.getProperty("jexer.ECMA48.jexerImages", + "jpg").toLowerCase(); + if (jexerImageStr.equals("false")) { + jexerImageOption = JexerImageOption.DISABLED; + } else if (jexerImageStr.equals("jpg")) { + jexerImageOption = JexerImageOption.JPG; + } else if (jexerImageStr.equals("png")) { + jexerImageOption = JexerImageOption.PNG; + } else if (jexerImageStr.equals("rgb")) { + jexerImageOption = JexerImageOption.RGB; + } + // Set custom colors setCustomSystemColors(); } @@ -2052,7 +2076,7 @@ public class ECMA48Terminal extends LogicalScreen if (cellsToDraw.size() > 0) { if (iterm2Images) { sb.append(toIterm2Image(x, y, cellsToDraw)); - } else if (jexerImages) { + } else if (jexerImageOption != JexerImageOption.DISABLED) { sb.append(toJexerImage(x, y, cellsToDraw)); } else { sb.append(toSixel(x, y, cellsToDraw)); @@ -2806,6 +2830,7 @@ public class ECMA48Terminal extends LogicalScreen if (decPrivateModeFlag == false) { break; } + boolean jexerImages = false; for (String x: params) { if (x.equals("4")) { // Terminal reports sixel support @@ -2821,6 +2846,11 @@ public class ECMA48Terminal extends LogicalScreen jexerImages = true; } } + if (jexerImages == false) { + // Terminal does not support Jexer images, disable + // them. + jexerImageOption = JexerImageOption.DISABLED; + } return; case 't': // windowOps @@ -3424,8 +3454,7 @@ public class ECMA48Terminal extends LogicalScreen int imageWidth = cells.get(0).getImage().getWidth(); int imageHeight = cells.get(0).getImage().getHeight(); - // cells.get(x).getImage() has a dithered bitmap containing indexes - // into the color palette. Piece these together into one larger + // Piece cells.get(x).getImage() pieces together into one larger // image for final rendering. int totalWidth = 0; int fullWidth = cells.size() * getTextWidth(); @@ -3641,7 +3670,7 @@ public class ECMA48Terminal extends LogicalScreen assert (cells.size() > 0); assert (cells.get(0).getImage() != null); - if (jexerImages == false) { + if (jexerImageOption == JexerImageOption.DISABLED) { sb.append(normal()); sb.append(gotoXY(x, y)); for (int i = 0; i < cells.size(); i++) { @@ -3677,8 +3706,7 @@ public class ECMA48Terminal extends LogicalScreen int imageWidth = cells.get(0).getImage().getWidth(); int imageHeight = cells.get(0).getImage().getHeight(); - // cells.get(x).getImage() has a dithered bitmap containing indexes - // into the color palette. Piece these together into one larger + // Piece cells.get(x).getImage() pieces together into one larger // image for final rendering. int totalWidth = 0; int fullWidth = cells.size() * getTextWidth(); @@ -3774,21 +3802,77 @@ public class ECMA48Terminal extends LogicalScreen } } - sb.append(String.format("\033]444;%d;%d;0;", image.getWidth(), - Math.min(image.getHeight(), fullHeight))); - - byte [] bytes = new byte[image.getWidth() * image.getHeight() * 3]; - int stride = image.getWidth(); - for (int px = 0; px < stride; px++) { - for (int py = 0; py < image.getHeight(); py++) { - int rgb = image.getRGB(px, py); - bytes[(py * stride * 3) + (px * 3)] = (byte) ((rgb >>> 16) & 0xFF); - bytes[(py * stride * 3) + (px * 3) + 1] = (byte) ((rgb >>> 8) & 0xFF); - bytes[(py * stride * 3) + (px * 3) + 2] = (byte) ( rgb & 0xFF); + if (jexerImageOption == JexerImageOption.PNG) { + // 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 ""; } + + sb.append("\033]444;1;0;"); + sb.append(base64.encodeToString(pngOutputStream.toByteArray())); + sb.append("\007"); + + } else if (jexerImageOption == JexerImageOption.JPG) { + + // Encode as JPG + ByteArrayOutputStream jpgOutputStream = new ByteArrayOutputStream(1024); + + // Convert from ARGB to RGB, otherwise the JPG encode will fail. + BufferedImage jpgImage = new BufferedImage(image.getWidth(), + image.getHeight(), BufferedImage.TYPE_INT_RGB); + int [] pixels = new int[image.getWidth() * image.getHeight()]; + image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, + 0, image.getWidth()); + jpgImage.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, + 0, image.getWidth()); + + try { + if (!ImageIO.write(jpgImage.getSubimage(0, 0, + jpgImage.getWidth(), + Math.min(jpgImage.getHeight(), fullHeight)), + "JPG", jpgOutputStream) + ) { + // We failed to render image, bail out. + return ""; + } + } catch (IOException e) { + // We failed to render image, bail out. + return ""; + } + + sb.append("\033]444;2;0;"); + sb.append(base64.encodeToString(jpgOutputStream.toByteArray())); + sb.append("\007"); + + } else if (jexerImageOption == JexerImageOption.RGB) { + + // RGB + sb.append(String.format("\033]444;0;%d;%d;0;", image.getWidth(), + Math.min(image.getHeight(), fullHeight))); + + byte [] bytes = new byte[image.getWidth() * image.getHeight() * 3]; + int stride = image.getWidth(); + for (int px = 0; px < stride; px++) { + for (int py = 0; py < image.getHeight(); py++) { + int rgb = image.getRGB(px, py); + bytes[(py * stride * 3) + (px * 3)] = (byte) ((rgb >>> 16) & 0xFF); + bytes[(py * stride * 3) + (px * 3) + 1] = (byte) ((rgb >>> 8) & 0xFF); + bytes[(py * stride * 3) + (px * 3) + 2] = (byte) ( rgb & 0xFF); + } + } + sb.append(base64.encodeToString(bytes)); + sb.append("\007"); } - sb.append(base64.encodeToString(bytes)); - sb.append("\007"); if (saveInCache) { // This row is OK to save into the cache. @@ -3804,7 +3888,7 @@ public class ECMA48Terminal extends LogicalScreen * @return true if this terminal is emitting Jexer images */ public boolean hasJexerImages() { - return jexerImages; + return (jexerImageOption != JexerImageOption.DISABLED); } // ------------------------------------------------------------------------