#113 Option to explicitly overwrite images with black pixels

This commit is contained in:
Autumn Lamonte 2024-08-31 01:15:01 -05:00
parent 1a25f90893
commit db74afade4
2 changed files with 92 additions and 7 deletions

View file

@ -337,6 +337,21 @@ public class ECMA48Terminal extends LogicalScreen
*/ */
private boolean hasSynchronizedOutput = false; private boolean hasSynchronizedOutput = false;
/**
* If true, this terminal requires explicitly overwriting images
* with black pixels to destroy them. If false, overwriting
* images with text will destroy them. Konsole is the only
* terminal known at this time that requires
* explicitlyDestroyImages to be true.
*/
private boolean explicitlyDestroyImages = false;
/**
* The cells containing all-black pixels used to erase images when
* explicityDestroyImages is true. Only initialized if needed.
*/
private ArrayList<Cell> blankImageRow = null;
/** /**
* The time we last flushed output in flushPhysical(). * The time we last flushed output in flushPhysical().
*/ */
@ -1128,6 +1143,14 @@ public class ECMA48Terminal extends LogicalScreen
imagesOverText = false; imagesOverText = false;
} }
String destroyImagesStr = System.getProperty("jexer.ECMA48.explicitlyDestroyImages",
"auto").toLowerCase();
if (destroyImagesStr.equals("true")) {
explicitlyDestroyImages = true;
} else {
explicitlyDestroyImages = false;
}
// Image thread count. // Image thread count.
imageThreadCount = 2; imageThreadCount = 2;
try { try {
@ -1697,7 +1720,6 @@ public class ECMA48Terminal extends LogicalScreen
} // for (int x = 0; x < width; x++) } // for (int x = 0; x < width; x++)
} }
/** /**
* Render the screen to a string that can be emitted to something that * Render the screen to a string that can be emitted to something that
* knows how to process ECMA-48/ANSI X3.64 escape sequences. * knows how to process ECMA-48/ANSI X3.64 escape sequences.
@ -1717,21 +1739,31 @@ public class ECMA48Terminal extends LogicalScreen
} }
/* /*
* For images support, draw all of the image output first, and then * For images support, draw all of the image output first, and
* draw everything else afterwards. * then draw all the text afterwards.
*/ */
GlyphMaker glyphMaker = GlyphMaker.getInstance(getTextHeight()); GlyphMaker glyphMaker = GlyphMaker.getInstance(getTextHeight());
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
boolean unsetRow = false; boolean unsetRow = false;
boolean eraseImagesOnRow = false;
for (int x = 0; x < width; x++) { 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 lCell = logical[x][y];
Cell pCell = physical[x][y]; Cell pCell = physical[x][y];
// If physical has image data that will be overwritten
// by text, then erase all of the images on this row
// for terminals that require explicitlyDestroyImages
// to be true.
if (pCell.isImage() && !lCell.isImage()) {
eraseImagesOnRow = true;
}
// If physical had non-image data that is now image data, the
// entire row must be redrawn.
if (lCell.isImage() && !pCell.isImage()) { if (lCell.isImage() && !pCell.isImage()) {
unsetRow = true; unsetRow = true;
} }
int ch = lCell.getChar(); int ch = lCell.getChar();
if (!lCell.isImage() if (!lCell.isImage()
&& (StringUtils.isLegacyComputingSymbol(ch) && (StringUtils.isLegacyComputingSymbol(ch)
@ -1750,7 +1782,38 @@ public class ECMA48Terminal extends LogicalScreen
if (unsetRow) { if (unsetRow) {
unsetImageRow(y); unsetImageRow(y);
} }
}
if (explicitlyDestroyImages && eraseImagesOnRow) {
for (int x = 0; x < width; x++) {
physical[x][y].unset();
}
if ((blankImageRow == null)
|| (blankImageRow.size() < width)
) {
blankImageRow = new ArrayList<Cell>(width);
Cell blank = new Cell();
BufferedImage newImage = new BufferedImage(textWidthPixels,
textHeightPixels, BufferedImage.TYPE_INT_ARGB);
java.awt.Graphics gr = newImage.getGraphics();
gr.setColor(java.awt.Color.BLACK);
gr.fillRect(0, 0, newImage.getWidth(),
newImage.getHeight());
gr.dispose();
blank.setImage(newImage);
for (int x = 0; x < width; x++) {
blankImageRow.add(new Cell(blank));
}
}
if (iterm2Images) {
sb.append(toIterm2Image(0, y, blankImageRow));
} else if (jexerImageOption != JexerImageOption.DISABLED) {
sb.append(toJexerImage(0, y, blankImageRow));
} else {
sb.append(toSixel(0, y, blankImageRow));
}
}
} //for (int y = 0; y < height; y++) {
/* /*
* Image encoding is expensive, especially when the image is not in * Image encoding is expensive, especially when the image is not in
@ -2467,6 +2530,7 @@ public class ECMA48Terminal extends LogicalScreen
if (text.contains("WezTerm") if (text.contains("WezTerm")
|| text.contains("mintty") || text.contains("mintty")
|| text.contains("iTerm2") || text.contains("iTerm2")
|| text.contains("Konsole")
) { ) {
String str = System.getProperty("jexer.ECMA48.iTerm2Images"); String str = System.getProperty("jexer.ECMA48.iTerm2Images");
if ((str != null) && (str.equals("false"))) { if ((str != null) && (str.equals("false"))) {
@ -2487,6 +2551,27 @@ public class ECMA48Terminal extends LogicalScreen
iterm2BottomRow = true; iterm2BottomRow = true;
} }
} }
// Konsole places image data underneath text, such that
// erasing text will re-expose the image. We need to
// explicitly destroy any images being overwritten by text for
// that case.
if (text.contains("Konsole")) {
String str = System.getProperty("jexer.ECMA48.explicitlyDestroyImages");
if ((str != null) && (str.equals("false"))) {
if (debugToStderr) {
System.err.println(" -- terminal requires " +
"explicitlyDestroyImages, but is disabled in config");
}
explicitlyDestroyImages = false;
} else {
if (debugToStderr) {
System.err.println(" -- terminal requires explicitlyDestroyImages");
}
explicitlyDestroyImages = true;
}
}
} }
/** /**

View file

@ -347,7 +347,7 @@ public class Cell extends CellAttributes {
} }
/** /**
* Flatten the image on this cell by rendering it either onto a * Flatten the image on this cell by rendering it onto a
* background color. * background color.
* *
* @param background the background color to draw on * @param background the background color to draw on