]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/image/JPEGFileFormat.java
Work around SWT 4.13 - 4.18 Win32 DnD bug 567422
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / internal / image / JPEGFileFormat.java
diff --git a/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/image/JPEGFileFormat.java b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/image/JPEGFileFormat.java
new file mode 100644 (file)
index 0000000..0f5c6f8
--- /dev/null
@@ -0,0 +1,1894 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * This source file is based in part on the work of the Independent JPEG Group (IJG)
+ * and is made available under the terms contained in the about_files/IJG_README
+ * file accompanying this program.
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal.image;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import java.io.*;
+
+public final class JPEGFileFormat extends FileFormat {
+       int restartInterval;
+       JPEGFrameHeader frameHeader;
+       int imageWidth, imageHeight;
+       int interleavedMcuCols, interleavedMcuRows;
+       int maxV, maxH;
+       boolean progressive;
+       int samplePrecision;
+       int nComponents;
+       int[][] frameComponents;
+       int[] componentIds;
+       byte[][] imageComponents;
+       int[] dataUnit;
+       int[][][] dataUnits;
+       int[] precedingDCs;
+       JPEGScanHeader scanHeader;
+       byte[] dataBuffer;
+       int currentBitCount;
+       int bufferCurrentPosition;
+       int restartsToGo;
+       int nextRestartNumber;
+       JPEGHuffmanTable[] acHuffmanTables;
+       JPEGHuffmanTable[] dcHuffmanTables;
+       int[][] quantizationTables;
+       int currentByte;
+       int encoderQFactor = 75;
+       int eobrun = 0;
+       /* JPEGConstants */
+       public static final int DCTSIZE = 8;
+       public static final int DCTSIZESQR = 64;
+       /* JPEGFixedPointConstants */
+       public static final int FIX_0_899976223 = 7373;
+       public static final int FIX_1_961570560 = 16069;
+       public static final int FIX_2_053119869 = 16819;
+       public static final int FIX_0_298631336 = 2446;
+       public static final int FIX_1_847759065 = 15137;
+       public static final int FIX_1_175875602 = 9633;
+       public static final int FIX_3_072711026 = 25172;
+       public static final int FIX_0_765366865 = 6270;
+       public static final int FIX_2_562915447 = 20995;
+       public static final int FIX_0_541196100 = 4433;
+       public static final int FIX_0_390180644 = 3196;
+       public static final int FIX_1_501321110 = 12299;
+       /* JPEGMarkerCodes */
+       public static final int APP0  = 0xFFE0;
+       public static final int APP15 = 0xFFEF;
+       public static final int COM   = 0xFFFE;
+       public static final int DAC   = 0xFFCC;
+       public static final int DHP   = 0xFFDE;
+       public static final int DHT   = 0xFFC4;
+       public static final int DNL   = 0xFFDC;
+       public static final int DRI   = 0xFFDD;
+       public static final int DQT   = 0xFFDB;
+       public static final int EOI   = 0xFFD9;
+       public static final int EXP   = 0xFFDF;
+       public static final int JPG   = 0xFFC8;
+       public static final int JPG0  = 0xFFF0;
+       public static final int JPG13 = 0xFFFD;
+       public static final int RST0  = 0xFFD0;
+       public static final int RST1  = 0xFFD1;
+       public static final int RST2  = 0xFFD2;
+       public static final int RST3  = 0xFFD3;
+       public static final int RST4  = 0xFFD4;
+       public static final int RST5  = 0xFFD5;
+       public static final int RST6  = 0xFFD6;
+       public static final int RST7  = 0xFFD7;
+       public static final int SOF0  = 0xFFC0;
+       public static final int SOF1  = 0xFFC1;
+       public static final int SOF2  = 0xFFC2;
+       public static final int SOF3  = 0xFFC3;
+       public static final int SOF5  = 0xFFC5;
+       public static final int SOF6  = 0xFFC6;
+       public static final int SOF7  = 0xFFC7;
+       public static final int SOF9  = 0xFFC9;
+       public static final int SOF10 = 0xFFCA;
+       public static final int SOF11 = 0xFFCB;
+       public static final int SOF13 = 0xFFCD;
+       public static final int SOF14 = 0xFFCE;
+       public static final int SOF15 = 0xFFCF;
+       public static final int SOI   = 0xFFD8;
+       public static final int SOS   = 0xFFDA;
+       public static final int TEM   = 0xFF01;
+       /* JPEGFrameComponentParameterConstants */
+       public static final int TQI     = 0;
+       public static final int HI      = 1;
+       public static final int VI      = 2;
+       public static final int CW      = 3;
+       public static final int CH      = 4;
+       /* JPEGScanComponentParameterConstants */
+       public static final int DC      = 0;
+       public static final int AC      = 1;
+       /* JFIF Component Constants */
+       public static final int ID_Y            = 1 - 1;
+       public static final int ID_CB   = 2 - 1;
+       public static final int ID_CR   = 3 - 1;
+       public static final RGB[] RGB16 = new RGB[] {
+               new RGB(0,0,0),
+               new RGB(0x80,0,0),
+               new RGB(0,0x80,0),
+               new RGB(0x80,0x80,0),
+               new RGB(0,0,0x80),
+               new RGB(0x80,0,0x80),
+               new RGB(0,0x80,0x80),
+               new RGB(0xC0,0xC0,0xC0),
+               new RGB(0x80,0x80,0x80),
+               new RGB(0xFF,0,0),
+               new RGB(0,0xFF,0),
+               new RGB(0xFF,0xFF,0),
+               new RGB(0,0,0xFF),
+               new RGB(0xFF,0,0xFF),
+               new RGB(0,0xFF,0xFF),
+               new RGB(0xFF,0xFF,0xFF),
+       };
+       public static final int[] ExtendTest = {
+               0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
+               4096, 8192, 16384, 32768, 65536, 131072, 262144
+       };
+       public static final int[] ExtendOffset = new int[] {
+               0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047,
+               -4095, -8191, -16383, -32767, -65535, -131071, -262143
+       };
+       public static final int[] ZigZag8x8 = {
+               0, 1, 8, 16, 9, 2, 3, 10,
+               17, 24, 32, 25, 18, 11, 4, 5,
+               12, 19, 26, 33, 40, 48, 41, 34,
+               27, 20, 13, 6, 7, 14, 21, 28,
+               35, 42, 49, 56, 57, 50, 43, 36,
+               29, 22, 15, 23, 30, 37, 44, 51,
+               58, 59, 52, 45, 38, 31, 39, 46,
+               53, 60, 61, 54, 47, 55, 62, 63
+       };
+
+       public static final int[] CrRTable, CbBTable, CrGTable, CbGTable;
+       public static final int[] RYTable, GYTable, BYTable,
+               RCbTable, GCbTable, BCbTable, RCrTable, GCrTable, BCrTable, NBitsTable;
+       static {
+               /* Initialize RGB-YCbCr Tables */
+               int [] rYTable = new int[256];
+               int [] gYTable = new int[256];
+               int [] bYTable = new int[256];
+               int [] rCbTable = new int[256];
+               int [] gCbTable = new int[256];
+               int [] bCbTable = new int[256];
+               int [] gCrTable = new int[256];
+               int [] bCrTable = new int[256];
+               for (int i = 0; i < 256; i++) {
+                       rYTable[i] = i * 19595;
+                       gYTable[i] = i * 38470;
+                       bYTable[i] = i * 7471 + 32768;
+                       rCbTable[i] = i * -11059;
+                       gCbTable[i] = i * -21709;
+                       bCbTable[i] = i * 32768 + 8388608;
+                       gCrTable[i] = i * -27439;
+                       bCrTable[i] = i * -5329;
+               }
+               RYTable = rYTable;
+               GYTable = gYTable;
+               BYTable = bYTable;
+               RCbTable = rCbTable;
+               GCbTable = gCbTable;
+               BCbTable = bCbTable;
+               RCrTable = bCbTable;
+               GCrTable = gCrTable;
+               BCrTable = bCrTable;
+
+               /* Initialize YCbCr-RGB Tables */
+               int [] crRTable = new int[256];
+               int [] cbBTable = new int[256];
+               int [] crGTable = new int[256];
+               int [] cbGTable = new int[256];
+               for (int i = 0; i < 256; i++) {
+                       int x2 = 2 * i - 255;
+                       crRTable[i] = (45941 * x2 + 32768) >> 16;
+                       cbBTable[i] = (58065 * x2 + 32768) >> 16;
+                       crGTable[i] = -23401 * x2;
+                       cbGTable[i] = -11277 * x2 + 32768;
+               }
+               CrRTable = crRTable;
+               CbBTable = cbBTable;
+               CrGTable = crGTable;
+               CbGTable = cbGTable;
+
+               /* Initialize BitCount Table */
+               int nBits = 1;
+               int power2 = 2;
+               int [] nBitsTable = new int[2048];
+               nBitsTable[0] = 0;
+               for (int i = 1; i < nBitsTable.length; i++) {
+                       if (!(i < power2)) {
+                               nBits++;
+                               power2 *= 2;
+                       }
+                       nBitsTable[i] = nBits;
+               }
+               NBitsTable = nBitsTable;
+       }
+void compress(ImageData image, byte[] dataYComp, byte[] dataCbComp, byte[] dataCrComp) {
+       int srcWidth = image.width;
+       int srcHeight = image.height;
+       int vhFactor = maxV * maxH;
+       int[] frameComponent;
+       imageComponents = new byte[nComponents][];
+       for (int i = 0; i < nComponents; i++) {
+               frameComponent = frameComponents[componentIds[i]];
+               imageComponents[i] = new byte[frameComponent[CW] * frameComponent[CH]];
+       }
+       frameComponent = frameComponents[componentIds[ID_Y]];
+       for (int yPos = 0; yPos < srcHeight; yPos++) {
+               int srcOfs = yPos * srcWidth;
+               int dstOfs = yPos * frameComponent[CW];
+               System.arraycopy(dataYComp, srcOfs, imageComponents[ID_Y], dstOfs, srcWidth);
+       }
+       frameComponent = frameComponents[componentIds[ID_CB]];
+       for (int yPos = 0; yPos < srcHeight / maxV; yPos++) {
+               int destRowIndex = yPos * frameComponent[CW];
+               for (int xPos = 0; xPos < srcWidth / maxH; xPos++) {
+                       int sum = 0;
+                       for (int iv = 0; iv < maxV; iv++) {
+                               int srcIndex = (yPos * maxV + iv) * srcWidth + (xPos * maxH);
+                               for (int ih = 0; ih < maxH; ih++) {
+                                       sum += dataCbComp[srcIndex + ih] & 0xFF;
+                               }
+                       }
+                       imageComponents[ID_CB][destRowIndex + xPos] = (byte)(sum / vhFactor);
+               }
+       }
+       frameComponent = frameComponents[componentIds[ID_CR]];
+       for (int yPos = 0; yPos < srcHeight / maxV; yPos++) {
+               int destRowIndex = yPos * frameComponent[CW];
+               for (int xPos = 0; xPos < srcWidth / maxH; xPos++) {
+                       int sum = 0;
+                       for (int iv = 0; iv < maxV; iv++) {
+                               int srcIndex = (yPos * maxV + iv) * srcWidth + (xPos * maxH);
+                               for (int ih = 0; ih < maxH; ih++) {
+                                       sum += dataCrComp[srcIndex + ih] & 0xFF;
+                               }
+                       }
+                       imageComponents[ID_CR][destRowIndex + xPos] = (byte)(sum / vhFactor);
+               }
+       }
+       for (int iComp = 0; iComp < nComponents; iComp++) {
+               byte[] imageComponent = imageComponents[iComp];
+               frameComponent = frameComponents[componentIds[iComp]];
+               int hFactor = frameComponent[HI];
+               int vFactor = frameComponent[VI];
+               int componentWidth = frameComponent[CW];
+               int componentHeight = frameComponent[CH];
+               int compressedWidth = srcWidth / (maxH / hFactor);
+               int compressedHeight = srcHeight / (maxV / vFactor);
+               if (compressedWidth < componentWidth) {
+                       int delta = componentWidth - compressedWidth;
+                       for (int yPos = 0; yPos < compressedHeight; yPos++) {
+                               int dstOfs = ((yPos + 1) * componentWidth - delta);
+                               int dataValue = imageComponent[(dstOfs > 0) ? dstOfs - 1 : 0] & 0xFF;
+                               for (int i = 0; i < delta; i++) {
+                                       imageComponent[dstOfs + i] = (byte)dataValue;
+                               }
+                       }
+               }
+               if (compressedHeight < componentHeight) {
+                       int srcOfs = (compressedHeight > 0) ? (compressedHeight - 1) * componentWidth : 1;
+                       for (int yPos = (compressedHeight > 0) ? compressedHeight : 1; yPos <= componentHeight; yPos++) {
+                               int dstOfs = (yPos - 1) * componentWidth;
+                               System.arraycopy(imageComponent, srcOfs, imageComponent, dstOfs, componentWidth);
+                       }
+               }
+       }
+}
+void convert4BitRGBToYCbCr(ImageData image) {
+       RGB[] rgbs = image.getRGBs();
+       int paletteSize = rgbs.length;
+       byte[] yComp = new byte[paletteSize];
+       byte[] cbComp = new byte[paletteSize];
+       byte[] crComp = new byte[paletteSize];
+       int srcWidth = image.width;
+       int srcHeight = image.height;
+       for (int i = 0; i < paletteSize; i++) {
+               RGB color = rgbs[i];
+               int r = color.red;
+               int g = color.green;
+               int b = color.blue;
+               int n = RYTable[r] + GYTable[g] + BYTable[b];
+               yComp[i] = (byte)(n >> 16);
+               if ((n < 0) && ((n & 0xFFFF) != 0)) yComp[i]--;
+               n = RCbTable[r] + GCbTable[g] + BCbTable[b];
+               cbComp[i] = (byte)(n >> 16);
+               if ((n < 0) && ((n & 0xFFFF) != 0)) cbComp[i]--;
+               n = RCrTable[r] + GCrTable[g] + BCrTable[b];
+               crComp[i] = (byte)(n >> 16);
+               if ((n < 0) && ((n & 0xFFFF) != 0)) crComp[i]--;
+       }
+       int bSize = srcWidth * srcHeight;
+       byte[] dataYComp = new byte[bSize];
+       byte[] dataCbComp = new byte[bSize];
+       byte[] dataCrComp = new byte[bSize];
+       byte[] origData = image.data;
+       int bytesPerLine = image.bytesPerLine;
+       int maxScanlineByte = srcWidth >> 1;
+       for (int yPos = 0; yPos < srcHeight; yPos++) {
+               for (int xPos = 0; xPos < maxScanlineByte; xPos++) {
+                       int srcIndex = yPos * bytesPerLine + xPos;
+                       int dstIndex = yPos * srcWidth + (xPos * 2);
+                       int value2 = origData[srcIndex] & 0xFF;
+                       int value1 = value2 >> 4;
+                       value2 &= 0x0F;
+                       dataYComp[dstIndex] = yComp[value1];
+                       dataCbComp[dstIndex] = cbComp[value1];
+                       dataCrComp[dstIndex] = crComp[value1];
+                       dataYComp[dstIndex + 1] = yComp[value2];
+                       dataCbComp[dstIndex + 1] = cbComp[value2];
+                       dataCrComp[dstIndex + 1] = crComp[value2];
+               }
+       }
+       compress(image, dataYComp, dataCbComp, dataCrComp);
+}
+void convert8BitRGBToYCbCr(ImageData image) {
+       RGB[] rgbs = image.getRGBs();
+       int paletteSize = rgbs.length;
+       byte[] yComp = new byte[paletteSize];
+       byte[] cbComp = new byte[paletteSize];
+       byte[] crComp = new byte[paletteSize];
+       int srcWidth = image.width;
+       int srcHeight = image.height;
+       for (int i = 0; i < paletteSize; i++) {
+               RGB color = rgbs[i];
+               int r = color.red;
+               int g = color.green;
+               int b = color.blue;
+               int n = RYTable[r] + GYTable[g] + BYTable[b];
+               yComp[i] = (byte)(n >> 16);
+               if ((n < 0) && ((n & 0xFFFF) != 0)) yComp[i]--;
+               n = RCbTable[r] + GCbTable[g] + BCbTable[b];
+               cbComp[i] = (byte)(n >> 16);
+               if ((n < 0) && ((n & 0xFFFF) != 0)) cbComp[i]--;
+               n = RCrTable[r] + GCrTable[g] + BCrTable[b];
+               crComp[i] = (byte)(n >> 16);
+               if ((n < 0) && ((n & 0xFFFF) != 0)) crComp[i]--;
+       }
+       int dstWidth = image.width;
+       int dstHeight = srcHeight;
+       int stride = ((srcWidth + 3) >> 2) << 2;
+       int bSize = dstWidth * dstHeight;
+       byte[] dataYComp = new byte[bSize];
+       byte[] dataCbComp = new byte[bSize];
+       byte[] dataCrComp = new byte[bSize];
+       byte[] origData = image.data;
+       for (int yPos = 0; yPos < srcHeight; yPos++) {
+               int srcRowIndex = yPos * stride;
+               int dstRowIndex = yPos * dstWidth;
+               for (int xPos = 0; xPos < srcWidth; xPos++) {
+                       int value = origData[srcRowIndex + xPos] & 0xFF;
+                       int dstIndex = dstRowIndex + xPos;
+                       dataYComp[dstIndex] = yComp[value];
+                       dataCbComp[dstIndex] = cbComp[value];
+                       dataCrComp[dstIndex] = crComp[value];
+               }
+       }
+       compress(image, dataYComp, dataCbComp, dataCrComp);
+}
+byte[] convertCMYKToRGB() {
+       /* Unsupported CMYK format. Answer an empty byte array. */
+       return new byte[0];
+}
+void convertImageToYCbCr(ImageData image) {
+       switch (image.depth) {
+               case 4:
+                       convert4BitRGBToYCbCr(image);
+                       return;
+               case 8:
+                       convert8BitRGBToYCbCr(image);
+                       return;
+               case 16:
+               case 24:
+               case 32:
+                       convertMultiRGBToYCbCr(image);
+                       return;
+               default:
+                       SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+       }
+       return;
+}
+void convertMultiRGBToYCbCr(ImageData image) {
+       int srcWidth = image.width;
+       int srcHeight = image.height;
+       int bSize = srcWidth * srcHeight;
+       byte[] dataYComp = new byte[bSize];
+       byte[] dataCbComp = new byte[bSize];
+       byte[] dataCrComp = new byte[bSize];
+       PaletteData palette = image.palette;
+       int[] buffer = new int[srcWidth];
+       if (palette.isDirect) {
+               int redMask = palette.redMask;
+               int greenMask = palette.greenMask;
+               int blueMask = palette.blueMask;
+               int redShift = palette.redShift;
+               int greenShift = palette.greenShift;
+               int blueShift = palette.blueShift;
+               for (int yPos = 0; yPos < srcHeight; yPos++) {
+                       image.getPixels(0, yPos, srcWidth, buffer, 0);
+                       int dstRowIndex = yPos * srcWidth;
+                       for (int xPos = 0; xPos < srcWidth; xPos++) {
+                               int pixel = buffer[xPos];
+                               int dstDataIndex = dstRowIndex + xPos;
+                               int r = pixel & redMask;
+                               r = (redShift < 0) ? r >>> -redShift : r << redShift;
+                               int g = pixel & greenMask;
+                               g = (greenShift < 0) ? g >>> -greenShift : g << greenShift;
+                               int b = pixel & blueMask;
+                               b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;
+                               dataYComp[dstDataIndex] = (byte)((RYTable[r] + GYTable[g] + BYTable[b]) >> 16);
+                               dataCbComp[dstDataIndex] = (byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) >> 16);
+                               dataCrComp[dstDataIndex] = (byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) >> 16);
+                       }
+               }
+       } else {
+               for (int yPos = 0; yPos < srcHeight; yPos++) {
+                       image.getPixels(0, yPos, srcWidth, buffer, 0);
+                       int dstRowIndex = yPos * srcWidth;
+                       for (int xPos = 0; xPos < srcWidth; xPos++) {
+                               int pixel = buffer[xPos];
+                               int dstDataIndex = dstRowIndex + xPos;
+                               RGB rgb = palette.getRGB(pixel);
+                               int r = rgb.red;
+                               int g = rgb.green;
+                               int b = rgb.blue;
+                               dataYComp[dstDataIndex] = (byte)((RYTable[r] + GYTable[g] + BYTable[b]) >> 16);
+                               dataCbComp[dstDataIndex] = (byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) >> 16);
+                               dataCrComp[dstDataIndex] = (byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) >> 16);
+                       }
+               }
+       }
+       compress(image, dataYComp, dataCbComp, dataCrComp);
+}
+byte[] convertYToRGB() {
+       int compWidth = frameComponents[componentIds[ID_Y]][CW];
+       int bytesPerLine = (((imageWidth * 8 + 7) / 8) + 3) / 4 * 4;
+       byte[] data = new byte[bytesPerLine * imageHeight];
+       byte[] yComp = imageComponents[ID_Y];
+       int destIndex = 0;
+       for (int i = 0; i < imageHeight; i++) {
+               int srcIndex = i * compWidth;
+               for (int j = 0; j < bytesPerLine; j++) {
+                       int y = yComp[srcIndex] & 0xFF;
+                       if (y < 0) {
+                               y = 0;
+                       } else {
+                               if (y > 255) y = 255;
+                       }
+                       if (j >= imageWidth) {
+                               y = 0;
+                       }
+                       data[destIndex] = (byte)y;
+                       srcIndex++;
+                       destIndex++;
+               }
+       }
+       return data;
+}
+byte[] convertYCbCrToRGB() {
+       /**
+        * Convert existing image components into an RGB format.
+        * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+        * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+        * The conversion equations to be implemented are therefore
+        *      R = Y                + 1.40200 * Cr
+        *      G = Y - 0.34414 * Cb - 0.71414 * Cr
+        *      B = Y + 1.77200 * Cb
+        * where Cb and Cr represent the incoming values less MAXJSAMPLE/2.
+        * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+        *
+        * To avoid floating-point arithmetic, we represent the fractional constants
+        * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+        * the products by 2^16, with appropriate rounding, to get the correct answer.
+        * Notice that Y, being an integral input, does not contribute any fraction
+        * so it need not participate in the rounding.
+        *
+        * For even more speed, we avoid doing any multiplications in the inner loop
+        * by precalculating the constants times Cb and Cr for all possible values.
+        * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+        * for 12-bit samples it is still acceptable.  It's not very reasonable for
+        * 16-bit samples, but if you want lossless storage you shouldn't be changing
+        * colorspace anyway.
+        * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
+        * values for the G calculation are left scaled up, since we must add them
+        * together before rounding.
+        */
+       int bSize = imageWidth * imageHeight * nComponents;
+       byte[] rgbData = new byte[bSize];
+       int destIndex = 0;
+       expandImageComponents();
+       byte[] yComp = imageComponents[ID_Y];
+       byte[] cbComp = imageComponents[ID_CB];
+       byte[] crComp = imageComponents[ID_CR];
+       int compWidth = frameComponents[componentIds[ID_Y]][CW];
+       for (int v = 0; v < imageHeight; v++) {
+               int srcIndex = v * compWidth;
+               for (int i = 0; i < imageWidth; i++) {
+                       int y = yComp[srcIndex] & 0xFF;
+                       int cb = cbComp[srcIndex] & 0xFF;
+                       int cr = crComp[srcIndex] & 0xFF;
+                       int r = y + CrRTable[cr];
+                       int g = y + ((CbGTable[cb] + CrGTable[cr]) >> 16);
+                       int b = y + CbBTable[cb];
+                       if (r < 0) {
+                               r = 0;
+                       } else {
+                               if (r > 255) r = 255;
+                       }
+                       if (g < 0) {
+                               g = 0;
+                       } else {
+                               if (g > 255) g = 255;
+                       }
+                       if (b < 0) {
+                               b = 0;
+                       } else {
+                               if (b > 255) b = 255;
+                       }
+                       rgbData[destIndex] = (byte)b;
+                       rgbData[destIndex + 1] = (byte)g;
+                       rgbData[destIndex + 2] = (byte)r;
+                       destIndex += 3;
+                       srcIndex++;
+               }
+       }
+       return rgbData;
+}
+void decodeACCoefficients(int[] dataUnit, int iComp) {
+       int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
+       JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
+       int k = 1;
+       while (k < 64) {
+               int rs = decodeUsingTable(acTable);
+               int r = rs >> 4;
+               int s = rs & 0xF;
+               if (s == 0) {
+                       if (r == 15) {
+                               k += 16;
+                       } else {
+                               break;
+                       }
+               } else {
+                       k += r;
+                       int bits = receive(s);
+                       dataUnit[ZigZag8x8[k]] = extendBy(bits, s);
+                       k++;
+               }
+       }
+}
+void decodeACFirstCoefficients(int[] dataUnit, int iComp, int start, int end, int approxBit) {
+       if (eobrun > 0) {
+               eobrun--;
+               return;
+       }
+       int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
+       JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
+       int k = start;
+       while (k <= end) {
+               int rs = decodeUsingTable(acTable);
+               int r = rs >> 4;
+               int s = rs & 0xF;
+               if (s == 0) {
+                       if (r == 15) {
+                               k += 16;
+                       } else {
+                               eobrun = (1 << r) + receive(r) - 1;
+                               break;
+                       }
+               } else {
+                       k += r;
+                       int bits = receive(s);
+                       dataUnit[ZigZag8x8[k]] = extendBy(bits, s) << approxBit;
+                       k++;
+               }
+       }
+}
+void decodeACRefineCoefficients(int[] dataUnit, int iComp, int start, int end, int approxBit) {
+       int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
+       JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
+       int k = start;
+       while (k <= end) {
+               if (eobrun > 0) {
+                       while (k <= end) {
+                               int zzIndex = ZigZag8x8[k];
+                               if (dataUnit[zzIndex] != 0) {
+                                       dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit);
+                               }
+                               k++;
+                       }
+                       eobrun--;
+               } else {
+                       int rs = decodeUsingTable(acTable);
+                       int r = rs >> 4;
+                       int s = rs & 0xF;
+                       if (s == 0) {
+                               if (r == 15) {
+                                       int zeros = 0;
+                                       while (zeros < 16 && k <= end) {
+                                               int zzIndex = ZigZag8x8[k];
+                                               if (dataUnit[zzIndex] != 0) {
+                                                       dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit);
+                                               } else {
+                                                       zeros++;
+                                               }
+                                               k++;
+                                       }
+                               } else {
+                                       eobrun = (1 << r) + receive(r);
+                               }
+                       } else {
+                               int bit = receive(s);
+                               int zeros = 0;
+                               int zzIndex = ZigZag8x8[k];
+                               while ((zeros < r || dataUnit[zzIndex] != 0) && k <= end) {
+                                       if (dataUnit[zzIndex] != 0) {
+                                               dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit);
+                                       } else {
+                                               zeros++;
+                                       }
+                                       k++;
+                                       zzIndex = ZigZag8x8[k];
+                               }
+                               if (bit != 0) {
+                                       dataUnit[zzIndex] = 1 << approxBit;
+                               } else {
+                                       dataUnit[zzIndex] = -1 << approxBit;
+                               }
+                               k++;
+                       }
+               }
+       }
+}
+int refineAC(int ac, int approxBit) {
+       if (ac > 0) {
+               int bit = nextBit();
+               if (bit != 0) {
+                       ac += 1 << approxBit;
+               }
+       } else if (ac < 0) {
+               int bit = nextBit();
+               if (bit != 0) {
+                       ac += -1 << approxBit;
+               }
+       }
+       return ac;
+}
+void decodeDCCoefficient(int[] dataUnit, int iComp, boolean first, int approxBit) {
+       int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
+       JPEGHuffmanTable dcTable = dcHuffmanTables[sParams[DC]];
+       int lastDC = 0;
+       if (progressive && !first) {
+               int bit = nextBit();
+               lastDC = dataUnit[0] + (bit << approxBit);
+       } else {
+               lastDC = precedingDCs[iComp];
+               int nBits = decodeUsingTable(dcTable);
+               if (nBits != 0) {
+                       int bits = receive(nBits);
+                       int diff = extendBy(bits, nBits);
+                       lastDC += diff;
+                       precedingDCs[iComp] = lastDC;
+               }
+               if (progressive) {
+                       lastDC = lastDC << approxBit;
+               }
+       }
+       dataUnit[0] = lastDC;
+}
+void dequantize(int[] dataUnit, int iComp) {
+       int[] qTable = quantizationTables[frameComponents[componentIds[iComp]][TQI]];
+       for (int i = 0; i < dataUnit.length; i++) {
+               int zzIndex = ZigZag8x8[i];
+               dataUnit[zzIndex] = dataUnit[zzIndex] * qTable[i];
+       }
+}
+byte[] decodeImageComponents() {
+       if (nComponents == 3) { // compIds 1, 2, 3
+               return convertYCbCrToRGB();
+       }
+//     if (nComponents == 3) { // compIds 1, 4, 5
+//             Unsupported CMYK format.
+//             return convertYIQToRGB();
+//     }
+       if (nComponents == 4) {
+               return convertCMYKToRGB();
+       }
+       return convertYToRGB();
+}
+void decodeMCUAtXAndY(int xmcu, int ymcu, int nComponentsInScan, boolean first, int start, int end, int approxBit) {
+       for (int iComp = 0; iComp < nComponentsInScan; iComp++) {
+               int scanComponent = iComp;
+               while (scanHeader.componentParameters[componentIds[scanComponent]] == null) {
+                       scanComponent++;
+               }
+               int[] frameComponent = frameComponents[componentIds[scanComponent]];
+               int hi = frameComponent[HI];
+               int vi = frameComponent[VI];
+               if (nComponentsInScan == 1) {
+                       hi = 1;
+                       vi = 1;
+               }
+               int compWidth = frameComponent[CW];
+               for (int ivi = 0; ivi < vi; ivi++) {
+                       for (int ihi = 0; ihi < hi; ihi++) {
+                               if (progressive) {
+                                       // Progressive: First scan - create a new data unit.
+                                       // Subsequent scans - refine the existing data unit.
+                                       int index = (ymcu * vi + ivi) * compWidth + xmcu * hi + ihi;
+                                       dataUnit = dataUnits[scanComponent][index];
+                                       if (dataUnit == null) {
+                                               dataUnit = new int[64];
+                                               dataUnits[scanComponent][index] = dataUnit;
+                                       }
+                               } else {
+                                       // Sequential: Clear and reuse the data unit buffer.
+                                       for (int i = 0; i < dataUnit.length; i++) {
+                                               dataUnit[i] = 0;
+                                       }
+                               }
+                               if (!progressive || scanHeader.isDCProgressiveScan()) {
+                                       decodeDCCoefficient(dataUnit, scanComponent, first, approxBit);
+                               }
+                               if (!progressive) {
+                                       decodeACCoefficients(dataUnit, scanComponent);
+                               } else {
+                                       if (scanHeader.isACProgressiveScan()) {
+                                               if (first) {
+                                                       decodeACFirstCoefficients(dataUnit, scanComponent, start, end, approxBit);
+                                               } else {
+                                                       decodeACRefineCoefficients(dataUnit, scanComponent, start, end, approxBit);
+                                               }
+                                       }
+                                       if (loader.hasListeners()) {
+                                               // Dequantization, IDCT, up-sampling and color conversion
+                                               // are done on a copy of the coefficient data in order to
+                                               // display the image incrementally.
+                                               int[] temp = dataUnit;
+                                               dataUnit = new int[64];
+                                               System.arraycopy(temp, 0, dataUnit, 0, 64);
+                                       }
+                               }
+                               if (!progressive || (progressive && loader.hasListeners())) {
+                                       dequantize(dataUnit, scanComponent);
+                                       inverseDCT(dataUnit);
+                                       storeData(dataUnit, scanComponent, xmcu, ymcu, hi, ihi, vi, ivi);
+                               }
+                       }
+               }
+       }
+}
+void decodeScan() {
+       if (progressive && !scanHeader.verifyProgressiveScan()) {
+               SWT.error(SWT.ERROR_INVALID_IMAGE);
+       }
+       int nComponentsInScan = scanHeader.getNumberOfImageComponents();
+       int mcuRowsInScan = interleavedMcuRows;
+       int mcusPerRow = interleavedMcuCols;
+       if (nComponentsInScan == 1) {
+               // Non-interleaved.
+               int scanComponent = 0;
+               while (scanHeader.componentParameters[componentIds[scanComponent]] == null) {
+                       scanComponent++;
+               }
+               int[] frameComponent = frameComponents[componentIds[scanComponent]];
+               int hi = frameComponent[HI];
+               int vi = frameComponent[VI];
+               int mcuWidth = DCTSIZE * maxH / hi;
+               int mcuHeight = DCTSIZE * maxV / vi;
+               mcusPerRow = (imageWidth + mcuWidth - 1) / mcuWidth;
+               mcuRowsInScan = (imageHeight + mcuHeight - 1) / mcuHeight;
+       }
+       boolean first = scanHeader.isFirstScan();
+       int start = scanHeader.getStartOfSpectralSelection();
+       int end = scanHeader.getEndOfSpectralSelection();
+       int approxBit = scanHeader.getApproxBitPositionLow();
+       restartsToGo = restartInterval;
+       nextRestartNumber = 0;
+       for (int ymcu = 0; ymcu < mcuRowsInScan; ymcu++) {
+               for (int xmcu = 0; xmcu < mcusPerRow; xmcu++) {
+                       if (restartInterval != 0) {
+                               if (restartsToGo == 0) processRestartInterval();
+                               restartsToGo--;
+                       }
+                       decodeMCUAtXAndY(xmcu, ymcu, nComponentsInScan, first, start, end, approxBit);
+               }
+       }
+}
+int decodeUsingTable(JPEGHuffmanTable huffmanTable) {
+       int i = 0;
+       int[] maxCodes = huffmanTable.getDhMaxCodes();
+       int[] minCodes = huffmanTable.getDhMinCodes();
+       int[] valPtrs = huffmanTable.getDhValPtrs();
+       int[] huffVals = huffmanTable.getDhValues();
+       int code = nextBit();
+       while (code > maxCodes[i]) {
+               code = code * 2 + nextBit();
+               i++;
+       }
+       int j = valPtrs[i] + code - minCodes[i];
+       return huffVals[j];
+}
+void emit(int huffCode, int nBits) {
+       if (nBits == 0) {
+               SWT.error(SWT.ERROR_INVALID_IMAGE);
+       }
+       int[] power2m1 = new int[] {
+               1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191,
+               16383, 32767, 65535, 131125
+       };
+       int code = (huffCode & power2m1[nBits - 1]) << (24 - nBits - currentBitCount);
+       byte[] codeBuffer = new byte[4];
+       codeBuffer[0] = (byte)(code & 0xFF);
+       codeBuffer[1] = (byte)((code >> 8) & 0xFF);
+       codeBuffer[2] = (byte)((code >> 16) & 0xFF);
+       codeBuffer[3] = (byte)((code >> 24) & 0xFF);
+       int abs = nBits - (8 - currentBitCount);
+       if (abs < 0) abs = -abs;
+       if ((abs >> 3) > 0) {
+               currentByte += codeBuffer[2];
+               emitByte((byte)currentByte);
+               emitByte(codeBuffer[1]);
+               currentByte = codeBuffer[0];
+               currentBitCount += nBits - 16;
+       } else {
+               currentBitCount += nBits;
+               if (currentBitCount >= 8) {
+                       currentByte += codeBuffer[2];
+                       emitByte((byte)currentByte);
+                       currentByte = codeBuffer[1];
+                       currentBitCount -= 8;
+               } else {
+                       currentByte += codeBuffer[2];
+               }
+       }
+}
+void emitByte(byte byteValue) {
+       if (bufferCurrentPosition >= 512) {
+               resetOutputBuffer();
+       }
+       dataBuffer[bufferCurrentPosition] = byteValue;
+       bufferCurrentPosition++;
+       if (byteValue == -1) {
+               emitByte((byte)0);
+       }
+}
+void encodeACCoefficients(int[] dataUnit, int iComp) {
+       int[] sParams = scanHeader.componentParameters[iComp];
+       JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
+       int[] ehCodes = acTable.ehCodes;
+       byte[] ehSizes = acTable.ehCodeLengths;
+       int r = 0;
+       int k = 1;
+       while (k < 64) {
+               k++;
+               int acValue = dataUnit[ZigZag8x8[k - 1]];
+               if (acValue == 0) {
+                       if (k == 64) {
+                               emit(ehCodes[0], ehSizes[0] & 0xFF);
+                       } else {
+                               r++;
+                       }
+               } else {
+                       while (r > 15) {
+                               emit(ehCodes[0xF0], ehSizes[0xF0] & 0xFF);
+                               r -= 16;
+                       }
+                       if (acValue < 0) {
+                               int absACValue = acValue;
+                               if (absACValue < 0) absACValue = -absACValue;
+                               int nBits = NBitsTable[absACValue];
+                               int rs = r * 16 + nBits;
+                               emit(ehCodes[rs], ehSizes[rs] & 0xFF);
+                               emit(0xFFFFFF - absACValue, nBits);
+                       } else {
+                               int nBits = NBitsTable[acValue];
+                               int rs = r * 16 + nBits;
+                               emit(ehCodes[rs], ehSizes[rs] & 0xFF);
+                               emit(acValue, nBits);
+                       }
+                       r = 0;
+               }
+       }
+}
+void encodeDCCoefficients(int[] dataUnit, int iComp) {
+       int[] sParams = scanHeader.componentParameters[iComp];
+       JPEGHuffmanTable dcTable = dcHuffmanTables[sParams[DC]];
+       int lastDC = precedingDCs[iComp];
+       int dcValue = dataUnit[0];
+       int diff = dcValue - lastDC;
+       precedingDCs[iComp] = dcValue;
+       if (diff < 0) {
+               int absDiff = 0 - diff;
+               int nBits = NBitsTable[absDiff];
+               emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]);
+               emit(0xFFFFFF - absDiff, nBits);
+       } else {
+               int nBits = NBitsTable[diff];
+               emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]);
+               if (nBits != 0) {
+                       emit(diff, nBits);
+               }
+       }
+}
+void encodeMCUAtXAndY(int xmcu, int ymcu) {
+       int nComponentsInScan = scanHeader.getNumberOfImageComponents();
+       dataUnit = new int[64];
+       for (int iComp = 0; iComp < nComponentsInScan; iComp++) {
+               int[] frameComponent = frameComponents[componentIds[iComp]];
+               int hi = frameComponent[HI];
+               int vi = frameComponent[VI];
+               for (int ivi = 0; ivi < vi; ivi++) {
+                       for (int ihi = 0; ihi < hi; ihi++) {
+                               extractData(dataUnit, iComp, xmcu, ymcu, ihi, ivi);
+                               forwardDCT(dataUnit);
+                               quantizeData(dataUnit, iComp);
+                               encodeDCCoefficients(dataUnit, iComp);
+                               encodeACCoefficients(dataUnit, iComp);
+                       }
+               }
+       }
+}
+void encodeScan() {
+       for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) {
+               for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) {
+                       encodeMCUAtXAndY(xmcu, ymcu);
+               }
+       }
+       if (currentBitCount != 0) {
+               emitByte((byte)currentByte);
+       }
+       resetOutputBuffer();
+}
+void expandImageComponents() {
+       for (int iComp = 0; iComp < nComponents; iComp++) {
+               int[] frameComponent = frameComponents[componentIds[iComp]];
+               int hi = frameComponent[HI];
+               int vi = frameComponent[VI];
+               int upH = maxH / hi;
+               int upV = maxV / vi;
+               if ((upH * upV) > 1) {
+                       byte[] component = imageComponents[iComp];
+                       int compWidth = frameComponent[CW];
+                       int compHeight = frameComponent[CH];
+                       int upCompWidth = compWidth * upH;
+                       int upCompHeight = compHeight * upV;
+                       ImageData src = new ImageData(compWidth, compHeight, 8, new PaletteData(RGB16), 4, component);
+                       ImageData dest = src.scaledTo(upCompWidth, upCompHeight);
+                       imageComponents[iComp] = dest.data;
+               }
+       }
+}
+int extendBy(int diff, int t) {
+       if (diff < ExtendTest[t]) {
+               return diff + ExtendOffset[t];
+       } else {
+               return diff;
+       }
+}
+void extractData(int[] dataUnit, int iComp, int xmcu, int ymcu, int ihi, int ivi) {
+       byte[] compImage = imageComponents[iComp];
+       int[] frameComponent = frameComponents[componentIds[iComp]];
+       int hi = frameComponent[HI];
+       int vi = frameComponent[VI];
+       int compWidth = frameComponent[CW];
+       int srcIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE);
+       int destIndex = 0;
+       for (int i = 0; i < DCTSIZE; i++) {
+               for (int col = 0; col < DCTSIZE; col++) {
+                       dataUnit[destIndex] = (compImage[srcIndex + col] & 0xFF) - 128;
+                       destIndex++;
+               }
+               srcIndex += compWidth;
+       }
+}
+void forwardDCT(int[] dataUnit) {
+       for (int row = 0; row < 8; row++) {
+               int rIndex = row * DCTSIZE;
+               int tmp0 = dataUnit[rIndex] + dataUnit[rIndex + 7];
+               int tmp7 = dataUnit[rIndex] - dataUnit[rIndex + 7];
+               int tmp1 = dataUnit[rIndex + 1] + dataUnit[rIndex + 6];
+               int tmp6 = dataUnit[rIndex + 1] - dataUnit[rIndex + 6];
+               int tmp2 = dataUnit[rIndex + 2] + dataUnit[rIndex + 5];
+               int tmp5 = dataUnit[rIndex + 2] - dataUnit[rIndex + 5];
+               int tmp3 = dataUnit[rIndex + 3] + dataUnit[rIndex + 4];
+               int tmp4 = dataUnit[rIndex + 3] - dataUnit[rIndex + 4];
+
+               /**
+                * Even part per LL&M figure 1 --- note that published figure
+                * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'.
+                */
+               int tmp10 = tmp0 + tmp3;
+               int tmp13 = tmp0 - tmp3;
+               int tmp11 = tmp1 + tmp2;
+               int tmp12 = tmp1 - tmp2;
+
+               dataUnit[rIndex] = (tmp10 + tmp11) * 4;
+               dataUnit[rIndex + 4]  = (tmp10 - tmp11) * 4;
+
+               int z1 = (tmp12 + tmp13) * FIX_0_541196100;
+               int n = z1 + (tmp13 * FIX_0_765366865) + 1024;
+               dataUnit[rIndex + 2] = n >> 11;
+               if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 2]--;
+               n = z1 + (tmp12 * (0 - FIX_1_847759065)) + 1024;
+               dataUnit[rIndex + 6] = n >> 11;
+               if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 6]--;
+
+               /**
+                * Odd part per figure 8 --- note paper omits factor of sqrt(2).
+                * cK represents cos(K*pi/16).
+                * i0..i3 in the paper are tmp4..tmp7 here.
+                */
+               z1 = tmp4 + tmp7;
+               int z2 = tmp5 + tmp6;
+               int z3 = tmp4 + tmp6;
+               int z4 = tmp5 + tmp7;
+               int z5 = (z3 + z4) * FIX_1_175875602;   // sqrt(2) * c3
+
+               tmp4 *= FIX_0_298631336;        // sqrt(2) * (-c1+c3+c5-c7)
+               tmp5 *= FIX_2_053119869;        // sqrt(2) * ( c1+c3-c5+c7)
+               tmp6 *= FIX_3_072711026;        // sqrt(2) * ( c1+c3+c5-c7)
+               tmp7 *= FIX_1_501321110;        // sqrt(2) * ( c1+c3-c5-c7)
+               z1 *= 0 - FIX_0_899976223;      // sqrt(2) * (c7-c3)
+               z2 *= 0 - FIX_2_562915447;      // sqrt(2) * (-c1-c3)
+               z3 *= 0 - FIX_1_961570560;      // sqrt(2) * (-c3-c5)
+               z4 *= 0 - FIX_0_390180644;      // sqrt(2) * (c5-c3)
+
+               z3 += z5;
+               z4 += z5;
+
+               n = tmp4 + z1 + z3 + 1024;
+               dataUnit[rIndex + 7] = n >> 11;
+               if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 7]--;
+               n = tmp5 + z2 + z4 + 1024;
+               dataUnit[rIndex + 5] = n >> 11;
+               if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 5]--;
+               n = tmp6 + z2 + z3 + 1024;
+               dataUnit[rIndex + 3] = n >> 11;
+               if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 3]--;
+               n = tmp7 + z1 + z4 + 1024;
+               dataUnit[rIndex + 1] = n >> 11;
+               if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 1]--;
+       }
+
+       /**
+        * Pass 2: process columns.
+        * Note that we must descale the results by a factor of 8 == 2**3,
+        * and also undo the PASS1_BITS scaling.
+        */
+       for (int col = 0; col < 8; col++) {
+               int c0 = col;
+               int c1 = col + 8;
+               int c2 = col + 16;
+               int c3 = col + 24;
+               int c4 = col + 32;
+               int c5 = col + 40;
+               int c6 = col + 48;
+               int c7 = col + 56;
+               int tmp0 = dataUnit[c0] + dataUnit[c7];
+               int tmp7 = dataUnit[c0] - dataUnit[c7];
+               int tmp1 = dataUnit[c1] + dataUnit[c6];
+               int tmp6 = dataUnit[c1] - dataUnit[c6];
+               int tmp2 = dataUnit[c2] + dataUnit[c5];
+               int tmp5 = dataUnit[c2] - dataUnit[c5];
+               int tmp3 = dataUnit[c3] + dataUnit[c4];
+               int tmp4 = dataUnit[c3] - dataUnit[c4];
+
+               /**
+                * Even part per LL&M figure 1 --- note that published figure
+                * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'.
+                */
+               int tmp10 = tmp0 + tmp3;
+               int tmp13 = tmp0 - tmp3;
+               int tmp11 = tmp1 + tmp2;
+               int tmp12 = tmp1 - tmp2;
+
+               int n = tmp10 + tmp11 + 16;
+               dataUnit[c0] = n >> 5;
+               if ((n < 0) && ((n & 0x1F) != 0)) dataUnit[c0]--;
+               n = tmp10 - tmp11 + 16;
+               dataUnit[c4] = n >> 5;
+               if ((n < 0) && ((n & 0x1F) != 0)) dataUnit[c4]--;
+
+               int z1 = (tmp12 + tmp13) * FIX_0_541196100;
+               n = z1 + (tmp13 * FIX_0_765366865) + 131072;
+               dataUnit[c2] = n >> 18;
+               if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c2]--;
+               n = z1 + (tmp12 * (0 - FIX_1_847759065)) + 131072;
+               dataUnit[c6] = n >> 18;
+               if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c6]--;
+
+               /**
+                * Odd part per figure 8 --- note paper omits factor of sqrt(2).
+                * cK represents cos(K*pi/16).
+                * i0..i3 in the paper are tmp4..tmp7 here.
+                */
+               z1 = tmp4 + tmp7;
+               int z2 = tmp5 + tmp6;
+               int z3 = tmp4 + tmp6;
+               int z4 = tmp5 + tmp7;
+               int z5 = (z3 + z4) * FIX_1_175875602;   // sqrt(2) * c3
+
+               tmp4 *= FIX_0_298631336;        // sqrt(2) * (-c1+c3+c5-c7)
+               tmp5 *= FIX_2_053119869;        // sqrt(2) * ( c1+c3-c5+c7)
+               tmp6 *= FIX_3_072711026;        // sqrt(2) * ( c1+c3+c5-c7)
+               tmp7 *= FIX_1_501321110;        // sqrt(2) * ( c1+c3-c5-c7)
+               z1 *= 0 - FIX_0_899976223;      // sqrt(2) * (c7-c3)
+               z2 *= 0 - FIX_2_562915447;      // sqrt(2) * (-c1-c3)
+               z3 *= 0 - FIX_1_961570560;      // sqrt(2) * (-c3-c5)
+               z4 *= 0 - FIX_0_390180644;      // sqrt(2) * (c5-c3)
+
+               z3 += z5;
+               z4 += z5;
+
+               n = tmp4 + z1 + z3 + 131072;
+               dataUnit[c7] = n >> 18;
+               if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c7]--;
+               n = tmp5 + z2 + z4 + 131072;
+               dataUnit[c5] = n >> 18;
+               if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c5]--;
+               n = tmp6 + z2 + z3 + 131072;
+               dataUnit[c3] = n >> 18;
+               if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c3]--;
+               n = tmp7 + z1 + z4 + 131072;
+               dataUnit[c1] = n >> 18;
+               if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c1]--;
+       }
+}
+void getAPP0() {
+       JPEGAppn appn = new JPEGAppn(inputStream);
+       if (!appn.verify()) {
+               SWT.error(SWT.ERROR_INVALID_IMAGE);
+       }
+}
+void getCOM() {
+       new JPEGComment(inputStream);
+}
+void getDAC() {
+       new JPEGArithmeticConditioningTable(inputStream);
+}
+void getDHT() {
+       JPEGHuffmanTable dht = new JPEGHuffmanTable(inputStream);
+       if (!dht.verify()) {
+               SWT.error(SWT.ERROR_INVALID_IMAGE);
+       }
+       if (acHuffmanTables == null) {
+               acHuffmanTables = new JPEGHuffmanTable[4];
+       }
+       if (dcHuffmanTables == null) {
+               dcHuffmanTables = new JPEGHuffmanTable[4];
+       }
+       JPEGHuffmanTable[] dhtTables = dht.getAllTables();
+       for (int i = 0; i < dhtTables.length; i++) {
+               JPEGHuffmanTable dhtTable = dhtTables[i];
+               if (dhtTable.getTableClass() == 0) {
+                       dcHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable;
+               } else {
+                       acHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable;
+               }
+       }
+}
+void getDNL() {
+       new JPEGRestartInterval(inputStream);
+}
+void getDQT() {
+       JPEGQuantizationTable dqt = new JPEGQuantizationTable(inputStream);
+       int[][] currentTables = quantizationTables;
+       if (currentTables == null) {
+               currentTables = new int[4][];
+       }
+       int[] dqtTablesKeys = dqt.getQuantizationTablesKeys();
+       int[][] dqtTablesValues = dqt.getQuantizationTablesValues();
+       for (int i = 0; i < dqtTablesKeys.length; i++) {
+               int index = dqtTablesKeys[i];
+               currentTables[index] = dqtTablesValues[i];
+       }
+       quantizationTables = currentTables;
+}
+void getDRI() {
+       JPEGRestartInterval dri = new JPEGRestartInterval(inputStream);
+       if (!dri.verify()) {
+               SWT.error(SWT.ERROR_INVALID_IMAGE);
+       }
+       restartInterval = dri.getRestartInterval();
+}
+void inverseDCT(int[] dataUnit) {
+       for (int row = 0; row < 8; row++) {
+               int rIndex = row * DCTSIZE;
+               /**
+                * Due to quantization, we will usually find that many of the input
+                * coefficients are zero, especially the AC terms.  We can exploit this
+                * by short-circuiting the IDCT calculation for any row in which all
+                * the AC terms are zero.  In that case each output is equal to the
+                * DC coefficient (with scale factor as needed).
+                * With typical images and quantization tables, half or more of the
+                * row DCT calculations can be simplified this way.
+                */
+               if (isZeroInRow(dataUnit, rIndex)) {
+                       int dcVal = dataUnit[rIndex] << 2;
+                       for (int i = rIndex + 7; i >= rIndex; i--) {
+                               dataUnit[i] = dcVal;
+                       }
+               } else {
+                       /**
+                        * Even part: reverse the even part of the forward DCT.
+                        * The rotator is sqrt(2)*c(-6).
+                        */
+                       int z2 = dataUnit[rIndex + 2];
+                       int z3 = dataUnit[rIndex + 6];
+                       int z1 = (z2 + z3) * FIX_0_541196100;
+                       int tmp2 = z1 + (z3 * (0 - FIX_1_847759065));
+                       int tmp3 = z1 + (z2 * FIX_0_765366865);
+                       int tmp0 = (dataUnit[rIndex] + dataUnit[rIndex + 4]) << 13;
+                       int tmp1 = (dataUnit[rIndex] - dataUnit[rIndex + 4]) << 13;
+                       int tmp10 = tmp0 + tmp3;
+                       int tmp13 = tmp0 - tmp3;
+                       int tmp11 = tmp1 + tmp2;
+                       int tmp12 = tmp1 - tmp2;
+                       /**
+                        * Odd part per figure 8; the matrix is unitary and hence its
+                        * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+                        */
+                       tmp0 = dataUnit[rIndex + 7];
+                       tmp1 = dataUnit[rIndex + 5];
+                       tmp2 = dataUnit[rIndex + 3];
+                       tmp3 = dataUnit[rIndex + 1];
+                       z1 = tmp0 + tmp3;
+                       z2 = tmp1 + tmp2;
+                       z3 = tmp0 + tmp2;
+                       int z4 = tmp1 + tmp3;
+                       int z5 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */
+
+                       tmp0 *= FIX_0_298631336;                /* sqrt(2) * (-c1+c3+c5-c7) */
+                       tmp1 *= FIX_2_053119869;                /* sqrt(2) * ( c1+c3-c5+c7) */
+                       tmp2 *= FIX_3_072711026;                /* sqrt(2) * ( c1+c3+c5-c7) */
+                       tmp3 *= FIX_1_501321110;                /* sqrt(2) * ( c1+c3-c5-c7) */
+                       z1 *= 0 - FIX_0_899976223;      /* sqrt(2) * (c7-c3) */
+                       z2 *= 0 - FIX_2_562915447;      /* sqrt(2) * (-c1-c3) */
+                       z3 *= 0 - FIX_1_961570560;      /* sqrt(2) * (-c3-c5) */
+                       z4 *= 0 - FIX_0_390180644;      /* sqrt(2) * (c5-c3) */
+
+                       z3 += z5;
+                       z4 += z5;
+                       tmp0 += z1 + z3;
+                       tmp1 += z2 + z4;
+                       tmp2 += z2 + z3;
+                       tmp3 += z1 + z4;
+
+                       dataUnit[rIndex] = (tmp10 + tmp3 + 1024) >> 11;
+                       dataUnit[rIndex + 7] = (tmp10 - tmp3 + 1024) >> 11;
+                       dataUnit[rIndex + 1] = (tmp11 + tmp2 + 1024) >> 11;
+                       dataUnit[rIndex + 6] = (tmp11 - tmp2 + 1024) >> 11;
+                       dataUnit[rIndex + 2] = (tmp12 + tmp1 + 1024) >> 11;
+                       dataUnit[rIndex + 5] = (tmp12 - tmp1 + 1024) >> 11;
+                       dataUnit[rIndex + 3] = (tmp13 + tmp0 + 1024) >> 11;
+                       dataUnit[rIndex + 4] = (tmp13 - tmp0 + 1024) >> 11;
+               }
+       }
+       /**
+        * Pass 2: process columns.
+        * Note that we must descale the results by a factor of 8 == 2**3,
+        * and also undo the PASS1_BITS scaling.
+        */
+       for (int col = 0; col < 8; col++) {
+               int c0 = col;
+               int c1 = col + 8;
+               int c2 = col + 16;
+               int c3 = col + 24;
+               int c4 = col + 32;
+               int c5 = col + 40;
+               int c6 = col + 48;
+               int c7 = col + 56;
+               if (isZeroInColumn(dataUnit, col)) {
+                       int dcVal = (dataUnit[c0] + 16) >> 5;
+                       dataUnit[c0] = dcVal;
+                       dataUnit[c1] = dcVal;
+                       dataUnit[c2] = dcVal;
+                       dataUnit[c3] = dcVal;
+                       dataUnit[c4] = dcVal;
+                       dataUnit[c5] = dcVal;
+                       dataUnit[c6] = dcVal;
+                       dataUnit[c7] = dcVal;
+               } else {
+                       /**
+                        * Even part: reverse the even part of the forward DCT.
+                        * The rotator is sqrt(2)*c(-6).
+                        */
+                       int z0 = dataUnit[c0];
+                       int z2 = dataUnit[c2];
+                       int z3 = dataUnit[c6];
+                       int z4 = dataUnit[c4];
+                       int z1 = (z2 + z3) * FIX_0_541196100;
+                       int tmp2 = z1 + (z3 * (0 - FIX_1_847759065));
+                       int tmp3 = z1 + (z2 * FIX_0_765366865);
+                       int tmp0 = (z0 + z4) << 13;
+                       int tmp1 = (z0 - z4) << 13;
+                       int tmp10 = tmp0 + tmp3;
+                       int tmp13 = tmp0 - tmp3;
+                       int tmp11 = tmp1 + tmp2;
+                       int tmp12 = tmp1 - tmp2;
+                       /**
+                        * Odd part per figure 8; the matrix is unitary and hence its
+                        * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+                        */
+                       tmp0 = dataUnit[c7];
+                       tmp1 = dataUnit[c5];
+                       tmp2 = dataUnit[c3];
+                       tmp3 = dataUnit[c1];
+                       z1 = tmp0 + tmp3;
+                       z2 = tmp1 + tmp2;
+                       z3 = tmp0 + tmp2;
+                       z4 = tmp1 + tmp3;
+                       z0 = (z3 + z4) * FIX_1_175875602;       /* sqrt(2) * c3 */
+
+                       tmp0 *= FIX_0_298631336;                /* sqrt(2) * (-c1+c3+c5-c7) */
+                       tmp1 *= FIX_2_053119869;                /* sqrt(2) * ( c1+c3-c5+c7) */
+                       tmp2 *= FIX_3_072711026;                /* sqrt(2) * ( c1+c3+c5-c7) */
+                       tmp3 *= FIX_1_501321110;                /* sqrt(2) * ( c1+c3-c5-c7) */
+                       z1 *= 0 - FIX_0_899976223;      /* sqrt(2) * (c7-c3) */
+                       z2 *= 0 - FIX_2_562915447;      /* sqrt(2) * (-c1-c3) */
+                       z3 *= 0 - FIX_1_961570560;      /* sqrt(2) * (-c3-c5) */
+                       z4 *= 0 - FIX_0_390180644;      /* sqrt(2) * (c5-c3) */
+
+                       z3 += z0;
+                       z4 += z0;
+
+                       tmp0 += z1 + z3;
+                       tmp1 += z2 + z4;
+                       tmp2 += z2 + z3;
+                       tmp3 += z1 + z4;
+
+                       /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+                       dataUnit[c0] = (tmp10 + tmp3 + 131072) >> 18;
+                       dataUnit[c7] = (tmp10 - tmp3 + 131072) >> 18;
+                       dataUnit[c1] = (tmp11 + tmp2 + 131072) >> 18;
+                       dataUnit[c6] = (tmp11 - tmp2 + 131072) >> 18;
+                       dataUnit[c2] = (tmp12 + tmp1 + 131072) >> 18;
+                       dataUnit[c5] = (tmp12 - tmp1 + 131072) >> 18;
+                       dataUnit[c3] = (tmp13 + tmp0 + 131072) >> 18;
+                       dataUnit[c4] = (tmp13 - tmp0 + 131072) >> 18;
+               }
+       }
+}
+@Override
+boolean isFileFormat(LEDataInputStream stream) {
+       try {
+               JPEGStartOfImage soi = new JPEGStartOfImage(stream);
+               stream.unread(soi.reference);
+               return soi.verify();  // we no longer check for appN
+       } catch (Exception e) {
+               return false;
+       }
+}
+boolean isZeroInColumn(int[] dataUnit, int col) {
+       return dataUnit[col + 8] == 0 && dataUnit[col + 16] == 0
+                       && dataUnit[col + 24] == 0 && dataUnit[col + 32] == 0
+                       && dataUnit[col + 40] == 0 && dataUnit[col + 48] == 0
+                       && dataUnit[col + 56] == 0;
+}
+boolean isZeroInRow(int[] dataUnit, int rIndex) {
+       return dataUnit[rIndex + 1] == 0 && dataUnit[rIndex + 2] == 0
+                       && dataUnit[rIndex + 3] == 0 && dataUnit[rIndex + 4] == 0
+                       && dataUnit[rIndex + 5] == 0 && dataUnit[rIndex + 6] == 0
+                       && dataUnit[rIndex + 7] == 0;
+}
+@Override
+ImageData[] loadFromByteStream() {
+       //TEMPORARY CODE
+       if (System.getProperty("org.eclipse.swt.internal.image.JPEGFileFormat_3.2") == null) {
+               return JPEGDecoder.loadFromByteStream(inputStream, loader);
+       }
+       JPEGStartOfImage soi = new JPEGStartOfImage(inputStream);
+       if (!soi.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
+       restartInterval = 0;
+
+       /* Process the tables preceding the frame header. */
+       processTables();
+
+       /* Start of Frame. */
+       frameHeader = new JPEGFrameHeader(inputStream);
+       if (!frameHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
+       imageWidth = frameHeader.getSamplesPerLine();
+       imageHeight = frameHeader.getNumberOfLines();
+       maxH = frameHeader.getMaxHFactor();
+       maxV = frameHeader.getMaxVFactor();
+       int mcuWidth = maxH * DCTSIZE;
+       int mcuHeight = maxV * DCTSIZE;
+       interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth;
+       interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight;
+       progressive = frameHeader.isProgressive();
+       samplePrecision = frameHeader.getSamplePrecision();
+       nComponents = frameHeader.getNumberOfImageComponents();
+       frameComponents = frameHeader.componentParameters;
+       componentIds = frameHeader.componentIdentifiers;
+       imageComponents = new byte[nComponents][];
+       if (progressive) {
+               // Progressive jpeg: need to keep all of the data units.
+               dataUnits = new int[nComponents][][];
+       } else {
+               // Sequential jpeg: only need one data unit.
+               dataUnit = new int[8 * 8];
+       }
+       for (int i = 0; i < nComponents; i++) {
+               int[] frameComponent = frameComponents[componentIds[i]];
+               int bufferSize = frameComponent[CW] * frameComponent[CH];
+               imageComponents[i] = new byte[bufferSize];
+               if (progressive) {
+                       dataUnits[i] = new int[bufferSize][];
+               }
+       }
+
+       /* Process the tables preceding the scan header. */
+       processTables();
+
+       /* Start of Scan. */
+       scanHeader = new JPEGScanHeader(inputStream);
+       if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
+
+       /* Process scan(s) and further tables until EOI. */
+       int progressiveScanCount = 0;
+       boolean done = false;
+       while(!done) {
+               resetInputBuffer();
+               precedingDCs = new int[4];
+               decodeScan();
+               if (progressive && loader.hasListeners()) {
+                       ImageData imageData = createImageData();
+                       loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, false));
+                       progressiveScanCount++;
+               }
+
+               /* Unread any buffered data before looking for tables again. */
+               int delta = 512 - bufferCurrentPosition - 1;
+               if (delta > 0) {
+                       byte[] unreadBuffer = new byte[delta];
+                       System.arraycopy(dataBuffer, bufferCurrentPosition + 1, unreadBuffer, 0, delta);
+                       try {
+                               inputStream.unread(unreadBuffer);
+                       } catch (IOException e) {
+                               SWT.error(SWT.ERROR_IO, e);
+                       }
+               }
+
+               /* Process the tables preceding the next scan header. */
+               JPEGSegment jpegSegment = processTables();
+               if (jpegSegment == null || jpegSegment.getSegmentMarker() == EOI) {
+                       done = true;
+               } else {
+                       scanHeader = new JPEGScanHeader(inputStream);
+                       if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE);
+               }
+       }
+
+       if (progressive) {
+               for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) {
+                       for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) {
+                               for (int iComp = 0; iComp < nComponents; iComp++) {
+                                       int[] frameComponent = frameComponents[componentIds[iComp]];
+                                       int hi = frameComponent[HI];
+                                       int vi = frameComponent[VI];
+                                       int compWidth = frameComponent[CW];
+                                       for (int ivi = 0; ivi < vi; ivi++) {
+                                               for (int ihi = 0; ihi < hi; ihi++) {
+                                                       int index = (ymcu * vi + ivi) * compWidth + xmcu * hi + ihi;
+                                                       dataUnit = dataUnits[iComp][index];
+                                                       dequantize(dataUnit, iComp);
+                                                       inverseDCT(dataUnit);
+                                                       storeData(dataUnit, iComp, xmcu, ymcu, hi, ihi, vi, ivi);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               dataUnits = null; // release memory
+       }
+       ImageData imageData = createImageData();
+       if (progressive && loader.hasListeners()) {
+               loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, true));
+       }
+       return new ImageData[] {imageData};
+}
+ImageData createImageData() {
+       return ImageData.internal_new(
+               imageWidth,
+               imageHeight,
+               nComponents * samplePrecision,
+               setUpPalette(),
+               nComponents == 1 ? 4 : 1,
+               decodeImageComponents(),
+               0,
+               null,
+               null,
+               -1,
+               -1,
+               SWT.IMAGE_JPEG,
+               0,
+               0,
+               0,
+               0);
+}
+int nextBit() {
+       if (currentBitCount != 0) {
+               currentBitCount--;
+               currentByte *= 2;
+               if (currentByte > 255) {
+                       currentByte -= 256;
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+       bufferCurrentPosition++;
+       if (bufferCurrentPosition >= 512) {
+               resetInputBuffer();
+               bufferCurrentPosition = 0;
+       }
+       currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
+       currentBitCount = 8;
+       byte nextByte;
+       if (bufferCurrentPosition == 511) {
+               resetInputBuffer();
+               currentBitCount = 8;
+               nextByte = dataBuffer[0];
+       } else {
+               nextByte = dataBuffer[bufferCurrentPosition + 1];
+       }
+       if (currentByte == 0xFF) {
+               if (nextByte == 0) {
+                       bufferCurrentPosition ++;
+                       currentBitCount--;
+                       currentByte *= 2;
+                       if (currentByte > 255) {
+                               currentByte -= 256;
+                               return 1;
+                       } else {
+                               return 0;
+                       }
+               } else {
+                       if ((nextByte & 0xFF) + 0xFF00 == DNL) {
+                               getDNL();
+                               return 0;
+                       } else {
+                               SWT.error(SWT.ERROR_INVALID_IMAGE);
+                               return 0;
+                       }
+               }
+       } else {
+               currentBitCount--;
+               currentByte *= 2;
+               if (currentByte > 255) {
+                       currentByte -= 256;
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+}
+void processRestartInterval() {
+       do {
+               bufferCurrentPosition++;
+               if (bufferCurrentPosition > 511) {
+                       resetInputBuffer();
+                       bufferCurrentPosition = 0;
+               }
+               currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
+       } while (currentByte != 0xFF);
+       while (currentByte == 0xFF) {
+               bufferCurrentPosition++;
+               if (bufferCurrentPosition > 511) {
+                       resetInputBuffer();
+                       bufferCurrentPosition = 0;
+               }
+               currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
+       }
+       if (currentByte != ((RST0 + nextRestartNumber) & 0xFF)) {
+               SWT.error(SWT.ERROR_INVALID_IMAGE);
+       }
+       bufferCurrentPosition++;
+       if (bufferCurrentPosition > 511) {
+               resetInputBuffer();
+               bufferCurrentPosition = 0;
+       }
+       currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
+       currentBitCount = 8;
+       restartsToGo = restartInterval;
+       nextRestartNumber = (nextRestartNumber + 1) & 0x7;
+       precedingDCs = new int[4];
+       eobrun = 0;
+}
+/* Process all markers until a frame header, scan header, or EOI is found. */
+JPEGSegment processTables() {
+       while (true) {
+               JPEGSegment jpegSegment = seekUnspecifiedMarker(inputStream);
+               if (jpegSegment == null) return null;
+               JPEGFrameHeader sof = new JPEGFrameHeader(jpegSegment.reference);
+               if (sof.verify()) {
+                       return jpegSegment;
+               }
+               int marker = jpegSegment.getSegmentMarker();
+               switch (marker) {
+                       case SOI: // there should only be one SOI per file
+                               SWT.error(SWT.ERROR_INVALID_IMAGE);
+                       case EOI:
+                       case SOS:
+                               return jpegSegment;
+                       case DQT:
+                               getDQT();
+                               break;
+                       case DHT:
+                               getDHT();
+                               break;
+                       case DAC:
+                               getDAC();
+                               break;
+                       case DRI:
+                               getDRI();
+                               break;
+                       case APP0:
+                               getAPP0();
+                               break;
+                       case COM:
+                               getCOM();
+                               break;
+                       default:
+                               skipSegmentFrom(inputStream);
+
+               }
+       }
+}
+void quantizeData(int[] dataUnit, int iComp) {
+       int[] qTable = quantizationTables[frameComponents[componentIds[iComp]][TQI]];
+       for (int i = 0; i < dataUnit.length; i++) {
+               int zzIndex = ZigZag8x8[i];
+               int data = dataUnit[zzIndex];
+               int absData = data < 0 ? 0 - data : data;
+               int qValue = qTable[i];
+               int q2 = qValue >> 1;
+               absData += q2;
+               if (absData < qValue) {
+                       dataUnit[zzIndex] = 0;
+               } else {
+                       absData /= qValue;
+                       if (data >= 0) {
+                               dataUnit[zzIndex] = absData;
+                       } else {
+                               dataUnit[zzIndex] = 0 - absData;
+                       }
+               }
+       }
+}
+int receive(int nBits) {
+       int v = 0;
+       for (int i = 0; i < nBits; i++) {
+               v = v * 2 + nextBit();
+       }
+       return v;
+}
+void resetInputBuffer() {
+       if (dataBuffer == null) {
+               dataBuffer = new byte[512];
+       }
+       try {
+               inputStream.read(dataBuffer);
+       } catch (IOException e) {
+               SWT.error(SWT.ERROR_IO, e);
+       }
+       currentBitCount = 0;
+       bufferCurrentPosition = -1;
+}
+void resetOutputBuffer() {
+       if (dataBuffer == null) {
+               dataBuffer = new byte[512];
+       } else {
+               try {
+                       outputStream.write(dataBuffer, 0, bufferCurrentPosition);
+               } catch (IOException e) {
+                       SWT.error(SWT.ERROR_IO, e);
+               }
+       }
+       bufferCurrentPosition = 0;
+}
+static JPEGSegment seekUnspecifiedMarker(LEDataInputStream byteStream) {
+       byte[] byteArray = new byte[2];
+       try {
+               while (true) {
+                       if (byteStream.read(byteArray, 0, 1) != 1) return null;
+                       if (byteArray[0] == (byte) 0xFF) {
+                               if (byteStream.read(byteArray, 1, 1) != 1) return null;
+                               if (byteArray[1] != (byte) 0xFF && byteArray[1] != 0) {
+                                       byteStream.unread(byteArray);
+                                       return new JPEGSegment(byteArray);
+                               }
+                       }
+               }
+       } catch (IOException e) {
+               SWT.error(SWT.ERROR_IO, e);
+       }
+       return null;
+}
+PaletteData setUpPalette() {
+       if (nComponents == 1) {
+               RGB[] entries = new RGB[256];
+               for (int i = 0; i < 256; i++) {
+                       entries[i] = new RGB(i, i, i);
+               }
+               return new PaletteData(entries);
+       }
+       return new PaletteData(0xFF, 0xFF00, 0xFF0000);
+}
+static void skipSegmentFrom(LEDataInputStream byteStream) {
+       try {
+               byte[] byteArray = new byte[4];
+               JPEGSegment jpegSegment = new JPEGSegment(byteArray);
+
+               if (byteStream.read(byteArray) != byteArray.length) {
+                       SWT.error(SWT.ERROR_INVALID_IMAGE);
+               }
+               if (!(byteArray[0] == -1 && byteArray[1] != 0 && byteArray[1] != -1)) {
+                       SWT.error(SWT.ERROR_INVALID_IMAGE);
+               }
+               int delta = jpegSegment.getSegmentLength() - 2;
+               byteStream.skip(delta);
+       } catch (Exception e) {
+               SWT.error(SWT.ERROR_IO, e);
+       }
+}
+void storeData(int[] dataUnit, int iComp, int xmcu, int ymcu, int hi, int ihi, int vi, int ivi) {
+       byte[] compImage = imageComponents[iComp];
+       int[] frameComponent = frameComponents[componentIds[iComp]];
+       int compWidth = frameComponent[CW];
+       int destIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE);
+       int srcIndex = 0;
+       for (int i = 0; i < DCTSIZE; i++) {
+               for (int col = 0; col < DCTSIZE; col++) {
+                       int x = dataUnit[srcIndex] + 128;
+                       if (x < 0) {
+                               x = 0;
+                       } else {
+                               if (x > 255) x = 255;
+                       }
+                       compImage[destIndex + col] = (byte)x;
+                       srcIndex++;
+               }
+               destIndex += compWidth;
+       }
+}
+@Override
+void unloadIntoByteStream(ImageLoader loader) {
+       ImageData image = loader.data[0];
+       if (!new JPEGStartOfImage().writeToStream(outputStream)) {
+               SWT.error(SWT.ERROR_IO);
+       }
+       JPEGAppn appn = new JPEGAppn(new byte[] {(byte)0xFF, (byte)0xE0, 0, 0x10, 0x4A, 0x46, 0x49, 0x46, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0});
+       if (!appn.writeToStream(outputStream)) {
+               SWT.error(SWT.ERROR_IO);
+       }
+       quantizationTables = new int[4][];
+       JPEGQuantizationTable chromDQT = JPEGQuantizationTable.defaultChrominanceTable();
+       int encoderQFactor = loader.compression >= 1 && loader.compression <= 100 ? loader.compression : 75;
+       chromDQT.scaleBy(encoderQFactor);
+       int[] jpegDQTKeys = chromDQT.getQuantizationTablesKeys();
+       int[][] jpegDQTValues = chromDQT.getQuantizationTablesValues();
+       for (int i = 0; i < jpegDQTKeys.length; i++) {
+               quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i];
+       }
+       JPEGQuantizationTable lumDQT = JPEGQuantizationTable.defaultLuminanceTable();
+       lumDQT.scaleBy(encoderQFactor);
+       jpegDQTKeys = lumDQT.getQuantizationTablesKeys();
+       jpegDQTValues = lumDQT.getQuantizationTablesValues();
+       for (int i = 0; i < jpegDQTKeys.length; i++) {
+               quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i];
+       }
+       if (!lumDQT.writeToStream(outputStream)) {
+               SWT.error(SWT.ERROR_IO);
+       }
+       if (!chromDQT.writeToStream(outputStream)) {
+               SWT.error(SWT.ERROR_IO);
+       }
+       int frameLength, scanLength, precision;
+       int[][] frameParams, scanParams;
+       if (image.depth == 1) {
+               frameLength = 11;
+               frameParams = new int[1][];
+               frameParams[0] = new int[] {1, 1, 1, 0, 0};
+               scanParams = new int[1][];
+               scanParams[0] = new int[] {0, 0};
+               scanLength = 8;
+               nComponents = 1;
+               precision = 1;
+       } else {
+               frameLength = 17;
+               frameParams = new int[3][];
+               frameParams[0] = new int[] {0, 2, 2, 0, 0};
+               frameParams[1] = new int[] {1, 1, 1, 0, 0};
+               frameParams[2] = new int[] {1, 1, 1, 0, 0};
+               scanParams = new int[3][];
+               scanParams[0] = new int[] {0, 0};
+               scanParams[1] = new int[] {1, 1};
+               scanParams[2] = new int[] {1, 1};
+               scanLength = 12;
+               nComponents = 3;
+               precision = 8;
+       }
+       imageWidth = image.width;
+       imageHeight = image.height;
+       frameHeader = new JPEGFrameHeader(new byte[19]);
+       frameHeader.setSegmentMarker(SOF0);
+       frameHeader.setSegmentLength(frameLength);
+       frameHeader.setSamplePrecision(precision);
+       frameHeader.setSamplesPerLine(imageWidth);
+       frameHeader.setNumberOfLines(imageHeight);
+       frameHeader.setNumberOfImageComponents(nComponents);
+       frameHeader.componentParameters = frameParams;
+       frameHeader.componentIdentifiers = new int[] {0, 1, 2};
+       frameHeader.initializeContents();
+       if (!frameHeader.writeToStream(outputStream)) {
+               SWT.error(SWT.ERROR_IO);
+       }
+       frameComponents = frameParams;
+       componentIds = frameHeader.componentIdentifiers;
+       maxH = frameHeader.getMaxHFactor();
+       maxV = frameHeader.getMaxVFactor();
+       int mcuWidth = maxH * DCTSIZE;
+       int mcuHeight = maxV * DCTSIZE;
+       interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth;
+       interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight;
+       acHuffmanTables = new JPEGHuffmanTable[4];
+       dcHuffmanTables = new JPEGHuffmanTable[4];
+       JPEGHuffmanTable[] dhtTables = new JPEGHuffmanTable[] {
+               JPEGHuffmanTable.getDefaultDCLuminanceTable(),
+               JPEGHuffmanTable.getDefaultDCChrominanceTable(),
+               JPEGHuffmanTable.getDefaultACLuminanceTable(),
+               JPEGHuffmanTable.getDefaultACChrominanceTable()
+       };
+       for (int i = 0; i < dhtTables.length; i++) {
+               JPEGHuffmanTable dhtTable = dhtTables[i];
+               if (!dhtTable.writeToStream(outputStream)) {
+                       SWT.error(SWT.ERROR_IO);
+               }
+               JPEGHuffmanTable[] allTables = dhtTable.getAllTables();
+               for (int j = 0; j < allTables.length; j++) {
+                       JPEGHuffmanTable huffmanTable = allTables[j];
+                       if (huffmanTable.getTableClass() == 0) {
+                               dcHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable;
+                       } else {
+                               acHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable;
+                       }
+               }
+       }
+       precedingDCs = new int[4];
+       scanHeader = new JPEGScanHeader(new byte[14]);
+       scanHeader.setSegmentMarker(SOS);
+       scanHeader.setSegmentLength(scanLength);
+       scanHeader.setNumberOfImageComponents(nComponents);
+       scanHeader.setStartOfSpectralSelection(0);
+       scanHeader.setEndOfSpectralSelection(63);
+       scanHeader.componentParameters = scanParams;
+       scanHeader.initializeContents();
+       if (!scanHeader.writeToStream(outputStream)) {
+               SWT.error(SWT.ERROR_IO);
+       }
+       convertImageToYCbCr(image);
+       resetOutputBuffer();
+       currentByte = 0;
+       currentBitCount = 0;
+       encodeScan();
+       if (!new JPEGEndOfImage().writeToStream(outputStream)) {
+               SWT.error(SWT.ERROR_IO);
+       }
+}
+}