expose sixel palette size
authorKevin Lamonte <kevin.lamonte@gmail.com>
Sun, 11 Aug 2019 00:09:09 +0000 (19:09 -0500)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Sun, 11 Aug 2019 00:09:09 +0000 (19:09 -0500)
src/jexer/TApplication.java
src/jexer/TFontChooserWindow.java
src/jexer/TFontChooserWindow.properties
src/jexer/backend/ECMA48Terminal.java
src/jexer/demos/DemoApplication.java
src/jexer/menu/TMenu.java
src/jexer/menu/TMenu.properties

index fdbc0e39ad964318a801a211a71972f3a7f4bdb0..b21c066fefb8ecd11dda667aec245e0ea28c98db 100644 (file)
@@ -929,7 +929,7 @@ public class TApplication implements Runnable {
             openImage();
             return true;
         }
-        if (menu.getId() == TMenu.MID_CHANGE_FONT) {
+        if (menu.getId() == TMenu.MID_SCREEN_OPTIONS) {
             new TFontChooserWindow(this);
             return true;
         }
@@ -3132,7 +3132,7 @@ public class TApplication implements Runnable {
         TMenu toolMenu = addMenu(i18n.getString("toolMenuTitle"));
         toolMenu.addDefaultItem(TMenu.MID_REPAINT);
         toolMenu.addDefaultItem(TMenu.MID_VIEW_IMAGE);
-        toolMenu.addDefaultItem(TMenu.MID_CHANGE_FONT);
+        toolMenu.addDefaultItem(TMenu.MID_SCREEN_OPTIONS);
         TStatusBar toolStatusBar = toolMenu.newStatusBar(i18n.
             getString("toolMenuStatus"));
         toolStatusBar.addShortcutKeypress(kbF1, cmHelp, i18n.getString("Help"));
index 5878b5923f025518190e203f4afb9c2ba932ad64..62eabb632d4841acd354bb5e0901a8e4ff4a8a93 100644 (file)
@@ -35,6 +35,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.ResourceBundle;
 
+import jexer.backend.ECMA48Terminal;
 import jexer.backend.SwingTerminal;
 import jexer.bits.CellAttributes;
 import jexer.bits.GraphicsChars;
@@ -62,6 +63,11 @@ public class TFontChooserWindow extends TWindow {
      */
     private SwingTerminal terminal = null;
 
+    /**
+     * The ECMA48 screen.
+     */
+    private ECMA48Terminal ecmaTerminal = null;
+
     /**
      * The font name.
      */
@@ -92,6 +98,11 @@ public class TFontChooserWindow extends TWindow {
      */
     private TField textAdjustWidth;
 
+    /**
+     * The sixel palette size.
+     */
+    private TComboBox sixelPaletteSize;
+
     /**
      * The original font size.
      */
@@ -122,6 +133,11 @@ public class TFontChooserWindow extends TWindow {
      */
     private int oldTextAdjustWidth = 0;
 
+    /**
+     * The original sixel palette (number of colors) value.
+     */
+    private int oldSixelPaletteSize = 1024;
+
     // ------------------------------------------------------------------------
     // Constructors -----------------------------------------------------------
     // ------------------------------------------------------------------------
@@ -134,7 +150,7 @@ public class TFontChooserWindow extends TWindow {
     public TFontChooserWindow(final TApplication application) {
 
         // Register with the TApplication
-        super(application, i18n.getString("windowTitle"), 0, 0, 60, 18, MODAL);
+        super(application, i18n.getString("windowTitle"), 0, 0, 60, 21, MODAL);
 
         // Add shortcut text
         newStatusBar(i18n.getString("statusBar"));
@@ -142,6 +158,9 @@ public class TFontChooserWindow extends TWindow {
         if (getScreen() instanceof SwingTerminal) {
             terminal = (SwingTerminal) getScreen();
         }
+        if (getScreen() instanceof ECMA48Terminal) {
+            ecmaTerminal = (ECMA48Terminal) getScreen();
+        }
 
         addLabel(i18n.getString("fontName"), 1, 1, "ttext", false);
         addLabel(i18n.getString("fontSize"), 1, 2, "ttext", false);
@@ -149,8 +168,9 @@ public class TFontChooserWindow extends TWindow {
         addLabel(i18n.getString("textAdjustY"), 1, 5, "ttext", false);
         addLabel(i18n.getString("textAdjustHeight"), 1, 6, "ttext", false);
         addLabel(i18n.getString("textAdjustWidth"), 1, 7, "ttext", false);
+        addLabel(i18n.getString("sixelPaletteSize"), 1, 9, "ttext", false);
 
-        int col = 18;
+        int col = 21;
         if (terminal == null) {
             // Non-Swing case: we can't change anything
             addLabel(i18n.getString("unavailable"), col, 1);
@@ -159,7 +179,32 @@ public class TFontChooserWindow extends TWindow {
             addLabel(i18n.getString("unavailable"), col, 5);
             addLabel(i18n.getString("unavailable"), col, 6);
             addLabel(i18n.getString("unavailable"), col, 7);
-        } else {
+        }
+        if (ecmaTerminal == null) {
+            addLabel(i18n.getString("unavailable"), col, 9);
+        }
+        if (ecmaTerminal != null) {
+            oldSixelPaletteSize = ecmaTerminal.getSixelPaletteSize();
+
+            String [] sixelSizes = { "2", "256", "512", "1024", "2048" };
+            List<String> sizes = new ArrayList<String>();
+            sizes.addAll(Arrays.asList(sixelSizes));
+            sixelPaletteSize = addComboBox(col, 9, 10, sizes, 0, 6,
+                new TAction() {
+                    public void DO() {
+                        try {
+                            ecmaTerminal.setSixelPaletteSize(Integer.parseInt(
+                                sixelPaletteSize.getText()));
+                        } catch (NumberFormatException e) {
+                            // SQUASH
+                        }
+                    }
+                }
+            );
+            sixelPaletteSize.setText(Integer.toString(oldSixelPaletteSize));
+        }
+
+        if (terminal != null) {
             oldFont = terminal.getFont();
             oldFontSize = terminal.getFontSize();
             oldTextAdjustX = terminal.getTextAdjustX();
@@ -514,6 +559,9 @@ public class TFontChooserWindow extends TWindow {
                         terminal.setTextAdjustHeight(oldTextAdjustHeight);
                         terminal.setTextAdjustWidth(oldTextAdjustWidth);
                     }
+                    if (ecmaTerminal != null) {
+                        ecmaTerminal.setSixelPaletteSize(oldSixelPaletteSize);
+                    }
                     TFontChooserWindow.this.close();
                 }
             });
@@ -541,6 +589,9 @@ public class TFontChooserWindow extends TWindow {
                 terminal.setFont(oldFont);
                 terminal.setFontSize(oldFontSize);
             }
+            if (ecmaTerminal != null) {
+                ecmaTerminal.setSixelPaletteSize(oldSixelPaletteSize);
+            }
             getApplication().closeWindow(this);
             return;
         }
index de30c1a57f2970261e247dfb25dddd76f02fedf4..4ab274efd9a470f8980d271c02593835b6b23be0 100644 (file)
@@ -1,7 +1,7 @@
-windowTitle=Font
+windowTitle=Screen
 okButton=\ \ &OK\ \ 
 cancelButton=&Cancel
-statusBar=Select Font Options
+statusBar=Select Screen Options
 
 fontName=Font name:
 fontSize=Font size:
@@ -10,6 +10,8 @@ textAdjustY=Y adjust:
 textAdjustHeight=Height adjust:
 textAdjustWidth=Width adjust:
 
+sixelPaletteSize=Sixel Palette Size:
+
 unavailable=Unavailable
 builtInTerminus=Built-In Terminus
 sample=\ Sample Window\ 
index ca1d499594734c75275a53f90a7f5fb8aa9f9a56..cb9724c4d5b1bfff85d4e7600b04e6d3b31a01d0 100644 (file)
@@ -81,14 +81,6 @@ public class ECMA48Terminal extends LogicalScreen
         MOUSE_SGR,
     }
 
-    /**
-     * Number of colors in the sixel palette.  Xterm 335 defines the max as
-     * 1024.
-     */
-    private static final int MAX_COLOR_REGISTERS = 1024;
-    // Black-and-white is possible too.
-    // private static final int MAX_COLOR_REGISTERS = 2;
-
     // ------------------------------------------------------------------------
     // Variables --------------------------------------------------------------
     // ------------------------------------------------------------------------
@@ -200,6 +192,13 @@ public class ECMA48Terminal extends LogicalScreen
      */
     private SixelCache sixelCache = null;
 
+    /**
+     * Number of colors in the sixel palette.  Xterm 335 defines the max as
+     * 1024.  Valid values are: 2 (black and white), 256, 512, 1024, and
+     * 2048.
+     */
+    private int sixelPaletteSize = 1024;
+
     /**
      * If true, then we changed System.in and need to change it back.
      */
@@ -234,7 +233,7 @@ public class ECMA48Terminal extends LogicalScreen
 
     /**
      * SixelPalette is used to manage the conversion of images between 24-bit
-     * RGB color and a palette of MAX_COLOR_REGISTERS colors.
+     * RGB color and a palette of sixelPaletteSize colors.
      */
     private class SixelPalette {
 
@@ -247,7 +246,7 @@ public class ECMA48Terminal extends LogicalScreen
          * Map of color palette index for sixel output, from the order it was
          * generated by makePalette() to rgbColors.
          */
-        private int [] rgbSortedIndex = new int[MAX_COLOR_REGISTERS];
+        private int [] rgbSortedIndex = new int[sixelPaletteSize];
 
         /**
          * The color palette, organized by hue, saturation, and luminance.
@@ -345,7 +344,7 @@ public class ECMA48Terminal extends LogicalScreen
             int green = (color >>>  8) & 0xFF;
             int blue  =  color         & 0xFF;
 
-            if (MAX_COLOR_REGISTERS == 2) {
+            if (sixelPaletteSize == 2) {
                 if (((red * red) + (green * green) + (blue * blue)) < 35568) {
                     // Black
                     return 0;
@@ -427,7 +426,7 @@ public class ECMA48Terminal extends LogicalScreen
                     ((255 - blue) * (255 - blue))) < diff) {
 
                 // White is a closer match.
-                idx = MAX_COLOR_REGISTERS - 1;
+                idx = sixelPaletteSize - 1;
             }
             assert (idx != -1);
             return idx;
@@ -450,7 +449,7 @@ public class ECMA48Terminal extends LogicalScreen
         }
 
         /**
-         * Dither an image to a MAX_COLOR_REGISTERS palette.  The dithered
+         * Dither an image to a sixelPaletteSize palette.  The dithered
          * image cells will contain indexes into the palette.
          *
          * @param image the image to dither
@@ -473,7 +472,7 @@ public class ECMA48Terminal extends LogicalScreen
                         imageY) & 0xFFFFFF;
                     int colorIdx = matchColor(oldPixel);
                     assert (colorIdx >= 0);
-                    assert (colorIdx < MAX_COLOR_REGISTERS);
+                    assert (colorIdx < sixelPaletteSize);
                     int newPixel = rgbColors.get(colorIdx);
                     ditheredImage.setRGB(imageX, imageY, colorIdx);
 
@@ -671,11 +670,11 @@ public class ECMA48Terminal extends LogicalScreen
         private void makePalette() {
             // Generate the sixel palette.  Because we have no idea at this
             // layer which image(s) will be shown, we have to use a common
-            // palette with MAX_COLOR_REGISTERS colors for everything, and
+            // palette with sixelPaletteSize colors for everything, and
             // map the BufferedImage colors to their nearest neighbor in RGB
             // space.
 
-            if (MAX_COLOR_REGISTERS == 2) {
+            if (sixelPaletteSize == 2) {
                 rgbColors.add(0);
                 rgbColors.add(0xFFFFFF);
                 rgbSortedIndex[0] = 0;
@@ -696,13 +695,13 @@ public class ECMA48Terminal extends LogicalScreen
             satBits = 2;
             lumBits = 1;
 
-            assert (MAX_COLOR_REGISTERS >= 256);
-            assert ((MAX_COLOR_REGISTERS == 256)
-                || (MAX_COLOR_REGISTERS == 512)
-                || (MAX_COLOR_REGISTERS == 1024)
-                || (MAX_COLOR_REGISTERS == 2048));
+            assert (sixelPaletteSize >= 256);
+            assert ((sixelPaletteSize == 256)
+                || (sixelPaletteSize == 512)
+                || (sixelPaletteSize == 1024)
+                || (sixelPaletteSize == 2048));
 
-            switch (MAX_COLOR_REGISTERS) {
+            switch (sixelPaletteSize) {
             case 512:
                 hueBits = 5;
                 satBits = 2;
@@ -788,7 +787,7 @@ public class ECMA48Terminal extends LogicalScreen
             }
             // System.err.printf("\n</body></html>\n");
 
-            assert (rgbColors.size() == MAX_COLOR_REGISTERS);
+            assert (rgbColors.size() == sixelPaletteSize);
 
             /*
              * We need to sort rgbColors, so that toSixel() can know where
@@ -800,19 +799,19 @@ public class ECMA48Terminal extends LogicalScreen
             Collections.sort(rgbColors);
             HashMap<Integer, Integer> rgbColorIndices = null;
             rgbColorIndices = new HashMap<Integer, Integer>();
-            for (int i = 0; i < MAX_COLOR_REGISTERS; i++) {
+            for (int i = 0; i < sixelPaletteSize; i++) {
                 rgbColorIndices.put(rgbColors.get(i), i);
             }
-            for (int i = 0; i < MAX_COLOR_REGISTERS; i++) {
+            for (int i = 0; i < sixelPaletteSize; i++) {
                 int rawColor = rawRgbList.get(i);
                 rgbSortedIndex[i] = rgbColorIndices.get(rawColor);
             }
             if (DEBUG) {
-                for (int i = 0; i < MAX_COLOR_REGISTERS; i++) {
+                for (int i = 0; i < sixelPaletteSize; i++) {
                     assert (rawRgbList != null);
                     int idx = rgbSortedIndex[i];
                     int rgbColor = rgbColors.get(idx);
-                    if ((idx != 0) && (idx != MAX_COLOR_REGISTERS - 1)) {
+                    if ((idx != 0) && (idx != sixelPaletteSize - 1)) {
                         /*
                         System.err.printf("%d %06x --> %d %06x\n",
                             i, rawRgbList.get(i), idx, rgbColors.get(idx));
@@ -825,7 +824,7 @@ public class ECMA48Terminal extends LogicalScreen
             // Set the dimmest color as true black, and the brightest as true
             // white.
             rgbColors.set(0, 0);
-            rgbColors.set(MAX_COLOR_REGISTERS - 1, 0xFFFFFF);
+            rgbColors.set(sixelPaletteSize - 1, 0xFFFFFF);
 
             /*
             System.err.printf("<html><body>\n");
@@ -850,7 +849,7 @@ public class ECMA48Terminal extends LogicalScreen
         public String emitPalette(final StringBuilder sb,
             final boolean [] used) {
 
-            for (int i = 0; i < MAX_COLOR_REGISTERS; i++) {
+            for (int i = 0; i < sixelPaletteSize; i++) {
                 if (((used != null) && (used[i] == true)) || (used == null)) {
                     int rgbColor = rgbColors.get(i);
                     sb.append(String.format("#%d;2;%d;%d;%d", i,
@@ -1380,6 +1379,27 @@ public class ECMA48Terminal extends LogicalScreen
         } else {
             sixel = false;
         }
+
+        // Palette size
+        int paletteSize = 1024;
+        try {
+            paletteSize = Integer.parseInt(System.getProperty(
+                "jexer.ECMA48.sixelPaletteSize", "1024"));
+            switch (paletteSize) {
+            case 2:
+            case 256:
+            case 512:
+            case 1024:
+            case 2048:
+                sixelPaletteSize = paletteSize;
+                break;
+            default:
+                // Ignore value
+                break;
+            }
+        } catch (NumberFormatException e) {
+            // SQUASH
+        }
     }
 
     // ------------------------------------------------------------------------
@@ -2748,6 +2768,46 @@ public class ECMA48Terminal extends LogicalScreen
     // Sixel output support ---------------------------------------------------
     // ------------------------------------------------------------------------
 
+    /**
+     * Get the number of colors in the sixel palette.
+     *
+     * @return the palette size
+     */
+    public int getSixelPaletteSize() {
+        return sixelPaletteSize;
+    }
+
+    /**
+     * Set the number of colors in the sixel palette.
+     *
+     * @param paletteSize the new palette size
+     */
+    public void setSixelPaletteSize(final int paletteSize) {
+        if (paletteSize == sixelPaletteSize) {
+            return;
+        }
+
+        switch (paletteSize) {
+        case 2:
+        case 256:
+        case 512:
+        case 1024:
+        case 2048:
+            break;
+        default:
+            throw new IllegalArgumentException("Unsupported sixel palette " +
+                " size: " + paletteSize);
+        }
+
+        // Don't step on the screen refresh thread.
+        synchronized (this) {
+            sixelPaletteSize = paletteSize;
+            palette = null;
+            sixelCache = null;
+            clearPhysical();
+        }
+    }
+
     /**
      * Start a sixel string for display one row's worth of bitmap data.
      *
@@ -2944,7 +3004,7 @@ public class ECMA48Terminal extends LogicalScreen
 
         // Emit the palette, but only for the colors actually used by these
         // cells.
-        boolean [] usedColors = new boolean[MAX_COLOR_REGISTERS];
+        boolean [] usedColors = new boolean[sixelPaletteSize];
         for (int imageX = 0; imageX < image.getWidth(); imageX++) {
             for (int imageY = 0; imageY < image.getHeight(); imageY++) {
                 usedColors[image.getRGB(imageX, imageY)] = true;
@@ -2964,13 +3024,13 @@ public class ECMA48Terminal extends LogicalScreen
 
                     int colorIdx = image.getRGB(imageX, imageY + currentRow);
                     assert (colorIdx >= 0);
-                    assert (colorIdx < MAX_COLOR_REGISTERS);
+                    assert (colorIdx < sixelPaletteSize);
 
                     sixels[imageX][imageY] = colorIdx;
                 }
             }
 
-            for (int i = 0; i < MAX_COLOR_REGISTERS; i++) {
+            for (int i = 0; i < sixelPaletteSize; i++) {
                 boolean isUsed = false;
                 for (int imageX = 0; imageX < image.getWidth(); imageX++) {
                     for (int j = 0; j < 6; j++) {
@@ -3047,7 +3107,7 @@ public class ECMA48Terminal extends LogicalScreen
                     sb.append((char) oldData);
                 }
 
-            } // for (int i = 0; i < MAX_COLOR_REGISTERS; i++)
+            } // for (int i = 0; i < sixelPaletteSize; i++)
 
             // Advance to the next scan line.
             sb.append("-");
index 85057037ec188e65184debba167945f5dc0a4d0a..3e4cbe92d56bcde373a7c6ec1d05e2327e86c0b1 100644 (file)
@@ -135,7 +135,10 @@ public class DemoApplication extends TApplication {
      * @throws Exception if TApplication can't instantiate the Backend.
      */
     public DemoApplication(final BackendType backendType) throws Exception {
-        super(backendType);
+        // For the Swing demo, use an initial size of 82x28 so that a
+        // terminal window precisely fits the window.
+        super(backendType, (backendType == BackendType.SWING ? 82 : -1),
+            (backendType == BackendType.SWING ? 28 : -1), 20);
         addAllWidgets();
         getBackend().setTitle(i18n.getString("applicationTitle"));
     }
index 58228f9900d1c311bf947be32410da6f0ea50427..75802439cce48c373b82384e36dc24b4b02c3a7c 100644 (file)
@@ -62,7 +62,7 @@ public class TMenu extends TWindow {
     // Tools menu
     public static final int MID_REPAINT         = 1;
     public static final int MID_VIEW_IMAGE      = 2;
-    public static final int MID_CHANGE_FONT     = 3;
+    public static final int MID_SCREEN_OPTIONS  = 3;
 
     // File menu
     public static final int MID_NEW             = 10;
@@ -565,8 +565,8 @@ public class TMenu extends TWindow {
             label = i18n.getString("menuViewImage");
             break;
 
-        case MID_CHANGE_FONT:
-            label = i18n.getString("menuChangeFont");
+        case MID_SCREEN_OPTIONS:
+            label = i18n.getString("menuScreenOptions");
             break;
 
         case MID_NEW:
index c31269a27e61924240b5c2878bf9edea17fe92b1..1581d0bd2491235cbf45d26fcb663ab4dfb5672f 100644 (file)
@@ -58,4 +58,4 @@ menuTableFileSaveText=Save As &Text...
 
 menuRepaintDesktop=&Repaint desktop
 menuViewImage=&Open image...
-menuChangeFont=Change &font...
+menuScreenOptions=&Screen options...