X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.eclipse.swt.win32.win32.x86_64%2Fsrc%2Forg%2Feclipse%2Fswt%2Finternal%2Fimage%2FJPEGFileFormat.java;fp=bundles%2Forg.eclipse.swt.win32.win32.x86_64%2Fsrc%2Forg%2Feclipse%2Fswt%2Finternal%2Fimage%2FJPEGFileFormat.java;h=0f5c6f82cae1c77c94c0e9ee8b929ff546fc42f3;hb=6b98970d0458754dd67f789afbd0a39e1e7ac6eb;hp=0000000000000000000000000000000000000000;hpb=56a61575ce0d27b340cb12438c8a7f303842095e;p=simantics%2Fplatform.git 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 index 000000000..0f5c6f82c --- /dev/null +++ b/bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/internal/image/JPEGFileFormat.java @@ -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); + } +} +}