*/
package jexer.backend;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import jexer.bits.Cell;
import jexer.bits.CellAttributes;
import jexer.bits.Color;
+import jexer.bits.StringUtils;
import jexer.event.TCommandEvent;
import jexer.event.TInputEvent;
import jexer.event.TKeypressEvent;
*/
private ImageCache jexerCache = null;
- /**
- * Base64 encoder used by iTerm2 and Jexer images.
- */
- private java.util.Base64.Encoder base64 = null;
-
/**
* If true, then we changed System.in and need to change it back.
*/
* @return the width in pixels of a character cell
*/
public int getTextWidth() {
- return (widthPixels / sessionInfo.getWindowWidth());
+ if (sessionInfo.getWindowWidth() > 0) {
+ return (widthPixels / sessionInfo.getWindowWidth());
+ }
+ return 16;
}
/**
* @return the height in pixels of a character cell
*/
public int getTextHeight() {
- return (heightPixels / sessionInfo.getWindowHeight());
+ if (sessionInfo.getWindowHeight() > 0) {
+ return (heightPixels / sessionInfo.getWindowHeight());
+ }
+ return 20;
}
/**
boolean eventMouse3 = false;
boolean eventMouseWheelUp = false;
boolean eventMouseWheelDown = false;
+ boolean eventAlt = false;
+ boolean eventCtrl = false;
+ boolean eventShift = false;
// System.err.printf("buttons: %04x\r\n", buttons);
- switch (buttons) {
+ switch (buttons & 0xE3) {
case 0:
eventMouse1 = true;
mouse1 = true;
eventType = TMouseEvent.Type.MOUSE_MOTION;
break;
}
+
+ if ((buttons & 0x04) != 0) {
+ eventShift = true;
+ }
+ if ((buttons & 0x08) != 0) {
+ eventAlt = true;
+ }
+ if ((buttons & 0x10) != 0) {
+ eventCtrl = true;
+ }
+
return new TMouseEvent(eventType, x, y, x, y,
eventMouse1, eventMouse2, eventMouse3,
- eventMouseWheelUp, eventMouseWheelDown);
+ eventMouseWheelUp, eventMouseWheelDown,
+ eventAlt, eventCtrl, eventShift);
}
/**
boolean eventMouse3 = false;
boolean eventMouseWheelUp = false;
boolean eventMouseWheelDown = false;
+ boolean eventAlt = false;
+ boolean eventCtrl = false;
+ boolean eventShift = false;
if (release) {
eventType = TMouseEvent.Type.MOUSE_UP;
}
- switch (buttons) {
+ switch (buttons & 0xE3) {
case 0:
eventMouse1 = true;
break;
// Unknown, bail out
return null;
}
+
+ if ((buttons & 0x04) != 0) {
+ eventShift = true;
+ }
+ if ((buttons & 0x08) != 0) {
+ eventAlt = true;
+ }
+ if ((buttons & 0x10) != 0) {
+ eventCtrl = true;
+ }
+
return new TMouseEvent(eventType, x, y, x, y,
eventMouse1, eventMouse2, eventMouse3,
- eventMouseWheelUp, eventMouseWheelDown);
+ eventMouseWheelUp, eventMouseWheelDown,
+ eventAlt, eventCtrl, eventShift);
}
/**
// them.
jexerImageOption = JexerImageOption.DISABLED;
}
+ resetParser();
return;
case 't':
// windowOps
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
- // image for final rendering.
+ // Piece these together into one larger image for final rendering.
int totalWidth = 0;
- int fullWidth = cells.size() * getTextWidth();
- int fullHeight = getTextHeight();
+ int fullWidth = cells.size() * imageWidth;
+ int fullHeight = imageHeight;
for (int i = 0; i < cells.size(); i++) {
totalWidth += cells.get(i).getImage().getWidth();
}
int [] rgbArray;
for (int i = 0; i < cells.size() - 1; i++) {
- int tileWidth = Math.min(cells.get(i).getImage().getWidth(),
- imageWidth);
- int tileHeight = Math.min(cells.get(i).getImage().getHeight(),
- imageHeight);
+ int tileWidth = imageWidth;
+ int tileHeight = imageHeight;
if (false && cells.get(i).isInvertedImage()) {
// I used to put an all-white cell over the cursor, don't do
image.setRGB((cells.size() - 1) * imageWidth, 0, totalWidth,
imageHeight, rgbArray, 0, totalWidth);
- if (totalWidth < getTextWidth()) {
+ if (totalWidth < imageWidth) {
int backgroundColor = cells.get(cells.size() - 1).getBackground().getRGB();
for (int imageX = image.getWidth() - totalWidth;
}
}
+ if ((image.getWidth() != cells.size() * getTextWidth())
+ || (image.getHeight() != getTextHeight())
+ ) {
+ // Rescale the image to fit the text cells it is going into.
+ BufferedImage newImage;
+ newImage = new BufferedImage(cells.size() * getTextWidth(),
+ getTextHeight(), BufferedImage.TYPE_INT_ARGB);
+
+ Graphics gr = newImage.getGraphics();
+ if (gr instanceof Graphics2D) {
+ ((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ ((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ }
+ gr.drawImage(image, 0, 0, newImage.getWidth(),
+ newImage.getHeight(), null, null);
+ gr.dispose();
+ image = newImage;
+ fullHeight = image.getHeight();
+ }
+
// Dither the image. It is ok to lose the original here.
if (palette == null) {
palette = new SixelPalette();
if (iterm2Cache == null) {
iterm2Cache = new ImageCache(height * 10);
- base64 = java.util.Base64.getEncoder();
}
// Save and get rows to/from the cache that do NOT have inverted
// Piece cells.get(x).getImage() pieces together into one larger
// image for final rendering.
int totalWidth = 0;
- int fullWidth = cells.size() * getTextWidth();
- int fullHeight = getTextHeight();
+ int fullWidth = cells.size() * imageWidth;
+ int fullHeight = imageHeight;
for (int i = 0; i < cells.size(); i++) {
totalWidth += cells.get(i).getImage().getWidth();
}
int [] rgbArray;
for (int i = 0; i < cells.size() - 1; i++) {
- int tileWidth = Math.min(cells.get(i).getImage().getWidth(),
- imageWidth);
- int tileHeight = Math.min(cells.get(i).getImage().getHeight(),
- imageHeight);
+ int tileWidth = imageWidth;
+ int tileHeight = imageHeight;
if (false && cells.get(i).isInvertedImage()) {
// I used to put an all-white cell over the cursor, don't do
// that anymore.
image.setRGB((cells.size() - 1) * imageWidth, 0, totalWidth,
imageHeight, rgbArray, 0, totalWidth);
- if (totalWidth < getTextWidth()) {
+ if (totalWidth < imageWidth) {
int backgroundColor = cells.get(cells.size() - 1).getBackground().getRGB();
for (int imageX = image.getWidth() - totalWidth;
}
}
+ if ((image.getWidth() != cells.size() * getTextWidth())
+ || (image.getHeight() != getTextHeight())
+ ) {
+ // Rescale the image to fit the text cells it is going into.
+ BufferedImage newImage;
+ newImage = new BufferedImage(cells.size() * getTextWidth(),
+ getTextHeight(), BufferedImage.TYPE_INT_ARGB);
+
+ Graphics gr = newImage.getGraphics();
+ if (gr instanceof Graphics2D) {
+ ((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ ((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ }
+ gr.drawImage(image, 0, 0, newImage.getWidth(),
+ newImage.getHeight(), null, null);
+ gr.dispose();
+ image = newImage;
+ fullHeight = image.getHeight();
+ }
+
/*
* From https://iterm2.com/documentation-images.html:
*
getTextHeight())));
*/
sb.append("inline=1:");
- sb.append(base64.encodeToString(pngOutputStream.toByteArray()));
+ sb.append(StringUtils.toBase64(pngOutputStream.toByteArray()));
sb.append("\007");
if (saveInCache) {
if (jexerCache == null) {
jexerCache = new ImageCache(height * 10);
- base64 = java.util.Base64.getEncoder();
}
// Save and get rows to/from the cache that do NOT have inverted
// Piece cells.get(x).getImage() pieces together into one larger
// image for final rendering.
int totalWidth = 0;
- int fullWidth = cells.size() * getTextWidth();
- int fullHeight = getTextHeight();
+ int fullWidth = cells.size() * imageWidth;
+ int fullHeight = imageHeight;
for (int i = 0; i < cells.size(); i++) {
totalWidth += cells.get(i).getImage().getWidth();
}
int [] rgbArray;
for (int i = 0; i < cells.size() - 1; i++) {
- int tileWidth = Math.min(cells.get(i).getImage().getWidth(),
- imageWidth);
- int tileHeight = Math.min(cells.get(i).getImage().getHeight(),
- imageHeight);
+ int tileWidth = imageWidth;
+ int tileHeight = imageHeight;
if (false && cells.get(i).isInvertedImage()) {
// I used to put an all-white cell over the cursor, don't do
// that anymore.
image.setRGB((cells.size() - 1) * imageWidth, 0, totalWidth,
imageHeight, rgbArray, 0, totalWidth);
- if (totalWidth < getTextWidth()) {
+ if (totalWidth < imageWidth) {
int backgroundColor = cells.get(cells.size() - 1).getBackground().getRGB();
for (int imageX = image.getWidth() - totalWidth;
}
}
+ if ((image.getWidth() != cells.size() * getTextWidth())
+ || (image.getHeight() != getTextHeight())
+ ) {
+ // Rescale the image to fit the text cells it is going into.
+ BufferedImage newImage;
+ newImage = new BufferedImage(cells.size() * getTextWidth(),
+ getTextHeight(), BufferedImage.TYPE_INT_ARGB);
+
+ Graphics gr = newImage.getGraphics();
+ if (gr instanceof Graphics2D) {
+ ((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ ((Graphics2D) gr).setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ }
+ gr.drawImage(image, 0, 0, newImage.getWidth(),
+ newImage.getHeight(), null, null);
+ gr.dispose();
+ image = newImage;
+ fullHeight = image.getHeight();
+ }
+
if (jexerImageOption == JexerImageOption.PNG) {
// Encode as PNG
ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream(1024);
}
sb.append("\033]444;1;0;");
- sb.append(base64.encodeToString(pngOutputStream.toByteArray()));
+ sb.append(StringUtils.toBase64(pngOutputStream.toByteArray()));
sb.append("\007");
} else if (jexerImageOption == JexerImageOption.JPG) {
}
sb.append("\033]444;2;0;");
- sb.append(base64.encodeToString(jpgOutputStream.toByteArray()));
+ sb.append(StringUtils.toBase64(jpgOutputStream.toByteArray()));
sb.append("\007");
} else if (jexerImageOption == JexerImageOption.RGB) {
bytes[(py * stride * 3) + (px * 3) + 2] = (byte) ( rgb & 0xFF);
}
}
- sb.append(base64.encodeToString(bytes));
+ sb.append(StringUtils.toBase64(bytes));
sb.append("\007");
}