#57 parse raster attribute in terminal sixel
authorKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 31 Aug 2019 18:15:15 +0000 (13:15 -0500)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 31 Aug 2019 18:15:15 +0000 (13:15 -0500)
src/jexer/tterminal/Sixel.java

index f19087770f82e37d1a7474b0d2db42ac2098d0c7..8e363ef125c6830f2ad759aefff42a4a56179db2 100644 (file)
@@ -48,7 +48,7 @@ public class Sixel {
      */
     private enum ScanState {
         GROUND,
-        QUOTE,
+        RASTER,
         COLOR,
         REPEAT,
     }
@@ -112,6 +112,16 @@ public class Sixel {
      */
     private int height = 0;
 
+    /**
+     * The width of image provided in the raster attribute.
+     */
+    private int rasterWidth = 0;
+
+    /**
+     * The height of image provided in the raster attribute.
+     */
+    private int rasterHeight = 0;
+
     /**
      * The repeat count.
      */
@@ -144,7 +154,6 @@ public class Sixel {
     public Sixel(final String buffer) {
         this.buffer = buffer;
         palette = new HashMap<Integer, Color>();
-        image = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB);
         for (int i = 0; i < buffer.length(); i++) {
             consume(buffer.charAt(i));
         }
@@ -160,7 +169,16 @@ public class Sixel {
      * @return the sixel data as an image.
      */
     public BufferedImage getImage() {
-        if ((width > 0) && (height > 0)) {
+        if ((width > 0) && (height > 0) && (image != null)) {
+            /*
+            System.err.println(String.format("%d %d %d %d", width, y + 1,
+                    rasterWidth, rasterHeight));
+            */
+
+            if ((rasterWidth > width) || (rasterHeight > y + 1)) {
+                resizeImage(Math.max(width, rasterWidth),
+                    Math.max(y + 1, rasterHeight));
+            }
             return image.getSubimage(0, 0, width, y + 1);
         }
         return null;
@@ -176,6 +194,11 @@ public class Sixel {
         BufferedImage newImage = new BufferedImage(newWidth, newHeight,
             BufferedImage.TYPE_INT_ARGB);
 
+        if (image == null) {
+            image = newImage;
+            return;
+        }
+
         if (DEBUG) {
             System.err.println("resizeImage(); old " + image.getWidth() + "x" +
                 image.getHeight() + " new " + newWidth + "x" + newHeight);
@@ -206,7 +229,7 @@ public class Sixel {
      * @param defaultValue value to use if colorParams[position] doesn't exist
      * @return parameter value
      */
-    private int getColorParam(final int position, final int defaultValue) {
+    private int getParam(final int position, final int defaultValue) {
         if (position > paramsI) {
             return defaultValue;
         }
@@ -222,11 +245,11 @@ public class Sixel {
      * @param maxValue maximum value inclusive
      * @return parameter value
      */
-    private int getColorParam(final int position, final int defaultValue,
+    private int getParam(final int position, final int defaultValue,
         final int minValue, final int maxValue) {
 
         assert (minValue <= maxValue);
-        int value = getColorParam(position, defaultValue);
+        int value = getParam(position, defaultValue);
         if (value < minValue) {
             value = minValue;
         }
@@ -259,6 +282,11 @@ public class Sixel {
 
         assert (n >= 0);
 
+        if (image == null) {
+            // The raster attributes was not provided.
+            resizeImage(WIDTH_INCREASE, HEIGHT_INCREASE);
+        }
+
         if (x + rep > image.getWidth()) {
             // Resize the image, give us another max(rep, WIDTH_INCREASE)
             // pixels of horizontal length.
@@ -315,7 +343,7 @@ public class Sixel {
      * Process a color palette change.
      */
     private void setPalette() {
-        int idx = getColorParam(0, 0);
+        int idx = getParam(0, 0);
 
         if (paramsI == 0) {
             Color newColor = palette.get(idx);
@@ -334,10 +362,10 @@ public class Sixel {
             return;
         }
 
-        int type = getColorParam(1, 0);
-        float red   = (float) (getColorParam(2, 0, 0, 100) / 100.0);
-        float green = (float) (getColorParam(3, 0, 0, 100) / 100.0);
-        float blue  = (float) (getColorParam(4, 0, 0, 100) / 100.0);
+        int type = getParam(1, 0);
+        float red   = (float) (getParam(2, 0, 0, 100) / 100.0);
+        float green = (float) (getParam(3, 0, 0, 100) / 100.0);
+        float blue  = (float) (getParam(4, 0, 0, 100) / 100.0);
 
         if (type == 2) {
             Color newColor = new Color(red, green, blue);
@@ -353,6 +381,22 @@ public class Sixel {
         }
     }
 
+    /**
+     * Parse the raster attributes.
+     */
+    private void parseRaster() {
+        int pan = getParam(0, 0);  // Aspect ratio numerator
+        int pad = getParam(1, 0);  // Aspect ratio denominator
+        int pah = getParam(2, 0);  // Horizontal width
+        int pav = getParam(3, 0);  // Vertical height
+
+        if ((pan == pad) && (pah > 0) && (pav > 0)) {
+            rasterWidth = pah;
+            rasterHeight = pav;
+            resizeImage(rasterWidth, rasterHeight);
+        }
+    }
+
     /**
      * Run this input character through the sixel state machine.
      *
@@ -368,6 +412,10 @@ public class Sixel {
             if (scanState == ScanState.COLOR) {
                 setPalette();
             }
+            if (scanState == ScanState.RASTER) {
+                parseRaster();
+                toGround();
+            }
             addSixel(ch);
             toGround();
             return;
@@ -379,6 +427,10 @@ public class Sixel {
                 setPalette();
                 toGround();
             }
+            if (scanState == ScanState.RASTER) {
+                parseRaster();
+                toGround();
+            }
             scanState = ScanState.COLOR;
             return;
         }
@@ -389,6 +441,10 @@ public class Sixel {
                 setPalette();
                 toGround();
             }
+            if (scanState == ScanState.RASTER) {
+                parseRaster();
+                toGround();
+            }
             scanState = ScanState.REPEAT;
             repeatCount = 0;
             return;
@@ -399,6 +455,10 @@ public class Sixel {
                 setPalette();
                 toGround();
             }
+            if (scanState == ScanState.RASTER) {
+                parseRaster();
+                toGround();
+            }
 
             height += 6;
             x = 0;
@@ -417,6 +477,10 @@ public class Sixel {
                 setPalette();
                 toGround();
             }
+            if (scanState == ScanState.RASTER) {
+                parseRaster();
+                toGround();
+            }
             x = 0;
             return;
         }
@@ -426,7 +490,7 @@ public class Sixel {
                 setPalette();
                 toGround();
             }
-            scanState = ScanState.QUOTE;
+            scanState = ScanState.RASTER;
             return;
         }
 
@@ -439,8 +503,17 @@ public class Sixel {
             }
             return;
 
-        case QUOTE:
-            // Ignore everything else in the quote header.
+        case RASTER:
+            // 30-39, 3B --> param
+            if ((ch >= '0') && (ch <= '9')) {
+                params[paramsI] *= 10;
+                params[paramsI] += (ch - '0');
+            }
+            if (ch == ';') {
+                if (paramsI < params.length - 1) {
+                    paramsI++;
+                }
+            }
             return;
 
         case COLOR: