X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Ftterminal%2FSixel.java;h=a4c00fc67f1da1ca38847b9bb5dad63daac5e006;hb=12b90437b5f22c2ae6e9b9b14c3b62b60f6143e5;hp=de3232c6588da3b1e6445a8d031b3804f8ab69eb;hpb=69a8c36844309a07dfe7c8c7576d9c0e47be3303;p=nikiroo-utils.git diff --git a/src/jexer/tterminal/Sixel.java b/src/jexer/tterminal/Sixel.java index de3232c..a4c00fc 100644 --- a/src/jexer/tterminal/Sixel.java +++ b/src/jexer/tterminal/Sixel.java @@ -48,7 +48,7 @@ public class Sixel { */ private enum ScanState { GROUND, - QUOTE, + RASTER, COLOR, REPEAT, } @@ -72,15 +72,30 @@ public class Sixel { */ private static int HEIGHT_INCREASE = 400; + /** + * Maximum width in pixels. + */ + private static int MAX_WIDTH = 1000; + + /** + * Maximum height in pixels. + */ + private static int MAX_HEIGHT = 1000; + /** * Current scanning state. */ private ScanState scanState = ScanState.GROUND; /** - * Parameter characters being collected. + * Parameters being collected. */ - private ArrayList colorParams; + private int [] params = new int[5]; + + /** + * Current parameter being collected. + */ + private int paramsI = 0; /** * The sixel palette colors specified. @@ -107,6 +122,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. */ @@ -117,11 +142,21 @@ public class Sixel { */ private int x = 0; + /** + * The maximum y drawn to. This will set the final image height. + */ + private int y = 0; + /** * The current drawing color. */ private Color color = Color.BLACK; + /** + * If set, abort processing this image. + */ + private boolean abort = false; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -130,14 +165,14 @@ public class Sixel { * Public constructor. * * @param buffer the sixel data to parse + * @param palette palette to use, or null for a private palette */ - public Sixel(final String buffer) { + public Sixel(final String buffer, final HashMap palette) { this.buffer = buffer; - colorParams = new ArrayList(); - palette = new HashMap(); - image = new BufferedImage(200, 100, BufferedImage.TYPE_INT_ARGB); - for (int i = 0; i < buffer.length(); i++) { - consume(buffer.charAt(i)); + if (palette == null) { + this.palette = new HashMap(); + } else { + this.palette = palette; } } @@ -151,8 +186,27 @@ public class Sixel { * @return the sixel data as an image. */ public BufferedImage getImage() { - if ((width > 0) && (height > 0)) { - return image.getSubimage(0, 0, width, height + 6); + if (buffer != null) { + for (int i = 0; (i < buffer.length()) && (abort == false); i++) { + consume(buffer.charAt(i)); + } + buffer = null; + } + if (abort == true) { + return null; + } + + 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; } @@ -167,6 +221,16 @@ 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); + } + Graphics2D gr = newImage.createGraphics(); gr.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); gr.dispose(); @@ -177,32 +241,14 @@ public class Sixel { * Clear the parameters and flags. */ private void toGround() { - colorParams.clear(); + paramsI = 0; + for (int i = 0; i < params.length; i++) { + params[i] = 0; + } scanState = ScanState.GROUND; repeatCount = -1; } - /** - * Save a byte into the color parameters buffer. - * - * @param ch byte to save - */ - private void param(final byte ch) { - if (colorParams.size() == 0) { - colorParams.add(Integer.valueOf(0)); - } - Integer n = colorParams.get(colorParams.size() - 1); - if ((ch >= '0') && (ch <= '9')) { - n *= 10; - n += (ch - '0'); - colorParams.set(colorParams.size() - 1, n); - } - - if ((ch == ';') && (colorParams.size() < 16)) { - colorParams.add(Integer.valueOf(0)); - } - } - /** * Get a color parameter value, with a default. * @@ -210,11 +256,11 @@ 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) { - if (colorParams.size() < position + 1) { + private int getParam(final int position, final int defaultValue) { + if (position > paramsI) { return defaultValue; } - return colorParams.get(position).intValue(); + return params[position]; } /** @@ -226,11 +272,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; } @@ -247,6 +293,12 @@ public class Sixel { */ private void addSixel(final char ch) { int n = ((int) ch - 63); + + if (DEBUG && (color == null)) { + System.err.println("color is null?!"); + System.err.println(buffer); + } + int rgb = color.getRGB(); int rep = (repeatCount == -1 ? 1 : repeatCount); @@ -257,6 +309,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. @@ -270,33 +327,51 @@ public class Sixel { if (x > width) { width = x; } + if (width > MAX_WIDTH) { + abort = true; + } return; } + int dy = 0; for (int i = 0; i < rep; i++) { if ((n & 0x01) != 0) { - image.setRGB(x, height + 0, rgb); + dy = 0; + image.setRGB(x, height + dy, rgb); } if ((n & 0x02) != 0) { - image.setRGB(x, height + 1, rgb); + dy = 1; + image.setRGB(x, height + dy, rgb); } if ((n & 0x04) != 0) { - image.setRGB(x, height + 2, rgb); + dy = 2; + image.setRGB(x, height + dy, rgb); } if ((n & 0x08) != 0) { - image.setRGB(x, height + 3, rgb); + dy = 3; + image.setRGB(x, height + dy, rgb); } if ((n & 0x10) != 0) { - image.setRGB(x, height + 4, rgb); + dy = 4; + image.setRGB(x, height + dy, rgb); } if ((n & 0x20) != 0) { - image.setRGB(x, height + 5, rgb); + dy = 5; + image.setRGB(x, height + dy, rgb); } - x++; - if (x > width) { - width++; - assert (x == width); + if (height + dy > y) { + y = height + dy; } + x++; + } + if (x > width) { + width = x; + } + if (width > MAX_WIDTH) { + abort = true; + } + if (y + 1 > MAX_HEIGHT) { + abort = true; } } @@ -304,14 +379,17 @@ public class Sixel { * Process a color palette change. */ private void setPalette() { - int idx = getColorParam(0, 0); + int idx = getParam(0, 0); - if (colorParams.size() == 1) { + if (paramsI == 0) { Color newColor = palette.get(idx); if (newColor != null) { color = newColor; } else { - System.err.println("COLOR " + idx + " NOT FOUND"); + if (DEBUG) { + System.err.println("COLOR " + idx + " NOT FOUND"); + } + color = Color.BLACK; } if (DEBUG) { @@ -320,10 +398,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); @@ -339,6 +417,28 @@ 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; + if ((rasterWidth <= MAX_WIDTH) && (rasterHeight <= MAX_HEIGHT)) { + resizeImage(rasterWidth, rasterHeight); + } else { + abort = true; + } + } else { + abort = true; + } + } + /** * Run this input character through the sixel state machine. * @@ -353,6 +453,9 @@ public class Sixel { if ((ch >= 63) && (ch < 127)) { if (scanState == ScanState.COLOR) { setPalette(); + } + if (scanState == ScanState.RASTER) { + parseRaster(); toGround(); } addSixel(ch); @@ -366,6 +469,10 @@ public class Sixel { setPalette(); toGround(); } + if (scanState == ScanState.RASTER) { + parseRaster(); + toGround(); + } scanState = ScanState.COLOR; return; } @@ -376,6 +483,10 @@ public class Sixel { setPalette(); toGround(); } + if (scanState == ScanState.RASTER) { + parseRaster(); + toGround(); + } scanState = ScanState.REPEAT; repeatCount = 0; return; @@ -386,15 +497,20 @@ public class Sixel { setPalette(); toGround(); } + if (scanState == ScanState.RASTER) { + parseRaster(); + toGround(); + } - if (height + 6 < image.getHeight()) { + height += 6; + x = 0; + + if (height + 6 > image.getHeight()) { // Resize the image, give us another HEIGHT_INCREASE // pixels of vertical length. resizeImage(image.getWidth(), image.getHeight() + HEIGHT_INCREASE); } - height += 6; - x = 0; return; } @@ -403,6 +519,10 @@ public class Sixel { setPalette(); toGround(); } + if (scanState == ScanState.RASTER) { + parseRaster(); + toGround(); + } x = 0; return; } @@ -412,7 +532,7 @@ public class Sixel { setPalette(); toGround(); } - scanState = ScanState.QUOTE; + scanState = ScanState.RASTER; return; } @@ -425,17 +545,29 @@ 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: // 30-39, 3B --> param if ((ch >= '0') && (ch <= '9')) { - param((byte) ch); + params[paramsI] *= 10; + params[paramsI] += (ch - '0'); } if (ch == ';') { - param((byte) ch); + if (paramsI < params.length - 1) { + paramsI++; + } } return;