Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Northover2007-02-16 20:12:21 +0000
committerSteve Northover2007-02-16 20:12:21 +0000
commiteb48e967aaf75d9fe92c60f55ad1e4d8556944b7 (patch)
treed5c3c57158b2f0dba35886d2505eb0d61bc8ce6b
parent2e62c2482bd812395dd792c7b9788f3a7362be56 (diff)
downloadeclipse.platform.swt-R3_0_2_PMR12401_661_706.tar.gz
eclipse.platform.swt-R3_0_2_PMR12401_661_706.tar.xz
eclipse.platform.swt-R3_0_2_PMR12401_661_706.zip
Backport ImageLoader changes from 3.2.2 to 3.0.2R3_0_2_PMR12401_661_706
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java5
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java71
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java216
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGAppn.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGArithmeticConditioningTable.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGComment.java8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGDecoder.java6360
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGEndOfImage.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java436
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFixedSizeSegment.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFrameHeader.java12
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGHuffmanTable.java18
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGQuantizationTable.java26
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGRestartInterval.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGScanHeader.java22
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGSegment.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGStartOfImage.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGVariableSizeSegment.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataInputStream.java25
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataOutputStream.java17
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java12
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWNode.java8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java294
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java96
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java67
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunkReader.java10
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDecodingDataStream.java76
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngFileReadState.java11
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTable.java45
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTables.java19
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIdatChunk.java32
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIendChunk.java20
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIhdrChunk.java115
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngInputStream.java61
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngLzBlockReader.java23
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngPlteChunk.java57
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngTrnsChunk.java25
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFDirectory.java14
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java15
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFModifiedHuffmanCodec.java8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFRandomFileAccess.java8
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java39
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java25
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/package.html2
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/CloneableCompatibility.java8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java49
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventListener.java8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventObject.java12
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTMessages.properties18
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SerializableCompatibility.java8
50 files changed, 7734 insertions, 731 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
index fc89c1ec68..ef249a8a7a 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
@@ -2414,6 +2414,11 @@ public class SWT {
public static final int IMAGE_TIFF = 6;
/**
+ * Image format constant indicating an OS/2 BMP format image (value is 7).
+ */
+ public static final int IMAGE_OS2_BMP = 7;
+
+ /**
* GIF image disposal method constants indicating that the
* disposal method is unspecified (value is 0).
*/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java
index 98f67e61e1..074b038bb5 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/FileFormat.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -15,24 +15,21 @@ import java.io.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
+/**
+ * Abstract factory class for loading/unloading images from files or streams
+ * in various image file formats.
+ *
+ */
public abstract class FileFormat {
static final String FORMAT_PACKAGE = "org.eclipse.swt.internal.image"; //$NON-NLS-1$
static final String FORMAT_SUFFIX = "FileFormat"; //$NON-NLS-1$
- static final String[] FORMATS = {"WinBMP", "WinBMP", "GIF", "WinICO", "JPEG", "PNG", "TIFF"}; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$ //$NON-NLS-6$//$NON-NLS-7$
+ static final String[] FORMATS = {"WinBMP", "WinBMP", "GIF", "WinICO", "JPEG", "PNG", "TIFF", "OS2BMP"}; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$ //$NON-NLS-6$//$NON-NLS-7$//$NON-NLS-8$
LEDataInputStream inputStream;
LEDataOutputStream outputStream;
ImageLoader loader;
int compression;
-byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
- // Destructively bit invert data in the given byte array.
- for (int i = startIndex; i < endIndex; i++) {
- data[i] = (byte)(255 - data[i - startIndex]);
- }
- return data;
-}
-
/**
* Return whether or not the specified input stream
* represents a supported file format.
@@ -41,16 +38,28 @@ abstract boolean isFileFormat(LEDataInputStream stream);
abstract ImageData[] loadFromByteStream();
+/**
+ * Read the specified input stream, and return the
+ * device independent image array represented by the stream.
+ */
public ImageData[] loadFromStream(LEDataInputStream stream) {
try {
inputStream = stream;
return loadFromByteStream();
} catch (Exception e) {
- SWT.error(SWT.ERROR_IO, e);
+ if (e instanceof IOException) {
+ SWT.error(SWT.ERROR_IO, e);
+ } else {
+ SWT.error(SWT.ERROR_INVALID_IMAGE, e);
+ }
return null;
}
}
+/**
+ * Read the specified input stream using the specified loader, and
+ * return the device independent image array represented by the stream.
+ */
public static ImageData[] load(InputStream is, ImageLoader loader) {
FileFormat fileFormat = null;
LEDataInputStream stream = new LEDataInputStream(is);
@@ -75,39 +84,45 @@ public static ImageData[] load(InputStream is, ImageLoader loader) {
return fileFormat.loadFromStream(stream);
}
+/**
+ * Write the device independent image array stored in the specified loader
+ * to the specified output stream using the specified file format.
+ */
public static void save(OutputStream os, int format, ImageLoader loader) {
- if (format < 0 || format >= FORMATS.length) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- if (FORMATS[format] == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (format < 0 || format >= FORMATS.length) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
+ if (FORMATS[format] == null) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
+ if (loader.data == null || loader.data.length < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
- /* We do not currently support writing multi-image files,
- * so we use the first image data in the loader's array. */
- ImageData data = loader.data[0];
LEDataOutputStream stream = new LEDataOutputStream(os);
FileFormat fileFormat = null;
try {
Class clazz = Class.forName(FORMAT_PACKAGE + '.' + FORMATS[format] + FORMAT_SUFFIX);
fileFormat = (FileFormat) clazz.newInstance();
} catch (Exception e) {
- SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
}
if (format == SWT.IMAGE_BMP_RLE) {
- switch (data.depth) {
+ switch (loader.data[0].depth) {
case 8: fileFormat.compression = 1; break;
case 4: fileFormat.compression = 2; break;
}
}
- fileFormat.unloadIntoStream(data, stream);
+ fileFormat.unloadIntoStream(loader, stream);
}
-abstract void unloadIntoByteStream(ImageData image);
+abstract void unloadIntoByteStream(ImageLoader loader);
-public void unloadIntoStream(ImageData image, LEDataOutputStream stream) {
+/**
+ * Write the device independent image array stored in the specified loader
+ * to the specified output stream.
+ */
+public void unloadIntoStream(ImageLoader loader, LEDataOutputStream stream) {
try {
outputStream = stream;
- unloadIntoByteStream(image);
- outputStream.close();
+ unloadIntoByteStream(loader);
+ outputStream.flush();
} catch (Exception e) {
- try {outputStream.close();} catch (Exception f) {}
+ try {outputStream.flush();} catch (Exception f) {}
SWT.error(SWT.ERROR_IO, e);
}
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java
index 0c3e0db53c..22273cfc74 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/GIFFileFormat.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -16,10 +16,8 @@ import org.eclipse.swt.graphics.*;
import java.io.*;
final class GIFFileFormat extends FileFormat {
- String signature, version;
- boolean sorted;
- int screenWidth, screenHeight, backgroundPixel, aspect, bitsPerPixel, defaultDepth;
- boolean userInput = false;
+ String signature;
+ int screenWidth, screenHeight, backgroundPixel, bitsPerPixel, defaultDepth;
int disposalMethod = 0;
int delayTime = 0;
int transparentPixel = -1;
@@ -32,6 +30,8 @@ final class GIFFileFormat extends FileFormat {
static final int GIF_EXTENSION_BLOCK_ID = 0x21;
static final int GIF_IMAGE_BLOCK_ID = 0x2C;
static final int GIF_TRAILER_ID = 0x3B;
+ static final byte [] GIF89a = new byte[] { (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'9', (byte)'a' };
+ static final byte [] NETSCAPE2_0 = new byte[] { (byte)'N', (byte)'E', (byte)'T', (byte)'S', (byte)'C', (byte)'A', (byte)'P', (byte)'E', (byte)'2', (byte)'.', (byte)'0' };
/**
* Answer a palette containing numGrays
@@ -73,7 +73,6 @@ final class GIFFileFormat extends FileFormat {
SWT.error(SWT.ERROR_INVALID_IMAGE);
inputStream.read(versionBytes);
- version = new String(versionBytes);
inputStream.read(block);
} catch (IOException e) {
@@ -85,17 +84,17 @@ final class GIFFileFormat extends FileFormat {
loader.logicalScreenHeight = screenHeight;
byte bitField = block[4];
backgroundPixel = block[5] & 0xFF;
- aspect = block[6] & 0xFF;
+ //aspect = block[6] & 0xFF;
bitsPerPixel = ((bitField >> 4) & 0x07) + 1;
defaultDepth = (bitField & 0x7) + 1;
PaletteData palette = null;
if ((bitField & 0x80) != 0) {
// Global palette.
- sorted = (bitField & 0x8) != 0;
+ //sorted = (bitField & 0x8) != 0;
palette = readPalette(1 << defaultDepth);
} else {
// No global palette.
- sorted = false;
+ //sorted = false;
backgroundPixel = -1;
defaultDepth = bitsPerPixel;
}
@@ -267,21 +266,14 @@ final class GIFFileFormat extends FileFormat {
inputStream.read(controlBlock);
byte bitField = controlBlock[0];
// Store the user input field.
- userInput = (bitField & 0x02) != 0;
+ //userInput = (bitField & 0x02) != 0;
// Store the disposal method.
disposalMethod = (bitField >> 2) & 0x07;
// Store the delay time.
delayTime = (controlBlock[1] & 0xFF) | ((controlBlock[2] & 0xFF) << 8);
// Store the transparent color.
if ((bitField & 0x01) != 0) {
- int colorIndex = controlBlock[3] & 0xFF;
- /* Work around: a customer has a GIF that specifies an
- * invalid color index that is larger than the number
- * of entries in the palette. Detect this case, and
- * ignore the specified color index. */
- if (colorIndex <= 1 << defaultDepth) {
- transparentPixel = colorIndex;
- }
+ transparentPixel = controlBlock[3] & 0xFF;
} else {
transparentPixel = -1;
}
@@ -354,7 +346,7 @@ final class GIFFileFormat extends FileFormat {
int height = (block[6] & 0xFF) | ((block[7] & 0xFF) << 8);
byte bitField = block[8];
boolean interlaced = (bitField & 0x40) != 0;
-// boolean sorted = (bitField & 0x20) != 0;
+ //boolean sorted = (bitField & 0x20) != 0;
if ((bitField & 0x80) != 0) {
// Local palette.
depth = (bitField & 0x7) + 1;
@@ -364,6 +356,12 @@ final class GIFFileFormat extends FileFormat {
depth = defaultDepth;
palette = defaultPalette;
}
+ /* Work around: Ignore the case where a GIF specifies an
+ * invalid index for the transparent pixel that is larger
+ * than the number of entries in the palette. */
+ if (transparentPixel > 1 << depth) {
+ transparentPixel = -1;
+ }
// Promote depth to next highest supported value.
if (!(depth == 1 || depth == 4 || depth == 8)) {
if (depth < 4)
@@ -423,31 +421,128 @@ final class GIFFileFormat extends FileFormat {
return new PaletteData(colors);
}
- /**
- * Write the specified device independent image
- * to the output stream.
- */
- void unloadIntoByteStream(ImageData image) {
- if (!((image.depth == 1) || (image.depth == 4) || (image.depth == 8))) {
+ void unloadIntoByteStream(ImageLoader loader) {
+
+ /* Step 1: Acquire GIF parameters. */
+ ImageData[] data = loader.data;
+ int frameCount = data.length;
+ boolean multi = frameCount > 1;
+ ImageData firstImage = data[0];
+ int logicalScreenWidth = multi ? loader.logicalScreenWidth : firstImage.width;
+ int logicalScreenHeight = multi ? loader.logicalScreenHeight : firstImage.height;
+ int backgroundPixel = loader.backgroundPixel;
+ int depth = firstImage.depth;
+ PaletteData palette = firstImage.palette;
+ RGB[] colors = palette.getRGBs();
+ short globalTable = 1;
+
+ /* Step 2: Check for validity and global/local color map. */
+ if (!(depth == 1 || depth == 4 || depth == 8)) {
SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
}
- byte bitField = (byte)((0x80 & 0xF8 & 0xF7 & 0x8F) + (image.depth - 1) + ((image.depth - 1) * 16));
+ for (int i=0; i<frameCount; i++) {
+ if (data[i].palette.isDirect) {
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
+ if (multi) {
+ if (!(data[i].height <= logicalScreenHeight && data[i].width <= logicalScreenWidth && data[i].depth == depth)) {
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
+ if (globalTable == 1) {
+ RGB rgbs[] = data[i].palette.getRGBs();
+ if (rgbs.length != colors.length) {
+ globalTable = 0;
+ } else {
+ for (int j=0; j<colors.length; j++) {
+ if (!(rgbs[j].red == colors[j].red &&
+ rgbs[j].green == colors[j].green &&
+ rgbs[j].blue == colors[j].blue))
+ globalTable = 0;
+ }
+ }
+ }
+ }
+ }
+
try {
- outputStream.write(new byte[] { (byte)'G', (byte)'I', (byte)'F' });
- outputStream.write(new byte[] { (byte)'8', (byte)'9', (byte)'a' });
- outputStream.writeShort((short)image.width);
- outputStream.writeShort((short)image.height);
- outputStream.writeByte(bitField);
- outputStream.writeByte((byte)0);
- outputStream.writeByte((byte)0);
+ /* Step 3: Write the GIF89a Header and Logical Screen Descriptor. */
+ outputStream.write(GIF89a);
+ int bitField = globalTable*128 + (depth-1)*16 + depth-1;
+ outputStream.writeShort((short)logicalScreenWidth);
+ outputStream.writeShort((short)logicalScreenHeight);
+ outputStream.write(bitField);
+ outputStream.write(backgroundPixel);
+ outputStream.write(0); // Aspect ratio is 1:1
} catch (IOException e) {
SWT.error(SWT.ERROR_IO, e);
}
- writePalette(image.palette, image.depth);
- if (image.transparentPixel != -1 || image.disposalMethod != 0 || image.delayTime != 0) {
- writeGraphicsControlBlock(image);
+
+ /* Step 4: Write Global Color Table if applicable. */
+ if (globalTable == 1) {
+ writePalette(palette, depth);
+ }
+
+ /* Step 5: Write Application Extension if applicable. */
+ if (multi) {
+ int repeatCount = loader.repeatCount;
+ try {
+ outputStream.write(GIF_EXTENSION_BLOCK_ID);
+ outputStream.write(GIF_APPLICATION_EXTENSION_BLOCK_ID);
+ outputStream.write(NETSCAPE2_0.length);
+ outputStream.write(NETSCAPE2_0);
+ outputStream.write(3); // Three bytes follow
+ outputStream.write(1); // Extension type
+ outputStream.writeShort((short) repeatCount);
+ outputStream.write(0); // Block terminator
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ }
+
+ for (int frame=0; frame<frameCount; frame++) {
+
+ /* Step 6: Write Graphics Control Block for each frame if applicable. */
+ if (multi || data[frame].transparentPixel != -1) {
+ writeGraphicsControlBlock(data[frame]);
+ }
+
+ /* Step 7: Write Image Header for each frame. */
+ int x = data[frame].x;
+ int y = data[frame].y;
+ int width = data[frame].width;
+ int height = data[frame].height;
+ try {
+ outputStream.write(GIF_IMAGE_BLOCK_ID);
+ byte[] block = new byte[9];
+ block[0] = (byte)(x & 0xFF);
+ block[1] = (byte)((x >> 8) & 0xFF);
+ block[2] = (byte)(y & 0xFF);
+ block[3] = (byte)((y >> 8) & 0xFF);
+ block[4] = (byte)(width & 0xFF);
+ block[5] = (byte)((width >> 8) & 0xFF);
+ block[6] = (byte)(height & 0xFF);
+ block[7] = (byte)((height >> 8) & 0xFF);
+ block[8] = (byte)(globalTable == 0 ? (depth-1) | 0x80 : 0x00);
+ outputStream.write(block);
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+
+ /* Step 8: Write Local Color Table for each frame if applicable. */
+ if (globalTable == 0) {
+ writePalette(data[frame].palette, depth);
+ }
+
+ /* Step 9: Write the actual data for each frame. */
+ try {
+ outputStream.write(depth); // Minimum LZW Code size
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ new LZWCodec().encode(outputStream, data[frame]);
}
- writeImageBlock(image);
+
+ /* Step 10: Write GIF terminator. */
try {
outputStream.write(0x3B);
} catch (IOException e) {
@@ -463,55 +558,28 @@ final class GIFFileFormat extends FileFormat {
try {
outputStream.write(GIF_EXTENSION_BLOCK_ID);
outputStream.write(GIF_GRAPHICS_CONTROL_BLOCK_ID);
- outputStream.write(0x04); // size of block
byte[] gcBlock = new byte[4];
- gcBlock[0] = (byte)0xFD;
+ gcBlock[0] = 0;
gcBlock[1] = 0;
gcBlock[2] = 0;
gcBlock[3] = 0;
- if (image.transparentPixel == -1) {
- gcBlock[0] = (byte)(gcBlock[0] & 0xFE);
- } else {
- gcBlock[0] = (byte)(gcBlock[0] | 0x01);
+ if (image.transparentPixel != -1) {
+ gcBlock[0] = (byte)0x01;
gcBlock[3] = (byte)image.transparentPixel;
}
if (image.disposalMethod != 0) {
- gcBlock[0] = (byte)(gcBlock[0] | ((image.disposalMethod & 0x07) << 2));
+ gcBlock[0] |= (byte)((image.disposalMethod & 0x07) << 2);
}
if (image.delayTime != 0) {
gcBlock[1] = (byte)(image.delayTime & 0xFF);
gcBlock[2] = (byte)((image.delayTime >> 8) & 0xFF);
}
+ outputStream.write((byte)gcBlock.length);
outputStream.write(gcBlock);
- outputStream.write(0); // block terminator
- } catch (IOException e) {
- SWT.error(SWT.ERROR_IO, e);
- }
- }
-
- /**
- * Write the specified device independent image
- * to the current position in the output stream.
- */
- void writeImageBlock(ImageData image) {
- try {
- outputStream.write(GIF_IMAGE_BLOCK_ID);
- byte[] block = new byte[9];
- block[0] = (byte)(image.x & 0xFF);
- block[1] = (byte)((image.x >> 8) & 0xFF);
- block[2] = (byte)(image.y & 0xFF);
- block[3] = (byte)((image.y >> 8) & 0xFF);
- block[4] = (byte)(image.width & 0xFF);
- block[5] = (byte)((image.width >> 8) & 0xFF);
- block[6] = (byte)(image.height & 0xFF);
- block[7] = (byte)((image.height >> 8) & 0xFF);
- block[8] = 0; // no interlace, no sort, no local palette
- outputStream.write(block);
- outputStream.write(image.depth);
+ outputStream.write(0); // Block terminator
} catch (IOException e) {
SWT.error(SWT.ERROR_IO, e);
}
- new LZWCodec().encode(outputStream, image);
}
/**
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGAppn.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGAppn.java
index 3595b9baee..5c54492537 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGAppn.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGAppn.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGArithmeticConditioningTable.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGArithmeticConditioningTable.java
index b52b59a27b..fb4b9a305f 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGArithmeticConditioningTable.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGArithmeticConditioningTable.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGComment.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGComment.java
index 35d85afa73..dfb5c0f8b9 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGComment.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGComment.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGDecoder.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGDecoder.java
new file mode 100644
index 0000000000..1ecfff9636
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGDecoder.java
@@ -0,0 +1,6360 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal.image;
+
+import java.io.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+
+public class JPEGDecoder {
+
+ static final int DCTSIZE = 8;
+ static final int DCTSIZE2 = 64;
+ static final int NUM_QUANT_TBLS = 4;
+ static final int NUM_HUFF_TBLS = 4;
+ static final int NUM_ARITH_TBLS = 16;
+ static final int MAX_COMPS_IN_SCAN = 4;
+ static final int MAX_COMPONENTS = 10;
+ static final int MAX_SAMP_FACTOR = 4;
+ static final int D_MAX_BLOCKS_IN_MCU = 10;
+ static final int HUFF_LOOKAHEAD = 8;
+ static final int MAX_Q_COMPS = 4;
+ static final int IFAST_SCALE_BITS = 2;
+ static final int MAXJSAMPLE = 255;
+ static final int CENTERJSAMPLE = 128;
+ static final int MIN_GET_BITS = 32-7;
+ static final int INPUT_BUFFER_SIZE = 4096;
+
+ static final int SCALEBITS = 16; /* speediest right-shift on some machines */
+ static final int ONE_HALF = 1 << (SCALEBITS-1);
+
+ static final int RGB_RED = 2; /* Offset of Red in an RGB scanline element */
+ static final int RGB_GREEN = 1; /* Offset of Green */
+ static final int RGB_BLUE = 0; /* Offset of Blue */
+ static final int RGB_PIXELSIZE = 3;
+
+ static final int JBUF_PASS_THRU = 0;
+ static final int JBUF_SAVE_SOURCE = 1; /* Run source subobject only, save output */
+ static final int JBUF_CRANK_DEST = 2; /* Run dest subobject only, using saved data */
+ static final int JBUF_SAVE_AND_PASS = 3;
+
+ static final int JPEG_MAX_DIMENSION = 65500;
+ static final int BITS_IN_JSAMPLE = 8;
+
+ static final int JDITHER_NONE = 0; /* no dithering */
+ static final int JDITHER_ORDERED = 1; /* simple ordered dither */
+ static final int JDITHER_FS = 2;
+
+ static final int JDCT_ISLOW = 0; /* slow but accurate integer algorithm */
+ static final int JDCT_IFAST = 1; /* faster, less accurate integer method */
+ static final int JDCT_FLOAT = 2; /* floating-point: accurate, fast on fast HW */
+ static final int JDCT_DEFAULT = JDCT_ISLOW;
+
+ static final int JCS_UNKNOWN = 0; /* error/unspecified */
+ static final int JCS_GRAYSCALE = 1; /* monochrome */
+ static final int JCS_RGB = 2; /* red/green/blue */
+ static final int JCS_YCbCr = 3; /* Y/Cb/Cr (also known as YUV) */
+ static final int JCS_CMYK = 4; /* C/M/Y/K */
+ static final int JCS_YCCK = 5; /* Y/Cb/Cr/K */
+
+ static final int SAVED_COEFS = 6;
+ static final int Q01_POS = 1;
+ static final int Q10_POS = 8;
+ static final int Q20_POS = 16;
+ static final int Q11_POS = 9;
+ static final int Q02_POS = 2;
+
+ static final int CTX_PREPARE_FOR_IMCU = 0; /* need to prepare for MCU row */
+ static final int CTX_PROCESS_IMCU = 1; /* feeding iMCU to postprocessor */
+ static final int CTX_POSTPONED_ROW = 2; /* feeding postponed row group */
+
+ static final int APP0_DATA_LEN = 14; /* Length of interesting data in APP0 */
+ static final int APP14_DATA_LEN = 12; /* Length of interesting data in APP14 */
+ static final int APPN_DATA_LEN = 14; /* Must be the largest of the above!! */
+
+ /* markers */
+ static final int M_SOF0 = 0xc0;
+ static final int M_SOF1 = 0xc1;
+ static final int M_SOF2 = 0xc2;
+ static final int M_SOF3 = 0xc3;
+ static final int M_SOF5 = 0xc5;
+ static final int M_SOF6 = 0xc6;
+ static final int M_SOF7 = 0xc7;
+ static final int M_JPG = 0xc8;
+ static final int M_SOF9 = 0xc9;
+ static final int M_SOF10 = 0xca;
+ static final int M_SOF11 = 0xcb;
+ static final int M_SOF13 = 0xcd;
+ static final int M_SOF14 = 0xce;
+ static final int M_SOF15 = 0xcf;
+ static final int M_DHT = 0xc4;
+ static final int M_DAC = 0xcc;
+ static final int M_RST0 = 0xd0;
+ static final int M_RST1 = 0xd1;
+ static final int M_RST2 = 0xd2;
+ static final int M_RST3 = 0xd3;
+ static final int M_RST4 = 0xd4;
+ static final int M_RST5 = 0xd5;
+ static final int M_RST6 = 0xd6;
+ static final int M_RST7 = 0xd7;
+ static final int M_SOI = 0xd8;
+ static final int M_EOI = 0xd9;
+ static final int M_SOS = 0xda;
+ static final int M_DQT = 0xdb;
+ static final int M_DNL = 0xdc;
+ static final int M_DRI = 0xdd;
+ static final int M_DHP = 0xde;
+ static final int M_EXP = 0xdf;
+ static final int M_APP0 = 0xe0;
+ static final int M_APP1 = 0xe1;
+ static final int M_APP2 = 0xe2;
+ static final int M_APP3 = 0xe3;
+ static final int M_APP4 = 0xe4;
+ static final int M_APP5 = 0xe5;
+ static final int M_APP6 = 0xe6;
+ static final int M_APP7 = 0xe7;
+ static final int M_APP8 = 0xe8;
+ static final int M_APP9 = 0xe9;
+ static final int M_APP10 = 0xea;
+ static final int M_APP11 = 0xeb;
+ static final int M_APP12 = 0xec;
+ static final int M_APP13 = 0xed;
+ static final int M_APP14 = 0xee;
+ static final int M_APP15 = 0xef;
+ static final int M_JPG0 = 0xf0;
+ static final int M_JPG13 = 0xfd;
+ static final int M_COM = 0xfe;
+ static final int M_TEM = 0x01;
+ static final int M_ERROR = 0x100;
+
+ /* Values of global_state field (jdapi.c has some dependencies on ordering!) */
+ static final int CSTATE_START = 100; /* after create_compress */
+ static final int CSTATE_SCANNING = 101; /* start_compress done, write_scanlines OK */
+ static final int CSTATE_RAW_OK = 102; /* start_compress done, write_raw_data OK */
+ static final int CSTATE_WRCOEFS = 103; /* jpeg_write_coefficients done */
+ static final int DSTATE_START = 200; /* after create_decompress */
+ static final int DSTATE_INHEADER = 201; /* reading header markers, no SOS yet */
+ static final int DSTATE_READY = 202; /* found SOS, ready for start_decompress */
+ static final int DSTATE_PRELOAD = 203; /* reading multiscan file in start_decompress*/
+ static final int DSTATE_PRESCAN = 204; /* performing dummy pass for 2-pass quant */
+ static final int DSTATE_SCANNING = 205; /* start_decompress done, read_scanlines OK */
+ static final int DSTATE_RAW_OK = 206; /* start_decompress done, read_raw_data OK */
+ static final int DSTATE_BUFIMAGE = 207; /* expecting jpeg_start_output */
+ static final int DSTATE_BUFPOST = 208; /* looking for SOS/EOI in jpeg_finish_output */
+ static final int DSTATE_RDCOEFS = 209; /* reading file in jpeg_read_coefficients */
+ static final int DSTATE_STOPPING = 210; /* looking for EOI in jpeg_finish_decompress */
+
+ static final int JPEG_REACHED_SOS = 1; /* Reached start of new scan */
+ static final int JPEG_REACHED_EOI = 2; /* Reached end of image */
+ static final int JPEG_ROW_COMPLETED = 3; /* Completed one iMCU row */
+ static final int JPEG_SCAN_COMPLETED = 4; /* Completed last iMCU row of a scan */
+
+ static final int JPEG_SUSPENDED = 0; /* Suspended due to lack of input data */
+ static final int JPEG_HEADER_OK = 1; /* Found valid image datastream */
+ static final int JPEG_HEADER_TABLES_ONLY = 2; /* Found valid table-specs-only datastream */
+
+ /* Function pointers */
+ static final int DECOMPRESS_DATA = 0;
+ static final int DECOMPRESS_SMOOTH_DATA = 1;
+ static final int DECOMPRESS_ONEPASS = 2;
+
+ static final int CONSUME_DATA = 0;
+ static final int DUMMY_CONSUME_DATA = 1;
+
+ static final int PROCESS_DATA_SIMPLE_MAIN = 0;
+ static final int PROCESS_DATA_CONTEXT_MAIN = 1;
+ static final int PROCESS_DATA_CRANK_POST = 2;
+
+ static final int POST_PROCESS_1PASS = 0;
+ static final int POST_PROCESS_DATA_UPSAMPLE = 1;
+
+ static final int NULL_CONVERT = 0;
+ static final int GRAYSCALE_CONVERT = 1;
+ static final int YCC_RGB_CONVERT = 2;
+ static final int GRAY_RGB_CONVERT = 3;
+ static final int YCCK_CMYK_CONVERT = 4;
+
+ static final int NOOP_UPSAMPLE = 0;
+ static final int FULLSIZE_UPSAMPLE = 1;
+ static final int H2V1_FANCY_UPSAMPLE = 2;
+ static final int H2V1_UPSAMPLE = 3;
+ static final int H2V2_FANCY_UPSAMPLE = 4;
+ static final int H2V2_UPSAMPLE = 5;
+ static final int INT_UPSAMPLE = 6;
+
+ static final int INPUT_CONSUME_INPUT = 0;
+ static final int COEF_CONSUME_INPUT = 1;
+
+ static int extend_test[] = /* entry n is 2**(n-1) */
+ {
+ 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000
+ };
+
+ static int extend_offset[] = /* entry n is (-1 << n) + 1 */
+ {
+ 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
+ ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
+ ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
+ ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1
+ };
+
+ static int jpeg_natural_order[] = {
+ 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,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+ };
+
+ static final class JQUANT_TBL {
+ /* This array gives the coefficient quantizers in natural array order
+ * (not the zigzag order in which they are stored in a JPEG DQT marker).
+ * CAUTION: IJG versions prior to v6a kept this array in zigzag order.
+ */
+ short[] quantval = new short[DCTSIZE2]; /* quantization step for each coefficient */
+ /* This field is used only during compression. It's initialized false when
+ * the table is created, and set true when it's been output to the file.
+ * You could suppress output of a table by setting this to true.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* true when table has been output */
+ }
+
+ static final class JHUFF_TBL {
+ /* These two fields directly represent the contents of a JPEG DHT marker */
+ byte[] bits = new byte[17]; /* bits[k] = # of symbols with codes of */
+ /* length k bits; bits[0] is unused */
+ byte[] huffval = new byte[256]; /* The symbols, in order of incr code length */
+ /* This field is used only during compression. It's initialized false when
+ * the table is created, and set true when it's been output to the file.
+ * You could suppress output of a table by setting this to true.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* true when table has been output */
+ }
+
+ static final class bitread_perm_state { /* Bitreading state saved across MCUs */
+ int get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+ }
+
+ static final class bitread_working_state { /* Bitreading working state within an MCU */
+ /* Current data source location */
+ /* We need a copy, rather than munging the original, in case of suspension */
+ byte[] buffer; /* => next byte to read from source */
+ int bytes_offset;
+ int bytes_in_buffer; /* # of bytes remaining in source buffer */
+ /* Bit input buffer --- note these values are kept in register variables,
+ * not in this struct, inside the inner loops.
+ */
+ int get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+ /* Pointer needed by jpeg_fill_bit_buffer. */
+ jpeg_decompress_struct cinfo; /* back link to decompress master record */
+ }
+
+ static final class savable_state {
+ int EOBRUN; //Note that this is only used in the progressive case
+ int[] last_dc_val = new int[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+ }
+
+ static final class d_derived_tbl {
+ /* Basic tables: (element [0] of each array is unused) */
+ int[] maxcode = new int[18]; /* largest code of length k (-1 if none) */
+ /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
+ int[] valoffset = new int[17]; /* huffval[] offset for codes of length k */
+ /* valoffset[k] = huffval[] index of 1st symbol of code length k, less
+ * the smallest code of length k; so given a code of length k, the
+ * corresponding symbol is huffval[code + valoffset[k]]
+ */
+
+ /* Link to public Huffman table (needed only in jpeg_huff_decode) */
+ JHUFF_TBL pub;
+
+ /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
+ * the input data stream. If the next Huffman code is no more
+ * than HUFF_LOOKAHEAD bits long, we can obtain its length and
+ * the corresponding symbol directly from these tables.
+ */
+ int[] look_nbits = new int[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */
+ byte[] look_sym = new byte[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */
+ }
+
+ static final class jpeg_d_coef_controller {
+ int consume_data;
+ int decompress_data;
+
+ /* Pointer to array of coefficient virtual arrays, or null if none */
+ short[][][] coef_arrays;
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo.input_iMCU_row is also used for this. */
+ int MCU_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo.output_iMCU_row. */
+
+ /* In single-pass modes, it's sufficient to buffer just one MCU.
+ * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
+ * and let the entropy decoder write into that workspace each time.
+ * (On 80x86, the workspace is FAR even though it's not really very big;
+ * this is to keep the module interfaces unchanged when a large coefficient
+ * buffer is necessary.)
+ * In multi-pass modes, this array points to the current MCU's blocks
+ * within the virtual arrays; it is used only by the input side.
+ */
+ short[][] MCU_buffer = new short[D_MAX_BLOCKS_IN_MCU][];
+
+ /* In multi-pass modes, we need a virtual block array for each component. */
+ short[][][][] whole_image = new short[MAX_COMPONENTS][][][];
+
+ /* When doing block smoothing, we latch coefficient Al values here */
+ int[] coef_bits_latch;
+
+ short[] workspace;
+
+ void start_input_pass (jpeg_decompress_struct cinfo) {
+ cinfo.input_iMCU_row = 0;
+ start_iMCU_row(cinfo);
+ }
+
+ /* Reset within-iMCU-row counters for a new row (input side) */
+ void start_iMCU_row (jpeg_decompress_struct cinfo) {
+ jpeg_d_coef_controller coef = cinfo.coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo.comps_in_scan > 1) {
+ coef.MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (cinfo.input_iMCU_row < (cinfo.total_iMCU_rows-1))
+ coef.MCU_rows_per_iMCU_row = cinfo.cur_comp_info[0].v_samp_factor;
+ else
+ coef.MCU_rows_per_iMCU_row = cinfo.cur_comp_info[0].last_row_height;
+ }
+
+ coef.MCU_ctr = 0;
+ coef.MCU_vert_offset = 0;
+ }
+
+ }
+
+ static abstract class jpeg_entropy_decoder {
+ abstract void start_pass (jpeg_decompress_struct cinfo);
+ abstract boolean decode_mcu (jpeg_decompress_struct cinfo, short[][] MCU_data);
+
+ /* This is here to share code between baseline and progressive decoders; */
+ /* other modules probably should not use it */
+ boolean insufficient_data; /* set true after emitting warning */
+
+ bitread_working_state br_state_local = new bitread_working_state();
+ savable_state state_local = new savable_state();
+ }
+
+ static final class huff_entropy_decoder extends jpeg_entropy_decoder {
+ bitread_perm_state bitstate = new bitread_perm_state(); /* Bit buffer at start of MCU */
+ savable_state saved = new savable_state(); /* Other state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl[] dc_derived_tbls = new d_derived_tbl[NUM_HUFF_TBLS];
+ d_derived_tbl[] ac_derived_tbls = new d_derived_tbl[NUM_HUFF_TBLS];
+
+ /* Precalculated info set up by start_pass for use in decode_mcu: */
+
+ /* Pointers to derived tables to be used for each block within an MCU */
+ d_derived_tbl[] dc_cur_tbls = new d_derived_tbl[D_MAX_BLOCKS_IN_MCU];
+ d_derived_tbl[] ac_cur_tbls = new d_derived_tbl[D_MAX_BLOCKS_IN_MCU];
+ /* Whether we care about the DC and AC coefficient values for each block */
+ boolean[] dc_needed = new boolean[D_MAX_BLOCKS_IN_MCU];
+ boolean[] ac_needed = new boolean[D_MAX_BLOCKS_IN_MCU];
+
+ void start_pass (jpeg_decompress_struct cinfo) {
+ start_pass_huff_decoder(cinfo);
+ }
+
+ boolean decode_mcu (jpeg_decompress_struct cinfo, short[][] MCU_data) {
+ huff_entropy_decoder entropy = this;
+ int blkn;
+// BITREAD_STATE_VARS;
+ int get_buffer;
+ int bits_left;
+// bitread_working_state br_state = new bitread_working_state();
+// savable_state state = new savable_state();
+ bitread_working_state br_state = br_state_local;
+ savable_state state = state_local;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo.restart_interval != 0) {
+ if (entropy.restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return false;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy.insufficient_data) {
+
+ /* Load up working state */
+// BITREAD_LOAD_STATE(cinfo,entropy.bitstate);
+ br_state.cinfo = cinfo;
+ br_state.buffer = cinfo.buffer;
+ br_state.bytes_in_buffer = cinfo.bytes_in_buffer;
+ br_state.bytes_offset = cinfo.bytes_offset;
+ get_buffer = entropy.bitstate.get_buffer;
+ bits_left = entropy.bitstate.bits_left;
+
+// ASSIGN_STATE(state, entropy.saved);
+ state.last_dc_val[0] = entropy.saved.last_dc_val[0];
+ state.last_dc_val[1] = entropy.saved.last_dc_val[1];
+ state.last_dc_val[2] = entropy.saved.last_dc_val[2];
+ state.last_dc_val[3] = entropy.saved.last_dc_val[3];
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) {
+ short[] block = MCU_data[blkn];
+ d_derived_tbl dctbl = entropy.dc_cur_tbls[blkn];
+ d_derived_tbl actbl = entropy.ac_cur_tbls[blkn];
+ int s = 0, k, r;
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+// HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);
+ {
+ int nb = 0, look;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ if (!jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ nb = 1;
+// goto slowlabel;
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,dctbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+// look = PEEK_BITS(HUFF_LOOKAHEAD);
+ if (nb != 1) {
+ look = (( (get_buffer >> (bits_left - (HUFF_LOOKAHEAD)))) & ((1<<(HUFF_LOOKAHEAD))-1));
+ if ((nb = dctbl.look_nbits[look]) != 0) {
+// DROP_BITS(nb);
+ bits_left -= nb;
+ s = dctbl.look_sym[look] & 0xFF;
+ } else {
+ nb = HUFF_LOOKAHEAD+1;
+// slowlabel:
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,dctbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ }
+
+ if (s != 0) {
+// CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ {
+ if (bits_left < (s)) {
+ if (!jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) {
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// r = GET_BITS(s);
+ r = (( (get_buffer >> (bits_left -= (s)))) & ((1<<(s))-1));
+// s = HUFF_EXTEND(r, s);
+ s = ((r) < extend_test[s] ? (r) + extend_offset[s] : (r));
+ }
+
+ if (entropy.dc_needed[blkn]) {
+ /* Convert DC difference to actual value, update last_dc_val */
+ int ci = cinfo.MCU_membership[blkn];
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
+ block[0] = (short) s;
+ }
+
+ if (entropy.ac_needed[blkn]) {
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* Since zeroes are skipped, output area must be cleared beforehand */
+ for (k = 1; k < DCTSIZE2; k++) {
+// HUFF_DECODE(s, br_state, actbl, return FALSE, label2);
+ {
+ int nb = 0, look;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ if (!jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ nb = 1;
+// goto slowlabel;
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ if (nb != 1) {
+// look = PEEK_BITS(HUFF_LOOKAHEAD);
+ look = (( (get_buffer >> (bits_left - (HUFF_LOOKAHEAD)))) & ((1<<(HUFF_LOOKAHEAD))-1));
+ if ((nb = actbl.look_nbits[look]) != 0) {
+// DROP_BITS(nb);
+ bits_left -= (nb);
+ s = actbl.look_sym[look] & 0xFF;
+ } else {
+ nb = HUFF_LOOKAHEAD+1;
+// slowlabel:
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ }
+ r = s >> 4;
+ s &= 15;
+
+ if (s != 0) {
+ k += r;
+// CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ {
+ if (bits_left < (s)) {
+ if (!jpeg_fill_bit_buffer(br_state, get_buffer, bits_left, s)) {
+ return false;
+ }
+ get_buffer = (br_state).get_buffer;
+ bits_left = (br_state).bits_left;
+ }
+ }
+// r = GET_BITS(s);
+ r = (((get_buffer >> (bits_left -= (s)))) & ((1 << (s)) - 1));
+// s = HUFF_EXTEND(r, s);
+ s = ((r) < extend_test[s] ? (r) + extend_offset[s] : (r));
+ /*
+ * Output coefficient in natural (dezigzagged)
+ * order. Note: the extra entries in
+ * jpeg_natural_order[] will save us if k >=
+ * DCTSIZE2, which could happen if the data is
+ * corrupted.
+ */
+ block[jpeg_natural_order[k]] = (short) s;
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ } else {
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* In this path we just discard the values */
+ for (k = 1; k < DCTSIZE2; k++) {
+// HUFF_DECODE(s, br_state, actbl, return FALSE, label3);
+ {
+ int nb = 0, look;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ if (!jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ nb = 1;
+// goto slowlabel;
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ if (nb != 1) {
+// look = PEEK_BITS(HUFF_LOOKAHEAD);
+ look = (( (get_buffer >> (bits_left - (HUFF_LOOKAHEAD)))) & ((1<<(HUFF_LOOKAHEAD))-1));
+ if ((nb = actbl.look_nbits[look]) != 0) {
+// DROP_BITS(nb);
+ bits_left -= (nb);
+ s = actbl.look_sym[look] & 0xFF;
+ } else {
+ nb = HUFF_LOOKAHEAD+1;
+// slowlabel:
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ }
+ r = s >> 4;
+ s &= 15;
+
+ if (s != 0) {
+ k += r;
+// CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ {
+ if (bits_left < (s)) {
+ if (!jpeg_fill_bit_buffer((br_state),get_buffer,bits_left,s)) {
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// DROP_BITS(s);
+ bits_left -= s;
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ }
+ }
+
+ /* Completed MCU, so update state */
+// BITREAD_SAVE_STATE(cinfo,entropy.bitstate);
+ cinfo.buffer = br_state.buffer;
+ cinfo.bytes_in_buffer = br_state.bytes_in_buffer;
+ cinfo.bytes_offset = br_state.bytes_offset;
+ entropy.bitstate.get_buffer = get_buffer;
+ entropy.bitstate.bits_left = bits_left;
+// ASSIGN_STATE(entropy.saved, state);
+ entropy.saved.last_dc_val[0] = state.last_dc_val[0];
+ entropy.saved.last_dc_val[1] = state.last_dc_val[1];
+ entropy.saved.last_dc_val[2] = state.last_dc_val[2];
+ entropy.saved.last_dc_val[3] = state.last_dc_val[3];
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy.restarts_to_go--;
+
+ return true;
+ }
+
+ void start_pass_huff_decoder (jpeg_decompress_struct cinfo) {
+ huff_entropy_decoder entropy = this;
+ int ci, blkn, dctbl, actbl;
+ jpeg_component_info compptr;
+
+ /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+ * This ought to be an error condition, but we make it a warning because
+ * there are some baseline files out there with all zeroes in these bytes.
+ */
+ if (cinfo.Ss != 0 || cinfo.Se != DCTSIZE2-1 || cinfo.Ah != 0 || cinfo.Al != 0) {
+// WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+ }
+
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+ compptr = cinfo.cur_comp_info[ci];
+ dctbl = compptr.dc_tbl_no;
+ actbl = compptr.ac_tbl_no;
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_d_derived_tbl(cinfo, true, dctbl, entropy.dc_derived_tbls[dctbl] = new d_derived_tbl());
+ jpeg_make_d_derived_tbl(cinfo, false, actbl, entropy.ac_derived_tbls[actbl] = new d_derived_tbl());
+ /* Initialize DC predictions to 0 */
+ entropy.saved.last_dc_val[ci] = 0;
+ }
+
+ /* Precalculate decoding info for each block in an MCU of this scan */
+ for (blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) {
+ ci = cinfo.MCU_membership[blkn];
+ compptr = cinfo.cur_comp_info[ci];
+ /* Precalculate which table to use for each block */
+ entropy.dc_cur_tbls[blkn] = entropy.dc_derived_tbls[compptr.dc_tbl_no];
+ entropy.ac_cur_tbls[blkn] = entropy.ac_derived_tbls[compptr.ac_tbl_no];
+ /* Decide whether we really care about the coefficient values */
+ if (compptr.component_needed) {
+ entropy.dc_needed[blkn] = true;
+ /* we don't need the ACs if producing a 1/8th-size image */
+ entropy.ac_needed[blkn] = (compptr.DCT_scaled_size > 1);
+ } else {
+ entropy.dc_needed[blkn] = entropy.ac_needed[blkn] = false;
+ }
+ }
+
+ /* Initialize bitread state variables */
+ entropy.bitstate.bits_left = 0;
+ entropy.bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy.insufficient_data = false;
+
+ /* Initialize restart counter */
+ entropy.restarts_to_go = cinfo.restart_interval;
+ }
+
+ boolean process_restart (jpeg_decompress_struct cinfo) {
+ huff_entropy_decoder entropy = this;
+ int ci;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo.marker.discarded_bytes += entropy.bitstate.bits_left / 8;
+ entropy.bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (! read_restart_marker (cinfo))
+ return false;
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++)
+ entropy.saved.last_dc_val[ci] = 0;
+
+ /* Reset restart counter */
+ entropy.restarts_to_go = cinfo.restart_interval;
+
+ /* Reset out-of-data flag, unless read_restart_marker left us smack up
+ * against a marker. In that case we will end up treating the next data
+ * segment as empty, and we can avoid producing bogus output pixels by
+ * leaving the flag set.
+ */
+ if (cinfo.unread_marker == 0)
+ entropy.insufficient_data = false;
+
+ return true;
+ }
+ }
+
+ static final class phuff_entropy_decoder extends jpeg_entropy_decoder {
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate = new bitread_perm_state(); /* Bit buffer at start of MCU */
+ savable_state saved = new savable_state(); /* Other state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl[] derived_tbls = new d_derived_tbl[NUM_HUFF_TBLS];
+
+ d_derived_tbl ac_derived_tbl; /* active table during an AC scan */
+
+ int[] newnz_pos = new int[DCTSIZE2];
+
+ void start_pass (jpeg_decompress_struct cinfo) {
+ start_pass_phuff_decoder(cinfo);
+ }
+
+ boolean decode_mcu (jpeg_decompress_struct cinfo, short[][] MCU_data) {
+ boolean is_DC_band = (cinfo.Ss == 0);
+ if (cinfo.Ah == 0) {
+ if (is_DC_band)
+ return decode_mcu_DC_first(cinfo, MCU_data);
+ else
+ return decode_mcu_AC_first(cinfo, MCU_data);
+ } else {
+ if (is_DC_band)
+ return decode_mcu_DC_refine(cinfo, MCU_data);
+ else
+ return decode_mcu_AC_refine(cinfo, MCU_data);
+ }
+ }
+
+ boolean decode_mcu_DC_refine (jpeg_decompress_struct cinfo, short[][] MCU_data) {
+ phuff_entropy_decoder entropy = this;
+ int p1 = 1 << cinfo.Al; /* 1 in the bit position being coded */
+ int blkn;
+ short[] block;
+// BITREAD_STATE_VARS;
+ int get_buffer;
+ int bits_left;
+// bitread_working_state br_state = new bitread_working_state();
+ bitread_working_state br_state = br_state_local;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo.restart_interval != 0) {
+ if (entropy.restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return false;
+ }
+
+ /* Not worth the cycles to check insufficient_data here,
+ * since we will not change the data anyway if we read zeroes.
+ */
+
+ /* Load up working state */
+// BITREAD_LOAD_STATE(cinfo,entropy.bitstate);
+ br_state.cinfo = cinfo;
+ br_state.buffer = cinfo.buffer;
+ br_state.bytes_in_buffer = cinfo.bytes_in_buffer;
+ br_state.bytes_offset = cinfo.bytes_offset;
+ get_buffer = entropy.bitstate.get_buffer;
+ bits_left = entropy.bitstate.bits_left;
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* Encoded data is simply the next bit of the two's-complement DC value */
+// CHECK_BIT_BUFFER(br_state, 1, return FALSE);
+ {
+ if (bits_left < (1)) {
+ if (!jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) {
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// if (GET_BITS(1))
+ if ((( (get_buffer >> (bits_left -= (1)))) & ((1<<(1))-1)) != 0)
+ block[0] |= p1;
+ /* Note: since we use |=, repeating the assignment later is safe */
+ }
+
+ /* Completed MCU, so update state */
+// BITREAD_SAVE_STATE(cinfo,entropy.bitstate);
+ cinfo.buffer = br_state.buffer;
+ cinfo.bytes_in_buffer = br_state.bytes_in_buffer;
+ cinfo.bytes_offset = br_state.bytes_offset;
+ entropy.bitstate.get_buffer = get_buffer;
+ entropy.bitstate.bits_left = bits_left;
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy.restarts_to_go--;
+
+ return true;
+
+ }
+
+ boolean decode_mcu_AC_refine (jpeg_decompress_struct cinfo, short[][] MCU_data) {
+ phuff_entropy_decoder entropy = this;
+ int Se = cinfo.Se;
+ int p1 = 1 << cinfo.Al; /* 1 in the bit position being coded */
+ int m1 = (-1) << cinfo.Al; /* -1 in the bit position being coded */
+ int s = 0, k, r;
+ int EOBRUN;
+ short[] block;
+ short[] thiscoef;
+// BITREAD_STATE_VARS;
+ int get_buffer;
+ int bits_left;
+// bitread_working_state br_state = new bitread_working_state();
+ bitread_working_state br_state = br_state_local;
+
+ d_derived_tbl tbl;
+ int num_newnz;
+ int[] newnz_pos = entropy.newnz_pos;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo.restart_interval != 0) {
+ if (entropy.restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return false;
+ }
+
+ /* If we've run out of data, don't modify the MCU.
+ */
+ if (! entropy.insufficient_data) {
+
+ /* Load up working state */
+// BITREAD_LOAD_STATE(cinfo,entropy.bitstate);
+ br_state.cinfo = cinfo;
+ br_state.buffer = cinfo.buffer;
+ br_state.bytes_in_buffer = cinfo.bytes_in_buffer;
+ br_state.bytes_offset = cinfo.bytes_offset;
+ get_buffer = entropy.bitstate.get_buffer;
+ bits_left = entropy.bitstate.bits_left;
+
+ EOBRUN = entropy.saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = entropy.ac_derived_tbl;
+
+ /* If we are forced to suspend, we must undo the assignments to any newly
+ * nonzero coefficients in the block, because otherwise we'd get confused
+ * next time about which coefficients were already nonzero.
+ * But we need not undo addition of bits to already-nonzero coefficients;
+ * instead, we can test the current bit to see if we already did it.
+ */
+ num_newnz = 0;
+
+ /* initialize coefficient loop counter to start of band */
+ k = cinfo.Ss;
+
+ if (EOBRUN == 0) {
+ for (; k <= Se; k++) {
+// HUFF_DECODE(s, br_state, tbl, goto undoit, label3);
+ {
+ int nb = 0, look;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) {
+// failaction;
+ while (num_newnz > 0)
+ block[newnz_pos[--num_newnz]] = 0;
+
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ nb = 1;
+// goto slowlabel;
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb)) < 0) {
+// failaction;
+ while (num_newnz > 0)
+ block[newnz_pos[--num_newnz]] = 0;
+
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ if (nb != 1) {
+// look = PEEK_BITS(HUFF_LOOKAHEAD);
+ look = (( (get_buffer >> (bits_left - (HUFF_LOOKAHEAD)))) & ((1<<(HUFF_LOOKAHEAD))-1));
+ if ((nb = tbl.look_nbits[look]) != 0) {
+// DROP_BITS(nb);
+ bits_left -= nb;
+ s = tbl.look_sym[look] & 0xFF;
+ } else {
+ nb = HUFF_LOOKAHEAD+1;
+// slowlabel:
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb)) < 0) {
+// failaction;
+ while (num_newnz > 0)
+ block[newnz_pos[--num_newnz]] = 0;
+
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ }
+ r = s >> 4;
+ s &= 15;
+ if (s != 0) {
+ if (s != 1) { /* size of new coef should always be 1 */
+// WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
+ }
+// CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ {
+ if (bits_left < (1)) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) {
+// failaction;
+ while (num_newnz > 0)
+ block[newnz_pos[--num_newnz]] = 0;
+
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// if (GET_BITS(1))
+ if ((( (get_buffer >> (bits_left -= (1)))) & ((1<<(1))-1)) != 0)
+ s = p1; /* newly nonzero coef is positive */
+ else
+ s = m1; /* newly nonzero coef is negative */
+ } else {
+ if (r != 15) {
+ EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */
+ if (r != 0) {
+// CHECK_BIT_BUFFER(br_state, r, goto undoit);
+ {
+ if (bits_left < (r)) {
+ if (!jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,r)) {
+// failaction;
+ while (num_newnz > 0)
+ block[newnz_pos[--num_newnz]] = 0;
+
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// r = GET_BITS(r);
+ r = (( (get_buffer >> (bits_left -= (r)))) & ((1<<(r))-1));
+ EOBRUN += r;
+ }
+ break; /* rest of block is handled by EOB logic */
+ }
+ /* note s = 0 for processing ZRL */
+ }
+ /* Advance over already-nonzero coefs and r still-zero coefs,
+ * appending correction bits to the nonzeroes. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ do {
+ thiscoef = block;
+ int thiscoef_offset = jpeg_natural_order[k];
+ if (thiscoef[thiscoef_offset] != 0) {
+// CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ {
+ if (bits_left < (1)) {
+ if (!jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) {
+// failaction;
+ while (num_newnz > 0)
+ block[newnz_pos[--num_newnz]] = 0;
+
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// if (GET_BITS(1)) {
+ if ((( (get_buffer >> (bits_left -= (1)))) & ((1<<(1))-1)) != 0) {
+ if ((thiscoef[thiscoef_offset] & p1) == 0) { /* do nothing if already set it */
+ if (thiscoef[thiscoef_offset] >= 0)
+ thiscoef[thiscoef_offset] += p1;
+ else
+ thiscoef[thiscoef_offset] += m1;
+ }
+ }
+ } else {
+ if (--r < 0)
+ break; /* reached target zero coefficient */
+ }
+ k++;
+ } while (k <= Se);
+ if (s != 0) {
+ int pos = jpeg_natural_order[k];
+ /* Output newly nonzero coefficient */
+ block[pos] = (short) s;
+ /* Remember its position in case we have to suspend */
+ newnz_pos[num_newnz++] = pos;
+ }
+ }
+ }
+
+ if (EOBRUN > 0) {
+ /* Scan any remaining coefficient positions after the end-of-band
+ * (the last newly nonzero coefficient, if any). Append a correction
+ * bit to each already-nonzero coefficient. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ for (; k <= Se; k++) {
+ thiscoef = block;
+ int thiscoef_offset = jpeg_natural_order[k];
+ if (thiscoef[thiscoef_offset] != 0) {
+// CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ {
+ if (bits_left < (1)) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) {
+// failaction;
+ while (num_newnz > 0)
+ block[newnz_pos[--num_newnz]] = 0;
+
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// if (GET_BITS(1)) {
+ if ((( (get_buffer >> (bits_left -= (1)))) & ((1<<(1))-1)) != 0) {
+ if ((thiscoef[thiscoef_offset] & p1) == 0) { /* do nothing if already changed it */
+ if (thiscoef[thiscoef_offset] >= 0)
+ thiscoef[thiscoef_offset] += p1;
+ else
+ thiscoef[thiscoef_offset] += m1;
+ }
+ }
+ }
+ }
+ /* Count one block completed in EOB run */
+ EOBRUN--;
+ }
+
+ /* Completed MCU, so update state */
+// BITREAD_SAVE_STATE(cinfo,entropy.bitstate);
+ cinfo.buffer = br_state.buffer;
+ cinfo.bytes_in_buffer = br_state.bytes_in_buffer;
+ cinfo.bytes_offset = br_state.bytes_offset;
+ entropy.bitstate.get_buffer = get_buffer;
+ entropy.bitstate.bits_left = bits_left;
+
+ entropy.saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy.restarts_to_go--;
+
+ return true;
+
+// undoit:
+// /* Re-zero any output coefficients that we made newly nonzero */
+// while (num_newnz > 0)
+// (*block)[newnz_pos[--num_newnz]] = 0;
+//
+// return false;
+
+ }
+
+ boolean decode_mcu_AC_first (jpeg_decompress_struct cinfo, short[][] MCU_data) {
+ phuff_entropy_decoder entropy = this;
+ int Se = cinfo.Se;
+ int Al = cinfo.Al;
+ int s = 0, k, r;
+ int EOBRUN;
+ short[] block;
+// BITREAD_STATE_VARS;
+ int get_buffer;
+ int bits_left;
+// bitread_working_state br_state = new bitread_working_state();
+ bitread_working_state br_state = br_state_local;
+
+ d_derived_tbl tbl;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo.restart_interval != 0) {
+ if (entropy.restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return false;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy.insufficient_data) {
+
+ /* Load up working state.
+ * We can avoid loading/saving bitread state if in an EOB run.
+ */
+ EOBRUN = entropy.saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+
+ if (EOBRUN > 0) /* if it's a band of zeroes... */
+ EOBRUN--; /* ...process it now (we do nothing) */
+ else {
+// BITREAD_LOAD_STATE(cinfo,entropy.bitstate);
+ br_state.cinfo = cinfo;
+ br_state.buffer = cinfo.buffer;
+ br_state.bytes_in_buffer = cinfo.bytes_in_buffer;
+ br_state.bytes_offset = cinfo.bytes_offset;
+ get_buffer = entropy.bitstate.get_buffer;
+ bits_left = entropy.bitstate.bits_left;
+
+ block = MCU_data[0];
+ tbl = entropy.ac_derived_tbl;
+
+ for (k = cinfo.Ss; k <= Se; k++) {
+// HUFF_DECODE(s, br_state, tbl, return FALSE, label2);
+ {
+ int nb = 0, look;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ nb = 1;
+// goto slowlabel;
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ if (nb != 1) {
+// look = PEEK_BITS(HUFF_LOOKAHEAD);
+ look = (( (get_buffer >> (bits_left - (HUFF_LOOKAHEAD)))) & ((1<<(HUFF_LOOKAHEAD))-1));
+
+ if ((nb = tbl.look_nbits[look]) != 0) {
+// DROP_BITS(nb);
+ bits_left -= nb;
+ s = tbl.look_sym[look] & 0xFF;
+ } else {
+ nb = HUFF_LOOKAHEAD+1;
+// slowlabel:
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ }
+ r = s >> 4;
+ s &= 15;
+ if (s != 0) {
+ k += r;
+// CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ {
+ if (bits_left < (s)) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) {
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// r = GET_BITS(s);
+ r = (( (get_buffer >> (bits_left -= (s)))) & ((1<<(s))-1));
+// s = HUFF_EXTEND(r, s);
+ s = ((r) < extend_test[s] ? (r) + extend_offset[s] : (r));
+ /* Scale and output coefficient in natural (dezigzagged) order */
+ block[jpeg_natural_order[k]] = (short) (s << Al);
+ } else {
+ if (r == 15) { /* ZRL */
+ k += 15; /* skip 15 zeroes in band */
+ } else { /* EOBr, run length is 2^r + appended bits */
+ EOBRUN = 1 << r;
+ if (r != 0) { /* EOBr, r > 0 */
+// CHECK_BIT_BUFFER(br_state, r, return FALSE);
+ {
+ if (bits_left < (r)) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,r)) {
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// r = GET_BITS(r);
+ r = (( (get_buffer >> (bits_left -= (r)))) & ((1<<(r))-1));
+ EOBRUN += r;
+ }
+ EOBRUN--; /* this band is processed at this moment */
+ break; /* force end-of-band */
+ }
+ }
+ }
+
+// BITREAD_SAVE_STATE(cinfo,entropy.bitstate);
+ cinfo.buffer = br_state.buffer;
+ cinfo.bytes_in_buffer = br_state.bytes_in_buffer;
+ cinfo.bytes_offset = br_state.bytes_offset;
+ entropy.bitstate.get_buffer = get_buffer;
+ entropy.bitstate.bits_left = bits_left;
+ }
+
+ /* Completed MCU, so update state */
+ entropy.saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy.restarts_to_go--;
+
+ return true;
+ }
+
+ boolean decode_mcu_DC_first (jpeg_decompress_struct cinfo, short[][] MCU_data) {
+ phuff_entropy_decoder entropy = this;
+ int Al = cinfo.Al;
+ int s = 0, r;
+ int blkn, ci;
+ short[] block;
+// BITREAD_STATE_VARS;
+ int get_buffer;
+ int bits_left;
+// bitread_working_state br_state = new bitread_working_state();
+ bitread_working_state br_state = br_state_local;
+
+// savable_state state = new savable_state();
+ savable_state state = state_local;
+ d_derived_tbl tbl;
+ jpeg_component_info compptr;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo.restart_interval != 0) {
+ if (entropy.restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return false;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy.insufficient_data) {
+
+ /* Load up working state */
+// BITREAD_LOAD_STATE(cinfo,entropy.bitstate);
+ br_state.cinfo = cinfo;
+ br_state.buffer = cinfo.buffer;
+ br_state.bytes_in_buffer = cinfo.bytes_in_buffer;
+ br_state.bytes_offset = cinfo.bytes_offset;
+ get_buffer = entropy.bitstate.get_buffer;
+ bits_left = entropy.bitstate.bits_left;
+
+// ASSIGN_STATE(state, entropy.saved);
+ state.EOBRUN = entropy.saved.EOBRUN;
+ state.last_dc_val[0] = entropy.saved.last_dc_val[0];
+ state.last_dc_val[1] = entropy.saved.last_dc_val[1];
+ state.last_dc_val[2] = entropy.saved.last_dc_val[2];
+ state.last_dc_val[3] = entropy.saved.last_dc_val[3];
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo.blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo.MCU_membership[blkn];
+ compptr = cinfo.cur_comp_info[ci];
+ tbl = entropy.derived_tbls[compptr.dc_tbl_no];
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+// HUFF_DECODE(s, br_state, tbl, return FALSE, label1);
+ {
+ int nb = 0, look;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ if (bits_left < HUFF_LOOKAHEAD) {
+ nb = 1;
+// goto slowlabel;
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ if (nb != 1) {
+// look = PEEK_BITS(HUFF_LOOKAHEAD);
+ look = (( (get_buffer >> (bits_left - (HUFF_LOOKAHEAD)))) & ((1<<(HUFF_LOOKAHEAD))-1));
+
+ if ((nb = tbl.look_nbits[look]) != 0) {
+// DROP_BITS(nb);
+ bits_left -= nb;
+ s = tbl.look_sym[look] & 0xFF;
+ } else {
+ nb = HUFF_LOOKAHEAD+1;
+// slowlabel:
+ if ((s=jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb)) < 0) {
+ return false;
+ }
+ get_buffer = br_state.get_buffer; bits_left = br_state.bits_left;
+ }
+ }
+ }
+ if (s != 0) {
+// CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ {
+ if (bits_left < (s)) {
+ if (! jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) {
+ return false;
+ }
+ get_buffer = (br_state).get_buffer; bits_left = (br_state).bits_left;
+ }
+ }
+// r = GET_BITS(s);
+ r = (( (get_buffer >> (bits_left -= (s)))) & ((1<<(s))-1));
+// s = HUFF_EXTEND(r, s);
+ s = ((r) < extend_test[s] ? (r) + extend_offset[s] : (r));
+ }
+
+ /* Convert DC difference to actual value, update last_dc_val */
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */
+ block[0] = (short) (s << Al);
+ }
+
+ /* Completed MCU, so update state */
+// BITREAD_SAVE_STATE(cinfo,entropy.bitstate);
+ cinfo.buffer = br_state.buffer;
+ cinfo.bytes_in_buffer = br_state.bytes_in_buffer;
+ cinfo.bytes_offset = br_state.bytes_offset;
+ entropy.bitstate.get_buffer = get_buffer;
+ entropy.bitstate.bits_left = bits_left;
+// ASSIGN_STATE(entropy.saved, state);
+ entropy.saved.EOBRUN = state.EOBRUN;
+ entropy.saved.last_dc_val[0] = state.last_dc_val[0];
+ entropy.saved.last_dc_val[1] = state.last_dc_val[1];
+ entropy.saved.last_dc_val[2] = state.last_dc_val[2];
+ entropy.saved.last_dc_val[3] = state.last_dc_val[3];
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy.restarts_to_go--;
+
+ return true;
+ }
+
+ boolean process_restart (jpeg_decompress_struct cinfo) {
+ phuff_entropy_decoder entropy = this;
+ int ci;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo.marker.discarded_bytes += entropy.bitstate.bits_left / 8;
+ entropy.bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (! read_restart_marker (cinfo))
+ return false;
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++)
+ entropy.saved.last_dc_val[ci] = 0;
+ /* Re-init EOB run count, too */
+ entropy.saved.EOBRUN = 0;
+
+ /* Reset restart counter */
+ entropy.restarts_to_go = cinfo.restart_interval;
+
+ /* Reset out-of-data flag, unless read_restart_marker left us smack up
+ * against a marker. In that case we will end up treating the next data
+ * segment as empty, and we can avoid producing bogus output pixels by
+ * leaving the flag set.
+ */
+ if (cinfo.unread_marker == 0)
+ entropy.insufficient_data = false;
+
+ return true;
+ }
+
+ void start_pass_phuff_decoder (jpeg_decompress_struct cinfo) {
+ phuff_entropy_decoder entropy = this;
+ boolean is_DC_band, bad;
+ int ci, coefi, tbl;
+ int[] coef_bit_ptr;
+ jpeg_component_info compptr;
+
+ is_DC_band = (cinfo.Ss == 0);
+
+ /* Validate scan parameters */
+ bad = false;
+ if (is_DC_band) {
+ if (cinfo.Se != 0)
+ bad = true;
+ } else {
+ /* need not check Ss/Se < 0 since they came from unsigned bytes */
+ if (cinfo.Ss > cinfo.Se || cinfo.Se >= DCTSIZE2)
+ bad = true;
+ /* AC scans may have only one component */
+ if (cinfo.comps_in_scan != 1)
+ bad = true;
+ }
+ if (cinfo.Ah != 0) {
+ /* Successive approximation refinement scan: must have Al = Ah-1. */
+ if (cinfo.Al != cinfo.Ah-1)
+ bad = true;
+ }
+ if (cinfo.Al > 13) /* need not check for < 0 */
+ bad = true;
+ /* Arguably the maximum Al value should be less than 13 for 8-bit precision,
+ * but the spec doesn't say so, and we try to be liberal about what we
+ * accept. Note: large Al values could result in out-of-range DC
+ * coefficients during early scans, leading to bizarre displays due to
+ * overflows in the IDCT math. But we won't crash.
+ */
+ if (bad)
+ error();
+// ERREXIT4(cinfo, JERR_BAD_PROGRESSION, cinfo.Ss, cinfo.Se, cinfo.Ah, cinfo.Al);
+ /* Update progression status, and verify that scan order is legal.
+ * Note that inter-scan inconsistencies are treated as warnings
+ * not fatal errors ... not clear if this is right way to behave.
+ */
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+ int cindex = cinfo.cur_comp_info[ci].component_index;
+ coef_bit_ptr = cinfo.coef_bits[cindex];
+ if (!is_DC_band && coef_bit_ptr[0] < 0) {/* AC without prior DC scan */
+// WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+ }
+ for (coefi = cinfo.Ss; coefi <= cinfo.Se; coefi++) {
+ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+ if (cinfo.Ah != expected) {
+// WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+ }
+ coef_bit_ptr[coefi] = cinfo.Al;
+ }
+ }
+
+ /* Select MCU decoding routine */
+// if (cinfo.Ah == 0) {
+// if (is_DC_band)
+// entropy.pub.decode_mcu = decode_mcu_DC_first;
+// else
+// entropy.pub.decode_mcu = decode_mcu_AC_first;
+// } else {
+// if (is_DC_band)
+// entropy.pub.decode_mcu = decode_mcu_DC_refine;
+// else
+// entropy.pub.decode_mcu = decode_mcu_AC_refine;
+// }
+
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+ compptr = cinfo.cur_comp_info[ci];
+ /* Make sure requested tables are present, and compute derived tables.
+ * We may build same derived table more than once, but it's not expensive.
+ */
+ if (is_DC_band) {
+ if (cinfo.Ah == 0) { /* DC refinement needs no table */
+ tbl = compptr.dc_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, true, tbl, entropy.derived_tbls[tbl] = new d_derived_tbl());
+ }
+ } else {
+ tbl = compptr.ac_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, false, tbl, entropy.derived_tbls[tbl] = new d_derived_tbl());
+ /* remember the single active table */
+ entropy.ac_derived_tbl = entropy.derived_tbls[tbl];
+ }
+ /* Initialize DC predictions to 0 */
+ entropy.saved.last_dc_val[ci] = 0;
+ }
+
+ /* Initialize bitread state variables */
+ entropy.bitstate.bits_left = 0;
+ entropy.bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy.insufficient_data = false;
+
+ /* Initialize private state variables */
+ entropy.saved.EOBRUN = 0;
+
+ /* Initialize restart counter */
+ entropy.restarts_to_go = cinfo.restart_interval;
+ }
+
+ }
+
+ static final class jpeg_component_info {
+ /* These values are fixed over the whole image. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOF marker. */
+ int component_id; /* identifier for this component (0..255) */
+ int component_index; /* its index in SOF or cinfo.comp_info[] */
+ int h_samp_factor; /* horizontal sampling factor (1..4) */
+ int v_samp_factor; /* vertical sampling factor (1..4) */
+ int quant_tbl_no; /* quantization table selector (0..3) */
+ /* These values may vary between scans. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOS marker. */
+ /* The decompressor output side may not use these variables. */
+ int dc_tbl_no; /* DC entropy table selector (0..3) */
+ int ac_tbl_no; /* AC entropy table selector (0..3) */
+
+ /* Remaining fields should be treated as private by applications. */
+
+ /* These values are computed during compression or decompression startup: */
+ /* Component's size in DCT blocks.
+ * Any dummy blocks added to complete an MCU are not counted; therefore
+ * these values do not depend on whether a scan is interleaved or not.
+ */
+ int width_in_blocks;
+ int height_in_blocks;
+ /* Size of a DCT block in samples. Always DCTSIZE for compression.
+ * For decompression this is the size of the output from one DCT block,
+ * reflecting any scaling we choose to apply during the IDCT step.
+ * Values of 1,2,4,8 are likely to be supported. Note that different
+ * components may receive different IDCT scalings.
+ */
+ int DCT_scaled_size;
+ /* The downsampled dimensions are the component's actual, unpadded number
+ * of samples at the main buffer (preprocessing/compression interface), thus
+ * downsampled_width = ceil(image_width * Hi/Hmax)
+ * and similarly for height. For decompression, IDCT scaling is included, so
+ * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)
+ */
+ int downsampled_width; /* actual width in samples */
+ int downsampled_height; /* actual height in samples */
+ /* This flag is used only for decompression. In cases where some of the
+ * components will be ignored (eg grayscale output from YCbCr image),
+ * we can skip most computations for the unused components.
+ */
+ boolean component_needed; /* do we need the value of this component? */
+
+ /* These values are computed before starting a scan of the component. */
+ /* The decompressor output side may not use these variables. */
+ int MCU_width; /* number of blocks per MCU, horizontally */
+ int MCU_height; /* number of blocks per MCU, vertically */
+ int MCU_blocks; /* MCU_width * MCU_height */
+ int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */
+ int last_col_width; /* # of non-dummy blocks across in last MCU */
+ int last_row_height; /* # of non-dummy blocks down in last MCU */
+
+ /* Saved quantization table for component; null if none yet saved.
+ * See jdinput.c comments about the need for this information.
+ * This field is currently used only for decompression.
+ */
+ JQUANT_TBL quant_table;
+
+ /* Private per-component storage for DCT or IDCT subsystem. */
+ int[] dct_table;
+ }
+
+ static final class jpeg_color_quantizer {
+// JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
+// JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
+// JSAMPARRAY input_buf, JSAMPARRAY output_buf,
+// int num_rows));
+// JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
+// JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
+
+ /* Initially allocated colormap is saved here */
+ int[][] sv_colormap; /* The color map as a 2-D pixel array */
+ int sv_actual; /* number of entries in use */
+
+ int[][] colorindex; /* Precomputed mapping for speed */
+ /* colorindex[i][j] = index of color closest to pixel value j in component i,
+ * premultiplied as described above. Since colormap indexes must fit into
+ * JSAMPLEs, the entries of this array will too.
+ */
+ boolean is_padded; /* is the colorindex padded for odither? */
+
+ int[] Ncolors = new int [MAX_Q_COMPS]; /* # of values alloced to each component */
+
+ /* Variables for ordered dithering */
+ int row_index; /* cur row's vertical index in dither matrix */
+// ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */
+
+ /* Variables for Floyd-Steinberg dithering */
+// FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */
+ boolean on_odd_row;
+
+ void start_pass (jpeg_decompress_struct cinfo, boolean is_pre_scan) {
+ error();
+ }
+ }
+
+ static final class jpeg_upsampler {
+// JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+// JMETHOD(void, upsample, (j_decompress_ptr cinfo,
+// JSAMPIMAGE input_buf,
+// JDIMENSION *in_row_group_ctr,
+// JDIMENSION in_row_groups_avail,
+// JSAMPARRAY output_buf,
+// JDIMENSION *out_row_ctr,
+// JDIMENSION out_rows_avail));
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+
+ /* Color conversion buffer. When using separate upsampling and color
+ * conversion steps, this buffer holds one upsampled row group until it
+ * has been color converted and output.
+ * Note: we do not allocate any storage for component(s) which are full-size,
+ * ie do not need rescaling. The corresponding entry of color_buf[] is
+ * simply set to point to the input data array, thereby avoiding copying.
+ */
+ byte[][][] color_buf = new byte[MAX_COMPONENTS][][];
+ int[] color_buf_offset = new int[MAX_COMPONENTS];
+
+ /* Per-component upsampling method pointers */
+ int[] methods = new int[MAX_COMPONENTS];
+
+ int next_row_out; /* counts rows emitted from color_buf */
+ int rows_to_go; /* counts rows remaining in image */
+
+ /* Height of an input row group for each component. */
+ int[] rowgroup_height = new int[MAX_COMPONENTS];
+
+ /* These arrays save pixel expansion factors so that int_expand need not
+ * recompute them each time. They are unused for other upsampling methods.
+ */
+ byte[] h_expand = new byte[MAX_COMPONENTS];
+ byte[] v_expand = new byte[MAX_COMPONENTS];
+
+ void start_pass (jpeg_decompress_struct cinfo) {
+ jpeg_upsampler upsample = cinfo.upsample;
+
+ /* Mark the conversion buffer empty */
+ upsample.next_row_out = cinfo.max_v_samp_factor;
+ /* Initialize total-height counter for detecting bottom of image */
+ upsample.rows_to_go = cinfo.output_height;
+ }
+
+ }
+
+ static final class jpeg_marker_reader {
+ /* Read a restart marker --- exported for use by entropy decoder only */
+// jpeg_marker_parser_method read_restart_marker;
+
+ /* State of marker reader --- nominally internal, but applications
+ * supplying COM or APPn handlers might like to know the state.
+ */
+ boolean saw_SOI; /* found SOI? */
+ boolean saw_SOF; /* found SOF? */
+ int next_restart_num; /* next restart number expected (0-7) */
+ int discarded_bytes; /* # of bytes skipped looking for a marker */
+
+ /* Application-overridable marker processing methods */
+// jpeg_marker_parser_method process_COM;
+// jpeg_marker_parser_method process_APPn[16];
+
+ /* Limit on marker data length to save for each marker type */
+ int length_limit_COM;
+ int[] length_limit_APPn = new int[16];
+
+ /* Status of COM/APPn marker saving */
+// jpeg_marker_reader cur_marker; /* null if not processing a marker */
+// int bytes_read; /* data bytes read so far in marker */
+ /* Note: cur_marker is not linked into marker_list until it's all read. */
+ }
+
+
+ static final class jpeg_d_main_controller {
+// JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ int process_data;
+
+ /* Pointer to allocated workspace (M or M+2 row groups). */
+ byte[][][] buffer = new byte[MAX_COMPONENTS][][];
+ int[] buffer_offset = new int[MAX_COMPONENTS];
+
+ boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
+ int[] rowgroup_ctr = new int[1]; /* counts row groups output to postprocessor */
+
+ /* Remaining fields are only used in the context case. */
+
+ /* These are the master pointers to the funny-order pointer lists. */
+ byte[][][][] xbuffer = new byte[2][][][]; /* pointers to weird pointer lists */
+ int[][] xbuffer_offset = new int[2][];
+
+ int whichptr; /* indicates which pointer set is now in use */
+ int context_state; /* process_data state machine status */
+ int rowgroups_avail; /* row groups available to postprocessor */
+ int iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
+
+ void start_pass (jpeg_decompress_struct cinfo, int pass_mode) {
+ jpeg_d_main_controller main = cinfo.main;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo.upsample.need_context_rows) {
+ main.process_data = PROCESS_DATA_CONTEXT_MAIN;
+ make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
+ main.whichptr = 0; /* Read first iMCU row into xbuffer[0] */
+ main.context_state = CTX_PREPARE_FOR_IMCU;
+ main.iMCU_row_ctr = 0;
+ } else {
+ /* Simple case with no context needed */
+ main.process_data = PROCESS_DATA_SIMPLE_MAIN;
+ }
+ main.buffer_full = false; /* Mark buffer empty */
+ main.rowgroup_ctr[0] = 0;
+ break;
+// #ifdef QUANT_2PASS_SUPPORTED
+// case JBUF_CRANK_DEST:
+// /* For last pass of 2-pass quantization, just crank the postprocessor */
+// main.process_data = PROCESS_DATA_CRANK_POST;
+// break;
+// #endif
+ default:
+ error();
+// ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+ }
+
+ }
+
+ static final class jpeg_decomp_master {
+// JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));
+// JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean is_dummy_pass;
+
+ int pass_number; /* # of passes completed */
+
+ boolean using_merged_upsample; /* true if using merged upsample/cconvert */
+
+ /* Saved references to initialized quantizer modules,
+ * in case we need to switch modes.
+ */
+ jpeg_color_quantizer quantizer_1pass;
+ jpeg_color_quantizer quantizer_2pass;
+ }
+
+ static final class jpeg_inverse_dct {
+// JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+// /* It is useful to allow each component to have a separate IDCT method. */
+// inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
+ int[] cur_method = new int[MAX_COMPONENTS];
+
+ void start_pass (jpeg_decompress_struct cinfo) {
+ jpeg_inverse_dct idct = cinfo.idct;
+ int ci, i;
+ jpeg_component_info compptr;
+ int method = 0;
+// inverse_DCT_method_ptr method_ptr = NULL;
+ JQUANT_TBL qtbl;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* Select the proper IDCT routine for this component's scaling */
+ switch (compptr.DCT_scaled_size) {
+// #ifdef IDCT_SCALING_SUPPORTED
+// case 1:
+// method_ptr = jpeg_idct_1x1;
+// method = JDCT_ISLOW; /* jidctred uses islow-style table */
+// break;
+// case 2:
+// method_ptr = jpeg_idct_2x2;
+// method = JDCT_ISLOW; /* jidctred uses islow-style table */
+// break;
+// case 4:
+// method_ptr = jpeg_idct_4x4;
+// method = JDCT_ISLOW; /* jidctred uses islow-style table */
+// break;
+// #endif
+ case DCTSIZE:
+ switch (cinfo.dct_method) {
+// #ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+// method_ptr = jpeg_idct_islow;
+ method = JDCT_ISLOW;
+ break;
+// #endif
+// #ifdef DCT_IFAST_SUPPORTED
+// case JDCT_IFAST:
+// method_ptr = jpeg_idct_ifast;
+// method = JDCT_IFAST;
+// break;
+// #endif
+// #ifdef DCT_FLOAT_SUPPORTED
+// case JDCT_FLOAT:
+// method_ptr = jpeg_idct_float;
+// method = JDCT_FLOAT;
+// break;
+// #endif
+ default:
+ error();
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ break;
+ default:
+ error();
+// ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr.DCT_scaled_size);
+ break;
+ }
+// idct.inverse_DCT[ci] = method_ptr;
+ /* Create multiplier table from quant table.
+ * However, we can skip this if the component is uninteresting
+ * or if we already built the table. Also, if no quant table
+ * has yet been saved for the component, we leave the
+ * multiplier table all-zero; we'll be reading zeroes from the
+ * coefficient controller's buffer anyway.
+ */
+ if (! compptr.component_needed || idct.cur_method[ci] == method)
+ continue;
+ qtbl = compptr.quant_table;
+ if (qtbl == null) /* happens if no data yet for component */
+ continue;
+ idct.cur_method[ci] = method;
+ switch (method) {
+// #ifdef PROVIDE_ISLOW_TABLES
+ case JDCT_ISLOW:
+ {
+ /* For LL&M IDCT method, multipliers are equal to raw quantization
+ * coefficients, but are stored as ints to ensure access efficiency.
+ */
+ int[] ismtbl = compptr.dct_table;
+ for (i = 0; i < DCTSIZE2; i++) {
+ ismtbl[i] = qtbl.quantval[i];
+ }
+ }
+ break;
+// #endif
+// #ifdef DCT_IFAST_SUPPORTED
+// case JDCT_IFAST:
+// {
+// /* For AA&N IDCT method, multipliers are equal to quantization
+// * coefficients scaled by scalefactor[row]*scalefactor[col], where
+// * scalefactor[0] = 1
+// * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+// * For integer operation, the multiplier table is to be scaled by
+// * IFAST_SCALE_BITS.
+// */
+// int[] ifmtbl = compptr.dct_table;
+// short aanscales[] = {
+// /* precomputed values scaled up by 14 bits */
+// 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+// 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+// 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+// 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+// 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+// 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+// 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+// 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+// };
+// SHIFT_TEMPS
+//
+// for (i = 0; i < DCTSIZE2; i++) {
+// ifmtbl[i] = DESCALE(MULTIPLY16V16( qtbl.quantval[i], aanscales[i]), CONST_BITS-IFAST_SCALE_BITS);
+// }
+// }
+// break;
+// #endif
+// #ifdef DCT_FLOAT_SUPPORTED
+// case JDCT_FLOAT:
+// {
+// /* For float AA&N IDCT method, multipliers are equal to quantization
+// * coefficients scaled by scalefactor[row]*scalefactor[col], where
+// * scalefactor[0] = 1
+// * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+// */
+// FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr.dct_table;
+// int row, col;
+// static const double aanscalefactor[DCTSIZE] = {
+// 1.0, 1.387039845, 1.306562965, 1.175875602,
+// 1.0, 0.785694958, 0.541196100, 0.275899379
+// };
+//
+// i = 0;
+// for (row = 0; row < DCTSIZE; row++) {
+// for (col = 0; col < DCTSIZE; col++) {
+// fmtbl[i] = (FLOAT_MULT_TYPE)
+// ((double) qtbl.quantval[i] *
+// aanscalefactor[row] * aanscalefactor[col]);
+// i++;
+// }
+// }
+// }
+// break;
+// #endif
+ default:
+ error();
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ }
+ }
+ }
+
+ static final class jpeg_input_controller {
+ int consume_input;
+ boolean has_multiple_scans; /* True if file has multiple scans */
+ boolean eoi_reached;
+
+ boolean inheaders; /* true until first SOS is reached */
+ }
+
+ static final class jpeg_color_deconverter {
+// JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ int color_convert;
+
+ /* Private state for YCC.RGB conversion */
+ int[] Cr_r_tab; /* => table for Cr to R conversion */
+ int[] Cb_b_tab; /* => table for Cb to B conversion */
+ int[] Cr_g_tab; /* => table for Cr to G conversion */
+ int[] Cb_g_tab; /* => table for Cb to G conversion */
+
+ void start_pass (jpeg_decompress_struct cinfo) {
+ /* no work needed */
+ }
+
+ }
+
+ static final class jpeg_d_post_controller {
+// JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ int post_process_data;
+
+ /* Color quantization source buffer: this holds output data from
+ * the upsample/color conversion step to be passed to the quantizer.
+ * For two-pass color quantization, we need a full-image buffer;
+ * for one-pass operation, a strip buffer is sufficient.
+ */
+ int[] whole_image; /* virtual array, or NULL if one-pass */
+ int[][] buffer; /* strip buffer, or current strip of virtual */
+ int strip_height; /* buffer size in rows */
+ /* for two-pass mode only: */
+ int starting_row; /* row # of first row in current strip */
+ int next_row; /* index of next row to fill/empty in strip */
+
+ void start_pass (jpeg_decompress_struct cinfo, int pass_mode) {
+ jpeg_d_post_controller post = cinfo.post;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo.quantize_colors) {
+ error(SWT.ERROR_NOT_IMPLEMENTED);
+// /* Single-pass processing with color quantization. */
+// post.post_process_data = POST_PROCESS_1PASS;
+// /* We could be doing buffered-image output before starting a 2-pass
+// * color quantization; in that case, jinit_d_post_controller did not
+// * allocate a strip buffer. Use the virtual-array buffer as workspace.
+// */
+// if (post.buffer == null) {
+// post.buffer = (*cinfo.mem.access_virt_sarray)
+// ((j_common_ptr) cinfo, post.whole_image,
+// (JDIMENSION) 0, post.strip_height, TRUE);
+// }
+ } else {
+ /* For single-pass processing without color quantization,
+ * I have no work to do; just call the upsampler directly.
+ */
+ post.post_process_data = POST_PROCESS_DATA_UPSAMPLE;
+ }
+ break;
+// #ifdef QUANT_2PASS_SUPPORTED
+// case JBUF_SAVE_AND_PASS:
+// /* First pass of 2-pass quantization */
+// if (post.whole_image == NULL)
+// ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+// post.pub.post_process_data = post_process_prepass;
+// break;
+// case JBUF_CRANK_DEST:
+// /* Second pass of 2-pass quantization */
+// if (post.whole_image == NULL)
+// ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+// post.pub.post_process_data = post_process_2pass;
+// break;
+// #endif /* QUANT_2PASS_SUPPORTED */
+ default:
+ error();
+// ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+ post.starting_row = post.next_row = 0;
+ }
+
+ }
+
+ static final class jpeg_decompress_struct {
+// jpeg_error_mgr * err; /* Error handler module */\
+// struct jpeg_memory_mgr * mem; /* Memory manager module */\
+// struct jpeg_progress_mgr * progress; /* Progress monitor, or null if none */\
+// void * client_data; /* Available for use by application */\
+ boolean is_decompressor; /* So common code can tell which is which */
+ int global_state; /* For checking call sequence validity */
+
+// /* Source of compressed data */
+// struct jpeg_source_mgr * src;
+ InputStream inputStream;
+ byte[] buffer;
+ int bytes_in_buffer;
+ int bytes_offset;
+ boolean start_of_file;
+
+ /* Basic description of image --- filled in by jpeg_read_header(). */
+ /* Application may inspect these values to decide how to process image. */
+
+ int image_width; /* nominal image width (from SOF marker) */
+ int image_height; /* nominal image height */
+ int num_components; /* # of color components in JPEG image */
+ int jpeg_color_space; /* colorspace of JPEG image */
+
+ /* Decompression processing parameters --- these fields must be set before
+ * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes
+ * them to default values.
+ */
+
+ int out_color_space; /* colorspace for output */
+
+ int scale_num, scale_denom; /* fraction by which to scale image */
+
+ double output_gamma; /* image gamma wanted in output */
+
+ boolean buffered_image; /* true=multiple output passes */
+ boolean raw_data_out; /* true=downsampled data wanted */
+
+ int dct_method; /* IDCT algorithm selector */
+ boolean do_fancy_upsampling; /* true=apply fancy upsampling */
+ boolean do_block_smoothing; /* true=apply interblock smoothing */
+
+ boolean quantize_colors; /* true=colormapped output wanted */
+ /* the following are ignored if not quantize_colors: */
+ int dither_mode; /* type of color dithering to use */
+ boolean two_pass_quantize; /* true=use two-pass color quantization */
+ int desired_number_of_colors; /* max # colors to use in created colormap */
+ /* these are significant only in buffered-image mode: */
+ boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */
+ boolean enable_external_quant;/* enable future use of external colormap */
+ boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */
+
+ /* Description of actual output image that will be returned to application.
+ * These fields are computed by jpeg_start_decompress().
+ * You can also use jpeg_calc_output_dimensions() to determine these values
+ * in advance of calling jpeg_start_decompress().
+ */
+
+ int output_width; /* scaled image width */
+ int output_height; /* scaled image height */
+ int out_color_components; /* # of color components in out_color_space */
+ int output_components; /* # of color components returned */
+ /* output_components is 1 (a colormap index) when quantizing colors;
+ * otherwise it equals out_color_components.
+ */
+ int rec_outbuf_height; /* min recommended height of scanline buffer */
+ /* If the buffer passed to jpeg_read_scanlines() is less than this many rows
+ * high, space and time will be wasted due to unnecessary data copying.
+ * Usually rec_outbuf_height will be 1 or 2, at most 4.
+ */
+
+ /* When quantizing colors, the output colormap is described by these fields.
+ * The application can supply a colormap by setting colormap non-null before
+ * calling jpeg_start_decompress; otherwise a colormap is created during
+ * jpeg_start_decompress or jpeg_start_output.
+ * The map has out_color_components rows and actual_number_of_colors columns.
+ */
+ int actual_number_of_colors; /* number of entries in use */
+ int[] colormap; /* The color map as a 2-D pixel array */
+
+ /* State variables: these variables indicate the progress of decompression.
+ * The application may examine these but must not modify them.
+ */
+
+ /* Row index of next scanline to be read from jpeg_read_scanlines().
+ * Application may use this to control its processing loop, e.g.,
+ * "while (output_scanline < output_height)".
+ */
+ int output_scanline; /* 0 .. output_height-1 */
+
+ /* Current input scan number and number of iMCU rows completed in scan.
+ * These indicate the progress of the decompressor input side.
+ */
+ int input_scan_number; /* Number of SOS markers seen so far */
+ int input_iMCU_row; /* Number of iMCU rows completed */
+
+ /* The "output scan number" is the notional scan being displayed by the
+ * output side. The decompressor will not allow output scan/row number
+ * to get ahead of input scan/row, but it can fall arbitrarily far behind.
+ */
+ int output_scan_number; /* Nominal scan number being displayed */
+ int output_iMCU_row; /* Number of iMCU rows read */
+
+ /* Current progression status. coef_bits[c][i] indicates the precision
+ * with which component c's DCT coefficient i (in zigzag order) is known.
+ * It is -1 when no data has yet been received, otherwise it is the point
+ * transform (shift) value for the most recent scan of the coefficient
+ * (thus, 0 at completion of the progression).
+ * This pointer is null when reading a non-progressive file.
+ */
+ int[][] coef_bits; /* -1 or current Al value for each coef */
+
+ /* Internal JPEG parameters --- the application usually need not look at
+ * these fields. Note that the decompressor output side may not use
+ * any parameters that can change between scans.
+ */
+
+ /* Quantization and Huffman tables are carried forward across input
+ * datastreams when processing abbreviated JPEG datastreams.
+ */
+
+ JQUANT_TBL[] quant_tbl_ptrs = new JQUANT_TBL[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or null if not defined */
+
+ JHUFF_TBL[] dc_huff_tbl_ptrs = new JHUFF_TBL[NUM_HUFF_TBLS];
+ JHUFF_TBL[] ac_huff_tbl_ptrs = new JHUFF_TBL[NUM_HUFF_TBLS];
+ /* ptrs to Huffman coding tables, or null if not defined */
+
+ /* These parameters are never carried across datastreams, since they
+ * are given in SOF/SOS markers or defined to be reset by SOI.
+ */
+
+ int data_precision; /* bits of precision in image data */
+
+ jpeg_component_info[] comp_info;
+ /* comp_info[i] describes component that appears i'th in SOF */
+
+ boolean progressive_mode; /* true if SOFn specifies progressive mode */
+ boolean arith_code; /* true=arithmetic coding, false=Huffman */
+
+ byte[] arith_dc_L = new byte[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+ byte[] arith_dc_U = new byte[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+ byte[] arith_ac_K = new byte[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+ int restart_interval; /* MCUs per restart interval, or 0 for no restart */
+
+ /* These fields record data obtained from optional markers recognized by
+ * the JPEG library.
+ */
+ boolean saw_JFIF_marker; /* true iff a JFIF APP0 marker was found */
+ /* Data copied from JFIF marker; only valid if saw_JFIF_marker is true: */
+ byte JFIF_major_version; /* JFIF version number */
+ byte JFIF_minor_version;
+ byte density_unit; /* JFIF code for pixel size units */
+ short X_density; /* Horizontal pixel density */
+ short Y_density; /* Vertical pixel density */
+ boolean saw_Adobe_marker; /* true iff an Adobe APP14 marker was found */
+ byte Adobe_transform; /* Color transform code from Adobe marker */
+
+ boolean CCIR601_sampling; /* true=first samples are cosited */
+
+ /* Aside from the specific data retained from APPn markers known to the
+ * library, the uninterpreted contents of any or all APPn and COM markers
+ * can be saved in a list for examination by the application.
+ */
+ jpeg_marker_reader marker_list; /* Head of list of saved markers */
+
+ /* Remaining fields are known throughout decompressor, but generally
+ * should not be touched by a surrounding application.
+ */
+
+ /*
+ * These fields are computed during decompression startup
+ */
+ int max_h_samp_factor; /* largest h_samp_factor */
+ int max_v_samp_factor; /* largest v_samp_factor */
+
+ int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */
+
+ int total_iMCU_rows; /* # of iMCU rows in image */
+ /* The coefficient controller's input and output progress is measured in
+ * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows
+ * in fully interleaved JPEG scans, but are used whether the scan is
+ * interleaved or not. We define an iMCU row as v_samp_factor DCT block
+ * rows of each component. Therefore, the IDCT output contains
+ * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row.
+ */
+
+ byte[] sample_range_limit; /* table for fast range-limiting */
+ int sample_range_limit_offset;
+
+ /*
+ * These fields are valid during any one scan.
+ * They describe the components and MCUs actually appearing in the scan.
+ * Note that the decompressor output side must not use these fields.
+ */
+ int comps_in_scan; /* # of JPEG components in this scan */
+ jpeg_component_info[] cur_comp_info = new jpeg_component_info[MAX_COMPS_IN_SCAN];
+ /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+ int MCUs_per_row; /* # of MCUs across the image */
+ int MCU_rows_in_scan; /* # of MCU rows in the image */
+
+ int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int[] MCU_membership = new int[D_MAX_BLOCKS_IN_MCU];
+ /* MCU_membership[i] is index in cur_comp_info of component owning */
+ /* i'th block in an MCU */
+
+ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+
+ /* This field is shared between entropy decoder and marker parser.
+ * It is either zero or the code of a JPEG marker that has been
+ * read from the data source, but has not yet been processed.
+ */
+ int unread_marker;
+
+ int[] workspace = new int[DCTSIZE2];
+ int[] row_ctr = new int[1];
+
+ /*
+ * Links to decompression subobjects (methods, private variables of modules)
+ */
+ jpeg_decomp_master master;
+ jpeg_d_main_controller main;
+ jpeg_d_coef_controller coef;
+ jpeg_d_post_controller post;
+ jpeg_input_controller inputctl;
+ jpeg_marker_reader marker;
+ jpeg_entropy_decoder entropy;
+ jpeg_inverse_dct idct;
+ jpeg_upsampler upsample;
+ jpeg_color_deconverter cconvert;
+ jpeg_color_quantizer cquantize;
+ }
+
+static void error() {
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+}
+
+static void error(int code) {
+ SWT.error(code);
+}
+
+static void error(String msg) {
+ SWT.error(SWT.ERROR_INVALID_IMAGE, null, msg);
+}
+
+static void jinit_marker_reader (jpeg_decompress_struct cinfo) {
+ jpeg_marker_reader marker = cinfo.marker = new jpeg_marker_reader();
+// int i;
+
+ /* Initialize COM/APPn processing.
+ * By default, we examine and then discard APP0 and APP14,
+ * but simply discard COM and all other APPn.
+ */
+// marker.process_COM = skip_variable;
+ marker.length_limit_COM = 0;
+// for (i = 0; i < 16; i++) {
+// marker.process_APPn[i] = skip_variable;
+// marker.length_limit_APPn[i] = 0;
+// }
+// marker.process_APPn[0] = get_interesting_appn;
+// marker.process_APPn[14] = get_interesting_appn;
+ /* Reset marker processing state */
+ reset_marker_reader(cinfo);
+}
+
+static void jinit_d_coef_controller (jpeg_decompress_struct cinfo, boolean need_full_buffer) {
+ jpeg_d_coef_controller coef = new jpeg_d_coef_controller();
+ cinfo.coef = coef;
+// coef.pub.start_input_pass = start_input_pass;
+// coef.pub.start_output_pass = start_output_pass;
+ coef.coef_bits_latch = null;
+
+ /* Create the coefficient buffer. */
+ if (need_full_buffer) {
+//#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor DCT blocks in each direction. */
+ /* Note we ask for a pre-zeroed array. */
+ int ci, access_rows;
+ jpeg_component_info compptr;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ access_rows = compptr.v_samp_factor;
+//#ifdef BLOCK_SMOOTHING_SUPPORTED
+ /* If block smoothing could be used, need a bigger window */
+ if (cinfo.progressive_mode)
+ access_rows *= 3;
+//#endif
+ coef.whole_image[ci] =
+ new short
+ [(int)jround_up( compptr.height_in_blocks, compptr.v_samp_factor)]
+ [(int)jround_up( compptr.width_in_blocks, compptr.h_samp_factor)]
+ [DCTSIZE2];
+ }
+// coef.consume_data = consume_data;
+ coef.decompress_data = DECOMPRESS_DATA;
+ coef.coef_arrays = coef.whole_image[0]; /* link to virtual arrays */
+// #else
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+// #endif
+ } else {
+ /* We only need a single-MCU buffer. */
+ coef.MCU_buffer = new short[D_MAX_BLOCKS_IN_MCU][DCTSIZE2];
+// coef.consume_data = dummy_consume_data;
+ coef.decompress_data = DECOMPRESS_ONEPASS;
+ coef.coef_arrays = null; /* flag for no virtual arrays */
+ }
+}
+
+static void start_output_pass (jpeg_decompress_struct cinfo) {
+//#ifdef BLOCK_SMOOTHING_SUPPORTED
+ jpeg_d_coef_controller coef = cinfo.coef;
+
+ /* If multipass, check to see whether to use block smoothing on this pass */
+ if (coef.coef_arrays != null) {
+ if (cinfo.do_block_smoothing && smoothing_ok(cinfo))
+ coef.decompress_data = DECOMPRESS_SMOOTH_DATA;
+ else
+ coef.decompress_data = DECOMPRESS_DATA;
+ }
+//#endif
+ cinfo.output_iMCU_row = 0;
+}
+
+static void jpeg_create_decompress(jpeg_decompress_struct cinfo) {
+ cinfo.is_decompressor = true;
+
+
+ /* Initialize marker processor so application can override methods
+ * for COM, APPn markers before calling jpeg_read_header.
+ */
+ cinfo.marker_list = null;
+ jinit_marker_reader(cinfo);
+
+ /* And initialize the overall input controller. */
+ jinit_input_controller(cinfo);
+
+ /* OK, I'm ready */
+ cinfo.global_state = DSTATE_START;
+}
+
+static void jpeg_calc_output_dimensions (jpeg_decompress_struct cinfo)
+/* Do computations that are needed before master selection phase */
+{
+//#ifdef IDCT_SCALING_SUPPORTED
+// int ci;
+// jpeg_component_info compptr;
+//#endif
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo.global_state != DSTATE_READY)
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+
+//#ifdef IDCT_SCALING_SUPPORTED
+//
+// /* Compute actual output image dimensions and DCT scaling choices. */
+// if (cinfo.scale_num * 8 <= cinfo.scale_denom) {
+// /* Provide 1/8 scaling */
+// cinfo.output_width = (int)
+// jdiv_round_up(cinfo.image_width, 8L);
+// cinfo.output_height = (int)
+// jdiv_round_up(cinfo.image_height, 8L);
+// cinfo.min_DCT_scaled_size = 1;
+// } else if (cinfo.scale_num * 4 <= cinfo.scale_denom) {
+// /* Provide 1/4 scaling */
+// cinfo.output_width = (int)
+// jdiv_round_up(cinfo.image_width, 4L);
+// cinfo.output_height = (int)
+// jdiv_round_up(cinfo.image_height, 4L);
+// cinfo.min_DCT_scaled_size = 2;
+// } else if (cinfo.scale_num * 2 <= cinfo.scale_denom) {
+// /* Provide 1/2 scaling */
+// cinfo.output_width = (int)
+// jdiv_round_up(cinfo.image_width, 2L);
+// cinfo.output_height = (int)
+// jdiv_round_up(cinfo.image_height, 2L);
+// cinfo.min_DCT_scaled_size = 4;
+// } else {
+// /* Provide 1/1 scaling */
+// cinfo.output_width = cinfo.image_width;
+// cinfo.output_height = cinfo.image_height;
+// cinfo.min_DCT_scaled_size = DCTSIZE;
+// }
+// /* In selecting the actual DCT scaling for each component, we try to
+// * scale up the chroma components via IDCT scaling rather than upsampling.
+// * This saves time if the upsampler gets to use 1:1 scaling.
+// * Note this code assumes that the supported DCT scalings are powers of 2.
+// */
+// for (ci = 0; ci < cinfo.num_components; ci++) {
+// compptr = cinfo.comp_info[ci];
+// int ssize = cinfo.min_DCT_scaled_size;
+// while (ssize < DCTSIZE &&
+// (compptr.h_samp_factor * ssize * 2 <= cinfo.max_h_samp_factor * cinfo.min_DCT_scaled_size) &&
+// (compptr.v_samp_factor * ssize * 2 <= cinfo.max_v_samp_factor * cinfo.min_DCT_scaled_size))
+// {
+// ssize = ssize * 2;
+// }
+// compptr.DCT_scaled_size = ssize;
+// }
+//
+// /* Recompute downsampled dimensions of components;
+// * application needs to know these if using raw downsampled data.
+// */
+// for (ci = 0; ci < cinfo.num_components; ci++) {
+// compptr = cinfo.comp_info[ci];
+// /* Size in samples, after IDCT scaling */
+// compptr.downsampled_width = (int)
+// jdiv_round_up((long) cinfo.image_width * (long) (compptr.h_samp_factor * compptr.DCT_scaled_size),
+// (cinfo.max_h_samp_factor * DCTSIZE));
+// compptr.downsampled_height = (int)
+// jdiv_round_up((long) cinfo.image_height * (long) (compptr.v_samp_factor * compptr.DCT_scaled_size),
+// (cinfo.max_v_samp_factor * DCTSIZE));
+// }
+//
+//#else /* !IDCT_SCALING_SUPPORTED */
+
+ /* Hardwire it to "no scaling" */
+ cinfo.output_width = cinfo.image_width;
+ cinfo.output_height = cinfo.image_height;
+ /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+
+//#endif /* IDCT_SCALING_SUPPORTED */
+
+ /* Report number of components in selected colorspace. */
+ /* Probably this should be in the color conversion module... */
+ switch (cinfo.out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo.out_color_components = 1;
+ break;
+ case JCS_RGB:
+ if (RGB_PIXELSIZE != 3) {
+ cinfo.out_color_components = RGB_PIXELSIZE;
+ break;
+ }
+ //FALLTHROUGH
+ case JCS_YCbCr:
+ cinfo.out_color_components = 3;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo.out_color_components = 4;
+ break;
+ default: /* else must be same colorspace as in file */
+ cinfo.out_color_components = cinfo.num_components;
+ break;
+ }
+ cinfo.output_components = (cinfo.quantize_colors ? 1 : cinfo.out_color_components);
+
+ /* See if upsampler will want to emit more than one row at a time */
+ if (use_merged_upsample(cinfo))
+ cinfo.rec_outbuf_height = cinfo.max_v_samp_factor;
+ else
+ cinfo.rec_outbuf_height = 1;
+}
+
+static boolean use_merged_upsample (jpeg_decompress_struct cinfo) {
+//#ifdef UPSAMPLE_MERGING_SUPPORTED
+ /* Merging is the equivalent of plain box-filter upsampling */
+ if (cinfo.do_fancy_upsampling || cinfo.CCIR601_sampling)
+ return false;
+ /* jdmerge.c only supports YCC=>RGB color conversion */
+ if (cinfo.jpeg_color_space != JCS_YCbCr || cinfo.num_components != 3 ||
+ cinfo.out_color_space != JCS_RGB ||
+ cinfo.out_color_components != RGB_PIXELSIZE)
+ return false;
+ /* and it only handles 2h1v or 2h2v sampling ratios */
+ if (cinfo.comp_info[0].h_samp_factor != 2 ||
+ cinfo.comp_info[1].h_samp_factor != 1 ||
+ cinfo.comp_info[2].h_samp_factor != 1 ||
+ cinfo.comp_info[0].v_samp_factor > 2 ||
+ cinfo.comp_info[1].v_samp_factor != 1 ||
+ cinfo.comp_info[2].v_samp_factor != 1)
+ return false;
+ /* furthermore, it doesn't work if we've scaled the IDCTs differently */
+ if (cinfo.comp_info[0].DCT_scaled_size != cinfo.min_DCT_scaled_size ||
+ cinfo.comp_info[1].DCT_scaled_size != cinfo.min_DCT_scaled_size ||
+ cinfo.comp_info[2].DCT_scaled_size != cinfo.min_DCT_scaled_size)
+ return false;
+ /* ??? also need to test for upsample-time rescaling, when & if supported */
+ return true; /* by golly, it'll work... */
+//#else
+// return false;
+//#endif
+}
+
+static void prepare_range_limit_table (jpeg_decompress_struct cinfo)
+/* Allocate and fill in the sample_range_limit table */
+{
+ byte[] table;
+ int i;
+
+ table = new byte[5 * (MAXJSAMPLE+1) + CENTERJSAMPLE];
+ int offset = (MAXJSAMPLE+1); /* allow negative subscripts of simple table */
+ cinfo.sample_range_limit_offset = offset;
+ cinfo.sample_range_limit = table;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJSAMPLE; i++)
+ table[i + offset] = (byte)i;
+ offset += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
+ table[i+offset] = (byte)MAXJSAMPLE;
+ /* Second half of post-IDCT table */
+ System.arraycopy(cinfo.sample_range_limit, cinfo.sample_range_limit_offset, table, offset + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), CENTERJSAMPLE);
+}
+
+static void build_ycc_rgb_table (jpeg_decompress_struct cinfo) {
+ jpeg_color_deconverter cconvert = cinfo.cconvert;
+ int i;
+ int x;
+// SHIFT_TEMPS
+
+ cconvert.Cr_r_tab = new int[MAXJSAMPLE+1];
+ cconvert.Cb_b_tab = new int[MAXJSAMPLE+1];
+ cconvert.Cr_g_tab = new int[MAXJSAMPLE+1];
+ cconvert.Cb_g_tab = new int[MAXJSAMPLE+1];
+
+ for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>R value is nearest int to 1.40200 * x */
+ cconvert.Cr_r_tab[i] = ((int)(1.40200f * (1<<SCALEBITS) + 0.5f) * x + ONE_HALF) >> SCALEBITS;
+ /* Cb=>B value is nearest int to 1.77200 * x */
+ cconvert.Cb_b_tab[i] = ((int)(1.77200f * (1<<SCALEBITS) + 0.5f) * x + ONE_HALF) >> SCALEBITS;
+ /* Cr=>G value is scaled-up -0.71414 * x */
+ cconvert.Cr_g_tab[i] = ((int)(- (0.71414f * (1<<SCALEBITS) + 0.5f)) * x);
+ /* Cb=>G value is scaled-up -0.34414 * x */
+ /* We also add in ONE_HALF so that need not do it in inner loop */
+ cconvert.Cb_g_tab[i] = ((int)(- (0.34414f* (1<<SCALEBITS) + 0.5f)) * x + ONE_HALF);
+ }
+}
+
+static void jinit_color_deconverter (jpeg_decompress_struct cinfo) {
+ jpeg_color_deconverter cconvert = cinfo.cconvert = new jpeg_color_deconverter();
+// cconvert.start_pass = start_pass_dcolor;
+
+ /* Make sure num_components agrees with jpeg_color_space */
+ switch (cinfo.jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo.num_components != 1)
+ error();
+// ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_RGB:
+ case JCS_YCbCr:
+ if (cinfo.num_components != 3)
+ error();
+// ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ if (cinfo.num_components != 4)
+ error();
+// ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ default: /* JCS_UNKNOWN can be anything */
+ if (cinfo.num_components < 1)
+ error();
+// ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+ }
+
+ /* Set out_color_components and conversion method based on requested space.
+ * Also clear the component_needed flags for any unused components,
+ * so that earlier pipeline stages can avoid useless computation.
+ */
+
+ int ci;
+ switch (cinfo.out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo.out_color_components = 1;
+ if (cinfo.jpeg_color_space == JCS_GRAYSCALE || cinfo.jpeg_color_space == JCS_YCbCr) {
+ cconvert.color_convert = GRAYSCALE_CONVERT;
+ /* For color.grayscale conversion, only the Y (0) component is needed */
+ for (ci = 1; ci < cinfo.num_components; ci++)
+ cinfo.comp_info[ci].component_needed = false;
+ } else
+ error();
+// ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB:
+ cinfo.out_color_components = RGB_PIXELSIZE;
+ if (cinfo.jpeg_color_space == JCS_YCbCr) {
+ cconvert.color_convert = YCC_RGB_CONVERT;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
+ cconvert.color_convert = GRAY_RGB_CONVERT;
+ } else if (cinfo.jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) {
+ cconvert.color_convert = NULL_CONVERT;
+ } else
+ error();
+// ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_CMYK:
+ cinfo.out_color_components = 4;
+ if (cinfo.jpeg_color_space == JCS_YCCK) {
+ cconvert.color_convert = YCCK_CMYK_CONVERT;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo.jpeg_color_space == JCS_CMYK) {
+ cconvert.color_convert = NULL_CONVERT;
+ } else
+ error();
+// ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ default:
+ /* Permit null conversion to same output space */
+ if (cinfo.out_color_space == cinfo.jpeg_color_space) {
+ cinfo.out_color_components = cinfo.num_components;
+ cconvert.color_convert = NULL_CONVERT;
+ } else /* unsupported non-null conversion */
+ error();
+// ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+ }
+
+ if (cinfo.quantize_colors)
+ cinfo.output_components = 1; /* single colormapped output component */
+ else
+ cinfo.output_components = cinfo.out_color_components;
+}
+
+static void jinit_d_post_controller (jpeg_decompress_struct cinfo, boolean need_full_buffer) {
+ jpeg_d_post_controller post = cinfo.post = new jpeg_d_post_controller();
+// post.pub.start_pass = start_pass_dpost;
+ post.whole_image = null; /* flag for no virtual arrays */
+ post.buffer = null; /* flag for no strip buffer */
+
+ /* Create the quantization buffer, if needed */
+ if (cinfo.quantize_colors) {
+ error(SWT.ERROR_NOT_IMPLEMENTED);
+// /* The buffer strip height is max_v_samp_factor, which is typically
+// * an efficient number of rows for upsampling to return.
+// * (In the presence of output rescaling, we might want to be smarter?)
+// */
+// post.strip_height = cinfo.max_v_samp_factor;
+// if (need_full_buffer) {
+// /* Two-pass color quantization: need full-image storage. */
+// /* We round up the number of rows to a multiple of the strip height. */
+//#ifdef QUANT_2PASS_SUPPORTED
+// post.whole_image = (*cinfo.mem.request_virt_sarray)
+// ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+// cinfo.output_width * cinfo.out_color_components,
+// (JDIMENSION) jround_up((long) cinfo.output_height,
+// (long) post.strip_height),
+// post.strip_height);
+//#else
+// ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+//#endif /* QUANT_2PASS_SUPPORTED */
+// } else {
+// /* One-pass color quantization: just make a strip buffer. */
+// post.buffer = (*cinfo.mem.alloc_sarray)
+// ((j_common_ptr) cinfo, JPOOL_IMAGE,
+// cinfo.output_width * cinfo.out_color_components,
+// post.strip_height);
+// }
+ }
+}
+
+static void make_funny_pointers (jpeg_decompress_struct cinfo)
+/* Create the funny pointer lists discussed in the comments above.
+ * The actual workspace is already allocated (in main.buffer),
+ * and the space for the pointer lists is allocated too.
+ * This routine just fills in the curiously ordered lists.
+ * This will be repeated at the beginning of each pass.
+ */
+{
+ jpeg_d_main_controller main = cinfo.main;
+ int ci, i, rgroup;
+ int M = cinfo.min_DCT_scaled_size;
+ jpeg_component_info compptr;
+ byte[][] buf, xbuf0, xbuf1;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ rgroup = (compptr.v_samp_factor * compptr.DCT_scaled_size) /
+ cinfo.min_DCT_scaled_size; /* height of a row group of component */
+ xbuf0 = main.xbuffer[0][ci];
+ int xbuf0_offset = main.xbuffer_offset[0][ci];
+ xbuf1 = main.xbuffer[1][ci];
+ int xbuf1_offset = main.xbuffer_offset[1][ci];
+ /* First copy the workspace pointers as-is */
+ buf = main.buffer[ci];
+ for (i = 0; i < rgroup * (M + 2); i++) {
+ xbuf0[i + xbuf0_offset] = xbuf1[i + xbuf1_offset] = buf[i];
+ }
+ /* In the second list, put the last four row groups in swapped order */
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf1[rgroup*(M-2) + i + xbuf1_offset] = buf[rgroup*M + i];
+ xbuf1[rgroup*M + i + xbuf1_offset] = buf[rgroup*(M-2) + i];
+ }
+ /* The wraparound pointers at top and bottom will be filled later
+ * (see set_wraparound_pointers, below). Initially we want the "above"
+ * pointers to duplicate the first actual data line. This only needs
+ * to happen in xbuffer[0].
+ */
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup + xbuf0_offset] = xbuf0[0 + xbuf0_offset];
+ }
+ }
+}
+
+static void alloc_funny_pointers (jpeg_decompress_struct cinfo)
+/* Allocate space for the funny pointer lists.
+ * This is done only once, not once per pass.
+ */
+{
+ jpeg_d_main_controller main = cinfo.main;
+ int ci, rgroup;
+ int M = cinfo.min_DCT_scaled_size;
+ jpeg_component_info compptr;
+ byte[][] xbuf;
+
+ /* Get top-level space for component array pointers.
+ * We alloc both arrays with one call to save a few cycles.
+ */
+ main.xbuffer[0] = new byte[cinfo.num_components][][];
+ main.xbuffer[1] = new byte[cinfo.num_components][][];
+ main.xbuffer_offset[0] = new int[cinfo.num_components];
+ main.xbuffer_offset[1] = new int[cinfo.num_components];
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ rgroup = (compptr.v_samp_factor * compptr.DCT_scaled_size) / cinfo.min_DCT_scaled_size; /* height of a row group of component */
+ /* Get space for pointer lists --- M+4 row groups in each list.
+ * We alloc both pointer lists with one call to save a few cycles.
+ */
+ xbuf = new byte[2 * (rgroup * (M + 4))][];
+ int offset = rgroup;
+ main.xbuffer_offset[0][ci] = offset;
+ main.xbuffer[0][ci] = xbuf;
+ offset += rgroup * (M + 4);
+ main.xbuffer_offset[1][ci] = offset;
+ main.xbuffer[1][ci] = xbuf;
+ }
+}
+
+
+static void jinit_d_main_controller (jpeg_decompress_struct cinfo, boolean need_full_buffer) {
+ int ci, rgroup, ngroups;
+ jpeg_component_info compptr;
+
+ jpeg_d_main_controller main = cinfo.main = new jpeg_d_main_controller();
+// main.pub.start_pass = start_pass_main;
+
+ if (need_full_buffer) /* shouldn't happen */
+ error();
+// ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ /* Allocate the workspace.
+ * ngroups is the number of row groups we need.
+ */
+ if (cinfo.upsample.need_context_rows) {
+ if (cinfo.min_DCT_scaled_size < 2) /* unsupported, see comments above */
+ error();
+// ERREXIT(cinfo, JERR_NOTIMPL);
+ alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
+ ngroups = cinfo.min_DCT_scaled_size + 2;
+ } else {
+ ngroups = cinfo.min_DCT_scaled_size;
+ }
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ rgroup = (compptr.v_samp_factor * compptr.DCT_scaled_size) / cinfo.min_DCT_scaled_size; /* height of a row group of component */
+ main.buffer[ci] = new byte[rgroup * ngroups][compptr.width_in_blocks * compptr.DCT_scaled_size];
+ }
+}
+
+static long jround_up (long a, long b)
+/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
+/* Assumes a >= 0, b > 0 */
+{
+ a += b - 1L;
+ return a - (a % b);
+}
+
+static void jinit_upsampler (jpeg_decompress_struct cinfo) {
+ int ci;
+ jpeg_component_info compptr;
+ boolean need_buffer, do_fancy;
+ int h_in_group, v_in_group, h_out_group, v_out_group;
+
+ jpeg_upsampler upsample = new jpeg_upsampler();
+ cinfo.upsample = upsample;
+// upsample.start_pass = start_pass_upsample;
+// upsample.upsample = sep_upsample;
+ upsample.need_context_rows = false; /* until we find out differently */
+
+ if (cinfo.CCIR601_sampling) /* this isn't supported */
+ error();
+// ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+ /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1,
+ * so don't ask for it.
+ */
+ do_fancy = cinfo.do_fancy_upsampling && cinfo.min_DCT_scaled_size > 1;
+
+ /* Verify we can handle the sampling factors, select per-component methods,
+ * and create storage as needed.
+ */
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* Compute size of an "input group" after IDCT scaling. This many samples
+ * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
+ */
+ h_in_group = (compptr.h_samp_factor * compptr.DCT_scaled_size) /
+ cinfo.min_DCT_scaled_size;
+ v_in_group = (compptr.v_samp_factor * compptr.DCT_scaled_size) /
+ cinfo.min_DCT_scaled_size;
+ h_out_group = cinfo.max_h_samp_factor;
+ v_out_group = cinfo.max_v_samp_factor;
+ upsample.rowgroup_height[ci] = v_in_group; /* save for use later */
+ need_buffer = true;
+ if (! compptr.component_needed) {
+ /* Don't bother to upsample an uninteresting component. */
+ upsample.methods[ci] = NOOP_UPSAMPLE;
+ need_buffer = false;
+ } else if (h_in_group == h_out_group && v_in_group == v_out_group) {
+ /* Fullsize components can be processed without any work. */
+ upsample.methods[ci] = FULLSIZE_UPSAMPLE;
+ need_buffer = false;
+ } else if (h_in_group * 2 == h_out_group && v_in_group == v_out_group) {
+ /* Special cases for 2h1v upsampling */
+ if (do_fancy && compptr.downsampled_width > 2)
+ upsample.methods[ci] = H2V1_FANCY_UPSAMPLE;
+ else
+ upsample.methods[ci] = H2V1_UPSAMPLE;
+ } else if (h_in_group * 2 == h_out_group && v_in_group * 2 == v_out_group) {
+ /* Special cases for 2h2v upsampling */
+ if (do_fancy && compptr.downsampled_width > 2) {
+ upsample.methods[ci] = H2V2_FANCY_UPSAMPLE;
+ upsample.need_context_rows = true;
+ } else
+ upsample.methods[ci] = H2V2_UPSAMPLE;
+ } else if ((h_out_group % h_in_group) == 0 && (v_out_group % v_in_group) == 0) {
+ /* Generic integral-factors upsampling method */
+ upsample.methods[ci] = INT_UPSAMPLE;
+ upsample.h_expand[ci] = (byte) (h_out_group / h_in_group);
+ upsample.v_expand[ci] = (byte) (v_out_group / v_in_group);
+ } else
+ error();
+// ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+ if (need_buffer) {
+ upsample.color_buf[ci] = new byte[cinfo.max_v_samp_factor]
+ [(int) jround_up(cinfo.output_width, cinfo.max_h_samp_factor)];
+ }
+ }
+}
+
+static void jinit_phuff_decoder (jpeg_decompress_struct cinfo) {
+ int[][] coef_bit_ptr;
+ int ci, i;
+
+ cinfo.entropy = new phuff_entropy_decoder();
+// entropy.pub.start_pass = start_pass_phuff_decoder;
+
+ /* Create progression status table */
+ cinfo.coef_bits = new int[cinfo.num_components][DCTSIZE2];
+ coef_bit_ptr = cinfo.coef_bits;
+ for (ci = 0; ci < cinfo.num_components; ci++)
+ for (i = 0; i < DCTSIZE2; i++)
+ coef_bit_ptr[ci][i] = -1;
+}
+
+
+static void jinit_huff_decoder (jpeg_decompress_struct cinfo) {
+
+ cinfo.entropy = new huff_entropy_decoder();
+// entropy.pub.start_pass = start_pass_huff_decoder;
+// entropy.pub.decode_mcu = decode_mcu;
+
+}
+
+static void jinit_inverse_dct (jpeg_decompress_struct cinfo) {
+ int ci;
+ jpeg_component_info compptr;
+
+ jpeg_inverse_dct idct = cinfo.idct = new jpeg_inverse_dct();
+// idct.pub.start_pass = start_pass;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* Allocate and pre-zero a multiplier table for each component */
+ compptr.dct_table = new int[DCTSIZE2];
+ /* Mark multiplier table not yet set up for any method */
+ idct.cur_method[ci] = -1;
+ }
+}
+
+static final int CONST_BITS = 13;
+static final int PASS1_BITS = 2;
+static final int RANGE_MASK =(MAXJSAMPLE * 4 + 3);
+static void jpeg_idct_islow (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ short[] coef_block,
+ byte[][] output_buf, int output_buf_offset, int output_col)
+{
+ int tmp0, tmp1, tmp2, tmp3;
+ int tmp10, tmp11, tmp12, tmp13;
+ int z1, z2, z3, z4, z5;
+ short[] inptr;
+ int[] quantptr;
+ int[] wsptr;
+ byte[] outptr;
+ byte[] range_limit = cinfo.sample_range_limit;
+ int range_limit_offset = cinfo.sample_range_limit_offset + CENTERJSAMPLE;
+ int ctr;
+ int[] workspace = cinfo.workspace; /* buffers data between passes */
+// SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = compptr.dct_table;
+ wsptr = workspace;
+ int inptr_offset = 0, quantptr_offset = 0, wsptr_offset = 0;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* 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 column 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
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1+inptr_offset] == 0 && inptr[DCTSIZE*2+inptr_offset] == 0 &&
+ inptr[DCTSIZE*3+inptr_offset] == 0 && inptr[DCTSIZE*4+inptr_offset] == 0 &&
+ inptr[DCTSIZE*5+inptr_offset] == 0 && inptr[DCTSIZE*6+inptr_offset] == 0 &&
+ inptr[DCTSIZE*7+inptr_offset] == 0)
+ {
+ /* AC terms all zero */
+ int dcval = ((inptr[DCTSIZE*0+inptr_offset]) * quantptr[DCTSIZE*0+quantptr_offset]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0+wsptr_offset] = dcval;
+ wsptr[DCTSIZE*1+wsptr_offset] = dcval;
+ wsptr[DCTSIZE*2+wsptr_offset] = dcval;
+ wsptr[DCTSIZE*3+wsptr_offset] = dcval;
+ wsptr[DCTSIZE*4+wsptr_offset] = dcval;
+ wsptr[DCTSIZE*5+wsptr_offset] = dcval;
+ wsptr[DCTSIZE*6+wsptr_offset] = dcval;
+ wsptr[DCTSIZE*7+wsptr_offset] = dcval;
+
+ inptr_offset++; /* advance pointers to next column */
+ quantptr_offset++;
+ wsptr_offset++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = ((inptr[DCTSIZE*2+inptr_offset]) * quantptr[DCTSIZE*2+quantptr_offset]);
+ z3 = ((inptr[DCTSIZE*6+inptr_offset]) * quantptr[DCTSIZE*6+quantptr_offset]);
+
+ z1 = ((z2 + z3) * 4433/*FIX_0_541196100*/);
+ tmp2 = z1 + (z3 * - 15137/*FIX_1_847759065*/);
+ tmp3 = z1 + (z2 * 6270/*FIX_0_765366865*/);
+
+ z2 = ((inptr[DCTSIZE*0+inptr_offset]) * quantptr[DCTSIZE*0+quantptr_offset]);
+ z3 = ((inptr[DCTSIZE*4+inptr_offset]) * quantptr[DCTSIZE*4+quantptr_offset]);
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ 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 = ((inptr[DCTSIZE*7+inptr_offset]) * quantptr[DCTSIZE*7+quantptr_offset]);
+ tmp1 = ((inptr[DCTSIZE*5+inptr_offset]) * quantptr[DCTSIZE*5+quantptr_offset]);
+ tmp2 = ((inptr[DCTSIZE*3+inptr_offset]) * quantptr[DCTSIZE*3+quantptr_offset]);
+ tmp3 = ((inptr[DCTSIZE*1+inptr_offset]) * quantptr[DCTSIZE*1+quantptr_offset]);
+
+ z1 = tmp0 + tmp3;
+ z2 = tmp1 + tmp2;
+ z3 = tmp0 + tmp2;
+ z4 = tmp1 + tmp3;
+ z5 = ((z3 + z4) * 9633/*FIX_1_175875602*/); /* sqrt(2) * c3 */
+
+ tmp0 = (tmp0 * 2446/*FIX_0_298631336*/); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp1 = (tmp1 * 16819/*FIX_2_053119869*/); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = (tmp2 * 25172/*FIX_3_072711026*/); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp3 = (tmp3 * 12299/*FIX_1_501321110*/); /* sqrt(2) * ( c1+c3-c5-c7) */
+ z1 = (z1 * - 7373/*FIX_0_899976223*/); /* sqrt(2) * (c7-c3) */
+ z2 = (z2 * - 20995/*FIX_2_562915447*/); /* sqrt(2) * (-c1-c3) */
+ z3 = (z3 * - 16069/*FIX_1_961570560*/); /* sqrt(2) * (-c3-c5) */
+ z4 = (z4 * - 3196/*FIX_0_390180644*/); /* sqrt(2) * (c5-c3) */
+
+ z3 += z5;
+ z4 += z5;
+
+ tmp0 += z1 + z3;
+ tmp1 += z2 + z4;
+ tmp2 += z2 + z3;
+ tmp3 += z1 + z4;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+// #define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+ wsptr[DCTSIZE*0+wsptr_offset] = (((tmp10 + tmp3) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+ wsptr[DCTSIZE*7+wsptr_offset] = (((tmp10 - tmp3) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+ wsptr[DCTSIZE*1+wsptr_offset] = (((tmp11 + tmp2) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+ wsptr[DCTSIZE*6+wsptr_offset] = (((tmp11 - tmp2) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+ wsptr[DCTSIZE*2+wsptr_offset] = (((tmp12 + tmp1) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+ wsptr[DCTSIZE*5+wsptr_offset] = (((tmp12 - tmp1) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+ wsptr[DCTSIZE*3+wsptr_offset] = (((tmp13 + tmp0) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+ wsptr[DCTSIZE*4+wsptr_offset] = (((tmp13 - tmp0) + (1 << ((CONST_BITS-PASS1_BITS)-1))) >> (CONST_BITS-PASS1_BITS));
+
+ inptr_offset++; /* advance pointers to next column */
+ quantptr_offset++;
+ wsptr_offset++;
+ }
+
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ int outptr_offset = 0;
+ wsptr = workspace;
+ wsptr_offset =0;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr+output_buf_offset];
+ outptr_offset = output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+//#ifndef NO_ZERO_ROW_TEST
+ if (wsptr[1+wsptr_offset] == 0 && wsptr[2+wsptr_offset] == 0 && wsptr[3+wsptr_offset] == 0 && wsptr[4+wsptr_offset] == 0 &&
+ wsptr[5+wsptr_offset] == 0 && wsptr[6+wsptr_offset] == 0 && wsptr[7+wsptr_offset] == 0)
+ {
+ /* AC terms all zero */
+// #define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+ byte dcval = range_limit[range_limit_offset + ((((wsptr[0+wsptr_offset]) + (1 << ((PASS1_BITS+3)-1))) >> PASS1_BITS+3)
+ & RANGE_MASK)];
+
+ outptr[0+outptr_offset] = dcval;
+ outptr[1+outptr_offset] = dcval;
+ outptr[2+outptr_offset] = dcval;
+ outptr[3+outptr_offset] = dcval;
+ outptr[4+outptr_offset] = dcval;
+ outptr[5+outptr_offset] = dcval;
+ outptr[6+outptr_offset] = dcval;
+ outptr[7+outptr_offset] = dcval;
+
+ wsptr_offset += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+//#endif
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = wsptr[2+wsptr_offset];
+ z3 = wsptr[6+wsptr_offset];
+
+ z1 = ((z2 + z3) * 4433/*FIX_0_541196100*/);
+ tmp2 = z1 + (z3 * - 15137/*FIX_1_847759065*/);
+ tmp3 = z1 + (z2 * 6270/*FIX_0_765366865*/);
+
+ tmp0 = (wsptr[0+wsptr_offset] + wsptr[4+wsptr_offset]) << CONST_BITS;
+ tmp1 = (wsptr[0+wsptr_offset] - wsptr[4+wsptr_offset]) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ 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 = wsptr[7+wsptr_offset];
+ tmp1 = wsptr[5+wsptr_offset];
+ tmp2 = wsptr[3+wsptr_offset];
+ tmp3 = wsptr[1+wsptr_offset];
+
+ z1 = tmp0 + tmp3;
+ z2 = tmp1 + tmp2;
+ z3 = tmp0 + tmp2;
+ z4 = tmp1 + tmp3;
+ z5 = ((z3 + z4) * 9633/*FIX_1_175875602*/); /* sqrt(2) * c3 */
+
+ tmp0 = (tmp0 * 2446/*FIX_0_298631336*/); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp1 = (tmp1 * 16819/*FIX_2_053119869*/); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = (tmp2 * 25172/*FIX_3_072711026*/); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp3 = (tmp3 * 12299/*FIX_1_501321110*/); /* sqrt(2) * ( c1+c3-c5-c7) */
+ z1 = (z1 * - 7373/*FIX_0_899976223*/); /* sqrt(2) * (c7-c3) */
+ z2 = (z2 * - 20995/*FIX_2_562915447*/); /* sqrt(2) * (-c1-c3) */
+ z3 = (z3 * - 16069/*FIX_1_961570560*/); /* sqrt(2) * (-c3-c5) */
+ z4 = (z4 * - 3196/*FIX_0_390180644*/); /* sqrt(2) * (c5-c3) */
+
+ z3 += z5;
+ z4 += z5;
+
+ tmp0 += z1 + z3;
+ tmp1 += z2 + z4;
+ tmp2 += z2 + z3;
+ tmp3 += z1 + z4;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+
+// #define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+ outptr[0+outptr_offset] = range_limit[range_limit_offset + ((((tmp10 + tmp3) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+ outptr[7+outptr_offset] = range_limit[range_limit_offset + ((((tmp10 - tmp3) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+ outptr[1+outptr_offset] = range_limit[range_limit_offset + ((((tmp11 + tmp2) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+ outptr[6+outptr_offset] = range_limit[range_limit_offset + ((((tmp11 - tmp2) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+ outptr[2+outptr_offset] = range_limit[range_limit_offset + ((((tmp12 + tmp1) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+ outptr[5+outptr_offset] = range_limit[range_limit_offset + ((((tmp12 - tmp1) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+ outptr[3+outptr_offset] = range_limit[range_limit_offset + ((((tmp13 + tmp0) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+ outptr[4+outptr_offset] = range_limit[range_limit_offset + ((((tmp13 - tmp0) + (1 << ((CONST_BITS+PASS1_BITS+3)-1))) >>
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK)];
+
+ wsptr_offset += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+static void upsample (jpeg_decompress_struct cinfo,
+ byte[][][] input_buf, int[] input_buf_offset, int[] in_row_group_ctr,
+ int in_row_groups_avail,
+ byte[][] output_buf, int[] out_row_ctr,
+ int out_rows_avail)
+{
+ sep_upsample(cinfo, input_buf, input_buf_offset, in_row_group_ctr, in_row_groups_avail, output_buf, out_row_ctr, out_rows_avail);
+}
+
+static boolean smoothing_ok (jpeg_decompress_struct cinfo) {
+ jpeg_d_coef_controller coef = cinfo.coef;
+ boolean smoothing_useful = false;
+ int ci, coefi;
+ jpeg_component_info compptr;
+ JQUANT_TBL qtable;
+ int[] coef_bits;
+ int[] coef_bits_latch;
+
+ if (! cinfo.progressive_mode || cinfo.coef_bits == null)
+ return false;
+
+ /* Allocate latch area if not already done */
+ if (coef.coef_bits_latch == null)
+ coef.coef_bits_latch = new int[cinfo.num_components * SAVED_COEFS];
+ coef_bits_latch = coef.coef_bits_latch;
+ int coef_bits_latch_offset = 0;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* All components' quantization values must already be latched. */
+ if ((qtable = compptr.quant_table) == null)
+ return false;
+ /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
+ if (qtable.quantval[0] == 0 ||
+ qtable.quantval[Q01_POS] == 0 ||
+ qtable.quantval[Q10_POS] == 0 ||
+ qtable.quantval[Q20_POS] == 0 ||
+ qtable.quantval[Q11_POS] == 0 ||
+ qtable.quantval[Q02_POS] == 0)
+ return false;
+ /* DC values must be at least partly known for all components. */
+ coef_bits = cinfo.coef_bits[ci];
+ if (coef_bits[0] < 0)
+ return false;
+ /* Block smoothing is helpful if some AC coefficients remain inaccurate. */
+ for (coefi = 1; coefi <= 5; coefi++) {
+ coef_bits_latch[coefi+coef_bits_latch_offset] = coef_bits[coefi];
+ if (coef_bits[coefi] != 0)
+ smoothing_useful = true;
+ }
+ coef_bits_latch_offset += SAVED_COEFS;
+ }
+
+ return smoothing_useful;
+}
+
+static void master_selection (jpeg_decompress_struct cinfo) {
+ jpeg_decomp_master master = cinfo.master;
+ boolean use_c_buffer;
+ long samplesperrow;
+ int jd_samplesperrow;
+
+ /* Initialize dimensions and other stuff */
+ jpeg_calc_output_dimensions(cinfo);
+ prepare_range_limit_table(cinfo);
+
+ /* Width of an output scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo.output_width * (long) cinfo.out_color_components;
+ jd_samplesperrow = (int) samplesperrow;
+ if ( jd_samplesperrow != samplesperrow)
+ error();
+// ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* Initialize my private state */
+ master.pass_number = 0;
+ master.using_merged_upsample = use_merged_upsample(cinfo);
+
+ /* Color quantizer selection */
+ master.quantizer_1pass = null;
+ master.quantizer_2pass = null;
+ /* No mode changes if not using buffered-image mode. */
+ if (! cinfo.quantize_colors || ! cinfo.buffered_image) {
+ cinfo.enable_1pass_quant = false;
+ cinfo.enable_external_quant = false;
+ cinfo.enable_2pass_quant = false;
+ }
+ if (cinfo.quantize_colors) {
+ error(SWT.ERROR_NOT_IMPLEMENTED);
+// if (cinfo.raw_data_out)
+// ERREXIT(cinfo, JERR_NOTIMPL);
+// /* 2-pass quantizer only works in 3-component color space. */
+// if (cinfo.out_color_components != 3) {
+// cinfo.enable_1pass_quant = true;
+// cinfo.enable_external_quant = false;
+// cinfo.enable_2pass_quant = false;
+// cinfo.colormap = null;
+// } else if (cinfo.colormap != null) {
+// cinfo.enable_external_quant = true;
+// } else if (cinfo.two_pass_quantize) {
+// cinfo.enable_2pass_quant = true;
+// } else {
+// cinfo.enable_1pass_quant = true;
+// }
+//
+// if (cinfo.enable_1pass_quant) {
+//#ifdef QUANT_1PASS_SUPPORTED
+// jinit_1pass_quantizer(cinfo);
+// master.quantizer_1pass = cinfo.cquantize;
+//#else
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+//#endif
+// }
+//
+// /* We use the 2-pass code to map to external colormaps. */
+// if (cinfo.enable_2pass_quant || cinfo.enable_external_quant) {
+//#ifdef QUANT_2PASS_SUPPORTED
+// jinit_2pass_quantizer(cinfo);
+// master.quantizer_2pass = cinfo.cquantize;
+//#else
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+//#endif
+// }
+// /* If both quantizers are initialized, the 2-pass one is left active;
+// * this is necessary for starting with quantization to an external map.
+// */
+ }
+
+ /* Post-processing: in particular, color conversion first */
+ if (! cinfo.raw_data_out) {
+ if (master.using_merged_upsample) {
+//#ifdef UPSAMPLE_MERGING_SUPPORTED
+// jinit_merged_upsampler(cinfo); /* does color conversion too */
+//#else
+ error();
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+//#endif
+ } else {
+ jinit_color_deconverter(cinfo);
+ jinit_upsampler(cinfo);
+ }
+ jinit_d_post_controller(cinfo, cinfo.enable_2pass_quant);
+ }
+ /* Inverse DCT */
+ jinit_inverse_dct(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo.arith_code) {
+ error();
+// ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ if (cinfo.progressive_mode) {
+//#ifdef D_PROGRESSIVE_SUPPORTED
+ jinit_phuff_decoder(cinfo);
+//#else
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+//#endif
+ } else
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo.inputctl.has_multiple_scans || cinfo.buffered_image;
+ jinit_d_coef_controller(cinfo, use_c_buffer);
+
+ if (! cinfo.raw_data_out)
+ jinit_d_main_controller(cinfo, false /* never need full buffer here */);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ start_input_pass (cinfo);
+
+//#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* If jpeg_start_decompress will read the whole file, initialize
+ * progress monitoring appropriately. The input step is counted
+ * as one pass.
+ */
+// if (cinfo.progress != null && ! cinfo.buffered_image &&
+// cinfo.inputctl.has_multiple_scans) {
+// int nscans;
+// /* Estimate number of scans to set pass_limit. */
+// if (cinfo.progressive_mode) {
+// /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+// nscans = 2 + 3 * cinfo.num_components;
+// } else {
+// /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+// nscans = cinfo.num_components;
+// }
+// cinfo.progress.pass_counter = 0L;
+// cinfo.progress.pass_limit = (long) cinfo.total_iMCU_rows * nscans;
+// cinfo.progress.completed_passes = 0;
+// cinfo.progress.total_passes = (cinfo.enable_2pass_quant ? 3 : 2);
+// /* Count the input pass as done */
+// master.pass_number++;
+// }
+//#endif /* D_MULTISCAN_FILES_SUPPORTED */
+}
+
+static void jinit_master_decompress (jpeg_decompress_struct cinfo) {
+ jpeg_decomp_master master = new jpeg_decomp_master();
+ cinfo.master = master;
+// master.prepare_for_output_pass = prepare_for_output_pass;
+// master.finish_output_pass = finish_output_pass;
+
+ master.is_dummy_pass = false;
+
+ master_selection(cinfo);
+}
+
+static void
+jcopy_sample_rows (byte[][] input_array, int source_row,
+ byte[][] output_array, int dest_row,
+ int num_rows, int num_cols)
+/* Copy some rows of samples from one place to another.
+ * num_rows rows are copied from input_array[source_row++]
+ * to output_array[dest_row++]; these areas may overlap for duplication.
+ * The source and destination arrays must be at least as wide as num_cols.
+ */
+{
+ byte[] inptr, outptr;
+ int count = num_cols;
+ int row;
+
+ int input_array_offset = source_row;
+ int output_array_offset = dest_row;
+
+ for (row = num_rows; row > 0; row--) {
+ inptr = input_array[input_array_offset++];
+ outptr = output_array[output_array_offset++];
+ System.arraycopy(inptr, 0, outptr, 0, count);
+ }
+}
+
+static boolean jpeg_start_decompress (jpeg_decompress_struct cinfo) {
+ if (cinfo.global_state == DSTATE_READY) {
+ /* First call: initialize master control, select active modules */
+ jinit_master_decompress(cinfo);
+ if (cinfo.buffered_image) {
+ /* No more work here; expecting jpeg_start_output next */
+ cinfo.global_state = DSTATE_BUFIMAGE;
+ return true;
+ }
+ cinfo.global_state = DSTATE_PRELOAD;
+ }
+ if (cinfo.global_state == DSTATE_PRELOAD) {
+ /* If file has multiple scans, absorb them all into the coef buffer */
+ if (cinfo.inputctl.has_multiple_scans) {
+//#ifdef D_MULTISCAN_FILES_SUPPORTED
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+// if (cinfo.progress != null)
+// (*cinfo.progress.progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = consume_input (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return false;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+// if (cinfo.progress != null && (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+// if (++cinfo.progress.pass_counter >= cinfo.progress.pass_limit) {
+// /* jdmaster underestimated number of scans; ratchet up one scan */
+// cinfo.progress.pass_limit += (long) cinfo.total_iMCU_rows;
+// }
+// }
+ }
+//#else
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+//#endif /* D_MULTISCAN_FILES_SUPPORTED */
+ }
+ cinfo.output_scan_number = cinfo.input_scan_number;
+ } else if (cinfo.global_state != DSTATE_PRESCAN)
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+ /* Perform any dummy output passes, and set up for the final pass */
+ return output_pass_setup(cinfo);
+}
+
+static void prepare_for_output_pass (jpeg_decompress_struct cinfo) {
+ jpeg_decomp_master master = cinfo.master;
+
+ if (master.is_dummy_pass) {
+//#ifdef QUANT_2PASS_SUPPORTED
+// /* Final pass of 2-pass quantization */
+// master.pub.is_dummy_pass = FALSE;
+// (*cinfo.cquantize.start_pass) (cinfo, FALSE);
+// (*cinfo.post.start_pass) (cinfo, JBUF_CRANK_DEST);
+// (*cinfo.main.start_pass) (cinfo, JBUF_CRANK_DEST);
+//#else
+ error(SWT.ERROR_NOT_IMPLEMENTED);
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+//#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ if (cinfo.quantize_colors && cinfo.colormap == null) {
+ /* Select new quantization method */
+ if (cinfo.two_pass_quantize && cinfo.enable_2pass_quant) {
+ cinfo.cquantize = master.quantizer_2pass;
+ master.is_dummy_pass = true;
+ } else if (cinfo.enable_1pass_quant) {
+ cinfo.cquantize = master.quantizer_1pass;
+ } else {
+ error();
+// ERREXIT(cinfo, JERR_MODE_CHANGE);
+ }
+ }
+ cinfo.idct.start_pass (cinfo);
+ start_output_pass (cinfo);
+ if (! cinfo.raw_data_out) {
+ if (! master.using_merged_upsample)
+ cinfo.cconvert.start_pass (cinfo);
+ cinfo.upsample.start_pass (cinfo);
+ if (cinfo.quantize_colors)
+ cinfo.cquantize.start_pass (cinfo, master.is_dummy_pass);
+ cinfo.post.start_pass (cinfo, (master.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ cinfo.main.start_pass (cinfo, JBUF_PASS_THRU);
+ }
+ }
+
+// /* Set up progress monitor's pass info if present */
+// if (cinfo.progress != NULL) {
+// cinfo.progress.completed_passes = master.pass_number;
+// cinfo.progress.total_passes = master.pass_number +
+// (master.pub.is_dummy_pass ? 2 : 1);
+// /* In buffered-image mode, we assume one more output pass if EOI not
+// * yet reached, but no more passes if EOI has been reached.
+// */
+// if (cinfo.buffered_image && ! cinfo.inputctl.eoi_reached) {
+// cinfo.progress.total_passes += (cinfo.enable_2pass_quant ? 2 : 1);
+// }
+// }
+}
+
+
+static boolean jpeg_resync_to_restart (jpeg_decompress_struct cinfo, int desired) {
+ int marker = cinfo.unread_marker;
+ int action = 1;
+
+ /* Always put up a warning. */
+// WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired);
+
+ /* Outer loop handles repeated decision after scanning forward. */
+ for (;;) {
+ if (marker < M_SOF0)
+ action = 2; /* invalid marker */
+ else if (marker < M_RST0 || marker > M_RST7)
+ action = 3; /* valid non-restart marker */
+ else {
+ if (marker == (M_RST0 + ((desired+1) & 7)) || marker == ( M_RST0 + ((desired+2) & 7)))
+ action = 3; /* one of the next two expected restarts */
+ else if (marker == (M_RST0 + ((desired-1) & 7)) || marker == ( M_RST0 + ((desired-2) & 7)))
+ action = 2; /* a prior restart, so advance */
+ else
+ action = 1; /* desired restart or too far away */
+ }
+// TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action);
+ switch (action) {
+ case 1:
+ /* Discard marker and let entropy decoder resume processing. */
+ cinfo.unread_marker = 0;
+ return true;
+ case 2:
+ /* Scan to the next marker, and repeat the decision loop. */
+ if (! next_marker(cinfo))
+ return false;
+ marker = cinfo.unread_marker;
+ break;
+ case 3:
+ /* Return without advancing past this marker. */
+ /* Entropy decoder will be forced to process an empty segment. */
+ return true;
+ }
+ } /* end loop */
+}
+
+static boolean read_restart_marker (jpeg_decompress_struct cinfo) {
+ /* Obtain a marker unless we already did. */
+ /* Note that next_marker will complain if it skips any data. */
+ if (cinfo.unread_marker == 0) {
+ if (! next_marker(cinfo))
+ return false;
+ }
+
+ if (cinfo.unread_marker == (M_RST0 + cinfo.marker.next_restart_num)) {
+ /* Normal case --- swallow the marker and let entropy decoder continue */
+// TRACEMS1(cinfo, 3, JTRC_RST, cinfo.marker.next_restart_num);
+ cinfo.unread_marker = 0;
+ } else {
+ /* Uh-oh, the restart markers have been messed up. */
+ /* Let the data source manager determine how to resync. */
+ if (! jpeg_resync_to_restart (cinfo, cinfo.marker.next_restart_num))
+ return false;
+ }
+
+ /* Update next-restart state */
+ cinfo.marker.next_restart_num = (cinfo.marker.next_restart_num + 1) & 7;
+
+ return true;
+}
+
+static boolean jpeg_fill_bit_buffer (bitread_working_state state, int get_buffer, int bits_left, int nbits)
+/* Load up the bit buffer to a depth of at least nbits */
+{
+ /* Copy heavily used state fields into locals (hopefully registers) */
+ byte[] buffer = state.buffer;
+ int bytes_in_buffer = state.bytes_in_buffer;
+ int bytes_offset = state.bytes_offset;
+ jpeg_decompress_struct cinfo = state.cinfo;
+
+ /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
+ /* (It is assumed that no request will be for more than that many bits.) */
+ /* We fail to do so only if we hit a marker or are forced to suspend. */
+
+ if (cinfo.unread_marker == 0) { /* cannot advance past a marker */
+ while (bits_left < MIN_GET_BITS) {
+ int c;
+
+ /* Attempt to read a byte */
+ if (bytes_offset == bytes_in_buffer) {
+ if (! fill_input_buffer (cinfo))
+ return false;
+ buffer = cinfo.buffer;
+ bytes_in_buffer = cinfo.bytes_in_buffer;
+ bytes_offset = cinfo.bytes_offset;
+ }
+ c = buffer[bytes_offset++] & 0xFF;
+
+ /* If it's 0xFF, check and discard stuffed zero byte */
+ if (c == 0xFF) {
+ /* Loop here to discard any padding FF's on terminating marker,
+ * so that we can save a valid unread_marker value. NOTE: we will
+ * accept multiple FF's followed by a 0 as meaning a single FF data
+ * byte. This data pattern is not valid according to the standard.
+ */
+ do {
+ if (bytes_offset == bytes_in_buffer) {
+ if (! fill_input_buffer (cinfo))
+ return false;
+ buffer = cinfo.buffer;
+ bytes_in_buffer = cinfo.bytes_in_buffer;
+ bytes_offset = cinfo.bytes_offset;
+ }
+ c = buffer[bytes_offset++] & 0xFF;
+ } while (c == 0xFF);
+
+ if (c == 0) {
+ /* Found FF/00, which represents an FF data byte */
+ c = 0xFF;
+ } else {
+ /* Oops, it's actually a marker indicating end of compressed data.
+ * Save the marker code for later use.
+ * Fine point: it might appear that we should save the marker into
+ * bitread working state, not straight into permanent state. But
+ * once we have hit a marker, we cannot need to suspend within the
+ * current MCU, because we will read no more bytes from the data
+ * source. So it is OK to update permanent state right away.
+ */
+ cinfo.unread_marker = c;
+ /* See if we need to insert some fake zero bits. */
+// goto no_more_bytes;
+ if (nbits > bits_left) {
+ /* Uh-oh. Report corrupted data to user and stuff zeroes into
+ * the data stream, so that we can produce some kind of image.
+ * We use a nonvolatile flag to ensure that only one warning message
+ * appears per data segment.
+ */
+ if (! cinfo.entropy.insufficient_data) {
+// WARNMS(cinfo, JWRN_HIT_MARKER);
+ cinfo.entropy.insufficient_data = true;
+ }
+ /* Fill the buffer with zero bits */
+ get_buffer <<= MIN_GET_BITS - bits_left;
+ bits_left = MIN_GET_BITS;
+ }
+
+ /* Unload the local registers */
+ state.buffer = buffer;
+ state.bytes_in_buffer = bytes_in_buffer;
+ state.bytes_offset = bytes_offset;
+ state.get_buffer = get_buffer;
+ state.bits_left = bits_left;
+
+ return true;
+
+ }
+ }
+
+ /* OK, load c into get_buffer */
+ get_buffer = (get_buffer << 8) | c;
+ bits_left += 8;
+ } /* end while */
+ } else {
+// no_more_bytes:
+ /* We get here if we've read the marker that terminates the compressed
+ * data segment. There should be enough bits in the buffer register
+ * to satisfy the request; if so, no problem.
+ */
+ if (nbits > bits_left) {
+ /* Uh-oh. Report corrupted data to user and stuff zeroes into
+ * the data stream, so that we can produce some kind of image.
+ * We use a nonvolatile flag to ensure that only one warning message
+ * appears per data segment.
+ */
+ if (! cinfo.entropy.insufficient_data) {
+// WARNMS(cinfo, JWRN_HIT_MARKER);
+ cinfo.entropy.insufficient_data = true;
+ }
+ /* Fill the buffer with zero bits */
+ get_buffer <<= MIN_GET_BITS - bits_left;
+ bits_left = MIN_GET_BITS;
+ }
+ }
+
+ /* Unload the local registers */
+ state.buffer = buffer;
+ state.bytes_in_buffer = bytes_in_buffer;
+ state.bytes_offset = bytes_offset;
+ state.get_buffer = get_buffer;
+ state.bits_left = bits_left;
+
+ return true;
+}
+
+static int jpeg_huff_decode (bitread_working_state state, int get_buffer, int bits_left, d_derived_tbl htbl, int min_bits) {
+ int l = min_bits;
+ int code;
+
+ /* HUFF_DECODE has determined that the code is at least min_bits */
+ /* bits long, so fetch that many bits in one swoop. */
+
+// CHECK_BIT_BUFFER(*state, l, return -1);
+ {
+ if (bits_left < (l)) {
+ if (! jpeg_fill_bit_buffer(state,get_buffer,bits_left,l)) {
+ return -1;
+ }
+ get_buffer = (state).get_buffer; bits_left = (state).bits_left;
+ }
+ }
+// code = GET_BITS(l);
+ code = (( (get_buffer >> (bits_left -= (l)))) & ((1<<(l))-1));
+
+ /* Collect the rest of the Huffman code one bit at a time. */
+ /* This is per Figure F.16 in the JPEG spec. */
+
+ while (code > htbl.maxcode[l]) {
+ code <<= 1;
+// CHECK_BIT_BUFFER(*state, 1, return -1);
+ {
+ if (bits_left < (1)) {
+ if (! jpeg_fill_bit_buffer(state,get_buffer,bits_left,1)) {
+ return -1;
+ }
+ get_buffer = (state).get_buffer; bits_left = (state).bits_left;
+ }
+ }
+// code |= GET_BITS(1);
+ code |= (( (get_buffer >> (bits_left -= (1)))) & ((1<<(1))-1));
+ l++;
+ }
+
+ /* Unload the local registers */
+ state.get_buffer = get_buffer;
+ state.bits_left = bits_left;
+
+ /* With garbage input we may reach the sentinel value l = 17. */
+
+ if (l > 16) {
+// WARNMS(state.cinfo, JWRN_HUFF_BAD_CODE);
+ return 0; /* fake a zero as the safest result */
+ }
+
+ return htbl.pub.huffval[ (code + htbl.valoffset[l]) ] & 0xFF;
+}
+
+static int decompress_onepass (jpeg_decompress_struct cinfo, byte[][][] output_buf, int[] output_buf_offset) {
+ jpeg_d_coef_controller coef = cinfo.coef;
+ int MCU_col_num; /* index of current MCU within row */
+ int last_MCU_col = cinfo.MCUs_per_row - 1;
+ int last_iMCU_row = cinfo.total_iMCU_rows - 1;
+ int blkn, ci, xindex, yindex, yoffset, useful_width;
+ byte[][] output_ptr;
+ int start_col, output_col;
+ jpeg_component_info compptr;
+// inverse_DCT_method_ptr inverse_DCT;
+
+ /* Loop to process as much as one whole iMCU row */
+ for (yoffset = coef.MCU_vert_offset; yoffset < coef.MCU_rows_per_iMCU_row; yoffset++) {
+ for (MCU_col_num = coef.MCU_ctr; MCU_col_num <= last_MCU_col; MCU_col_num++) {
+ /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
+ for (int i = 0; i < cinfo.blocks_in_MCU; i++) {
+ short[] blk = coef.MCU_buffer[i];
+ for (int j = 0; j < blk.length; j++) {
+ blk[j] = 0;
+ }
+ }
+ if (! cinfo.entropy.decode_mcu (cinfo, coef.MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef.MCU_vert_offset = yoffset;
+ coef.MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ /* Determine where data should go in output_buf and do the IDCT thing.
+ * We skip dummy blocks at the right and bottom edges (but blkn gets
+ * incremented past them!). Note the inner loop relies on having
+ * allocated the MCU_buffer[] blocks sequentially.
+ */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+ compptr = cinfo.cur_comp_info[ci];
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr.component_needed) {
+ blkn += compptr.MCU_blocks;
+ continue;
+ }
+// inverse_DCT = cinfo.idct.inverse_DCT[compptr.component_index];
+ useful_width = (MCU_col_num < last_MCU_col) ? compptr.MCU_width : compptr.last_col_width;
+ output_ptr = output_buf[compptr.component_index];
+ int output_ptr_offset = output_buf_offset[compptr.component_index] + yoffset * compptr.DCT_scaled_size;
+ start_col = MCU_col_num * compptr.MCU_sample_width;
+ for (yindex = 0; yindex < compptr.MCU_height; yindex++) {
+ if (cinfo.input_iMCU_row < last_iMCU_row || yoffset+yindex < compptr.last_row_height) {
+ output_col = start_col;
+ for (xindex = 0; xindex < useful_width; xindex++) {
+ jpeg_idct_islow(cinfo, compptr, coef.MCU_buffer[blkn+xindex], output_ptr, output_ptr_offset, output_col);
+ output_col += compptr.DCT_scaled_size;
+ }
+ }
+ blkn += compptr.MCU_width;
+ output_ptr_offset += compptr.DCT_scaled_size;
+ }
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef.MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ cinfo.output_iMCU_row++;
+ if (++(cinfo.input_iMCU_row) < cinfo.total_iMCU_rows) {
+ coef.start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ finish_input_pass (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+static int decompress_smooth_data (jpeg_decompress_struct cinfo, byte[][][] output_buf, int[] output_buf_offset) {
+ jpeg_d_coef_controller coef = cinfo.coef;
+ int last_iMCU_row = cinfo.total_iMCU_rows - 1;
+ int block_num, last_block_column;
+ int ci, block_row, block_rows, access_rows;
+ short[][][] buffer;
+ short[][] buffer_ptr, prev_block_row, next_block_row;
+ byte[][] output_ptr;
+ int output_col;
+ jpeg_component_info compptr;
+// inverse_DCT_method_ptr inverse_DCT;
+ boolean first_row, last_row;
+ short[] workspace = coef.workspace;
+ if (workspace == null) workspace = coef.workspace = new short[DCTSIZE2];
+ int[] coef_bits;
+ JQUANT_TBL quanttbl;
+ int Q00,Q01,Q02,Q10,Q11,Q20, num;
+ int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
+ int Al, pred;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo.input_scan_number <= cinfo.output_scan_number && ! cinfo.inputctl.eoi_reached) {
+ if (cinfo.input_scan_number == cinfo.output_scan_number) {
+ /* If input is working on current scan, we ordinarily want it to
+ * have completed the current row. But if input scan is DC,
+ * we want it to keep one row ahead so that next block row's DC
+ * values are up to date.
+ */
+ int delta = (cinfo.Ss == 0) ? 1 : 0;
+ if (cinfo.input_iMCU_row > cinfo.output_iMCU_row+delta)
+ break;
+ }
+ if (consume_input(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr.component_needed)
+ continue;
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo.output_iMCU_row < last_iMCU_row) {
+ block_rows = compptr.v_samp_factor;
+ access_rows = block_rows * 2; /* this and next iMCU row */
+ last_row = false;
+ } else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (compptr.height_in_blocks % compptr.v_samp_factor);
+ if (block_rows == 0) block_rows = compptr.v_samp_factor;
+ access_rows = block_rows; /* this iMCU row only */
+ last_row = true;
+ }
+ /* Align the virtual buffer for this component. */
+ int buffer_offset;
+ if (cinfo.output_iMCU_row > 0) {
+ access_rows += compptr.v_samp_factor; /* prior iMCU row too */
+ buffer = coef.whole_image[ci];
+ buffer_offset = (cinfo.output_iMCU_row - 1) * compptr.v_samp_factor;
+ buffer_offset += compptr.v_samp_factor; /* point to current iMCU row */
+ first_row = false;
+ } else {
+ buffer = coef.whole_image[ci];
+ buffer_offset = 0;
+ first_row = true;
+ }
+ /* Fetch component-dependent info */
+ coef_bits = coef.coef_bits_latch;
+ int coef_offset = (ci * SAVED_COEFS);
+ quanttbl = compptr.quant_table;
+ Q00 = quanttbl.quantval[0];
+ Q01 = quanttbl.quantval[Q01_POS];
+ Q10 = quanttbl.quantval[Q10_POS];
+ Q20 = quanttbl.quantval[Q20_POS];
+ Q11 = quanttbl.quantval[Q11_POS];
+ Q02 = quanttbl.quantval[Q02_POS];
+// inverse_DCT = cinfo.idct.inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ int output_ptr_offset = output_buf_offset[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row+buffer_offset];
+ int buffer_ptr_offset = 0, prev_block_row_offset = 0, next_block_row_offset = 0;
+ if (first_row && block_row == 0) {
+ prev_block_row = buffer_ptr;
+ prev_block_row_offset = buffer_ptr_offset;
+ } else {
+ prev_block_row = buffer[block_row-1+buffer_offset];
+ prev_block_row_offset = 0;
+ }
+ if (last_row && block_row == block_rows-1) {
+ next_block_row = buffer_ptr;
+ next_block_row_offset = buffer_ptr_offset;
+ } else {
+ next_block_row = buffer[block_row+1+buffer_offset];
+ next_block_row_offset = 0;
+ }
+ /* We fetch the surrounding DC values using a sliding-register approach.
+ * Initialize all nine here so as to do the right thing on narrow pics.
+ */
+ DC1 = DC2 = DC3 = prev_block_row[0+prev_block_row_offset][0];
+ DC4 = DC5 = DC6 = buffer_ptr[0+buffer_ptr_offset][0];
+ DC7 = DC8 = DC9 = next_block_row[0+next_block_row_offset][0];
+ output_col = 0;
+ last_block_column = compptr.width_in_blocks - 1;
+ for (block_num = 0; block_num <= last_block_column; block_num++) {
+ /* Fetch current DCT block into workspace so we can modify it. */
+// jcopy_block_row(buffer_ptr, workspace, 1);
+ System.arraycopy(buffer_ptr[buffer_ptr_offset], 0, workspace, 0, workspace.length);
+ /* Update DC values */
+ if (block_num < last_block_column) {
+ DC3 = prev_block_row[1+prev_block_row_offset][0];
+ DC6 = buffer_ptr[1+buffer_ptr_offset][0];
+ DC9 = next_block_row[1+next_block_row_offset][0];
+ }
+ /* Compute coefficient estimates per K.8.
+ * An estimate is applied only if coefficient is still zero,
+ * and is not known to be fully accurate.
+ */
+ /* AC01 */
+ if ((Al=coef_bits[1+coef_offset]) != 0 && workspace[1] == 0) {
+ num = 36 * Q00 * (DC4 - DC6);
+ if (num >= 0) {
+ pred = (((Q01<<7) + num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (((Q01<<7) - num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[1] = (short) pred;
+ }
+ /* AC10 */
+ if ((Al=coef_bits[2+coef_offset]) != 0 && workspace[8] == 0) {
+ num = 36 * Q00 * (DC2 - DC8);
+ if (num >= 0) {
+ pred = (((Q10<<7) + num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (((Q10<<7) - num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[8] = (short) pred;
+ }
+ /* AC20 */
+ if ((Al=coef_bits[3+coef_offset]) != 0 && workspace[16] == 0) {
+ num = 9 * Q00 * (DC2 + DC8 - 2*DC5);
+ if (num >= 0) {
+ pred = (((Q20<<7) + num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (((Q20<<7) - num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[16] = (short) pred;
+ }
+ /* AC11 */
+ if ((Al=coef_bits[4+coef_offset]) != 0 && workspace[9] == 0) {
+ num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
+ if (num >= 0) {
+ pred = (((Q11<<7) + num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (((Q11<<7) - num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[9] = (short) pred;
+ }
+ /* AC02 */
+ if ((Al=coef_bits[5+coef_offset]) != 0 && workspace[2] == 0) {
+ num = 9 * Q00 * (DC4 + DC6 - 2*DC5);
+ if (num >= 0) {
+ pred = (((Q02<<7) + num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (((Q02<<7) - num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[2] = (short) pred;
+ }
+ /* OK, do the IDCT */
+ jpeg_idct_islow(cinfo, compptr, workspace, output_ptr, output_ptr_offset, output_col);
+ /* Advance for next column */
+ DC1 = DC2; DC2 = DC3;
+ DC4 = DC5; DC5 = DC6;
+ DC7 = DC8; DC8 = DC9;
+ buffer_ptr_offset++; prev_block_row_offset++; next_block_row_offset++;
+ output_col += compptr.DCT_scaled_size;
+ }
+ output_ptr_offset += compptr.DCT_scaled_size;
+ }
+ }
+
+ if (++(cinfo.output_iMCU_row) < cinfo.total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+static int decompress_data (jpeg_decompress_struct cinfo, byte[][][] output_buf, int[] output_buf_offset) {
+ jpeg_d_coef_controller coef = cinfo.coef;
+ int last_iMCU_row = cinfo.total_iMCU_rows - 1;
+ int block_num;
+ int ci, block_row, block_rows;
+ short[][][] buffer;
+ short[][] buffer_ptr;
+ byte[][] output_ptr;
+ int output_col;
+ jpeg_component_info compptr;
+// inverse_DCT_method_ptr inverse_DCT;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo.input_scan_number < cinfo.output_scan_number ||
+ (cinfo.input_scan_number == cinfo.output_scan_number &&
+ cinfo.input_iMCU_row <= cinfo.output_iMCU_row))
+ {
+ if (consume_input(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr.component_needed)
+ continue;
+ /* Align the virtual buffer for this component. */
+ buffer = coef.whole_image[ci];
+ int buffer_offset = cinfo.output_iMCU_row * compptr.v_samp_factor;
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo.output_iMCU_row < last_iMCU_row)
+ block_rows = compptr.v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (compptr.height_in_blocks % compptr.v_samp_factor);
+ if (block_rows == 0) block_rows = compptr.v_samp_factor;
+ }
+// inverse_DCT = cinfo.idct.inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ int output_ptr_offset = output_buf_offset[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row+buffer_offset];
+ int buffer_ptr_offset = 0;
+ output_col = 0;
+ for (block_num = 0; block_num < compptr.width_in_blocks; block_num++) {
+ jpeg_idct_islow(cinfo, compptr, buffer_ptr[buffer_ptr_offset], output_ptr, output_ptr_offset, output_col);
+
+ buffer_ptr_offset++;
+ output_col += compptr.DCT_scaled_size;
+ }
+ output_ptr_offset += compptr.DCT_scaled_size;
+ }
+ }
+
+ if (++(cinfo.output_iMCU_row) < cinfo.total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+static void post_process_data (jpeg_decompress_struct cinfo,
+ byte[][][] input_buf, int[] input_buf_offset, int[] in_row_group_ctr,
+ int in_row_groups_avail,
+ byte[][] output_buf, int[] out_row_ctr,
+ int out_rows_avail)
+{
+ upsample(cinfo, input_buf, input_buf_offset, in_row_group_ctr, in_row_groups_avail, output_buf, out_row_ctr, out_rows_avail);
+}
+
+static void set_bottom_pointers (jpeg_decompress_struct cinfo)
+/* Change the pointer lists to duplicate the last sample row at the bottom
+ * of the image. whichptr indicates which xbuffer holds the final iMCU row.
+ * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
+ */
+{
+ jpeg_d_main_controller main = cinfo.main;
+ int ci, i, rgroup, iMCUheight, rows_left;
+ jpeg_component_info compptr;
+ byte[][] xbuf;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* Count sample rows in one iMCU row and in one row group */
+ iMCUheight = compptr.v_samp_factor * compptr.DCT_scaled_size;
+ rgroup = iMCUheight / cinfo.min_DCT_scaled_size;
+ /* Count nondummy sample rows remaining for this component */
+ rows_left = (compptr.downsampled_height % iMCUheight);
+ if (rows_left == 0) rows_left = iMCUheight;
+ /* Count nondummy row groups. Should get same answer for each component,
+ * so we need only do it once.
+ */
+ if (ci == 0) {
+ main.rowgroups_avail = ((rows_left-1) / rgroup + 1);
+ }
+ /* Duplicate the last real sample row rgroup*2 times; this pads out the
+ * last partial rowgroup and ensures at least one full rowgroup of context.
+ */
+ xbuf = main.xbuffer[main.whichptr][ci];
+ int xbuf_offset = main.xbuffer_offset[main.whichptr][ci];
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf[rows_left + i + xbuf_offset] = xbuf[rows_left-1 + xbuf_offset];
+ }
+ }
+}
+
+static void set_wraparound_pointers (jpeg_decompress_struct cinfo)
+/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
+ * This changes the pointer list state from top-of-image to the normal state.
+ */
+{
+ jpeg_d_main_controller main = cinfo.main;
+ int ci, i, rgroup;
+ int M = cinfo.min_DCT_scaled_size;
+ jpeg_component_info compptr;
+ byte[][] xbuf0, xbuf1;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ rgroup = (compptr.v_samp_factor * compptr.DCT_scaled_size) / cinfo.min_DCT_scaled_size; /* height of a row group of component */
+ xbuf0 = main.xbuffer[0][ci];
+ int xbuf0_offset = main.xbuffer_offset[0][ci];
+ xbuf1 = main.xbuffer[1][ci];
+ int xbuf1_offset = main.xbuffer_offset[1][ci];
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup + xbuf0_offset] = xbuf0[rgroup*(M+1) + i + xbuf0_offset];
+ xbuf1[i - rgroup + xbuf1_offset] = xbuf1[rgroup*(M+1) + i + xbuf1_offset];
+ xbuf0[rgroup*(M+2) + i + xbuf0_offset] = xbuf0[i + xbuf0_offset];
+ xbuf1[rgroup*(M+2) + i + xbuf1_offset] = xbuf1[i + xbuf1_offset];
+ }
+ }
+}
+
+static void process_data_crank_post (jpeg_decompress_struct cinfo,
+ byte[][] output_buf, int[] out_row_ctr,
+ int out_rows_avail)
+{
+ error();
+}
+
+static void process_data_context_main (jpeg_decompress_struct cinfo,
+ byte[][] output_buf, int[] out_row_ctr,
+ int out_rows_avail)
+{
+ jpeg_d_main_controller main = cinfo.main;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main.buffer_full) {
+ int result;
+ switch (cinfo.coef.decompress_data) {
+ case DECOMPRESS_DATA:
+ result = decompress_data(cinfo, main.xbuffer[main.whichptr], main.xbuffer_offset[main.whichptr]);
+ break;
+ case DECOMPRESS_SMOOTH_DATA:
+ result = decompress_smooth_data(cinfo, main.xbuffer[main.whichptr], main.xbuffer_offset[main.whichptr]);
+ break;
+ case DECOMPRESS_ONEPASS:
+ result = decompress_onepass(cinfo, main.xbuffer[main.whichptr], main.xbuffer_offset[main.whichptr]);
+ break;
+ default: result = 0;
+ }
+ if (result == 0)
+ return; /* suspension forced, can do nothing more */
+ main.buffer_full = true; /* OK, we have an iMCU row to work with */
+ main.iMCU_row_ctr++; /* count rows received */
+ }
+
+ /* Postprocessor typically will not swallow all the input data it is handed
+ * in one call (due to filling the output buffer first). Must be prepared
+ * to exit and restart. This switch lets us keep track of how far we got.
+ * Note that each case falls through to the next on successful completion.
+ */
+ switch (main.context_state) {
+ case CTX_POSTPONED_ROW:
+ /* Call postprocessor using previously set pointers for postponed row */
+ post_process_data (cinfo, main.xbuffer[main.whichptr], main.xbuffer_offset[main.whichptr], main.rowgroup_ctr, main.rowgroups_avail, output_buf, out_row_ctr, out_rows_avail);
+ if (main.rowgroup_ctr[0] < main.rowgroups_avail)
+ return; /* Need to suspend */
+ main.context_state = CTX_PREPARE_FOR_IMCU;
+ if (out_row_ctr[0] >= out_rows_avail)
+ return; /* Postprocessor exactly filled output buf */
+ /*FALLTHROUGH*/
+ case CTX_PREPARE_FOR_IMCU:
+ /* Prepare to process first M-1 row groups of this iMCU row */
+ main.rowgroup_ctr[0] = 0;
+ main.rowgroups_avail = (cinfo.min_DCT_scaled_size - 1);
+ /* Check for bottom of image: if so, tweak pointers to "duplicate"
+ * the last sample row, and adjust rowgroups_avail to ignore padding rows.
+ */
+ if (main.iMCU_row_ctr == cinfo.total_iMCU_rows)
+ set_bottom_pointers(cinfo);
+ main.context_state = CTX_PROCESS_IMCU;
+ /*FALLTHROUGH*/
+ case CTX_PROCESS_IMCU:
+ /* Call postprocessor using previously set pointers */
+ post_process_data (cinfo, main.xbuffer[main.whichptr], main.xbuffer_offset[main.whichptr], main.rowgroup_ctr, main.rowgroups_avail, output_buf, out_row_ctr, out_rows_avail);
+ if (main.rowgroup_ctr[0] < main.rowgroups_avail)
+ return; /* Need to suspend */
+ /* After the first iMCU, change wraparound pointers to normal state */
+ if (main.iMCU_row_ctr == 1)
+ set_wraparound_pointers(cinfo);
+ /* Prepare to load new iMCU row using other xbuffer list */
+ main.whichptr ^= 1; /* 0=>1 or 1=>0 */
+ main.buffer_full = false;
+ /* Still need to process last row group of this iMCU row, */
+ /* which is saved at index M+1 of the other xbuffer */
+ main.rowgroup_ctr[0] = (cinfo.min_DCT_scaled_size + 1);
+ main.rowgroups_avail = (cinfo.min_DCT_scaled_size + 2);
+ main.context_state = CTX_POSTPONED_ROW;
+ }
+}
+
+static void process_data_simple_main (jpeg_decompress_struct cinfo, byte[][] output_buf, int[] out_row_ctr, int out_rows_avail) {
+ jpeg_d_main_controller main = cinfo.main;
+ int rowgroups_avail;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main.buffer_full) {
+ int result;
+ switch (cinfo.coef.decompress_data) {
+ case DECOMPRESS_DATA:
+ result = decompress_data(cinfo, main.buffer, main.buffer_offset);
+ break;
+ case DECOMPRESS_SMOOTH_DATA:
+ result = decompress_smooth_data(cinfo, main.buffer, main.buffer_offset);
+ break;
+ case DECOMPRESS_ONEPASS:
+ result = decompress_onepass(cinfo, main.buffer, main.buffer_offset);
+ break;
+ default: result = 0;
+ }
+ if (result == 0)
+ return; /* suspension forced, can do nothing more */
+ main.buffer_full = true; /* OK, we have an iMCU row to work with */
+ }
+
+ /* There are always min_DCT_scaled_size row groups in an iMCU row. */
+ rowgroups_avail = cinfo.min_DCT_scaled_size;
+ /* Note: at the bottom of the image, we may pass extra garbage row groups
+ * to the postprocessor. The postprocessor has to check for bottom
+ * of image anyway (at row resolution), so no point in us doing it too.
+ */
+
+ /* Feed the postprocessor */
+ post_process_data (cinfo, main.buffer, main.buffer_offset, main.rowgroup_ctr, rowgroups_avail, output_buf, out_row_ctr, out_rows_avail);
+
+ /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
+ if (main.rowgroup_ctr[0] >= rowgroups_avail) {
+ main.buffer_full = false;
+ main.rowgroup_ctr[0] = 0;
+ }
+}
+
+static int jpeg_read_scanlines (jpeg_decompress_struct cinfo, byte[][] scanlines, int max_lines) {
+
+ if (cinfo.global_state != DSTATE_SCANNING)
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+ if (cinfo.output_scanline >= cinfo.output_height) {
+// WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+// if (cinfo.progress != NULL) {
+// cinfo.progress.pass_counter = (long) cinfo.output_scanline;
+// cinfo.progress.pass_limit = (long) cinfo.output_height;
+// (*cinfo.progress.progress_monitor) ((j_common_ptr) cinfo);
+// }
+
+ /* Process some data */
+ cinfo.row_ctr[0] = 0;
+ switch (cinfo.main.process_data) {
+ case PROCESS_DATA_SIMPLE_MAIN:
+ process_data_simple_main (cinfo, scanlines, cinfo.row_ctr, max_lines);
+ break;
+ case PROCESS_DATA_CONTEXT_MAIN:
+ process_data_context_main (cinfo, scanlines, cinfo.row_ctr, max_lines);
+ break;
+ case PROCESS_DATA_CRANK_POST:
+ process_data_crank_post (cinfo, scanlines, cinfo.row_ctr, max_lines);
+ break;
+ default: error();
+ }
+ cinfo.output_scanline += cinfo.row_ctr[0];
+ return cinfo.row_ctr[0];
+}
+
+
+static boolean output_pass_setup (jpeg_decompress_struct cinfo) {
+ if (cinfo.global_state != DSTATE_PRESCAN) {
+ /* First call: do pass setup */
+ prepare_for_output_pass (cinfo);
+ cinfo.output_scanline = 0;
+ cinfo.global_state = DSTATE_PRESCAN;
+ }
+ /* Loop over any required dummy passes */
+ while (cinfo.master.is_dummy_pass) {
+ error();
+//#ifdef QUANT_2PASS_SUPPORTED
+// /* Crank through the dummy pass */
+// while (cinfo.output_scanline < cinfo.output_height) {
+// JDIMENSION last_scanline;
+// /* Call progress monitor hook if present */
+// if (cinfo.progress != NULL) {
+// cinfo.progress.pass_counter = (long) cinfo.output_scanline;
+// cinfo.progress.pass_limit = (long) cinfo.output_height;
+// (*cinfo.progress.progress_monitor) ((j_common_ptr) cinfo);
+// }
+// /* Process some data */
+// last_scanline = cinfo.output_scanline;
+// (*cinfo.main.process_data) (cinfo, (JSAMPARRAY) NULL,
+// &cinfo.output_scanline, (JDIMENSION) 0);
+// if (cinfo.output_scanline == last_scanline)
+// return FALSE; /* No progress made, must suspend */
+// }
+// /* Finish up dummy pass, and set up for another one */
+// (*cinfo.master.finish_output_pass) (cinfo);
+// (*cinfo.master.prepare_for_output_pass) (cinfo);
+// cinfo.output_scanline = 0;
+//#else
+// ERREXIT(cinfo, JERR_NOT_COMPILED);
+//#endif /* QUANT_2PASS_SUPPORTED */
+ }
+ /* Ready for application to drive output pass through
+ * jpeg_read_scanlines or jpeg_read_raw_data.
+ */
+ cinfo.global_state = cinfo.raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
+ return true;
+}
+
+static boolean get_dht (jpeg_decompress_struct cinfo)
+/* Process a DHT marker */
+{
+ int length;
+ byte[] bits = new byte[17];
+ byte[] huffval = new byte[256];
+ int i, index, count;
+ JHUFF_TBL htblptr;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ length -= 2;
+
+ while (length > 16) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ index = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+// TRACEMS1(cinfo, 1, JTRC_DHT, index);
+
+ bits[0] = 0;
+ count = 0;
+ for (i = 1; i <= 16; i++) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ bits[i] = cinfo.buffer[cinfo.bytes_offset++];
+ count += bits[i] & 0xFF;
+ }
+
+ length -= 1 + 16;
+
+// TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+// bits[1], bits[2], bits[3], bits[4],
+// bits[5], bits[6], bits[7], bits[8]);
+// TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+// bits[9], bits[10], bits[11], bits[12],
+// bits[13], bits[14], bits[15], bits[16]);
+
+ /* Here we just do minimal validation of the counts to avoid walking
+ * off the end of our table space. jdhuff.c will check more carefully.
+ */
+ if (count > 256 || (count) > length)
+ error();
+// ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+
+ for (i = 0; i < count; i++) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ huffval[i] = cinfo.buffer[cinfo.bytes_offset++];
+ }
+
+ length -= count;
+
+ if ((index & 0x10) != 0) { /* AC table definition */
+ index -= 0x10;
+ htblptr = cinfo.ac_huff_tbl_ptrs[index] = new JHUFF_TBL();
+ } else { /* DC table definition */
+ htblptr = cinfo.dc_huff_tbl_ptrs[index] = new JHUFF_TBL();
+ }
+
+ if (index < 0 || index >= NUM_HUFF_TBLS)
+ error();
+// ERREXIT1(cinfo, JERR_DHT_INDEX, index);
+
+ System.arraycopy(bits, 0, htblptr.bits, 0, bits.length);
+ System.arraycopy(huffval, 0, htblptr.huffval, 0, huffval.length);
+ }
+
+ if (length != 0)
+ error();
+// ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ return true;
+}
+
+
+static boolean get_dqt (jpeg_decompress_struct cinfo)
+/* Process a DQT marker */
+{
+ int length;
+ int n, i, prec;
+ int tmp;
+ JQUANT_TBL quant_ptr;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ length -= 2;
+
+ while (length > 0) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ n = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ prec = n >> 4;
+ n &= 0x0F;
+
+// TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);
+
+ if (n >= NUM_QUANT_TBLS)
+ error();
+// ERREXIT1(cinfo, JERR_DQT_INDEX, n);
+
+ if (cinfo.quant_tbl_ptrs[n] == null)
+ cinfo.quant_tbl_ptrs[n] = new JQUANT_TBL();
+ quant_ptr = cinfo.quant_tbl_ptrs[n];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ if (prec != 0) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ tmp = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ tmp |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ } else {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ tmp = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ }
+ /* We convert the zigzag-order table to natural array order. */
+ quant_ptr.quantval[jpeg_natural_order[i]] = (short) tmp;
+ }
+
+// if (cinfo.err.trace_level >= 2) {
+// for (i = 0; i < DCTSIZE2; i += 8) {
+// TRACEMS8(cinfo, 2, JTRC_QUANTVALS,
+// quant_ptr.quantval[i], quant_ptr.quantval[i+1],
+// quant_ptr.quantval[i+2], quant_ptr.quantval[i+3],
+// quant_ptr.quantval[i+4], quant_ptr.quantval[i+5],
+// quant_ptr.quantval[i+6], quant_ptr.quantval[i+7]);
+// }
+// }
+
+ length -= (DCTSIZE2+1);
+ if (prec != 0) length -= DCTSIZE2;
+ }
+
+ if (length != 0)
+ error();
+// ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ return true;
+}
+
+static boolean get_dri (jpeg_decompress_struct cinfo)
+/* Process a DRI marker */
+{
+ int length;
+ int tmp;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ if (length != 4)
+ error();
+// ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ tmp = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ tmp |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+// TRACEMS1(cinfo, 1, JTRC_DRI, tmp);
+
+ cinfo.restart_interval = tmp;
+
+ return true;
+}
+
+static boolean get_dac (jpeg_decompress_struct cinfo)
+/* Process a DAC marker */
+{
+ int length;
+ int index, val;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ length -= 2;
+
+ while (length > 0) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ index = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ val = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ length -= 2;
+
+// TRACEMS2(cinfo, 1, JTRC_DAC, index, val);
+
+ if (index < 0 || index >= (2*NUM_ARITH_TBLS))
+ error();
+// ERREXIT1(cinfo, JERR_DAC_INDEX, index);
+
+ if (index >= NUM_ARITH_TBLS) { /* define AC table */
+ cinfo.arith_ac_K[index-NUM_ARITH_TBLS] = (byte) val;
+ } else { /* define DC table */
+ cinfo.arith_dc_L[index] = (byte) (val & 0x0F);
+ cinfo.arith_dc_U[index] = (byte) (val >> 4);
+ if (cinfo.arith_dc_L[index] > cinfo.arith_dc_U[index])
+ error();
+// ERREXIT1(cinfo, JERR_DAC_VALUE, val);
+ }
+ }
+
+ if (length != 0)
+ error();
+// ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ return true;
+}
+
+
+static boolean get_sos (jpeg_decompress_struct cinfo)
+/* Process a SOS marker */
+{
+ int length;
+ int i, ci, n, c, cc;
+ jpeg_component_info compptr = null;
+
+ if (! cinfo.marker.saw_SOF)
+ error();
+// ERREXIT(cinfo, JERR_SOS_NO_SOF);
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ n = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+// TRACEMS1(cinfo, 1, JTRC_SOS, n);
+
+ if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN)
+ error();
+// ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ cinfo.comps_in_scan = n;
+
+ /* Collect the component-spec parameters */
+
+ for (i = 0; i < n; i++) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ cc = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ if (cc == compptr.component_id)
+ break;
+ }
+
+ if (ci == cinfo.num_components)
+ error();
+// ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc);
+
+ cinfo.cur_comp_info[i] = compptr;
+ compptr.dc_tbl_no = (c >> 4) & 15;
+ compptr.ac_tbl_no = (c ) & 15;
+
+// TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, compptr.dc_tbl_no, compptr.ac_tbl_no);
+ }
+
+ /* Collect the additional scan parameters Ss, Se, Ah/Al. */
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ cinfo.Ss = c;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ cinfo.Se = c;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ cinfo.Ah = (c >> 4) & 15;
+ cinfo.Al = (c ) & 15;
+
+// TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo.Ss, cinfo.Se, cinfo.Ah, cinfo.Al);
+
+ /* Prepare to scan data & restart markers */
+ cinfo.marker.next_restart_num = 0;
+
+ /* Count another SOS marker */
+ cinfo.input_scan_number++;
+
+ return true;
+}
+
+static boolean get_sof (jpeg_decompress_struct cinfo, boolean is_prog, boolean is_arith) {
+ int length;
+ int c, ci;
+
+ cinfo.progressive_mode = is_prog;
+ cinfo.arith_code = is_arith;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ cinfo.data_precision = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ cinfo.image_height = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ cinfo.image_height |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ cinfo.image_width = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ cinfo.image_width |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ cinfo.num_components = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ length -= 8;
+
+// TRACEMS4(cinfo, 1, JTRC_SOF, cinfo.unread_marker,
+// (int) cinfo.image_width, (int) cinfo.image_height,
+// cinfo.num_components);
+
+ if (cinfo.marker.saw_SOF)
+ error();
+// ERREXIT(cinfo, JERR_SOF_DUPLICATE);
+
+ /* We don't support files in which the image height is initially specified */
+ /* as 0 and is later redefined by DNL. As long as we have to check that, */
+ /* might as well have a general sanity check. */
+ if (cinfo.image_height <= 0 || cinfo.image_width <= 0 || cinfo.num_components <= 0)
+ error();
+// ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+ if (length != (cinfo.num_components * 3))
+ error();
+// ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ if (cinfo.comp_info == null) /* do only once, even if suspend */
+ cinfo.comp_info = new jpeg_component_info[cinfo.num_components];
+
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ jpeg_component_info compptr = cinfo.comp_info[ci] = new jpeg_component_info();
+ compptr.component_index = ci;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ compptr.component_id = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ compptr.h_samp_factor = (c >> 4) & 15;
+ compptr.v_samp_factor = (c ) & 15;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ compptr.quant_tbl_no = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+// TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT,
+// compptr.component_id, compptr.h_samp_factor,
+// compptr.v_samp_factor, compptr.quant_tbl_no);
+ }
+
+ cinfo.marker.saw_SOF = true;
+
+ return true;
+}
+
+static void sep_upsample (jpeg_decompress_struct cinfo, byte[][][] input_buf, int[] input_buf_offset,
+ int[] in_row_group_ctr, int in_row_groups_avail,
+ byte[][] output_buf, int[] out_row_ctr, int out_rows_avail)
+{
+ jpeg_upsampler upsample = cinfo.upsample;
+ int ci;
+ jpeg_component_info compptr;
+ int num_rows;
+
+ /* Fill the conversion buffer, if it's empty */
+ if (upsample.next_row_out >= cinfo.max_v_samp_factor) {
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ /* Invoke per-component upsample method. Notice we pass a POINTER
+ * to color_buf[ci], so that fullsize_upsample can change it.
+ */
+ int offset = input_buf_offset[ci] + (in_row_group_ctr[0] * upsample.rowgroup_height[ci]);
+ switch (upsample.methods[ci]) {
+ case NOOP_UPSAMPLE: noop_upsample(cinfo, compptr, input_buf[ci], offset, upsample.color_buf, upsample.color_buf_offset, ci); break;
+ case FULLSIZE_UPSAMPLE: fullsize_upsample(cinfo, compptr, input_buf[ci], offset, upsample.color_buf, upsample.color_buf_offset, ci); break;
+ case H2V1_FANCY_UPSAMPLE: h2v1_fancy_upsample(cinfo, compptr, input_buf[ci], offset, upsample.color_buf, upsample.color_buf_offset, ci); break;
+ case H2V1_UPSAMPLE: h2v1_upsample(cinfo, compptr, input_buf[ci], offset, upsample.color_buf, upsample.color_buf_offset, ci); break;
+ case H2V2_FANCY_UPSAMPLE: h2v2_fancy_upsample(cinfo, compptr, input_buf[ci], offset, upsample.color_buf, upsample.color_buf_offset, ci); break;
+ case H2V2_UPSAMPLE: h2v2_upsample(cinfo, compptr, input_buf[ci], offset, upsample.color_buf, upsample.color_buf_offset, ci); break;
+ case INT_UPSAMPLE: int_upsample(cinfo, compptr, input_buf[ci], offset, upsample.color_buf, upsample.color_buf_offset, ci); break;
+ }
+ }
+ upsample.next_row_out = 0;
+ }
+
+ /* Color-convert and emit rows */
+
+ /* How many we have in the buffer: */
+ num_rows = (cinfo.max_v_samp_factor - upsample.next_row_out);
+ /* Not more than the distance to the end of the image. Need this test
+ * in case the image height is not a multiple of max_v_samp_factor:
+ */
+ if (num_rows > upsample.rows_to_go)
+ num_rows = upsample.rows_to_go;
+ /* And not more than what the client can accept: */
+ out_rows_avail -= out_row_ctr[0];
+ if (num_rows > out_rows_avail)
+ num_rows = out_rows_avail;
+
+ switch (cinfo.cconvert.color_convert) {
+ case NULL_CONVERT: null_convert (cinfo, upsample.color_buf, upsample.color_buf_offset, upsample.next_row_out, output_buf, out_row_ctr[0], num_rows); break;
+ case GRAYSCALE_CONVERT: grayscale_convert (cinfo, upsample.color_buf, upsample.color_buf_offset, upsample.next_row_out, output_buf, out_row_ctr[0], num_rows); break;
+ case YCC_RGB_CONVERT: ycc_rgb_convert (cinfo, upsample.color_buf, upsample.color_buf_offset, upsample.next_row_out, output_buf, out_row_ctr[0], num_rows); break;
+ case GRAY_RGB_CONVERT: gray_rgb_convert (cinfo, upsample.color_buf, upsample.color_buf_offset, upsample.next_row_out, output_buf, out_row_ctr[0], num_rows); break;
+ case YCCK_CMYK_CONVERT: error(); break;
+ }
+
+ /* Adjust counts */
+ out_row_ctr[0] += num_rows;
+ upsample.rows_to_go -= num_rows;
+ upsample.next_row_out += num_rows;
+ /* When the buffer is emptied, declare this input row group consumed */
+ if (upsample.next_row_out >= cinfo.max_v_samp_factor) {
+ in_row_group_ctr[0]++;
+ }
+}
+
+static void noop_upsample (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int[] output_data_offset, int output_data_index)
+{
+ output_data_ptr[output_data_index] = null; /* safety check */
+}
+
+static void fullsize_upsample (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int[] output_data_offset, int output_data_index)
+{
+ output_data_ptr[output_data_index] = input_data;
+ output_data_offset[output_data_index] = input_data_offset;
+}
+
+static void h2v1_upsample (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int[] output_data_offset, int output_data_index)
+{
+ byte[][] output_data = output_data_ptr[output_data_index];
+ byte[] inptr, outptr;
+ byte invalue;
+ int outend;
+ int inrow;
+ output_data_offset[output_data_index] = 0;
+
+ for (inrow = 0; inrow < cinfo.max_v_samp_factor; inrow++) {
+ inptr = input_data[inrow+input_data_offset];
+ outptr = output_data[inrow];
+ int inptr_offset = 0, outptr_offset = 0;
+ outend = outptr_offset + cinfo.output_width;
+ while (outptr_offset < outend) {
+ invalue = inptr[inptr_offset++]; /* don't need GETJSAMPLE() here */
+ outptr[outptr_offset++] = invalue;
+ outptr[outptr_offset++] = invalue;
+ }
+ }
+}
+
+static void h2v2_upsample (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int[] output_data_offset, int output_data_index)
+{
+ byte[][] output_data = output_data_ptr[output_data_index];
+ byte[] inptr, outptr;
+ byte invalue;
+ int outend;
+ int inrow, outrow;
+ output_data_offset[output_data_index] = 0;
+
+ inrow = outrow = 0;
+ while (outrow < cinfo.max_v_samp_factor) {
+ inptr = input_data[inrow+input_data_offset];
+ outptr = output_data[outrow];
+ int inptr_offset = 0, outptr_offset = 0;
+ outend = outptr_offset + cinfo.output_width;
+ while (outptr_offset < outend) {
+ invalue = inptr[inptr_offset++]; /* don't need GETJSAMPLE() here */
+ outptr[outptr_offset++] = invalue;
+ outptr[outptr_offset++] = invalue;
+ }
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1, 1, cinfo.output_width);
+ inrow++;
+ outrow += 2;
+ }
+}
+
+static void h2v1_fancy_upsample (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int[] output_data_offset, int output_data_index)
+{
+ byte[][] output_data = output_data_ptr[output_data_index];
+ byte[] inptr, outptr;
+ int invalue;
+ int colctr;
+ int inrow;
+ output_data_offset[output_data_index] = 0;
+
+ for (inrow = 0; inrow < cinfo.max_v_samp_factor; inrow++) {
+ inptr = input_data[inrow+input_data_offset];
+ outptr = output_data[inrow];
+ int inptr_offset = 0, outptr_offset = 0;
+ /* Special case for first column */
+ invalue = inptr[inptr_offset++] & 0xFF;
+ outptr[outptr_offset++] = (byte) invalue;
+ outptr[outptr_offset++] = (byte) ((invalue * 3 + (inptr[inptr_offset] & 0xFF) + 2) >> 2);
+
+ for (colctr = compptr.downsampled_width - 2; colctr > 0; colctr--) {
+ /* General case: 3/4 * nearer pixel + 1/4 * further pixel */
+ invalue = (inptr[inptr_offset++] & 0xFF) * 3;
+ outptr[outptr_offset++] = (byte) ((invalue + (inptr[inptr_offset-2] & 0xFF) + 1) >> 2);
+ outptr[outptr_offset++] = (byte) ((invalue + (inptr[inptr_offset] & 0xFF) + 2) >> 2);
+ }
+
+ /* Special case for last column */
+ invalue = (inptr[inptr_offset] & 0xFF);
+ outptr[outptr_offset++] = (byte) ((invalue * 3 + (inptr[inptr_offset-1] & 0xFF) + 1) >> 2);
+ outptr[outptr_offset++] = (byte) invalue;
+ }
+}
+
+static void h2v2_fancy_upsample (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int[] output_data_offset, int output_data_index)
+{
+ byte[][] output_data = output_data_ptr[output_data_index];
+ byte[] inptr0, inptr1, outptr;
+ int thiscolsum, lastcolsum, nextcolsum;
+ int colctr;
+ int inrow, outrow, v;
+ output_data_offset[output_data_index] = 0;
+
+ inrow = outrow = 0;
+ while (outrow < cinfo.max_v_samp_factor) {
+ for (v = 0; v < 2; v++) {
+ /* inptr0 points to nearest input row, inptr1 points to next nearest */
+ inptr0 = input_data[inrow+input_data_offset];
+ if (v == 0) /* next nearest is row above */
+ inptr1 = input_data[inrow-1+input_data_offset];
+ else /* next nearest is row below */
+ inptr1 = input_data[inrow+1+input_data_offset];
+ outptr = output_data[outrow++];
+
+ int inptr0_offset = 0, inptr1_offset = 0, outptr_offset = 0;
+
+ /* Special case for first column */
+ thiscolsum = (inptr0[inptr0_offset++] & 0xFF) * 3 + (inptr1[inptr1_offset++] & 0xFF);
+ nextcolsum = (inptr0[inptr0_offset++] & 0xFF) * 3 + (inptr1[inptr1_offset++] & 0xFF);
+ outptr[outptr_offset++] = (byte) ((thiscolsum * 4 + 8) >> 4);
+ outptr[outptr_offset++] = (byte) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ lastcolsum = thiscolsum; thiscolsum = nextcolsum;
+
+ for (colctr = compptr.downsampled_width - 2; colctr > 0; colctr--) {
+ /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */
+ /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */
+ nextcolsum = (inptr0[inptr0_offset++] & 0xFF) * 3 + (inptr1[inptr1_offset++] & 0xFF);
+ outptr[outptr_offset++] = (byte) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ outptr[outptr_offset++] = (byte) ((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ lastcolsum = thiscolsum; thiscolsum = nextcolsum;
+ }
+
+ /* Special case for last column */
+ outptr[outptr_offset++] = (byte) ((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ outptr[outptr_offset++] = (byte) ((thiscolsum * 4 + 7) >> 4);
+ }
+ inrow++;
+ }
+}
+
+static void int_upsample (jpeg_decompress_struct cinfo, jpeg_component_info compptr,
+ byte[][] input_data, int input_data_offset, byte[][][] output_data_ptr, int[] output_data_offset, int output_data_index)
+{
+ jpeg_upsampler upsample = cinfo.upsample;
+ byte[][] output_data = output_data_ptr[output_data_index];
+ byte[] inptr, outptr;
+ byte invalue;
+ int h;
+ int outend;
+ int h_expand, v_expand;
+ int inrow, outrow;
+ output_data_offset[output_data_index] = 0;
+
+ h_expand = upsample.h_expand[compptr.component_index];
+ v_expand = upsample.v_expand[compptr.component_index];
+
+ inrow = outrow = 0;
+ while (outrow < cinfo.max_v_samp_factor) {
+ /* Generate one output row with proper horizontal expansion */
+ inptr = input_data[inrow+input_data_offset];
+ int inptr_offset = 0;
+ outptr = output_data[outrow];
+ int outptr_offset = 0;
+ outend = outptr_offset + cinfo.output_width;
+ while (outptr_offset < outend) {
+ invalue = inptr[inptr_offset++]; /* don't need GETJSAMPLE() here */
+ for (h = h_expand; h > 0; h--) {
+ outptr[outptr_offset++] = invalue;
+ }
+ }
+ /* Generate any additional output rows by duplicating the first one */
+ if (v_expand > 1) {
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1, v_expand-1, cinfo.output_width);
+ }
+ inrow++;
+ outrow += v_expand;
+ }
+}
+
+static void null_convert (jpeg_decompress_struct cinfo,
+ byte[][][] input_buf, int[] input_buf_offset, int input_row,
+ byte[][] output_buf, int output_buf_offset, int num_rows)
+{
+ byte[] inptr, outptr;
+ int count;
+ int num_components = cinfo.num_components;
+ int num_cols = cinfo.output_width;
+ int ci;
+
+ while (--num_rows >= 0) {
+ for (ci = 0; ci < num_components; ci++) {
+ inptr = input_buf[ci][input_row+input_buf_offset[0]];
+ outptr = output_buf[output_buf_offset];
+ /* BGR instead of RGB */
+ int offset = 0;
+ switch (ci) {
+ case 2: offset = RGB_BLUE; break;
+ case 1: offset = RGB_GREEN; break;
+ case 0: offset = RGB_RED; break;
+ }
+ int outptr_offset = offset, inptr_offset = 0;
+ for (count = num_cols; count > 0; count--) {
+ outptr[outptr_offset] = inptr[inptr_offset++]; /* needn't bother with GETJSAMPLE() here */
+ outptr_offset += num_components;
+ }
+ }
+ input_row++;
+ output_buf_offset++;
+ }
+}
+
+static void grayscale_convert (jpeg_decompress_struct cinfo,
+ byte[][][] input_buf, int[] input_buf_offset, int input_row,
+ byte[][] output_buf, int output_buf_offset, int num_rows)
+{
+ jcopy_sample_rows(input_buf[0], input_row+input_buf_offset[0], output_buf, output_buf_offset,
+ num_rows, cinfo.output_width);
+}
+
+static void gray_rgb_convert (jpeg_decompress_struct cinfo,
+ byte[][][] input_buf, int[] input_buf_offset, int input_row,
+ byte[][] output_buf, int output_buf_offset, int num_rows)
+{
+ byte[] inptr, outptr;
+ int col;
+ int num_cols = cinfo.output_width;
+
+ while (--num_rows >= 0) {
+ inptr = input_buf[0][input_row+++input_buf_offset[0]];
+ outptr = output_buf[output_buf_offset++];
+ int outptr_offset = 0;
+ for (col = 0; col < num_cols; col++) {
+ /* We can dispense with GETJSAMPLE() here */
+ outptr[RGB_RED+outptr_offset] = outptr[RGB_GREEN+outptr_offset] = outptr[RGB_BLUE+outptr_offset] = inptr[col];
+ outptr_offset += RGB_PIXELSIZE;
+ }
+ }
+}
+
+static void ycc_rgb_convert (jpeg_decompress_struct cinfo,
+ byte[][][] input_buf, int[] input_buf_offset, int input_row,
+ byte[][] output_buf, int output_buf_offset, int num_rows)
+{
+ jpeg_color_deconverter cconvert = cinfo.cconvert;
+ int y, cb, cr;
+ byte[] outptr;
+ byte[] inptr0, inptr1, inptr2;
+ int col;
+ int num_cols = cinfo.output_width;
+ /* copy these pointers into registers if possible */
+ byte[] range_limit = cinfo.sample_range_limit;
+ int range_limit_offset = cinfo.sample_range_limit_offset;
+ int[] Crrtab = cconvert.Cr_r_tab;
+ int[] Cbbtab = cconvert.Cb_b_tab;
+ int[] Crgtab = cconvert.Cr_g_tab;
+ int[] Cbgtab = cconvert.Cb_g_tab;
+// SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row+input_buf_offset[0]];
+ inptr1 = input_buf[1][input_row+input_buf_offset[1]];
+ inptr2 = input_buf[2][input_row+input_buf_offset[2]];
+ input_row++;
+ outptr = output_buf[output_buf_offset++];
+ int outptr_offset = 0;
+ for (col = 0; col < num_cols; col++) {
+ y = (inptr0[col] & 0xFF);
+ cb = (inptr1[col] & 0xFF);
+ cr = (inptr2[col] & 0xFF);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[outptr_offset + RGB_RED] = range_limit[y + Crrtab[cr] + range_limit_offset];
+ outptr[outptr_offset + RGB_GREEN] = range_limit[y + ((Cbgtab[cb] + Crgtab[cr]>>SCALEBITS)) + range_limit_offset];
+ outptr[outptr_offset + RGB_BLUE] = range_limit[y + Cbbtab[cb] + range_limit_offset];
+ outptr_offset += RGB_PIXELSIZE;
+ }
+ }
+}
+
+static boolean process_APPn(int n, jpeg_decompress_struct cinfo) {
+ if (n == 0 || n == 14) {
+ return get_interesting_appn(cinfo);
+ }
+ return skip_variable(cinfo);
+}
+
+static boolean process_COM(jpeg_decompress_struct cinfo) {
+ return skip_variable(cinfo);
+}
+
+static void skip_input_data (jpeg_decompress_struct cinfo, int num_bytes) {
+ if (num_bytes > 0) {
+ while (num_bytes > cinfo.bytes_in_buffer - cinfo.bytes_offset) {
+ num_bytes -= cinfo.bytes_in_buffer - cinfo.bytes_offset;
+ if (!fill_input_buffer(cinfo)) error();
+ /* note we assume that fill_input_buffer will never return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ cinfo.bytes_offset += num_bytes;
+ }
+}
+
+static boolean skip_variable (jpeg_decompress_struct cinfo)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ int length;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+
+ length -= 2;
+
+// TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo.unread_marker, (int) length);
+
+ if (length > 0) {
+ skip_input_data (cinfo, length);
+ }
+
+ return true;
+}
+
+static boolean get_interesting_appn (jpeg_decompress_struct cinfo)
+/* Process an APP0 or APP14 marker without saving it */
+{
+ int length;
+ byte[] b = new byte[APPN_DATA_LEN];
+ int i, numtoread;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length = (cinfo.buffer[cinfo.bytes_offset++] & 0xFF) << 8;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ length |= cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ length -= 2;
+
+ /* get the interesting part of the marker data */
+ if (length >= APPN_DATA_LEN)
+ numtoread = APPN_DATA_LEN;
+ else if (length > 0)
+ numtoread = length;
+ else
+ numtoread = 0;
+ for (i = 0; i < numtoread; i++) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ b[i] = cinfo.buffer[cinfo.bytes_offset++];
+ }
+ length -= numtoread;
+
+ /* process it */
+ switch (cinfo.unread_marker) {
+ case M_APP0:
+ examine_app0(cinfo, b, numtoread, length);
+ break;
+ case M_APP14:
+ examine_app14(cinfo, b, numtoread, length);
+ break;
+ default:
+ /* can't get here unless jpeg_save_markers chooses wrong processor */
+ error();
+// ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo.unread_marker);
+ break;
+ }
+
+ /* skip any remaining data -- could be lots */
+ if (length > 0)
+ skip_input_data (cinfo, length);
+
+ return true;
+}
+
+static void examine_app0 (jpeg_decompress_struct cinfo, byte[] data, int datalen, int remaining)
+/* Examine first few bytes from an APP0.
+ * Take appropriate action if it is a JFIF marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+ int totallen = datalen + remaining;
+
+ if (datalen >= APP0_DATA_LEN &&
+ (data[0] & 0xFF) == 0x4A &&
+ (data[1] & 0xFF) == 0x46 &&
+ (data[2] & 0xFF) == 0x49 &&
+ (data[3] & 0xFF) == 0x46 &&
+ (data[4] & 0xFF) == 0)
+ {
+ /* Found JFIF APP0 marker: save info */
+ cinfo.saw_JFIF_marker = true;
+ cinfo.JFIF_major_version = (data[5]);
+ cinfo.JFIF_minor_version = (byte)(data[6] & 0xFF);
+ cinfo.density_unit = (byte)(data[7] & 0xFF);
+ cinfo.X_density = (short)(((data[8] & 0xFF) << 8) + (data[9] & 0xFF));
+ cinfo.Y_density = (short)(((data[10] & 0xFF) << 8) + (data[11] & 0xFF));
+ /* Check version.
+ * Major version must be 1, anything else signals an incompatible change.
+ * (We used to treat this as an error, but now it's a nonfatal warning,
+ * because some bozo at Hijaak couldn't read the spec.)
+ * Minor version should be 0..2, but process anyway if newer.
+ */
+ if (cinfo.JFIF_major_version != 1) {
+// WARNMS2(cinfo, JWRN_JFIF_MAJOR,
+// cinfo.JFIF_major_version, cinfo.JFIF_minor_version);
+ }
+ /* Generate trace messages */
+// TRACEMS5(cinfo, 1, JTRC_JFIF,
+// cinfo.JFIF_major_version, cinfo.JFIF_minor_version,
+// cinfo.X_density, cinfo.Y_density, cinfo.density_unit);
+ /* Validate thumbnail dimensions and issue appropriate messages */
+ if (((data[12] & 0xFF) | (data[13]) & 0xFF) != 0) {
+// TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL,
+// GETJOCTET(data[12]), GETJOCTET(data[13]));
+ }
+ totallen -= APP0_DATA_LEN;
+ if (totallen != ((data[12] & 0xFF) * (data[13] & 0xFF) * 3)) {
+// TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
+ }
+ } else if (datalen >= 6 &&
+ (data[0] & 0xFF) == 0x4A &&
+ (data[1] & 0xFF) == 0x46 &&
+ (data[2] & 0xFF) == 0x58 &&
+ (data[3] & 0xFF) == 0x58 &&
+ (data[4] & 0xFF) == 0)
+ {
+ /* Found JFIF "JFXX" extension APP0 marker */
+ /* The library doesn't actually do anything with these,
+ * but we try to produce a helpful trace message.
+ */
+ switch ((data[5]) & 0xFF) {
+ case 0x10:
+// TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen);
+ break;
+ case 0x11:
+// TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen);
+ break;
+ case 0x13:
+// TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen);
+ break;
+ default:
+// TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION, GETJOCTET(data[5]), (int) totallen);
+ break;
+ }
+ } else {
+ /* Start of APP0 does not match "JFIF" or "JFXX", or too short */
+// TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen);
+ }
+}
+
+static void examine_app14 (jpeg_decompress_struct cinfo, byte[] data, int datalen, int remaining)
+/* Examine first few bytes from an APP14.
+ * Take appropriate action if it is an Adobe marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+ int /*version, flags0, flags1, */transform;
+
+ if (datalen >= APP14_DATA_LEN &&
+ (data[0] & 0xFF) == 0x41 &&
+ (data[1] & 0xFF) == 0x64 &&
+ (data[2] & 0xFF) == 0x6F &&
+ (data[3] & 0xFF) == 0x62 &&
+ (data[4] & 0xFF) == 0x65)
+ {
+ /* Found Adobe APP14 marker */
+// version = ((data[5] & 0xFF) << 8) + (data[6] & 0xFF);
+// flags0 = ((data[7] & 0xFF) << 8) + (data[8] & 0xFF);
+// flags1 = ((data[9] & 0xFF) << 8) + (data[10] & 0xFF);
+ transform = (data[11] & 0xFF);
+// TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
+ cinfo.saw_Adobe_marker = true;
+ cinfo.Adobe_transform = (byte) transform;
+ } else {
+ /* Start of APP14 does not match "Adobe", or too short */
+// TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining));
+ }
+}
+
+static boolean get_soi (jpeg_decompress_struct cinfo) /* Process an SOI marker */ {
+ int i;
+
+// TRACEMS(cinfo, 1, JTRC_SOI);
+
+ if (cinfo.marker.saw_SOI)
+ error();
+// ERREXIT(cinfo, JERR_SOI_DUPLICATE);
+
+ /* Reset all parameters that are defined to be reset by SOI */
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ cinfo.arith_dc_L[i] = 0;
+ cinfo.arith_dc_U[i] = 1;
+ cinfo.arith_ac_K[i] = 5;
+ }
+ cinfo.restart_interval = 0;
+
+ /* Set initial assumptions for colorspace etc */
+
+ cinfo.jpeg_color_space = JCS_UNKNOWN;
+ cinfo.CCIR601_sampling = false; /* Assume non-CCIR sampling??? */
+
+ cinfo.saw_JFIF_marker = false;
+ cinfo.JFIF_major_version = 1; /* set default JFIF APP0 values */
+ cinfo.JFIF_minor_version = 1;
+ cinfo.density_unit = 0;
+ cinfo.X_density = 1;
+ cinfo.Y_density = 1;
+ cinfo.saw_Adobe_marker = false;
+ cinfo.Adobe_transform = 0;
+
+ cinfo.marker.saw_SOI = true;
+
+ return true;
+}
+
+static void jinit_input_controller (jpeg_decompress_struct cinfo)
+{
+ /* Initialize state: can't use reset_input_controller since we don't
+ * want to try to reset other modules yet.
+ */
+ jpeg_input_controller inputctl = cinfo.inputctl = new jpeg_input_controller();
+ inputctl.has_multiple_scans = false; /* "unknown" would be better */
+ inputctl.eoi_reached = false;
+ inputctl.inheaders = true;
+}
+
+static void reset_marker_reader (jpeg_decompress_struct cinfo) {
+ jpeg_marker_reader marker = cinfo.marker;
+
+ cinfo.comp_info = null; /* until allocated by get_sof */
+ cinfo.input_scan_number = 0; /* no SOS seen yet */
+ cinfo.unread_marker = 0; /* no pending marker */
+ marker.saw_SOI = false; /* set internal state too */
+ marker.saw_SOF = false;
+ marker.discarded_bytes = 0;
+// marker.cur_marker = null;
+}
+
+static void reset_input_controller (jpeg_decompress_struct cinfo) {
+ jpeg_input_controller inputctl = cinfo.inputctl;
+
+ inputctl.has_multiple_scans = false; /* "unknown" would be better */
+ inputctl.eoi_reached = false;
+ inputctl.inheaders = true;
+ /* Reset other modules */
+ reset_marker_reader (cinfo);
+ /* Reset progression state -- would be cleaner if entropy decoder did this */
+ cinfo.coef_bits = null;
+}
+
+static void finish_output_pass (jpeg_decompress_struct cinfo) {
+ jpeg_decomp_master master = cinfo.master;
+
+ if (cinfo.quantize_colors) {
+ error(SWT.ERROR_NOT_IMPLEMENTED);
+// (*cinfo.cquantize.finish_pass) (cinfo);
+ }
+ master.pass_number++;
+}
+
+static void jpeg_destroy (jpeg_decompress_struct cinfo) {
+ /* We need only tell the memory manager to release everything. */
+ /* NB: mem pointer is NULL if memory mgr failed to initialize. */
+// if (cinfo.mem != NULL)
+// (*cinfo.mem.self_destruct) (cinfo);
+// cinfo.mem = NULL; /* be safe if jpeg_destroy is called twice */
+ cinfo.global_state = 0; /* mark it destroyed */
+}
+
+static void jpeg_destroy_decompress (jpeg_decompress_struct cinfo) {
+ jpeg_destroy(cinfo); /* use common routine */
+}
+
+static boolean jpeg_input_complete (jpeg_decompress_struct cinfo) {
+ /* Check for valid jpeg object */
+ if (cinfo.global_state < DSTATE_START || cinfo.global_state > DSTATE_STOPPING)
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+ return cinfo.inputctl.eoi_reached;
+}
+
+static boolean jpeg_start_output (jpeg_decompress_struct cinfo, int scan_number) {
+ if (cinfo.global_state != DSTATE_BUFIMAGE && cinfo.global_state != DSTATE_PRESCAN)
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+ /* Limit scan number to valid range */
+ if (scan_number <= 0)
+ scan_number = 1;
+ if (cinfo.inputctl.eoi_reached && scan_number > cinfo.input_scan_number)
+ scan_number = cinfo.input_scan_number;
+ cinfo.output_scan_number = scan_number;
+ /* Perform any dummy output passes, and set up for the real pass */
+ return output_pass_setup(cinfo);
+}
+
+static boolean jpeg_finish_output (jpeg_decompress_struct cinfo) {
+ if ((cinfo.global_state == DSTATE_SCANNING || cinfo.global_state == DSTATE_RAW_OK) && cinfo.buffered_image) {
+ /* Terminate this pass. */
+ /* We do not require the whole pass to have been completed. */
+ finish_output_pass (cinfo);
+ cinfo.global_state = DSTATE_BUFPOST;
+ } else if (cinfo.global_state != DSTATE_BUFPOST) {
+ /* BUFPOST = repeat call after a suspension, anything else is error */
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+ }
+ /* Read markers looking for SOS or EOI */
+ while (cinfo.input_scan_number <= cinfo.output_scan_number && !cinfo.inputctl.eoi_reached) {
+ if (consume_input (cinfo) == JPEG_SUSPENDED)
+ return false; /* Suspend, come back later */
+ }
+ cinfo.global_state = DSTATE_BUFIMAGE;
+ return true;
+}
+
+static boolean jpeg_finish_decompress (jpeg_decompress_struct cinfo) {
+ if ((cinfo.global_state == DSTATE_SCANNING || cinfo.global_state == DSTATE_RAW_OK) && ! cinfo.buffered_image) {
+ /* Terminate final pass of non-buffered mode */
+ if (cinfo.output_scanline < cinfo.output_height)
+ error();
+// ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+ finish_output_pass (cinfo);
+ cinfo.global_state = DSTATE_STOPPING;
+ } else if (cinfo.global_state == DSTATE_BUFIMAGE) {
+ /* Finishing after a buffered-image operation */
+ cinfo.global_state = DSTATE_STOPPING;
+ } else if (cinfo.global_state != DSTATE_STOPPING) {
+ /* STOPPING = repeat call after a suspension, anything else is error */
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+ }
+ /* Read until EOI */
+ while (! cinfo.inputctl.eoi_reached) {
+ if (consume_input (cinfo) == JPEG_SUSPENDED)
+ return false; /* Suspend, come back later */
+ }
+ /* Do final cleanup */
+// (*cinfo.src.term_source) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort(cinfo);
+ return true;
+}
+
+
+static int jpeg_read_header (jpeg_decompress_struct cinfo, boolean require_image) {
+ int retcode;
+
+ if (cinfo.global_state != DSTATE_START && cinfo.global_state != DSTATE_INHEADER)
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+
+ retcode = jpeg_consume_input(cinfo);
+
+ switch (retcode) {
+ case JPEG_REACHED_SOS:
+ retcode = JPEG_HEADER_OK;
+ break;
+ case JPEG_REACHED_EOI:
+ if (require_image) /* Complain if application wanted an image */
+ error();
+// ERREXIT(cinfo, JERR_NO_IMAGE);
+ /* Reset to start state; it would be safer to require the application to
+ * call jpeg_abort, but we can't change it now for compatibility reasons.
+ * A side effect is to free any temporary memory (there shouldn't be any).
+ */
+ jpeg_abort(cinfo); /* sets state = DSTATE_START */
+ retcode = JPEG_HEADER_TABLES_ONLY;
+ break;
+ case JPEG_SUSPENDED:
+ /* no work */
+ break;
+ }
+
+ return retcode;
+}
+
+static int dummy_consume_data (jpeg_decompress_struct cinfo) {
+ return JPEG_SUSPENDED; /* Always indicate nothing was done */
+}
+
+static int consume_data (jpeg_decompress_struct cinfo) {
+ jpeg_d_coef_controller coef = cinfo.coef;
+ int MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ int start_col;
+// short[][][][] buffer = new short[MAX_COMPS_IN_SCAN][][][];
+ short[][] buffer_ptr;
+ jpeg_component_info compptr;
+
+// /* Align the virtual buffers for the components used in this scan. */
+// for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+// compptr = cinfo.cur_comp_info[ci];
+// buffer[ci] = coef.whole_image[compptr.component_index];
+// /* Note: entropy decoder expects buffer to be zeroed,
+// * but this is handled automatically by the memory manager
+// * because we requested a pre-zeroed array.
+// */
+// }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef.MCU_vert_offset; yoffset < coef.MCU_rows_per_iMCU_row; yoffset++) {
+ for (MCU_col_num = coef.MCU_ctr; MCU_col_num < cinfo.MCUs_per_row; MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+ compptr = cinfo.cur_comp_info[ci];
+ start_col = MCU_col_num * compptr.MCU_width;
+ for (yindex = 0; yindex < compptr.MCU_height; yindex++) {
+// buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ buffer_ptr = coef.whole_image[compptr.component_index][yindex+yoffset+cinfo.input_iMCU_row*compptr.v_samp_factor];
+ int buffer_ptr_offset = start_col;
+ for (xindex = 0; xindex < compptr.MCU_width; xindex++) {
+ coef.MCU_buffer[blkn++] = buffer_ptr[buffer_ptr_offset++];
+ }
+ }
+ }
+ /* Try to fetch the MCU. */
+ if (! cinfo.entropy.decode_mcu (cinfo, coef.MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef.MCU_vert_offset = yoffset;
+ coef.MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef.MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ if (++(cinfo.input_iMCU_row) < cinfo.total_iMCU_rows) {
+ coef.start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ finish_input_pass (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+static int consume_input (jpeg_decompress_struct cinfo) {
+ switch (cinfo.inputctl.consume_input) {
+ case COEF_CONSUME_INPUT:
+ switch (cinfo.coef.consume_data) {
+ case CONSUME_DATA: return consume_data(cinfo);
+ case DUMMY_CONSUME_DATA: return dummy_consume_data(cinfo);
+ default: error();
+ }
+ break;
+ case INPUT_CONSUME_INPUT:
+ return consume_markers(cinfo);
+ default:
+ error();
+ }
+ return 0;
+}
+
+static boolean fill_input_buffer(jpeg_decompress_struct cinfo) {
+ try {
+ InputStream inputStream = cinfo.inputStream;
+ int nbytes = inputStream.read(cinfo.buffer, 0, Math.min(cinfo.buffer.length, inputStream.available()));
+ if (nbytes <= 0) {
+ if (cinfo.start_of_file) /* Treat empty input file as fatal error */
+ error();
+// ERREXIT(cinfo, JERR_INPUT_EMPTY);
+// WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ cinfo.buffer[0] = (byte)0xFF;
+ cinfo.buffer[1] = (byte)M_EOI;
+ nbytes = 2;
+ }
+ cinfo.bytes_in_buffer = nbytes;
+ cinfo.bytes_offset = 0;
+ cinfo.start_of_file = false;
+ } catch (IOException e) {
+ error(SWT.ERROR_IO);
+ return false;
+ }
+ return true;
+}
+
+static boolean first_marker (jpeg_decompress_struct cinfo) {
+ /* Like next_marker, but used to obtain the initial SOI marker. */
+ /* For this marker, we do not allow preceding garbage or fill; otherwise,
+ * we might well scan an entire input file before realizing it ain't JPEG.
+ * If an application wants to process non-JFIF files, it must seek to the
+ * SOI before calling the JPEG library.
+ */
+ int c, c2;
+
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c2 = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ if (c != 0xFF || c2 != M_SOI)
+ error();
+// ERREXIT2(cinfo, JERR_NO_SOI, c, c2);
+
+ cinfo.unread_marker = c2;
+
+ return true;
+}
+
+static boolean next_marker (jpeg_decompress_struct cinfo) {
+ int c;
+
+ for (;;) {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ /* Skip any non-FF bytes.
+ * This may look a bit inefficient, but it will not occur in a valid file.
+ * We sync after each discarded byte so that a suspending data source
+ * can discard the byte from its buffer.
+ */
+ while (c != 0xFF) {
+ cinfo.marker.discarded_bytes++;
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ }
+ /* This loop swallows any duplicate FF bytes. Extra FFs are legal as
+ * pad bytes, so don't count them in discarded_bytes. We assume there
+ * will not be so many consecutive FF bytes as to overflow a suspending
+ * data source's input buffer.
+ */
+ do {
+ if (cinfo.bytes_offset == cinfo.bytes_in_buffer) fill_input_buffer(cinfo);
+ c = cinfo.buffer[cinfo.bytes_offset++] & 0xFF;
+ } while (c == 0xFF);
+ if (c != 0)
+ break; /* found a valid marker, exit loop */
+ /* Reach here if we found a stuffed-zero data sequence (FF/00).
+ * Discard it and loop back to try again.
+ */
+ cinfo.marker.discarded_bytes += 2;
+ }
+
+ if (cinfo.marker.discarded_bytes != 0) {
+// WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo.marker.discarded_bytes, c);
+ cinfo.marker.discarded_bytes = 0;
+ }
+
+ cinfo.unread_marker = c;
+
+ return true;
+}
+
+static int read_markers (jpeg_decompress_struct cinfo) {
+ /* Outer loop repeats once for each marker. */
+ for (;;) {
+ /* Collect the marker proper, unless we already did. */
+ /* NB: first_marker() enforces the requirement that SOI appear first. */
+ if (cinfo.unread_marker == 0) {
+ if (! cinfo.marker.saw_SOI) {
+ if (! first_marker(cinfo))
+ return JPEG_SUSPENDED;
+ } else {
+ if (! next_marker(cinfo))
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* At this point cinfo.unread_marker contains the marker code and the
+ * input point is just past the marker proper, but before any parameters.
+ * A suspension will cause us to return with this state still true.
+ */
+ switch (cinfo.unread_marker) {
+ case M_SOI:
+ if (! get_soi(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF0: /* Baseline */
+ case M_SOF1: /* Extended sequential, Huffman */
+ if (! get_sof(cinfo, false, false))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF2: /* Progressive, Huffman */
+ if (! get_sof(cinfo, true, false))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF9: /* Extended sequential, arithmetic */
+ if (! get_sof(cinfo, false, true))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF10: /* Progressive, arithmetic */
+ if (! get_sof(cinfo, true, true))
+ return JPEG_SUSPENDED;
+ break;
+
+ /* Currently unsupported SOFn types */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_JPG: /* Reserved for JPEG extensions */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ error();
+// ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo.unread_marker);
+ break;
+
+ case M_SOS:
+ if (! get_sos(cinfo))
+ return JPEG_SUSPENDED;
+ cinfo.unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_SOS;
+
+ case M_EOI:
+// TRACEMS(cinfo, 1, JTRC_EOI);
+ cinfo.unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_EOI;
+
+ case M_DAC:
+ if (! get_dac(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DHT:
+ if (! get_dht(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DQT:
+ if (! get_dqt(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DRI:
+ if (! get_dri(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_APP0:
+ case M_APP1:
+ case M_APP2:
+ case M_APP3:
+ case M_APP4:
+ case M_APP5:
+ case M_APP6:
+ case M_APP7:
+ case M_APP8:
+ case M_APP9:
+ case M_APP10:
+ case M_APP11:
+ case M_APP12:
+ case M_APP13:
+ case M_APP14:
+ case M_APP15:
+ if (! process_APPn(cinfo.unread_marker - M_APP0, cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_COM:
+ if (! process_COM(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_RST0: /* these are all parameterless */
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ case M_TEM:
+// TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo.unread_marker);
+ break;
+
+ case M_DNL: /* Ignore DNL ... perhaps the wrong thing */
+ if (! skip_variable(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ default: /* must be DHP, EXP, JPGn, or RESn */
+ /* For now, we treat the reserved markers as fatal errors since they are
+ * likely to be used to signal incompatible JPEG Part 3 extensions.
+ * Once the JPEG 3 version-number marker is well defined, this code
+ * ought to change!
+ */
+ error();
+ // ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo.unread_marker);
+ break;
+ }
+ /* Successfully processed marker, so reset state variable */
+ cinfo.unread_marker = 0;
+ } /* end loop */
+}
+
+static long jdiv_round_up (long a, long b)
+/* Compute a/b rounded up to next integer, ie, ceil(a/b) */
+/* Assumes a >= 0, b > 0 */
+{
+ return (a + b - 1) / b;
+}
+
+static void initial_setup (jpeg_decompress_struct cinfo)
+/* Called once, when first SOS marker is reached */
+{
+ int ci;
+ jpeg_component_info compptr;
+
+ /* Make sure image isn't bigger than I can handle */
+ if (cinfo.image_height > JPEG_MAX_DIMENSION || cinfo.image_width > JPEG_MAX_DIMENSION)
+ error();
+// ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* For now, precision must match compiled-in value... */
+ if (cinfo.data_precision != BITS_IN_JSAMPLE)
+ error(" [data precision=" + cinfo.data_precision + "]");
+// ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo.data_precision);
+
+ /* Check that number of components won't exceed internal array sizes */
+ if (cinfo.num_components > MAX_COMPONENTS)
+ error();
+// ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo.num_components, MAX_COMPONENTS);
+
+ /* Compute maximum sampling factors; check factor validity */
+ cinfo.max_h_samp_factor = 1;
+ cinfo.max_v_samp_factor = 1;
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ if (compptr.h_samp_factor<=0 || compptr.h_samp_factor>MAX_SAMP_FACTOR || compptr.v_samp_factor<=0 || compptr.v_samp_factor>MAX_SAMP_FACTOR)
+ error();
+// ERREXIT(cinfo, JERR_BAD_SAMPLING);
+ cinfo.max_h_samp_factor = Math.max(cinfo.max_h_samp_factor, compptr.h_samp_factor);
+ cinfo.max_v_samp_factor = Math.max(cinfo.max_v_samp_factor, compptr.v_samp_factor);
+ }
+
+ /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
+ * In the full decompressor, this will be overridden by jdmaster.c;
+ * but in the transcoder, jdmaster.c is not used, so we must do it here.
+ */
+ cinfo.min_DCT_scaled_size = DCTSIZE;
+
+ /* Compute dimensions of components */
+ for (ci = 0; ci < cinfo.num_components; ci++) {
+ compptr = cinfo.comp_info[ci];
+ compptr.DCT_scaled_size = DCTSIZE;
+ /* Size in DCT blocks */
+ compptr.width_in_blocks = (int)jdiv_round_up((long) cinfo.image_width * (long) compptr.h_samp_factor, (cinfo.max_h_samp_factor * DCTSIZE));
+ compptr.height_in_blocks = (int)jdiv_round_up((long) cinfo.image_height * (long) compptr.v_samp_factor, (cinfo.max_v_samp_factor * DCTSIZE));
+ /* downsampled_width and downsampled_height will also be overridden by
+ * jdmaster.c if we are doing full decompression. The transcoder library
+ * doesn't use these values, but the calling application might.
+ */
+ /* Size in samples */
+ compptr.downsampled_width = (int)jdiv_round_up((long) cinfo.image_width * (long) compptr.h_samp_factor, cinfo.max_h_samp_factor);
+ compptr.downsampled_height = (int)jdiv_round_up((long) cinfo.image_height * (long) compptr.v_samp_factor, cinfo.max_v_samp_factor);
+ /* Mark component needed, until color conversion says otherwise */
+ compptr.component_needed = true;
+ /* Mark no quantization table yet saved for component */
+ compptr.quant_table = null;
+ }
+
+ /* Compute number of fully interleaved MCU rows. */
+ cinfo.total_iMCU_rows = (int)jdiv_round_up( cinfo.image_height, (cinfo.max_v_samp_factor*DCTSIZE));
+
+ /* Decide whether file contains multiple scans */
+ if (cinfo.comps_in_scan < cinfo.num_components || cinfo.progressive_mode)
+ cinfo.inputctl.has_multiple_scans = true;
+ else
+ cinfo.inputctl.has_multiple_scans = false;
+}
+
+
+static void per_scan_setup (jpeg_decompress_struct cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo.comps_in_scan and cinfo.cur_comp_info[] were set from SOS marker */
+{
+ int ci, mcublks, tmp = 0;
+ jpeg_component_info compptr;
+
+ if (cinfo.comps_in_scan == 1) {
+
+ /* Noninterleaved (single-component) scan */
+ compptr = cinfo.cur_comp_info[0];
+
+ /* Overall image size in MCUs */
+ cinfo.MCUs_per_row = compptr.width_in_blocks;
+ cinfo.MCU_rows_in_scan = compptr.height_in_blocks;
+
+ /* For noninterleaved scan, always one block per MCU */
+ compptr.MCU_width = 1;
+ compptr.MCU_height = 1;
+ compptr.MCU_blocks = 1;
+ compptr.MCU_sample_width = compptr.DCT_scaled_size;
+ compptr.last_col_width = 1;
+ /* For noninterleaved scans, it is convenient to define last_row_height
+ * as the number of block rows present in the last iMCU row.
+ */
+ tmp = (compptr.height_in_blocks % compptr.v_samp_factor);
+ if (tmp == 0) tmp = compptr.v_samp_factor;
+ compptr.last_row_height = tmp;
+
+ /* Prepare array describing MCU composition */
+ cinfo.blocks_in_MCU = 1;
+ cinfo.MCU_membership[0] = 0;
+
+ } else {
+
+ /* Interleaved (multi-component) scan */
+ if (cinfo.comps_in_scan <= 0 || cinfo.comps_in_scan > MAX_COMPS_IN_SCAN)
+ error();
+// ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo.comps_in_scan, MAX_COMPS_IN_SCAN);
+
+ /* Overall image size in MCUs */
+ cinfo.MCUs_per_row = (int)jdiv_round_up( cinfo.image_width, (cinfo.max_h_samp_factor*DCTSIZE));
+ cinfo.MCU_rows_in_scan = (int)jdiv_round_up( cinfo.image_height, (cinfo.max_v_samp_factor*DCTSIZE));
+
+ cinfo.blocks_in_MCU = 0;
+
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+ compptr = cinfo.cur_comp_info[ci];
+ /* Sampling factors give # of blocks of component in each MCU */
+ compptr.MCU_width = compptr.h_samp_factor;
+ compptr.MCU_height = compptr.v_samp_factor;
+ compptr.MCU_blocks = compptr.MCU_width * compptr.MCU_height;
+ compptr.MCU_sample_width = compptr.MCU_width * compptr.DCT_scaled_size;
+ /* Figure number of non-dummy blocks in last MCU column & row */
+ tmp = (compptr.width_in_blocks % compptr.MCU_width);
+ if (tmp == 0) tmp = compptr.MCU_width;
+ compptr.last_col_width = tmp;
+ tmp = (compptr.height_in_blocks % compptr.MCU_height);
+ if (tmp == 0) tmp = compptr.MCU_height;
+ compptr.last_row_height = tmp;
+ /* Prepare array describing MCU composition */
+ mcublks = compptr.MCU_blocks;
+ if (cinfo.blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
+ error();
+// ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+ while (mcublks-- > 0) {
+ cinfo.MCU_membership[cinfo.blocks_in_MCU++] = ci;
+ }
+ }
+
+ }
+}
+
+static void latch_quant_tables (jpeg_decompress_struct cinfo) {
+ int ci, qtblno;
+ jpeg_component_info compptr;
+ JQUANT_TBL qtbl;
+
+ for (ci = 0; ci < cinfo.comps_in_scan; ci++) {
+ compptr = cinfo.cur_comp_info[ci];
+ /* No work if we already saved Q-table for this component */
+ if (compptr.quant_table != null)
+ continue;
+ /* Make sure specified quantization table is present */
+ qtblno = compptr.quant_tbl_no;
+ if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || cinfo.quant_tbl_ptrs[qtblno] == null)
+ error();
+// ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+ /* OK, save away the quantization table */
+ qtbl = new JQUANT_TBL();
+ System.arraycopy(cinfo.quant_tbl_ptrs[qtblno].quantval, 0, qtbl.quantval, 0, qtbl.quantval.length);
+ qtbl.sent_table = cinfo.quant_tbl_ptrs[qtblno].sent_table;
+ compptr.quant_table = qtbl;
+ }
+}
+
+static void jpeg_make_d_derived_tbl (jpeg_decompress_struct cinfo, boolean isDC, int tblno, d_derived_tbl dtbl) {
+ JHUFF_TBL htbl;
+ int p, i = 0, l, si, numsymbols;
+ int lookbits, ctr;
+ byte[] huffsize = new byte[257];
+ int[] huffcode = new int[257];
+ int code;
+
+ /* Note that huffsize[] and huffcode[] are filled in code-length order,
+ * paralleling the order of the symbols themselves in htbl.huffval[].
+ */
+
+ /* Find the input Huffman table */
+ if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
+ error();
+// ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+ htbl = isDC ? cinfo.dc_huff_tbl_ptrs[tblno] : cinfo.ac_huff_tbl_ptrs[tblno];
+ if (htbl == null)
+ error();
+// ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+
+ /* Allocate a workspace if we haven't already done so. */
+ dtbl.pub = htbl; /* fill in back link */
+
+ /* Figure C.1: make table of Huffman code length for each symbol */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ i = htbl.bits[l] & 0xFF;
+ if (i < 0 || p + i > 256) /* protect against table overrun */
+ error();
+// ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ while (i-- != 0)
+ huffsize[p++] = (byte) l;
+ }
+ huffsize[p] = 0;
+ numsymbols = p;
+
+ /* Figure C.2: generate the codes themselves */
+ /* We also validate that the counts represent a legal Huffman code tree. */
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while ((huffsize[p]) != 0) {
+ while (( huffsize[p]) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ /* code is now 1 more than the last code used for codelength si; but
+ * it must still fit in si bits, since no code is allowed to be all ones.
+ */
+ if (( code) >= (( 1) << si))
+ error();
+// ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure F.15: generate decoding tables for bit-sequential decoding */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ if ((htbl.bits[l] & 0xFF) != 0) {
+ /* valoffset[l] = huffval[] index of 1st symbol of code length l,
+ * minus the minimum code of length l
+ */
+ dtbl.valoffset[l] = p - huffcode[p];
+ p += (htbl.bits[l] & 0xFF);
+ dtbl.maxcode[l] = huffcode[p-1]; /* maximum code of length l */
+ } else {
+ dtbl.maxcode[l] = -1; /* -1 if no codes of this length */
+ }
+ }
+ dtbl.maxcode[17] = 0xFFFFF; /* ensures jpeg_huff_decode terminates */
+
+ /* Compute lookahead tables to speed up decoding.
+ * First we set all the table entries to 0, indicating "too long";
+ * then we iterate through the Huffman codes that are short enough and
+ * fill in all the entries that correspond to bit sequences starting
+ * with that code.
+ */
+
+ for (int j = 0; j < dtbl.look_nbits.length; j++) {
+ dtbl.look_nbits[j] = 0;
+ }
+
+ p = 0;
+ for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
+ for (i = 1; i <= (htbl.bits[l] & 0xFF); i++, p++) {
+ /* l = current code's length, p = its index in huffcode[] & huffval[]. */
+ /* Generate left-justified code followed by all possible bit sequences */
+ lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
+ for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
+ dtbl.look_nbits[lookbits] = l;
+ dtbl.look_sym[lookbits] = htbl.huffval[p];
+ lookbits++;
+ }
+ }
+ }
+
+ /* Validate symbols as being reasonable.
+ * For AC tables, we make no check, but accept all byte values 0..255.
+ * For DC tables, we require the symbols to be in range 0..15.
+ * (Tighter bounds could be applied depending on the data depth and mode,
+ * but this is sufficient to ensure safe decoding.)
+ */
+ if (isDC) {
+ for (i = 0; i < numsymbols; i++) {
+ int sym = htbl.huffval[i] & 0xFF;
+ if (sym < 0 || sym > 15)
+ error();
+// ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ }
+ }
+}
+
+static void start_input_pass (jpeg_decompress_struct cinfo) {
+ per_scan_setup(cinfo);
+ latch_quant_tables(cinfo);
+ cinfo.entropy.start_pass(cinfo);
+ cinfo.coef.start_input_pass (cinfo);
+ cinfo.inputctl.consume_input = COEF_CONSUME_INPUT;
+}
+
+static void finish_input_pass (jpeg_decompress_struct cinfo) {
+ cinfo.inputctl.consume_input = INPUT_CONSUME_INPUT;
+}
+
+static int consume_markers (jpeg_decompress_struct cinfo) {
+ jpeg_input_controller inputctl = cinfo.inputctl;
+ int val;
+
+ if (inputctl.eoi_reached) /* After hitting EOI, read no further */
+ return JPEG_REACHED_EOI;
+
+ val = read_markers (cinfo);
+
+ switch (val) {
+ case JPEG_REACHED_SOS: /* Found SOS */
+ if (inputctl.inheaders) { /* 1st SOS */
+ initial_setup(cinfo);
+ inputctl.inheaders = false;
+ /* Note: start_input_pass must be called by jdmaster.c
+ * before any more input can be consumed. jdapimin.c is
+ * responsible for enforcing this sequencing.
+ */
+ } else { /* 2nd or later SOS marker */
+ if (! inputctl.has_multiple_scans)
+ error();
+// ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */
+ start_input_pass(cinfo);
+ }
+ break;
+ case JPEG_REACHED_EOI: /* Found EOI */
+ inputctl.eoi_reached = true;
+ if (inputctl.inheaders) { /* Tables-only datastream, apparently */
+ if (cinfo.marker.saw_SOF)
+ error();
+// ERREXIT(cinfo, JERR_SOF_NO_SOS);
+ } else {
+ /* Prevent infinite loop in coef ctlr's decompress_data routine
+ * if user set output_scan_number larger than number of scans.
+ */
+ if (cinfo.output_scan_number > cinfo.input_scan_number)
+ cinfo.output_scan_number = cinfo.input_scan_number;
+ }
+ break;
+ case JPEG_SUSPENDED:
+ break;
+ }
+
+ return val;
+}
+
+static void default_decompress_parms (jpeg_decompress_struct cinfo) {
+ /* Guess the input colorspace, and set output colorspace accordingly. */
+ /* (Wish JPEG committee had provided a real way to specify this...) */
+ /* Note application may override our guesses. */
+ switch (cinfo.num_components) {
+ case 1:
+ cinfo.jpeg_color_space = JCS_GRAYSCALE;
+ cinfo.out_color_space = JCS_GRAYSCALE;
+ break;
+
+ case 3:
+ if (cinfo.saw_JFIF_marker) {
+ cinfo.jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */
+ } else if (cinfo.saw_Adobe_marker) {
+ switch (cinfo.Adobe_transform) {
+ case 0:
+ cinfo.jpeg_color_space = JCS_RGB;
+ break;
+ case 1:
+ cinfo.jpeg_color_space = JCS_YCbCr;
+ break;
+ default:
+// WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo.Adobe_transform);
+ cinfo.jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ break;
+ }
+ } else {
+ /* Saw no special markers, try to guess from the component IDs */
+ int cid0 = cinfo.comp_info[0].component_id;
+ int cid1 = cinfo.comp_info[1].component_id;
+ int cid2 = cinfo.comp_info[2].component_id;
+
+ if (cid0 == 1 && cid1 == 2 && cid2 == 3)
+ cinfo.jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
+ else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
+ cinfo.jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
+ else {
+// TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
+ cinfo.jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ }
+ }
+ /* Always guess RGB is proper output colorspace. */
+ cinfo.out_color_space = JCS_RGB;
+ break;
+
+ case 4:
+ if (cinfo.saw_Adobe_marker) {
+ switch (cinfo.Adobe_transform) {
+ case 0:
+ cinfo.jpeg_color_space = JCS_CMYK;
+ break;
+ case 2:
+ cinfo.jpeg_color_space = JCS_YCCK;
+ break;
+ default:
+// WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo.Adobe_transform);
+ cinfo.jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
+ break;
+ }
+ } else {
+ /* No special markers, assume straight CMYK. */
+ cinfo.jpeg_color_space = JCS_CMYK;
+ }
+ cinfo.out_color_space = JCS_CMYK;
+ break;
+
+ default:
+ cinfo.jpeg_color_space = JCS_UNKNOWN;
+ cinfo.out_color_space = JCS_UNKNOWN;
+ break;
+ }
+
+ /* Set defaults for other decompression parameters. */
+ cinfo.scale_num = 1; /* 1:1 scaling */
+ cinfo.scale_denom = 1;
+ cinfo.output_gamma = 1.0;
+ cinfo.buffered_image = false;
+ cinfo.raw_data_out = false;
+ cinfo.dct_method = JDCT_DEFAULT;
+ cinfo.do_fancy_upsampling = true;
+ cinfo.do_block_smoothing = true;
+ cinfo.quantize_colors = false;
+ /* We set these in case application only sets quantize_colors. */
+ cinfo.dither_mode = JDITHER_FS;
+ cinfo.two_pass_quantize = true;
+ cinfo.desired_number_of_colors = 256;
+ cinfo.colormap = null;
+ /* Initialize for no mode change in buffered-image mode. */
+ cinfo.enable_1pass_quant = false;
+ cinfo.enable_external_quant = false;
+ cinfo.enable_2pass_quant = false;
+}
+
+static void init_source(jpeg_decompress_struct cinfo) {
+ cinfo.buffer = new byte[INPUT_BUFFER_SIZE];
+ cinfo.bytes_in_buffer = 0;
+ cinfo.bytes_offset = 0;
+ cinfo.start_of_file = true;
+}
+
+static int jpeg_consume_input (jpeg_decompress_struct cinfo) {
+ int retcode = JPEG_SUSPENDED;
+
+ /* NB: every possible DSTATE value should be listed in this switch */
+ switch (cinfo.global_state) {
+ case DSTATE_START:
+ /* Start-of-datastream actions: reset appropriate modules */
+ reset_input_controller(cinfo);
+ /* Initialize application's data source module */
+ init_source (cinfo);
+ cinfo.global_state = DSTATE_INHEADER;
+ /*FALLTHROUGH*/
+ case DSTATE_INHEADER:
+ retcode = consume_input(cinfo);
+ if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
+ /* Set up default parameters based on header data */
+ default_decompress_parms(cinfo);
+ /* Set global state: ready for start_decompress */
+ cinfo.global_state = DSTATE_READY;
+ }
+ break;
+ case DSTATE_READY:
+ /* Can't advance past first SOS until start_decompress is called */
+ retcode = JPEG_REACHED_SOS;
+ break;
+ case DSTATE_PRELOAD:
+ case DSTATE_PRESCAN:
+ case DSTATE_SCANNING:
+ case DSTATE_RAW_OK:
+ case DSTATE_BUFIMAGE:
+ case DSTATE_BUFPOST:
+ case DSTATE_STOPPING:
+ retcode = consume_input (cinfo);
+ break;
+ default:
+ error();
+// ERREXIT1(cinfo, JERR_BAD_STATE, cinfo.global_state);
+ }
+ return retcode;
+}
+
+
+static void jpeg_abort (jpeg_decompress_struct cinfo) {
+// int pool;
+//
+// /* Releasing pools in reverse order might help avoid fragmentation
+// * with some (brain-damaged) malloc libraries.
+// */
+// for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {
+// (*cinfo.mem.free_pool) (cinfo, pool);
+// }
+
+ /* Reset overall state for possible reuse of object */
+ if (cinfo.is_decompressor) {
+ cinfo.global_state = DSTATE_START;
+ /* Try to keep application from accessing now-deleted marker list.
+ * A bit kludgy to do it here, but this is the most central place.
+ */
+// ((j_decompress_ptr) cinfo).marker_list = null;
+ } else {
+ cinfo.global_state = CSTATE_START;
+ }
+}
+
+
+static boolean isFileFormat(LEDataInputStream stream) {
+ try {
+ byte[] buffer = new byte[2];
+ stream.read(buffer);
+ stream.unread(buffer);
+ return (buffer[0] & 0xFF) == 0xFF && (buffer[1] & 0xFF) == M_SOI;
+ } catch (Exception e) {
+ return false;
+ }
+}
+
+static ImageData[] loadFromByteStream(InputStream inputStream, ImageLoader loader) {
+ jpeg_decompress_struct cinfo = new jpeg_decompress_struct();
+ cinfo.inputStream = inputStream;
+ jpeg_create_decompress(cinfo);
+ jpeg_read_header(cinfo, true);
+ cinfo.buffered_image = cinfo.progressive_mode && loader.hasListeners();
+ jpeg_start_decompress(cinfo);
+ PaletteData palette = null;
+ switch (cinfo.out_color_space) {
+ case JCS_RGB:
+ palette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ break;
+ case JCS_GRAYSCALE:
+ RGB[] colors = new RGB[256];
+ for (int i = 0; i < colors.length; i++) {
+ colors[i] = new RGB(i, i, i);
+ }
+ palette = new PaletteData(colors);
+ break;
+ default:
+ error();
+ }
+ int scanlinePad = 4;
+ int row_stride = (((cinfo.output_width * cinfo.out_color_components * 8 + 7) / 8) + (scanlinePad - 1)) / scanlinePad * scanlinePad;
+ byte[][] buffer = new byte[1][row_stride];
+ byte[] data = new byte[row_stride * cinfo.output_height];
+ ImageData imageData = ImageData.internal_new(
+ cinfo.output_width, cinfo.output_height, palette.isDirect ? 24 : 8, palette, scanlinePad, data,
+ 0, null, null, -1, -1, SWT.IMAGE_JPEG, 0, 0, 0, 0);
+ if (cinfo.buffered_image) {
+ boolean done;
+ do {
+ int incrementCount = cinfo.input_scan_number - 1;
+ jpeg_start_output(cinfo, cinfo.input_scan_number);
+ while (cinfo.output_scanline < cinfo.output_height) {
+ int offset = row_stride * cinfo.output_scanline;
+ jpeg_read_scanlines(cinfo, buffer, 1);
+ System.arraycopy(buffer[0], 0, data, offset, row_stride);
+ }
+ jpeg_finish_output(cinfo);
+ loader.notifyListeners(new ImageLoaderEvent(loader, (ImageData)imageData.clone(), incrementCount, done = jpeg_input_complete(cinfo)));
+ } while (!done);
+ } else {
+ while (cinfo.output_scanline < cinfo.output_height) {
+ int offset = row_stride * cinfo.output_scanline;
+ jpeg_read_scanlines(cinfo, buffer, 1);
+ System.arraycopy(buffer[0], 0, data, offset, row_stride);
+ }
+ }
+ jpeg_finish_decompress(cinfo);
+ jpeg_destroy_decompress(cinfo);
+ return new ImageData[]{imageData};
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGEndOfImage.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGEndOfImage.java
index f320dd57e8..df40f1febe 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGEndOfImage.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGEndOfImage.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java
index bb539f8a89..94825bcc54 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFileFormat.java
@@ -1,10 +1,9 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This source file is made available under the terms contained in the README file
+ * accompanying this program. The README file should be located in the about_files directory of the
+ * plug-in that contains this source file.
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -36,12 +35,10 @@ final class JPEGFileFormat extends FileFormat {
int bufferCurrentPosition;
int restartsToGo;
int nextRestartNumber;
- JPEGArithmeticConditioningTable arithmeticTables;
JPEGHuffmanTable[] acHuffmanTables;
JPEGHuffmanTable[] dcHuffmanTables;
int[][] quantizationTables;
int currentByte;
- int decoderQFactor;
int encoderQFactor = 75;
int eobrun = 0;
/* JPEGConstants */
@@ -112,7 +109,24 @@ final class JPEGFileFormat extends FileFormat {
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
@@ -131,6 +145,7 @@ final class JPEGFileFormat extends FileFormat {
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
+
public static int[] CrRTable, CbBTable, CrGTable, CbGTable;
public static int[] RYTable, GYTable, BYTable,
RCbTable, GCbTable, BCbTable, RCrTable, GCrTable, BCrTable, NBitsTable;
@@ -223,27 +238,29 @@ void convert4BitRGBToYCbCr(ImageData image) {
int g = color.green;
int b = color.blue;
int n = RYTable[r] + GYTable[g] + BYTable[b];
- yComp[i] = (byte)(n / 65536);
- if ((n < 0) && (n % 65536 != 0)) yComp[i]--;
+ yComp[i] = (byte)(n >> 16);
+ if ((n < 0) && ((n & 0xFFFF) != 0)) yComp[i]--;
n = RCbTable[r] + GCbTable[g] + BCbTable[b];
- cbComp[i] = (byte)(n / 65536);
- if ((n < 0) && (n % 65536 != 0)) cbComp[i]--;
+ cbComp[i] = (byte)(n >> 16);
+ if ((n < 0) && ((n & 0xFFFF) != 0)) cbComp[i]--;
n = RCrTable[r] + GCrTable[g] + BCrTable[b];
- crComp[i] = (byte)(n / 65536);
- if ((n < 0) && (n % 65536 != 0)) crComp[i]--;
+ 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 < srcWidth / 2; xPos++) {
- int srcIndex = yPos * (srcWidth / 2) + xPos;
+ 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 / 16;
- value2 = value2 % 16;
+ int value1 = value2 >> 4;
+ value2 &= 0x0F;
dataYComp[dstIndex] = yComp[value1];
dataCbComp[dstIndex] = cbComp[value1];
dataCrComp[dstIndex] = crComp[value1];
@@ -268,18 +285,18 @@ void convert8BitRGBToYCbCr(ImageData image) {
int g = color.green;
int b = color.blue;
int n = RYTable[r] + GYTable[g] + BYTable[b];
- yComp[i] = (byte)(n / 65536);
- if ((n < 0) && (n % 65536 != 0)) yComp[i]--;
+ yComp[i] = (byte)(n >> 16);
+ if ((n < 0) && ((n & 0xFFFF) != 0)) yComp[i]--;
n = RCbTable[r] + GCbTable[g] + BCbTable[b];
- cbComp[i] = (byte)(n / 65536);
- if ((n < 0) && (n % 65536 != 0)) cbComp[i]--;
+ cbComp[i] = (byte)(n >> 16);
+ if ((n < 0) && ((n & 0xFFFF) != 0)) cbComp[i]--;
n = RCrTable[r] + GCrTable[g] + BCrTable[b];
- crComp[i] = (byte)(n / 65536);
- if ((n < 0) && (n % 65536 != 0)) crComp[i]--;
+ crComp[i] = (byte)(n >> 16);
+ if ((n < 0) && ((n & 0xFFFF) != 0)) crComp[i]--;
}
int dstWidth = image.width;
int dstHeight = srcHeight;
- int stride = (srcWidth + 3) / 4 * 4;
+ int stride = ((srcWidth + 3) >> 2) << 2;
int bSize = dstWidth * dstHeight;
byte[] dataYComp = new byte[bSize];
byte[] dataCbComp = new byte[bSize];
@@ -348,9 +365,9 @@ void convertMultiRGBToYCbCr(ImageData image) {
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]) / 65536);
- dataCbComp[dstDataIndex] = (byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) / 65536);
- dataCrComp[dstDataIndex] = (byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) / 65536);
+ 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 {
@@ -364,9 +381,9 @@ void convertMultiRGBToYCbCr(ImageData image) {
int r = rgb.red;
int g = rgb.green;
int b = rgb.blue;
- dataYComp[dstDataIndex] = (byte)((RYTable[r] + GYTable[g] + BYTable[b]) / 65536);
- dataCbComp[dstDataIndex] = (byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) / 65536);
- dataCrComp[dstDataIndex] = (byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) / 65536);
+ 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);
}
}
}
@@ -440,7 +457,7 @@ byte[] convertYCbCrToRGB() {
int cb = cbComp[srcIndex] & 0xFF;
int cr = crComp[srcIndex] & 0xFF;
int r = y + CrRTable[cr];
- int g = y + ((CbGTable[cb] + CrGTable[cr]) / 65536);
+ int g = y + ((CbGTable[cb] + CrGTable[cr]) >> 16);
int b = y + CbBTable[cb];
if (r < 0) {
r = 0;
@@ -466,10 +483,6 @@ byte[] convertYCbCrToRGB() {
}
return rgbData;
}
-byte[] convertYIQToRGB() {
- /* Unsupported CMYK format. Answer an empty byte array. */
- return new byte[0];
-}
void decodeACCoefficients(int[] dataUnit, int iComp) {
int[] sParams = scanHeader.componentParameters[componentIds[iComp]];
JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]];
@@ -579,12 +592,12 @@ int refineAC(int ac, int approxBit) {
if (ac > 0) {
int bit = nextBit();
if (bit != 0) {
- ac = ac + (1 << approxBit);
+ ac += 1 << approxBit;
}
} else if (ac < 0) {
int bit = nextBit();
if (bit != 0) {
- ac = ac + (-1 << approxBit);
+ ac += -1 << approxBit;
}
}
return ac;
@@ -602,7 +615,7 @@ void decodeDCCoefficient(int[] dataUnit, int iComp, boolean first, int approxBit
if (nBits != 0) {
int bits = receive(nBits);
int diff = extendBy(bits, nBits);
- lastDC = lastDC + diff;
+ lastDC += diff;
precedingDCs[iComp] = lastDC;
}
if (progressive) {
@@ -619,25 +632,14 @@ void dequantize(int[] dataUnit, int iComp) {
}
}
byte[] decodeImageComponents() {
- int[] compIds = new int[nComponents];
- int compIdsIndex = 0;
- for (int i = 0; i < nComponents; i++) {
- compIds[compIdsIndex] = i + 1;
- compIdsIndex++;
- }
- if ((compIds.length == 3) &&
- (compIds[0] == 1) &&
- (compIds[1] == 2) &&
- (compIds[2] == 3)) {
- return convertYCbCrToRGB();
- }
- if ((compIds.length == 3) &&
- (compIds[0] == 1) &&
- (compIds[1] == 4) &&
- (compIds[2] == 5)) {
- return convertYIQToRGB();
- }
- if (compIds.length == 4) {
+ 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();
@@ -752,8 +754,7 @@ int decodeUsingTable(JPEGHuffmanTable huffmanTable) {
code = code * 2 + nextBit();
i++;
}
- int j = valPtrs[i];
- j = j + code - minCodes[i];
+ int j = valPtrs[i] + code - minCodes[i];
return huffVals[j];
}
void emit(int huffCode, int nBits) {
@@ -766,16 +767,16 @@ void emit(int huffCode, int nBits) {
};
int code = (huffCode & power2m1[nBits - 1]) << (24 - nBits - currentBitCount);
byte[] codeBuffer = new byte[4];
- codeBuffer[0] = (byte)(code % 256);
- codeBuffer[1] = (byte)((code / 256) % 256);
- codeBuffer[2] = (byte)((code / 65536) % 256);
- codeBuffer[3] = (byte)((code / 16777216) % 256);
+ 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 / 8) > 0) {
+ if ((abs >> 3) > 0) {
currentByte += codeBuffer[2];
emitByte((byte)currentByte);
- emitByte((byte)codeBuffer[1]);
+ emitByte(codeBuffer[1]);
currentByte = codeBuffer[0];
currentBitCount += nBits - 16;
} else {
@@ -900,25 +901,7 @@ void expandImageComponents() {
int compHeight = frameComponent[CH];
int upCompWidth = compWidth * upH;
int upCompHeight = compHeight * upV;
- RGB[] rgbs = 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),
- };
- ImageData src = new ImageData(compWidth, compHeight, 8, new PaletteData(rgbs), 4, component);
+ ImageData src = new ImageData(compWidth, compHeight, 8, new PaletteData(RGB16), 4, component);
ImageData dest = src.scaledTo(upCompWidth, upCompHeight);
imageComponents[iComp] = dest.data;
}
@@ -972,14 +955,12 @@ void forwardDCT(int[] dataUnit) {
dataUnit[rIndex + 4] = (tmp10 - tmp11) * 4;
int z1 = (tmp12 + tmp13) * FIX_0_541196100;
- int scaleFactor1 = ExtendTest[11];
- int scaleFactor2 = ExtendTest[12];
- int n = z1 + (tmp13 * FIX_0_765366865) + scaleFactor1;
- dataUnit[rIndex + 2] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 2]--;
- n = z1 + (tmp12 * (0 - FIX_1_847759065)) + scaleFactor1;
- dataUnit[rIndex + 6] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 6]--;
+ 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).
@@ -992,30 +973,30 @@ void forwardDCT(int[] dataUnit) {
int z4 = tmp5 + tmp7;
int z5 = (z3 + z4) * FIX_1_175875602; // sqrt(2) * c3
- tmp4 = tmp4 * FIX_0_298631336; // sqrt(2) * (-c1+c3+c5-c7)
- tmp5 = tmp5 * FIX_2_053119869; // sqrt(2) * ( c1+c3-c5+c7)
- tmp6 = tmp6 * FIX_3_072711026; // sqrt(2) * ( c1+c3+c5-c7)
- tmp7 = tmp7 * FIX_1_501321110; // sqrt(2) * ( c1+c3-c5-c7)
- z1 = z1 * (0 - FIX_0_899976223); // sqrt(2) * (c7-c3)
- z2 = z2 * (0 - FIX_2_562915447); // sqrt(2) * (-c1-c3)
- z3 = z3 * (0 - FIX_1_961570560); // sqrt(2) * (-c3-c5)
- z4 = z4 * (0 - FIX_0_390180644); // sqrt(2) * (c5-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 = z3 + z5;
- z4 = z4 + z5;
+ z3 += z5;
+ z4 += z5;
- n = tmp4 + z1 + z3 + scaleFactor1;
- dataUnit[rIndex + 7] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 7]--;
- n = tmp5 + z2 + z4 + scaleFactor1;
- dataUnit[rIndex + 5] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 5]--;
- n = tmp6 + z2 + z3 + scaleFactor1;
- dataUnit[rIndex + 3] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 3]--;
- n = tmp7 + z1 + z4 + scaleFactor1;
- dataUnit[rIndex + 1] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[rIndex + 1]--;
+ 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]--;
}
/**
@@ -1050,24 +1031,20 @@ void forwardDCT(int[] dataUnit) {
int tmp11 = tmp1 + tmp2;
int tmp12 = tmp1 - tmp2;
- int scaleFactor1 = ExtendTest[5];
- int scaleFactor2 = ExtendTest[6];
- int n = tmp10 + tmp11 + scaleFactor1;
- dataUnit[c0] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c0]--;
- n = tmp10 - tmp11 + scaleFactor1;
- dataUnit[c4] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c4]--;
+ 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;
- scaleFactor1 = ExtendTest[18];
- scaleFactor2 = ExtendTest[19];
- n = z1 + (tmp13 * FIX_0_765366865) + scaleFactor1;
- dataUnit[c2] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c2]--;
- n = z1 + (tmp12 * (0 - FIX_1_847759065)) + scaleFactor1;
- dataUnit[c6] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c6]--;
+ 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).
@@ -1080,30 +1057,30 @@ void forwardDCT(int[] dataUnit) {
int z4 = tmp5 + tmp7;
int z5 = (z3 + z4) * FIX_1_175875602; // sqrt(2) * c3
- tmp4 = tmp4 * FIX_0_298631336; // sqrt(2) * (-c1+c3+c5-c7)
- tmp5 = tmp5 * FIX_2_053119869; // sqrt(2) * ( c1+c3-c5+c7)
- tmp6 = tmp6 * FIX_3_072711026; // sqrt(2) * ( c1+c3+c5-c7)
- tmp7 = tmp7 * FIX_1_501321110; // sqrt(2) * ( c1+c3-c5-c7)
- z1 = z1 * (0 - FIX_0_899976223); // sqrt(2) * (c7-c3)
- z2 = z2 * (0 - FIX_2_562915447); // sqrt(2) * (-c1-c3)
- z3 = z3 * (0 - FIX_1_961570560); // sqrt(2) * (-c3-c5)
- z4 = z4 * (0 - FIX_0_390180644); // sqrt(2) * (c5-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 = z3 + z5;
- z4 = z4 + z5;
+ z3 += z5;
+ z4 += z5;
- n = tmp4 + z1 + z3 + scaleFactor1;
- dataUnit[c7] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c7]--;
- n = tmp5 + z2 + z4 + scaleFactor1;
- dataUnit[c5] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c5]--;
- n = tmp6 + z2 + z3 + scaleFactor1;
- dataUnit[c3] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c3]--;
- n = tmp7 + z1 + z4 + scaleFactor1;
- dataUnit[c1] = n / scaleFactor2;
- if ((n < 0) && (n % scaleFactor2 != 0)) dataUnit[c1]--;
+ 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() {
@@ -1116,8 +1093,7 @@ void getCOM() {
new JPEGComment(inputStream);
}
void getDAC() {
- JPEGArithmeticConditioningTable dac = new JPEGArithmeticConditioningTable(inputStream);
- arithmeticTables = dac;
+ new JPEGArithmeticConditioningTable(inputStream);
}
void getDHT() {
JPEGHuffmanTable dht = new JPEGHuffmanTable(inputStream);
@@ -1210,8 +1186,8 @@ static void initializeYCbCrRGBTables() {
CbGTable = new int[256];
for (int i = 0; i < 256; i++) {
int x2 = 2 * i - 255;
- CrRTable[i] = (45941 * x2 + 32768) / 65536;
- CbBTable[i] = (58065 * x2 + 32768) / 65536;
+ CrRTable[i] = (45941 * x2 + 32768) >> 16;
+ CbBTable[i] = (58065 * x2 + 32768) >> 16;
CrGTable[i] = -23401 * x2;
CbGTable[i] = -11277 * x2 + 32768;
}
@@ -1229,8 +1205,8 @@ void inverseDCT(int[] dataUnit) {
* row DCT calculations can be simplified this way.
*/
if (isZeroInRow(dataUnit, rIndex)) {
- int dcVal = dataUnit[rIndex] * 4;
- for (int i = rIndex; i < rIndex + 8; i++) {
+ int dcVal = dataUnit[rIndex] << 2;
+ for (int i = rIndex + 7; i >= rIndex; i--) {
dataUnit[i] = dcVal;
}
} else {
@@ -1243,8 +1219,8 @@ void inverseDCT(int[] dataUnit) {
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]) * 8192;
- int tmp1 = (dataUnit[rIndex] - dataUnit[rIndex + 4]) * 8192;
+ 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;
@@ -1261,34 +1237,32 @@ void inverseDCT(int[] dataUnit) {
z2 = tmp1 + tmp2;
z3 = tmp0 + tmp2;
int z4 = tmp1 + tmp3;
- int z5 = (z3 + z4)* FIX_1_175875602; /* sqrt(2) * c3 */
+ int z5 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */
- tmp0 = tmp0 * FIX_0_298631336; /* sqrt(2) * (-c1+c3+c5-c7) */
- tmp1 = tmp1 * FIX_2_053119869; /* sqrt(2) * ( c1+c3-c5+c7) */
- tmp2 = tmp2 * FIX_3_072711026; /* sqrt(2) * ( c1+c3+c5-c7) */
- tmp3 = tmp3 * FIX_1_501321110; /* sqrt(2) * ( c1+c3-c5-c7) */
- z1 = z1 * (0 - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
- z2 = z2 * (0 - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
- z3 = z3 * (0 - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
- z4 = z4 * (0 - FIX_0_390180644); /* sqrt(2) * (c5-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 = z3 + z5;
- z4 = z4 + z5;
- tmp0 = tmp0 + z1 + z3;
- tmp1 = tmp1 + z2 + z4;
- tmp2 = tmp2 + z2 + z3;
- tmp3 = tmp3 + z1 + z4;
+ z3 += z5;
+ z4 += z5;
+ tmp0 += z1 + z3;
+ tmp1 += z2 + z4;
+ tmp2 += z2 + z3;
+ tmp3 += z1 + z4;
- int descaleFactor1 = ExtendTest[11];
- int descaleFactor2 = ExtendTest[12];
- dataUnit[rIndex] = (tmp10 + tmp3 + descaleFactor1) / descaleFactor2;
- dataUnit[rIndex + 7] = (tmp10 - tmp3 + descaleFactor1) / descaleFactor2;
- dataUnit[rIndex + 1] = (tmp11 + tmp2 + descaleFactor1) / descaleFactor2;
- dataUnit[rIndex + 6] = (tmp11 - tmp2 + descaleFactor1) / descaleFactor2;
- dataUnit[rIndex + 2] = (tmp12 + tmp1 + descaleFactor1) / descaleFactor2;
- dataUnit[rIndex + 5] = (tmp12 - tmp1 + descaleFactor1) / descaleFactor2;
- dataUnit[rIndex + 3] = (tmp13 + tmp0 + descaleFactor1) / descaleFactor2;
- dataUnit[rIndex + 4] = (tmp13 - tmp0 + descaleFactor1) / descaleFactor2;
+ 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;
}
}
/**
@@ -1306,7 +1280,7 @@ void inverseDCT(int[] dataUnit) {
int c6 = col + 48;
int c7 = col + 56;
if (isZeroInColumn(dataUnit, col)) {
- int dcVal = (dataUnit[c0] + 16) / 32;
+ int dcVal = (dataUnit[c0] + 16) >> 5;
dataUnit[c0] = dcVal;
dataUnit[c1] = dcVal;
dataUnit[c2] = dcVal;
@@ -1320,13 +1294,15 @@ void inverseDCT(int[] dataUnit) {
* 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 = (dataUnit[c0] + dataUnit[c4]) * 8192;
- int tmp1 = (dataUnit[c0] - dataUnit[c4]) * 8192;
+ int tmp0 = (z0 + z4) << 13;
+ int tmp1 = (z0 - z4) << 13;
int tmp10 = tmp0 + tmp3;
int tmp13 = tmp0 - tmp3;
int tmp11 = tmp1 + tmp2;
@@ -1342,37 +1318,35 @@ void inverseDCT(int[] dataUnit) {
z1 = tmp0 + tmp3;
z2 = tmp1 + tmp2;
z3 = tmp0 + tmp2;
- int z4 = tmp1 + tmp3;
- int z5 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */
+ z4 = tmp1 + tmp3;
+ z0 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */
- tmp0 = tmp0 * FIX_0_298631336; /* sqrt(2) * (-c1+c3+c5-c7) */
- tmp1 = tmp1 * FIX_2_053119869; /* sqrt(2) * ( c1+c3-c5+c7) */
- tmp2 = tmp2 * FIX_3_072711026; /* sqrt(2) * ( c1+c3+c5-c7) */
- tmp3 = tmp3 * FIX_1_501321110; /* sqrt(2) * ( c1+c3-c5-c7) */
- z1 = z1 * (0 - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
- z2 = z2 * (0 - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
- z3 = z3 * (0 - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
- z4 = z4 * (0 - FIX_0_390180644); /* sqrt(2) * (c5-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 = z3 + z5;
- z4 = z4 + z5;
+ z3 += z0;
+ z4 += z0;
- tmp0 = tmp0 + z1 + z3;
- tmp1 = tmp1 + z2 + z4;
- tmp2 = tmp2 + z2 + z3;
- tmp3 = tmp3 + z1 + z4;
+ tmp0 += z1 + z3;
+ tmp1 += z2 + z4;
+ tmp2 += z2 + z3;
+ tmp3 += z1 + z4;
/* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
- int descaleFactor1 = ExtendTest[18];
- int descaleFactor2 = ExtendTest[19];
- dataUnit[c0] = (tmp10 + tmp3 + descaleFactor1) / descaleFactor2;
- dataUnit[c7] = (tmp10 - tmp3 + descaleFactor1) / descaleFactor2;
- dataUnit[c1] = (tmp11 + tmp2 + descaleFactor1) / descaleFactor2;
- dataUnit[c6] = (tmp11 - tmp2 + descaleFactor1) / descaleFactor2;
- dataUnit[c2] = (tmp12 + tmp1 + descaleFactor1) / descaleFactor2;
- dataUnit[c5] = (tmp12 - tmp1 + descaleFactor1) / descaleFactor2;
- dataUnit[c3] = (tmp13 + tmp0 + descaleFactor1) / descaleFactor2;
- dataUnit[c4] = (tmp13 - tmp0 + descaleFactor1) / descaleFactor2;
+ 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;
}
}
}
@@ -1386,18 +1360,22 @@ boolean isFileFormat(LEDataInputStream stream) {
}
}
boolean isZeroInColumn(int[] dataUnit, int col) {
- return (dataUnit[col + 8] + dataUnit[col + 16] +
- dataUnit[col + 24] + dataUnit[col + 32] +
- dataUnit[col + 40] + dataUnit[col + 48] +
- dataUnit[col + 56]) == 0;
+ 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] + dataUnit[rIndex + 2] +
- dataUnit[rIndex + 3] + dataUnit[rIndex + 4] +
- dataUnit[rIndex + 5] + dataUnit[rIndex + 6] +
- dataUnit[rIndex + 7]) == 0;
+ 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;
}
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;
@@ -1500,6 +1478,7 @@ ImageData[] loadFromByteStream() {
}
}
}
+ dataUnits = null; // release memory
}
ImageData imageData = createImageData();
if (progressive && loader.hasListeners()) {
@@ -1600,7 +1579,7 @@ void processRestartInterval() {
}
currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
}
- if (currentByte != ((RST0 + nextRestartNumber) % 256)) {
+ if (currentByte != ((RST0 + nextRestartNumber) & 0xFF)) {
SWT.error(SWT.ERROR_INVALID_IMAGE);
}
bufferCurrentPosition++;
@@ -1611,7 +1590,7 @@ void processRestartInterval() {
currentByte = dataBuffer[bufferCurrentPosition] & 0xFF;
currentBitCount = 8;
restartsToGo = restartInterval;
- nextRestartNumber = (nextRestartNumber + 1) % 8;
+ nextRestartNumber = (nextRestartNumber + 1) & 0x7;
precedingDCs = new int[4];
eobrun = 0;
}
@@ -1662,7 +1641,7 @@ void quantizeData(int[] dataUnit, int iComp) {
int data = dataUnit[zzIndex];
int absData = data < 0 ? 0 - data : data;
int qValue = qTable[i];
- int q2 = qValue / 2;
+ int q2 = qValue >> 1;
absData += q2;
if (absData < qValue) {
dataUnit[zzIndex] = 0;
@@ -1772,7 +1751,8 @@ void storeData(int[] dataUnit, int iComp, int xmcu, int ymcu, int hi, int ihi, i
destIndex += compWidth;
}
}
-void unloadIntoByteStream(ImageData image) {
+void unloadIntoByteStream(ImageLoader loader) {
+ ImageData image = loader.data[0];
if (!new JPEGStartOfImage().writeToStream(outputStream)) {
SWT.error(SWT.ERROR_IO);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFixedSizeSegment.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFixedSizeSegment.java
index e08a587c9f..9fea253c8c 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFixedSizeSegment.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFixedSizeSegment.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFrameHeader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFrameHeader.java
index a25ede0134..00d761078c 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFrameHeader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGFrameHeader.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -89,8 +89,8 @@ final class JPEGFrameHeader extends JPEGVariableSizeSegment {
int ofs = i * 3 + 10;
int ci = reference[ofs] & 0xFF;
componentIdentifiers[i] = ci;
- int hi = (reference[ofs + 1] & 0xFF) / 16;
- int vi = (reference[ofs + 1] & 0xFF) % 16;
+ int hi = (reference[ofs + 1] & 0xFF) >> 4;
+ int vi = reference[ofs + 1] & 0xF;
int tqi = reference[ofs + 2] & 0xFF;
if (hi > hmax) {
hmax = hi;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGHuffmanTable.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGHuffmanTable.java
index 2824b2b3de..043c6157e0 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGHuffmanTable.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGHuffmanTable.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -25,8 +25,6 @@ final class JPEGHuffmanTable extends JPEGVariableSizeSegment {
JPEGHuffmanTable[] allTables;
int tableClass;
int tableIdentifier;
- int[] dhCodes;
- int[] dhCodeLengths;
int[] dhMaxCodes;
int[] dhMinCodes;
int[] dhValPtrs;
@@ -144,8 +142,8 @@ void initialize() {
JPEGHuffmanTable[] huffTables = new JPEGHuffmanTable[8]; // maximum is 4 AC + 4 DC
int huffTableCount = 0;
while (totalLength > 0) {
- int tc = (reference[ofs] & 0xFF) / 16; // table class: AC (1) or DC (0)
- int tid = (reference[ofs] & 0xFF) % 16; // table id: 0-1 baseline, 0-3 prog/ext
+ int tc = (reference[ofs] & 0xFF) >> 4; // table class: AC (1) or DC (0)
+ int tid = reference[ofs] & 0xF; // table id: 0-1 baseline, 0-3 prog/ext
ofs++;
/* Read the 16 count bytes and add them together to get the table size. */
@@ -248,8 +246,6 @@ void initialize() {
dhtTable.tableClass = tc;
dhtTable.tableIdentifier = tid;
dhtTable.dhValues = huffVals;
- dhtTable.dhCodes = huffCodes;
- dhtTable.dhCodeLengths = huffCodeLengths;
dhtTable.dhMinCodes = minCodes;
dhtTable.dhMaxCodes = maxCodes;
dhtTable.dhValPtrs = valPtrs;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGQuantizationTable.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGQuantizationTable.java
index 650828a46d..18eab61ff6 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGQuantizationTable.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGQuantizationTable.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -61,8 +61,8 @@ public int[] getQuantizationTablesKeys() {
int totalLength = getSegmentLength() - 2;
int ofs = 4;
while (totalLength > 64) {
- int tq = (reference[ofs] & 0xFF) % 16;
- int pq = (reference[ofs] & 0xFF) / 16;
+ int tq = reference[ofs] & 0xF;
+ int pq = (reference[ofs] & 0xFF) >> 4;
if (pq == 0) {
ofs += 65;
totalLength -= 65;
@@ -90,10 +90,10 @@ public int[][] getQuantizationTablesValues() {
int ofs = 4;
while (totalLength > 64) {
int[] qk = new int[64];
- int pq = (reference[ofs] & 0xFF) / 16;
+ int pq = (reference[ofs] & 0xFF) >> 4;
if (pq == 0) {
for (int i = 0; i < qk.length; i++) {
- qk[i] = reference[ofs + i + 1];
+ qk[i] = reference[ofs + i + 1] & 0xFF;
}
ofs += 65;
totalLength -= 65;
@@ -134,8 +134,8 @@ public void scaleBy(int qualityFactor) {
int totalLength = getSegmentLength() - 2;
int ofs = 4;
while (totalLength > 64) {
-// int tq = (reference[ofs] & 0xFF) % 16;
- int pq = (reference[ofs] & 0xFF) / 16;
+// int tq = reference[ofs] & 0xFF;
+ int pq = (reference[ofs] & 0xFF) >> 4;
if (pq == 0) {
for (int i = ofs + 1; i <= ofs + 64; i++) {
int temp = ((reference[i] & 0xFF) * qFactor + 50) / 100;
@@ -150,8 +150,8 @@ public void scaleBy(int qualityFactor) {
int temp = (((reference[i] & 0xFF) * 256 + (reference[i + 1] & 0xFF)) * qFactor + 50) / 100;
if (temp <= 0) temp = 1;
if (temp > 32767) temp = 32767;
- reference[i] = (byte)(temp / 256);
- reference[i + 1] = (byte)(temp % 256);
+ reference[i] = (byte)(temp >> 8);
+ reference[i + 1] = (byte)(temp & 0xFF);
}
ofs += 129;
totalLength -= 129;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGRestartInterval.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGRestartInterval.java
index 205ac83a42..bd722fe488 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGRestartInterval.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGRestartInterval.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGScanHeader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGScanHeader.java
index 77b08ae7b4..ae8d25d884 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGScanHeader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGScanHeader.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -26,23 +26,23 @@ public JPEGScanHeader(LEDataInputStream byteStream) {
}
public int getApproxBitPositionHigh() {
- return (reference[(2 * getNumberOfImageComponents()) + 7] & 0xFF) / 16;
+ return reference[(2 * getNumberOfImageComponents()) + 7] >> 4;
}
public int getApproxBitPositionLow() {
- return (reference[(2 * getNumberOfImageComponents()) + 7] & 0xFF) % 16;
+ return reference[(2 * getNumberOfImageComponents()) + 7] & 0xF;
}
public int getEndOfSpectralSelection() {
- return (reference[(2 * getNumberOfImageComponents()) + 6] & 0xFF);
+ return reference[(2 * getNumberOfImageComponents()) + 6];
}
public int getNumberOfImageComponents() {
- return (reference[4] & 0xFF);
+ return reference[4];
}
public int getStartOfSpectralSelection() {
- return (reference[(2 * getNumberOfImageComponents()) + 5] & 0xFF);
+ return reference[(2 * getNumberOfImageComponents()) + 5];
}
/* Used when decoding. */
@@ -52,8 +52,8 @@ void initializeComponentParameters() {
for (int i = 0; i < compCount; i++) {
int ofs = 5 + i * 2;
int cid = reference[ofs] & 0xFF;
- int dc = (reference[ofs + 1] & 0xFF) / 16;
- int ac = (reference[ofs + 1] & 0xFF) % 16;
+ int dc = (reference[ofs + 1] & 0xFF) >> 4;
+ int ac = reference[ofs + 1] & 0xF;
if (componentParameters.length <= cid) {
int[][] newParams = new int[cid + 1][];
System.arraycopy(componentParameters, 0, newParams, 0, componentParameters.length);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGSegment.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGSegment.java
index fd5bcd98e5..3d1b733684 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGSegment.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGSegment.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGStartOfImage.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGStartOfImage.java
index e8367fdf44..fde151a5dd 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGStartOfImage.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGStartOfImage.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGVariableSizeSegment.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGVariableSizeSegment.java
index 2ef4f65fea..a8052f32bc 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGVariableSizeSegment.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/JPEGVariableSizeSegment.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataInputStream.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataInputStream.java
index 4e4bc9efad..7bef3b6da1 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataInputStream.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataInputStream.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -81,17 +81,14 @@ final class LEDataInputStream extends InputStream {
* of bytes when you can actually read them all.
*/
public int read(byte b[], int off, int len) throws IOException {
- int result;
- int left = len;
- result = readData(b, off, len);
- while (true) {
- if (result == -1) return -1;
- position += result;
- if (result == left) return len;
- left -= result;
- off += result;
- result = readData(b, off, left);
+ int read = 0, count;
+ while (read != len && (count = readData(b, off, len - read)) != -1) {
+ off += count;
+ read += count;
}
+ position += read;
+ if (read == 0 && read != len) return -1;
+ return read;
}
/**
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataOutputStream.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataOutputStream.java
index d0413cb430..bd8a330280 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataOutputStream.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LEDataOutputStream.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -18,9 +18,10 @@ final class LEDataOutputStream extends OutputStream {
public LEDataOutputStream(OutputStream output) {
this.out = output;
}
-public void close() throws IOException {
- out.close();
-}
+/**
+ * Write the specified number of bytes of the given byte array,
+ * starting at the specified offset, to the output stream.
+ */
public void write(byte b[], int off, int len) throws IOException {
out.write(b, off, len);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java
index d32dc14a36..190ff01b7e 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWCodec.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -17,7 +17,7 @@ import org.eclipse.swt.graphics.*;
final class LZWCodec {
int bitsPerPixel, blockSize, blockIndex, currentByte, bitsLeft,
codeSize, clearCode, endCode, newCodes, topSlot, currentSlot,
- imageWidth, imageHeight, imageX, imageY, pass, line, codeMask, buffer;
+ imageWidth, imageHeight, imageX, imageY, pass, line, codeMask;
byte[] block, lineArray;
int[] stack, suffix, prefix;
LZWNode[] nodeStack;
@@ -61,8 +61,6 @@ void decode() {
} else {
code = c;
if (code >= currentSlot) {
- if (code > currentSlot)
- SWT.error(SWT.ERROR_INVALID_IMAGE);
code = oc;
stack[stackIndex] = fc;
stackIndex++;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWNode.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWNode.java
index 7860d417c6..e24bff1fee 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWNode.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/LZWNode.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java
new file mode 100644
index 0000000000..e0af60781e
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/OS2BMPFileFormat.java
@@ -0,0 +1,294 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * 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.*;
+
+final class OS2BMPFileFormat extends FileFormat {
+ static final int BMPFileHeaderSize = 14;
+ static final int BMPHeaderFixedSize = 12;
+ int width, height, bitCount;
+
+boolean isFileFormat(LEDataInputStream stream) {
+ try {
+ byte[] header = new byte[18];
+ stream.read(header);
+ stream.unread(header);
+ int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24);
+ return header[0] == 0x42 && header[1] == 0x4D && infoHeaderSize == BMPHeaderFixedSize;
+ } catch (Exception e) {
+ return false;
+ }
+}
+byte[] loadData(byte[] infoHeader) {
+ int stride = (width * bitCount + 7) / 8;
+ stride = (stride + 3) / 4 * 4; // Round up to 4 byte multiple
+ byte[] data = loadData(infoHeader, stride);
+ flipScanLines(data, stride, height);
+ return data;
+}
+byte[] loadData(byte[] infoHeader, int stride) {
+ int dataSize = height * stride;
+ byte[] data = new byte[dataSize];
+ try {
+ if (inputStream.read(data) != dataSize)
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ return data;
+}
+int[] loadFileHeader() {
+ int[] header = new int[5];
+ try {
+ header[0] = inputStream.readShort();
+ header[1] = inputStream.readInt();
+ header[2] = inputStream.readShort();
+ header[3] = inputStream.readShort();
+ header[4] = inputStream.readInt();
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ if (header[0] != 0x4D42)
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ return header;
+}
+ImageData[] loadFromByteStream() {
+ int[] fileHeader = loadFileHeader();
+ byte[] infoHeader = new byte[BMPHeaderFixedSize];
+ try {
+ inputStream.read(infoHeader);
+ } catch (Exception e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8);
+ height = (infoHeader[6] & 0xFF) | ((infoHeader[7] & 0xFF) << 8);
+ bitCount = (infoHeader[10] & 0xFF) | ((infoHeader[11] & 0xFF) << 8);
+ PaletteData palette = loadPalette(infoHeader);
+ if (inputStream.getPosition() < fileHeader[4]) {
+ // Seek to the specified offset
+ try {
+ inputStream.skip(fileHeader[4] - inputStream.getPosition());
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ }
+ byte[] data = loadData(infoHeader);
+ int type = SWT.IMAGE_OS2_BMP;
+ return new ImageData[] {
+ ImageData.internal_new(
+ width,
+ height,
+ bitCount,
+ palette,
+ 4,
+ data,
+ 0,
+ null,
+ null,
+ -1,
+ -1,
+ type,
+ 0,
+ 0,
+ 0,
+ 0)
+ };
+}
+PaletteData loadPalette(byte[] infoHeader) {
+ if (bitCount <= 8) {
+ int numColors = 1 << bitCount;
+ byte[] buf = new byte[numColors * 3];
+ try {
+ if (inputStream.read(buf) != buf.length)
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ return paletteFromBytes(buf, numColors);
+ }
+ if (bitCount == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F);
+ if (bitCount == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ return new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+}
+PaletteData paletteFromBytes(byte[] bytes, int numColors) {
+ int bytesOffset = 0;
+ RGB[] colors = new RGB[numColors];
+ for (int i = 0; i < numColors; i++) {
+ colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF,
+ bytes[bytesOffset + 1] & 0xFF,
+ bytes[bytesOffset] & 0xFF);
+ bytesOffset += 3;
+ }
+ return new PaletteData(colors);
+}
+/**
+ * Answer a byte array containing the BMP representation of
+ * the given device independent palette.
+ */
+static byte[] paletteToBytes(PaletteData pal) {
+ int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256);
+ byte[] bytes = new byte[n * 3];
+ int offset = 0;
+ for (int i = 0; i < n; i++) {
+ RGB col = pal.colors[i];
+ bytes[offset] = (byte)col.blue;
+ bytes[offset + 1] = (byte)col.green;
+ bytes[offset + 2] = (byte)col.red;
+ offset += 3;
+ }
+ return bytes;
+}
+/**
+ * Unload the given image's data into the given byte stream.
+ * Answer the number of bytes written.
+ */
+int unloadData(ImageData image, OutputStream out) {
+ int bmpBpl = 0;
+ try {
+ int bpl = (image.width * image.depth + 7) / 8;
+ bmpBpl = (bpl + 3) / 4 * 4; // BMP pads scanlines to multiples of 4 bytes
+ int linesPerBuf = 32678 / bmpBpl;
+ byte[] buf = new byte[linesPerBuf * bmpBpl];
+ byte[] data = image.data;
+ int imageBpl = image.bytesPerLine;
+ int dataIndex = imageBpl * (image.height - 1); // Start at last line
+ if (image.depth == 16) {
+ for (int y = 0; y < image.height; y += linesPerBuf) {
+ int count = image.height - y;
+ if (linesPerBuf < count) count = linesPerBuf;
+ int bufOffset = 0;
+ for (int i = 0; i < count; i++) {
+ for (int wIndex = 0; wIndex < bpl; wIndex += 2) {
+ buf[bufOffset + wIndex + 1] = data[dataIndex + wIndex + 1];
+ buf[bufOffset + wIndex] = data[dataIndex + wIndex];
+ }
+ bufOffset += bmpBpl;
+ dataIndex -= imageBpl;
+ }
+ out.write(buf, 0, bufOffset);
+ }
+ } else {
+ for (int y = 0; y < image.height; y += linesPerBuf) {
+ int tmp = image.height - y;
+ int count = tmp < linesPerBuf ? tmp : linesPerBuf;
+ int bufOffset = 0;
+ for (int i = 0; i < count; i++) {
+ System.arraycopy(data, dataIndex, buf, bufOffset, bpl);
+ bufOffset += bmpBpl;
+ dataIndex -= imageBpl;
+ }
+ out.write(buf, 0, bufOffset);
+ }
+ }
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ return bmpBpl * image.height;
+}
+/**
+ * Unload a DeviceIndependentImage using Windows .BMP format into the given
+ * byte stream.
+ */
+void unloadIntoByteStream(ImageLoader loader) {
+ ImageData image = loader.data[0];
+ byte[] rgbs;
+ int numCols;
+ if (!((image.depth == 1) || (image.depth == 4) || (image.depth == 8) ||
+ (image.depth == 16) || (image.depth == 24) || (image.depth == 32)))
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ PaletteData pal = image.palette;
+ if ((image.depth == 16) || (image.depth == 24) || (image.depth == 32)) {
+ if (!pal.isDirect)
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ numCols = 0;
+ rgbs = null;
+ } else {
+ if (pal.isDirect)
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ numCols = pal.colors.length;
+ rgbs = paletteToBytes(pal);
+ }
+ // Fill in file header, except for bfsize, which is done later.
+ int headersSize = BMPFileHeaderSize + BMPHeaderFixedSize;
+ int[] fileHeader = new int[5];
+ fileHeader[0] = 0x4D42; // Signature
+ fileHeader[1] = 0; // File size - filled in later
+ fileHeader[2] = 0; // Reserved 1
+ fileHeader[3] = 0; // Reserved 2
+ fileHeader[4] = headersSize; // Offset to data
+ if (rgbs != null) {
+ fileHeader[4] += rgbs.length;
+ }
+
+ // Prepare data. This is done first so we don't have to try to rewind
+ // the stream and fill in the details later.
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ unloadData(image, out);
+ byte[] data = out.toByteArray();
+
+ // Calculate file size
+ fileHeader[1] = fileHeader[4] + data.length;
+
+ // Write the headers
+ try {
+ outputStream.writeShort(fileHeader[0]);
+ outputStream.writeInt(fileHeader[1]);
+ outputStream.writeShort(fileHeader[2]);
+ outputStream.writeShort(fileHeader[3]);
+ outputStream.writeInt(fileHeader[4]);
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ try {
+ outputStream.writeInt(BMPHeaderFixedSize);
+ outputStream.writeShort(image.width);
+ outputStream.writeShort(image.height);
+ outputStream.writeShort(1);
+ outputStream.writeShort((short)image.depth);
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+
+ // Unload palette
+ if (numCols > 0) {
+ try {
+ outputStream.write(rgbs);
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+ }
+
+ // Unload the data
+ try {
+ outputStream.write(data);
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+}
+void flipScanLines(byte[] data, int stride, int height) {
+ int i1 = 0;
+ int i2 = (height - 1) * stride;
+ for (int i = 0; i < height / 2; i++) {
+ for (int index = 0; index < stride; index++) {
+ byte b = data[index + i1];
+ data[index + i1] = data[index + i2];
+ data[index + i2] = b;
+ }
+ i1 += stride;
+ i2 -= stride;
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java
index 2fcfde06b4..205d585d2b 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -14,20 +14,23 @@ package org.eclipse.swt.internal.image;
import java.io.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
final class PNGFileFormat extends FileFormat {
static final int SIGNATURE_LENGTH = 8;
- PngDecodingDataStream decodingStream;
+ static final int PRIME = 65521;
PngIhdrChunk headerChunk;
PngPlteChunk paletteChunk;
- PngTrnsChunk trnsChunk;
ImageData imageData;
byte[] data;
byte[] alphaPalette;
+ byte headerByte1;
+ byte headerByte2;
+ int adler;
/**
* Skip over signature data. This has already been
- * verified in isPNGFile().
+ * verified in isFileFormat().
*/
void readSignature() throws IOException {
byte[] signature = new byte[SIGNATURE_LENGTH];
@@ -41,11 +44,13 @@ ImageData[] loadFromByteStream() {
readSignature();
PngChunkReader chunkReader = new PngChunkReader(inputStream);
headerChunk = chunkReader.getIhdrChunk();
- int imageSize = getAlignedBytesPerRow() * headerChunk.getHeight();
+ int width = headerChunk.getWidth(), height = headerChunk.getHeight();
+ if (width <= 0 || height <= 0) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ int imageSize = getAlignedBytesPerRow() * height;
data = new byte[imageSize];
imageData = ImageData.internal_new(
- headerChunk.getWidth(),
- headerChunk.getHeight(),
+ width,
+ height,
headerChunk.getSwtBitsPerPixel(),
new PaletteData(0, 0, 0),
4,
@@ -80,7 +85,7 @@ ImageData[] loadFromByteStream() {
* Read and handle the next chunk of data from the
* PNG file.
*/
-void readNextChunk(PngChunkReader chunkReader) {
+void readNextChunk(PngChunkReader chunkReader) throws IOException {
PngChunk chunk = chunkReader.readNextChunk();
switch (chunk.getChunkType()) {
case PngChunk.CHUNK_IEND:
@@ -136,8 +141,9 @@ void readNextChunk(PngChunkReader chunkReader) {
}
}
}
-void unloadIntoByteStream(ImageData p1) {
- SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+void unloadIntoByteStream(ImageLoader loader) {
+ /* We do not currently support writing png. */
+ SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
}
boolean isFileFormat(LEDataInputStream stream) {
try {
@@ -282,16 +288,28 @@ void setImageDataValues(byte[] data, ImageData imageData) {
* Read the image data from the data stream. This must handle
* decoding the data, filtering, and interlacing.
*/
-void readPixelData(PngIdatChunk chunk, PngChunkReader chunkReader) {
- decodingStream = new PngDecodingDataStream(chunk, chunkReader);
+void readPixelData(PngIdatChunk chunk, PngChunkReader chunkReader) throws IOException {
+ InputStream stream = new PngInputStream(chunk, chunkReader);
+ boolean use3_2 = System.getProperty("org.eclipse.swt.internal.image.PNGFileFormat_3.2") != null;
+ InputStream inflaterStream = use3_2 ? null : Compatibility.newInflaterInputStream(stream);
+ if (inflaterStream != null) {
+ stream = new BufferedInputStream(inflaterStream);
+ } else {
+ stream = new PngDecodingDataStream(stream);
+ }
int interlaceMethod = headerChunk.getInterlaceMethod();
if (interlaceMethod == PngIhdrChunk.INTERLACE_METHOD_NONE) {
- readNonInterlacedImage();
+ readNonInterlacedImage(stream);
} else {
- readInterlacedImage();
+ readInterlacedImage(stream);
}
- decodingStream.assertImageDataAtEnd();
- decodingStream.checkAdler();
+ /*
+ * InflaterInputStream does not consume all bytes in the stream
+ * when it is closed. This may leave unread IDAT chunks. The fix
+ * is to read all available bytes before closing it.
+ */
+ while (stream.available() > 0) stream.read();
+ stream.close();
}
/**
* Answer the number of bytes in a word-aligned row of pixel data.
@@ -337,11 +355,12 @@ int getBytesPerRow(int rowWidthInPixels) {
* 3. Notify the image loader's listeners of the frame load.
*/
void readInterlaceFrame(
+ InputStream inputStream,
int rowInterval,
int columnInterval,
int startRow,
int startColumn,
- int frameCount)
+ int frameCount) throws IOException
{
int width = headerChunk.getWidth();
int alignedBytesPerRow = getAlignedBytesPerRow();
@@ -355,9 +374,10 @@ void readInterlaceFrame(
byte[] currentRow = row1;
byte[] lastRow = row2;
for (int row = startRow; row < height; row += rowInterval) {
- byte filterType = decodingStream.getNextDecodedByte();
- for (int col = 0; col < bytesPerRow; col++) {
- currentRow[col] = decodingStream.getNextDecodedByte();
+ byte filterType = (byte)inputStream.read();
+ int read = 0;
+ while (read != bytesPerRow) {
+ read += inputStream.read(currentRow, read, bytesPerRow - read);
}
filterRow(currentRow, lastRow, filterType);
if (headerChunk.getBitDepth() >= 8) {
@@ -402,14 +422,14 @@ void readInterlaceFrame(
* Read the pixel data for an interlaced image from the
* data stream.
*/
-void readInterlacedImage() {
- readInterlaceFrame(8, 8, 0, 0, 0);
- readInterlaceFrame(8, 8, 0, 4, 1);
- readInterlaceFrame(8, 4, 4, 0, 2);
- readInterlaceFrame(4, 4, 0, 2, 3);
- readInterlaceFrame(4, 2, 2, 0, 4);
- readInterlaceFrame(2, 2, 0, 1, 5);
- readInterlaceFrame(2, 1, 1, 0, 6);
+void readInterlacedImage(InputStream inputStream) throws IOException {
+ readInterlaceFrame(inputStream, 8, 8, 0, 0, 0);
+ readInterlaceFrame(inputStream, 8, 8, 0, 4, 1);
+ readInterlaceFrame(inputStream, 8, 4, 4, 0, 2);
+ readInterlaceFrame(inputStream, 4, 4, 0, 2, 3);
+ readInterlaceFrame(inputStream, 4, 2, 2, 0, 4);
+ readInterlaceFrame(inputStream, 2, 2, 0, 1, 5);
+ readInterlaceFrame(inputStream, 2, 1, 1, 0, 6);
}
/**
* Fire an event to let listeners know that an interlaced
@@ -429,7 +449,7 @@ void fireInterlacedFrameEvent(int frameCount) {
* data stream.
* Update the imageData to reflect the new data.
*/
-void readNonInterlacedImage() {
+void readNonInterlacedImage(InputStream inputStream) throws IOException {
int dataOffset = 0;
int alignedBytesPerRow = getAlignedBytesPerRow();
int bytesPerRow = getBytesPerRow();
@@ -437,10 +457,12 @@ void readNonInterlacedImage() {
byte[] row2 = new byte[bytesPerRow];
byte[] currentRow = row1;
byte[] lastRow = row2;
- for (int row = 0; row < headerChunk.getHeight(); row++) {
- byte filterType = decodingStream.getNextDecodedByte();
- for (int col = 0; col < bytesPerRow; col++) {
- currentRow[col] = decodingStream.getNextDecodedByte();
+ int height = headerChunk.getHeight();
+ for (int row = 0; row < height; row++) {
+ byte filterType = (byte)inputStream.read();
+ int read = 0;
+ while (read != bytesPerRow) {
+ read += inputStream.read(currentRow, read, bytesPerRow - read);
}
filterRow(currentRow, lastRow, filterType);
System.arraycopy(currentRow, 0, data, dataOffset, bytesPerRow);
@@ -548,4 +570,4 @@ void filterRow(byte[] row, byte[] previousRow, int filterType) {
}
}
-}
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java
index 923f82cdcf..74b438ea46 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -12,7 +12,6 @@ package org.eclipse.swt.internal.image;
import org.eclipse.swt.*;
-import org.eclipse.swt.internal.Compatibility;
import java.io.*;
class PngChunk extends Object {
@@ -56,6 +55,8 @@ class PngChunk extends Object {
}
}
+ int length;
+
/**
* Construct a PngChunk using the reference bytes
* given.
@@ -63,6 +64,17 @@ class PngChunk extends Object {
PngChunk(byte[] reference) {
super();
setReference(reference);
+ if (reference.length < LENGTH_OFFSET + LENGTH_FIELD_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ length = getInt32(LENGTH_OFFSET);
+}
+
+/**
+ * Construct a PngChunk with the specified number of
+ * data bytes.
+ */
+PngChunk(int dataLength) {
+ this(new byte[MIN_LENGTH + dataLength]);
+ setLength(dataLength);
}
/**
@@ -80,6 +92,26 @@ void setReference(byte[] reference) {
}
/**
+ * Get the 16-bit integer from the reference byte
+ * array at the given offset.
+ */
+int getInt16(int offset) {
+ int answer = 0;
+ answer |= (reference[offset] & 0xFF) << 8;
+ answer |= (reference[offset + 1] & 0xFF);
+ return answer;
+}
+
+/**
+ * Set the 16-bit integer in the reference byte
+ * array at the given offset.
+ */
+void setInt16(int offset, int value) {
+ reference[offset] = (byte) ((value >> 8) & 0xFF);
+ reference[offset + 1] = (byte) (value & 0xFF);
+}
+
+/**
* Get the 32-bit integer from the reference byte
* array at the given offset.
*/
@@ -108,7 +140,7 @@ void setInt32(int offset, int value) {
* This is not the length of the entire chunk.
*/
int getLength() {
- return getInt32(LENGTH_OFFSET);
+ return length;
}
/**
@@ -117,6 +149,7 @@ int getLength() {
*/
void setLength(int value) {
setInt32(LENGTH_OFFSET, value);
+ length = value;
}
/**
@@ -239,7 +272,8 @@ boolean typeMatchesArray(byte[] array) {
}
boolean isCritical() {
- return Character.isUpperCase((char) getTypeBytes()[0]);
+ char c = (char) getTypeBytes()[0];
+ return 'A' <= c && c <= 'Z';
}
int getChunkType() {
@@ -251,9 +285,6 @@ int getChunkType() {
return CHUNK_UNKNOWN;
}
-
-
-
/**
* Read the next PNG chunk from the input stream given.
* If unable to read a chunk, return null.
@@ -301,11 +332,15 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
byte[] type = getTypeBytes();
// The third character MUST be upper case.
- if (!Character.isUpperCase((char) type[2])) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ char c = (char) type[2];
+ if (!('A' <= c && c <= 'Z')) SWT.error(SWT.ERROR_INVALID_IMAGE);
// All characters must be letters.
for (int i = 0; i < TYPE_FIELD_LENGTH; i++) {
- if (!Compatibility.isLetter((char) type[i])) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ c = (char) type[i];
+ if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) {
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
}
// The stored CRC must match the data's computed CRC.
@@ -318,6 +353,12 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
*/
void contributeToString(StringBuffer buffer) {}
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("{");
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunkReader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunkReader.java
index f16656293b..15f4777990 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunkReader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunkReader.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -29,6 +29,7 @@ PngIhdrChunk getIhdrChunk() {
if (headerChunk == null) {
try {
PngChunk chunk = PngChunk.readNextFromStream(inputStream);
+ if (chunk == null) SWT.error(SWT.ERROR_INVALID_IMAGE);
headerChunk = (PngIhdrChunk) chunk;
headerChunk.validate(readState, null);
} catch (ClassCastException e) {
@@ -42,6 +43,7 @@ PngChunk readNextChunk() {
if (headerChunk == null) return getIhdrChunk();
PngChunk chunk = PngChunk.readNextFromStream(inputStream);
+ if (chunk == null) SWT.error(SWT.ERROR_INVALID_IMAGE);
switch (chunk.getChunkType()) {
case PngChunk.CHUNK_tRNS:
((PngTrnsChunk) chunk).validate(readState, headerChunk, paletteChunk);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDecodingDataStream.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDecodingDataStream.java
index 8c1d32e1e4..a05021a0db 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDecodingDataStream.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDecodingDataStream.java
@@ -1,23 +1,23 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal.image;
+import java.io.*;
+
import org.eclipse.swt.*;
-public class PngDecodingDataStream {
- PngIdatChunk currentChunk;
- PngChunkReader chunkReader;
+public class PngDecodingDataStream extends InputStream {
+ InputStream stream;
byte currentByte;
- int nextByteIndex;
int nextBitIndex;
PngLzBlockReader lzBlockReader;
@@ -26,11 +26,9 @@ public class PngDecodingDataStream {
static final int PRIME = 65521;
static final int MAX_BIT = 7;
-PngDecodingDataStream(PngIdatChunk idatChunk, PngChunkReader chunkReader) {
+PngDecodingDataStream(InputStream stream) throws IOException {
super();
- this.currentChunk = idatChunk;
- this.chunkReader = chunkReader;
- nextByteIndex = 0;
+ this.stream = stream;
nextBitIndex = MAX_BIT + 1;
adlerValue = 1;
lzBlockReader = new PngLzBlockReader(this);
@@ -45,11 +43,16 @@ PngDecodingDataStream(PngIdatChunk idatChunk, PngChunkReader chunkReader) {
* block marker. If there are more blocks after this one,
* the method will read them and ensure that they are empty.
*/
-void assertImageDataAtEnd() {
+void assertImageDataAtEnd() throws IOException {
lzBlockReader.assertCompressedDataAtEnd();
}
-int getNextIdatBits(int length) {
+public void close() throws IOException {
+ assertImageDataAtEnd();
+ checkAdler();
+}
+
+int getNextIdatBits(int length) throws IOException {
int value = 0;
for (int i = 0; i < length; i++) {
value |= (getNextIdatBit() << i);
@@ -57,35 +60,21 @@ int getNextIdatBits(int length) {
return value;
}
-byte getNextIdatBit() {
+int getNextIdatBit() throws IOException {
if (nextBitIndex > MAX_BIT) {
currentByte = getNextIdatByte();
nextBitIndex = 0;
- }
- int mask = 1 << nextBitIndex;
- nextBitIndex++;
- return ((currentByte & mask) > 0) ? (byte) 1 : (byte) 0;
-}
-
-private PngIdatChunk getNextChunk() {
- PngChunk chunk = chunkReader.readNextChunk();
- if (chunk == null) error();
- if (chunk.getChunkType() != PngChunk.CHUNK_IDAT) error();
- return (PngIdatChunk) chunk;
+ }
+ return (currentByte & (1 << nextBitIndex)) >> nextBitIndex++;
}
-byte getNextIdatByte() {
- if (nextByteIndex > currentChunk.getLength() - 1) {
- currentChunk = getNextChunk();
- nextByteIndex = 0;
- }
- byte nextByte = currentChunk.getDataByteAtOffset(nextByteIndex);
- nextByteIndex++;
+byte getNextIdatByte() throws IOException {
+ byte nextByte = (byte)stream.read();
nextBitIndex = MAX_BIT + 1;
return nextByte;
}
-private void updateAdler(byte value) {
+void updateAdler(byte value) {
int low = adlerValue & 0xFFFF;
int high = (adlerValue >> 16) & 0xFFFF;
int valueInt = value & 0xFF;
@@ -94,17 +83,26 @@ private void updateAdler(byte value) {
adlerValue = (high << 16) | low;
}
-byte getNextDecodedByte() {
+public int read() throws IOException {
byte nextDecodedByte = lzBlockReader.getNextByte();
updateAdler(nextDecodedByte);
- return nextDecodedByte;
+ return nextDecodedByte & 0xFF;
+}
+
+public int read(byte[] buffer, int off, int len) throws IOException {
+ for (int i = 0; i < len; i++) {
+ int b = read();
+ if (b == -1) return i;
+ buffer[off + i] = (byte)b;
+ }
+ return len;
}
void error() {
SWT.error(SWT.ERROR_INVALID_IMAGE);
}
-private void readCompressedDataHeader() {
+private void readCompressedDataHeader() throws IOException {
byte headerByte1 = getNextIdatByte();
byte headerByte2 = getNextIdatByte();
@@ -125,7 +123,7 @@ private void readCompressedDataHeader() {
// int compressionLevel = (headerByte2 & 0xC0) >> 6;
}
-void checkAdler() {
+void checkAdler() throws IOException {
int storedAdler = ((getNextIdatByte() & 0xFF) << 24)
| ((getNextIdatByte() & 0xFF) << 16)
| ((getNextIdatByte() & 0xFF) << 8)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngFileReadState.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngFileReadState.java
index 3e82cdf1c9..3ad40e06c6 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngFileReadState.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngFileReadState.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -18,7 +18,6 @@ class PngFileReadState extends Object {
boolean readIEND;
// Non - critical chunks
- boolean readBKGD;
boolean readTRNS;
// Set to true after IDATs have been read.
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTable.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTable.java
index 5d06cf01ac..655c78541a 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTable.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTable.java
@@ -1,15 +1,16 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal.image;
+import java.io.*;
public class PngHuffmanTable {
CodeLengthInfo[] codeLengthInfo;
@@ -17,6 +18,7 @@ public class PngHuffmanTable {
static final int MAX_CODE_LENGTH = 15;
static final int BAD_CODE = 0xFFFFFFF;
+ static final int incs[] = {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1};
PngHuffmanTable (int[] lengths) {
super();
@@ -44,21 +46,20 @@ private void initialize(int[] lengths) {
}
private void generateTable(int[] lengths) {
- // Sort the values. Primary key is code size. Secondary key is value.
- for (int i = 0; i < lengths.length - 1; i++) {
- for (int j = i + 1; j < lengths.length; j++) {
- if (lengths[j] < lengths[i]
- || (lengths[j] == lengths[i]
- && codeValues[j] < codeValues[i]))
- {
- int tmp;
- tmp = lengths[j];
- lengths[j] = lengths[i];
- lengths[i] = tmp;
- tmp = codeValues[j];
- codeValues[j] = codeValues[i];
- codeValues[i] = tmp;
+ // Sort the values using shellsort. Primary key is code size. Secondary key is value.
+ int codeValuesTemp;
+ for (int k = 0; k < 16; k++) {
+ for (int h = incs[k], i = h; i < lengths.length; i++) {
+ int v = lengths[i];
+ codeValuesTemp = codeValues[i];
+ int j = i;
+ while (j >= h && (lengths[j - h] > v || (lengths[j - h] == v && codeValues[j - h] > codeValuesTemp))) {
+ lengths[j] = lengths[j - h];
+ codeValues[j] = codeValues[j - h];
+ j -= h;
}
+ lengths[j] = v;
+ codeValues[j] = codeValuesTemp;
}
}
@@ -90,7 +91,7 @@ private void generateTable(int[] lengths) {
}
}
-int getNextValue(PngDecodingDataStream stream) {
+int getNextValue(PngDecodingDataStream stream) throws IOException {
int code = stream.getNextIdatBit();
int codelength = 0;
@@ -114,10 +115,6 @@ int getNextValue(PngDecodingDataStream stream) {
return codeValues[index];
}
-class CodeValuePair {
- int value;
- int code;
-}
class CodeLengthInfo {
int length;
int max;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTables.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTables.java
index 85e5e61796..09bd04ef3d 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTables.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngHuffmanTables.java
@@ -1,15 +1,16 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal.image;
+import java.io.*;
public class PngHuffmanTables {
PngHuffmanTable literalTable;
@@ -46,7 +47,7 @@ public class PngHuffmanTables {
11, 4, 12, 3, 13, 2, 14, 1, 15
};
-static PngHuffmanTables getDynamicTables(PngDecodingDataStream stream){
+static PngHuffmanTables getDynamicTables(PngDecodingDataStream stream) throws IOException {
return new PngHuffmanTables(stream);
}
static PngHuffmanTables getFixedTables() {
@@ -72,7 +73,7 @@ private PngHuffmanTables () {
distanceTable = getFixedDistanceTable();
}
-private PngHuffmanTables (PngDecodingDataStream stream) {
+private PngHuffmanTables (PngDecodingDataStream stream) throws IOException {
int literals = PngLzBlockReader.FIRST_LENGTH_CODE
+ stream.getNextIdatBits(5);
int distances = PngLzBlockReader.FIRST_DISTANCE_CODE
@@ -110,7 +111,7 @@ private PngHuffmanTables (PngDecodingDataStream stream) {
private int [] readLengths (PngDecodingDataStream stream,
int numLengths,
PngHuffmanTable lengthsTable,
- int tableSize)
+ int tableSize) throws IOException
{
int[] lengths = new int[tableSize];
@@ -148,11 +149,11 @@ private int [] readLengths (PngDecodingDataStream stream,
return lengths;
}
-int getNextLiteralValue(PngDecodingDataStream stream) {
+int getNextLiteralValue(PngDecodingDataStream stream) throws IOException {
return literalTable.getNextValue(stream);
}
-int getNextDistanceValue(PngDecodingDataStream stream) {
+int getNextDistanceValue(PngDecodingDataStream stream) throws IOException {
return distanceTable.getNextValue(stream);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIdatChunk.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIdatChunk.java
index 613b88691f..6dfac62210 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIdatChunk.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIdatChunk.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -15,10 +15,30 @@ import org.eclipse.swt.*;
class PngIdatChunk extends PngChunk {
-PngIdatChunk(byte[] reference){
+ static final int HEADER_BYTES_LENGTH = 2;
+ static final int ADLER_FIELD_LENGTH = 4;
+ static final int HEADER_BYTE1_DATA_OFFSET = DATA_OFFSET + 0;
+ static final int HEADER_BYTE2_DATA_OFFSET = DATA_OFFSET + 1;
+ static final int ADLER_DATA_OFFSET = DATA_OFFSET + 2; // plus variable compressed data length
+
+PngIdatChunk(byte headerByte1, byte headerByte2, byte[] data, int adler) {
+ super(data.length + HEADER_BYTES_LENGTH + ADLER_FIELD_LENGTH);
+ setType(TYPE_IDAT);
+ reference[HEADER_BYTE1_DATA_OFFSET] = headerByte1;
+ reference[HEADER_BYTE2_DATA_OFFSET] = headerByte2;
+ System.arraycopy(data, 0, reference, DATA_OFFSET, data.length);
+ setInt32(ADLER_DATA_OFFSET, adler);
+ setCRC(computeCRC());
+}
+
+PngIdatChunk(byte[] reference) {
super(reference);
}
+int getChunkType() {
+ return CHUNK_IDAT;
+}
+
/**
* Answer whether the chunk is a valid IDAT chunk.
*/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIendChunk.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIendChunk.java
index a564f3f84a..ed604e0ae9 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIendChunk.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIendChunk.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -15,10 +15,20 @@ import org.eclipse.swt.*;
class PngIendChunk extends PngChunk {
+PngIendChunk() {
+ super(0);
+ setType(TYPE_IEND);
+ setCRC(computeCRC());
+}
+
PngIendChunk(byte[] reference){
super(reference);
}
+int getChunkType() {
+ return CHUNK_IEND;
+}
+
/**
* Answer whether the chunk is a valid IEND chunk.
*/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIhdrChunk.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIhdrChunk.java
index 895a740249..37d550883e 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIhdrChunk.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngIhdrChunk.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -13,10 +13,9 @@ package org.eclipse.swt.internal.image;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.internal.Compatibility;
class PngIhdrChunk extends PngChunk {
- static final int EXPECTED_DATA_LENGTH = 13;
+ static final int IHDR_DATA_LENGTH = 13;
static final int WIDTH_DATA_OFFSET = DATA_OFFSET + 0;
static final int HEIGHT_DATA_OFFSET = DATA_OFFSET + 4;
@@ -26,11 +25,11 @@ class PngIhdrChunk extends PngChunk {
static final int FILTER_METHOD_OFFSET = DATA_OFFSET + 11;
static final int INTERLACE_METHOD_OFFSET = DATA_OFFSET + 12;
- static final int COLOR_TYPE_GRAYSCALE = 0;
- static final int COLOR_TYPE_RGB = 2;
- static final int COLOR_TYPE_PALETTE = 3;
- static final int COLOR_TYPE_GRAYSCALE_WITH_ALPHA = 4;
- static final int COLOR_TYPE_RGB_WITH_ALPHA = 6;
+ static final byte COLOR_TYPE_GRAYSCALE = 0;
+ static final byte COLOR_TYPE_RGB = 2;
+ static final byte COLOR_TYPE_PALETTE = 3;
+ static final byte COLOR_TYPE_GRAYSCALE_WITH_ALPHA = 4;
+ static final byte COLOR_TYPE_RGB_WITH_ALPHA = 6;
static final int INTERLACE_METHOD_NONE = 0;
static final int INTERLACE_METHOD_ADAM7 = 1;
@@ -44,19 +43,47 @@ class PngIhdrChunk extends PngChunk {
static final byte[] ValidBitDepths = {1, 2, 4, 8, 16};
static final byte[] ValidColorTypes = {0, 2, 3, 4, 6};
+ int width, height;
+ byte bitDepth, colorType, compressionMethod, filterMethod, interlaceMethod;
+
+PngIhdrChunk(int width, int height, byte bitDepth, byte colorType, byte compressionMethod, byte filterMethod, byte interlaceMethod) {
+ super(IHDR_DATA_LENGTH);
+ setType(TYPE_IHDR);
+ setWidth(width);
+ setHeight(height);
+ setBitDepth(bitDepth);
+ setColorType(colorType);
+ setCompressionMethod(compressionMethod);
+ setFilterMethod(filterMethod);
+ setInterlaceMethod(interlaceMethod);
+ setCRC(computeCRC());
+}
+
/**
* Construct a PNGChunk using the reference bytes
* given.
*/
PngIhdrChunk(byte[] reference) {
super(reference);
+ if (reference.length <= IHDR_DATA_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ width = getInt32(WIDTH_DATA_OFFSET);
+ height = getInt32(HEIGHT_DATA_OFFSET);
+ bitDepth = reference[BIT_DEPTH_OFFSET];
+ colorType = reference[COLOR_TYPE_OFFSET];
+ compressionMethod = reference[COMPRESSION_METHOD_OFFSET];
+ filterMethod = reference[FILTER_METHOD_OFFSET];
+ interlaceMethod = reference[INTERLACE_METHOD_OFFSET];
+}
+
+int getChunkType() {
+ return CHUNK_IHDR;
}
/**
* Get the image's width in pixels.
*/
int getWidth() {
- return getInt32(WIDTH_DATA_OFFSET);
+ return width;
}
/**
@@ -64,13 +91,14 @@ int getWidth() {
*/
void setWidth(int value) {
setInt32(WIDTH_DATA_OFFSET, value);
+ width = value;
}
/**
* Get the image's height in pixels.
*/
int getHeight() {
- return getInt32(HEIGHT_DATA_OFFSET);
+ return height;
}
/**
@@ -78,6 +106,7 @@ int getHeight() {
*/
void setHeight(int value) {
setInt32(HEIGHT_DATA_OFFSET, value);
+ height = value;
}
/**
@@ -85,7 +114,7 @@ void setHeight(int value) {
* This is limited to the values 1, 2, 4, 8, or 16.
*/
byte getBitDepth() {
- return reference[BIT_DEPTH_OFFSET];
+ return bitDepth;
}
/**
@@ -94,6 +123,7 @@ byte getBitDepth() {
*/
void setBitDepth(byte value) {
reference[BIT_DEPTH_OFFSET] = value;
+ bitDepth = value;
}
/**
@@ -106,7 +136,7 @@ void setBitDepth(byte value) {
* 6 - RGB with Alpha channel.
*/
byte getColorType() {
- return reference[COLOR_TYPE_OFFSET];
+ return colorType;
}
/**
@@ -120,6 +150,7 @@ byte getColorType() {
*/
void setColorType(byte value) {
reference[COLOR_TYPE_OFFSET] = value;
+ colorType = value;
}
/**
@@ -127,7 +158,7 @@ void setColorType(byte value) {
* This value must be 0.
*/
byte getCompressionMethod() {
- return reference[COMPRESSION_METHOD_OFFSET];
+ return compressionMethod;
}
/**
@@ -136,6 +167,7 @@ byte getCompressionMethod() {
*/
void setCompressionMethod(byte value) {
reference[COMPRESSION_METHOD_OFFSET] = value;
+ compressionMethod = value;
}
/**
@@ -143,7 +175,7 @@ void setCompressionMethod(byte value) {
* This value must be 0.
*/
byte getFilterMethod() {
- return reference[FILTER_METHOD_OFFSET];
+ return filterMethod;
}
/**
@@ -152,6 +184,7 @@ byte getFilterMethod() {
*/
void setFilterMethod(byte value) {
reference[FILTER_METHOD_OFFSET] = value;
+ filterMethod = value;
}
/**
@@ -161,7 +194,7 @@ void setFilterMethod(byte value) {
* 1 - Adam7 interlacing used.
*/
byte getInterlaceMethod() {
- return reference[INTERLACE_METHOD_OFFSET];
+ return interlaceMethod;
}
/**
@@ -172,6 +205,7 @@ byte getInterlaceMethod() {
*/
void setInterlaceMethod(byte value) {
reference[INTERLACE_METHOD_OFFSET] = value;
+ interlaceMethod = value;
}
/**
@@ -192,15 +226,14 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
super.validate(readState, headerChunk);
- if (getLength() != EXPECTED_DATA_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
- if (getCompressionMethod() != 0) SWT.error(SWT.ERROR_INVALID_IMAGE);
- if (getInterlaceMethod() != INTERLACE_METHOD_NONE &&
- getInterlaceMethod() != INTERLACE_METHOD_ADAM7) {
+ if (length != IHDR_DATA_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ if (compressionMethod != 0) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ if (interlaceMethod != INTERLACE_METHOD_NONE &&
+ interlaceMethod != INTERLACE_METHOD_ADAM7) {
SWT.error(SWT.ERROR_INVALID_IMAGE);
}
boolean colorTypeIsValid = false;
- byte colorType = getColorType();
for (int i = 0; i < ValidColorTypes.length; i++) {
if (ValidColorTypes[i] == colorType) {
colorTypeIsValid = true;
@@ -210,7 +243,6 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
if (!colorTypeIsValid) SWT.error(SWT.ERROR_INVALID_IMAGE);
boolean bitDepthIsValid = false;
- byte bitDepth = getBitDepth();
for (int i = 0; i < ValidBitDepths.length; i++) {
if (ValidBitDepths[i] == bitDepth) {
bitDepthIsValid = true;
@@ -233,18 +265,18 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
}
String getColorTypeString() {
- switch (getColorType()) {
+ switch (colorType) {
case COLOR_TYPE_GRAYSCALE: return "Grayscale";
case COLOR_TYPE_RGB: return "RGB";
case COLOR_TYPE_PALETTE: return "Palette";
case COLOR_TYPE_GRAYSCALE_WITH_ALPHA: return "Grayscale with Alpha";
case COLOR_TYPE_RGB_WITH_ALPHA: return "RGB with Alpha";
- default: return "Unknown - " + getColorType();
+ default: return "Unknown - " + colorType;
}
}
String getFilterMethodString() {
- switch (getFilterMethod()) {
+ switch (filterMethod) {
case FILTER_NONE: return "None";
case FILTER_SUB: return "Sub";
case FILTER_UP: return "Up";
@@ -255,7 +287,7 @@ String getFilterMethodString() {
}
String getInterlaceMethodString() {
- switch (getInterlaceMethod()) {
+ switch (interlaceMethod) {
case INTERLACE_METHOD_NONE: return "Not Interlaced";
case INTERLACE_METHOD_ADAM7: return "Interlaced - ADAM7";
default: return "Unknown";
@@ -264,15 +296,15 @@ String getInterlaceMethodString() {
void contributeToString(StringBuffer buffer) {
buffer.append("\n\tWidth: ");
- buffer.append(getWidth());
+ buffer.append(width);
buffer.append("\n\tHeight: ");
- buffer.append(getHeight());
+ buffer.append(height);
buffer.append("\n\tBit Depth: ");
- buffer.append(getBitDepth());
+ buffer.append(bitDepth);
buffer.append("\n\tColor Type: ");
buffer.append(getColorTypeString());
buffer.append("\n\tCompression Method: ");
- buffer.append(getCompressionMethod());
+ buffer.append(compressionMethod);
buffer.append("\n\tFilter Method: ");
buffer.append(getFilterMethodString());
buffer.append("\n\tInterlace Method: ");
@@ -280,11 +312,10 @@ void contributeToString(StringBuffer buffer) {
}
boolean getMustHavePalette() {
- return getColorType() == COLOR_TYPE_PALETTE;
+ return colorType == COLOR_TYPE_PALETTE;
}
boolean getCanHavePalette() {
- int colorType = getColorType();
return colorType != COLOR_TYPE_GRAYSCALE &&
colorType != COLOR_TYPE_GRAYSCALE_WITH_ALPHA;
}
@@ -294,8 +325,7 @@ boolean getCanHavePalette() {
* and bit depth.
*/
int getBitsPerPixel() {
- int bitDepth = getBitDepth();
- switch (getColorType()) {
+ switch (colorType) {
case COLOR_TYPE_RGB_WITH_ALPHA:
return 4 * bitDepth;
case COLOR_TYPE_RGB:
@@ -316,8 +346,7 @@ int getBitsPerPixel() {
* and bit depth.
*/
int getSwtBitsPerPixel() {
- int bitDepth = getBitDepth();
- switch (getColorType()) {
+ switch (colorType) {
case COLOR_TYPE_RGB_WITH_ALPHA:
case COLOR_TYPE_RGB:
case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
@@ -332,12 +361,12 @@ int getSwtBitsPerPixel() {
}
int getFilterByteOffset() {
- if (getBitDepth() < 8) return 1;
+ if (bitDepth < 8) return 1;
return getBitsPerPixel() / 8;
}
boolean usesDirectColor() {
- switch (getColorType()) {
+ switch (colorType) {
case COLOR_TYPE_GRAYSCALE:
case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
case COLOR_TYPE_RGB:
@@ -349,8 +378,8 @@ boolean usesDirectColor() {
}
PaletteData createGrayscalePalette() {
- int bitDepth = Math.min(getBitDepth(), 8);
- int max = Compatibility.pow2(bitDepth) - 1;
+ int depth = Math.min(bitDepth, 8);
+ int max = (1 << depth) - 1;
int delta = 255 / max;
int gray = 0;
RGB[] rgbs = new RGB[max + 1];
@@ -362,7 +391,7 @@ PaletteData createGrayscalePalette() {
}
PaletteData getPaletteData() {
- switch (getColorType()) {
+ switch (colorType) {
case COLOR_TYPE_GRAYSCALE:
return createGrayscalePalette();
case COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngInputStream.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngInputStream.java
new file mode 100644
index 0000000000..c0fd08e329
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngInputStream.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal.image;
+
+import java.io.*;
+
+public class PngInputStream extends InputStream {
+ PngChunkReader reader;
+ PngChunk chunk;
+ int offset, length;
+
+ final static int DATA_OFFSET = 8;
+
+public PngInputStream(PngIdatChunk chunk, PngChunkReader reader) {
+ this.chunk = chunk;
+ this.reader = reader;
+ length = chunk.getLength();
+ offset = 0;
+}
+
+private boolean checkChunk() throws IOException {
+ while (offset == length) {
+ chunk = reader.readNextChunk();
+ if (chunk == null) throw new IOException();
+ if (chunk.getChunkType() == PngChunk.CHUNK_IEND) return false;
+ if (chunk.getChunkType() != PngChunk.CHUNK_IDAT) throw new IOException();
+ length = chunk.getLength();
+ offset = 0;
+ }
+ return true;
+}
+
+public void close() throws IOException {
+ chunk = null;
+}
+
+public int read() throws IOException {
+ if (chunk == null) throw new IOException();
+ if (offset == length && !checkChunk()) return -1;
+ int b = chunk.reference[DATA_OFFSET + offset] & 0xFF;
+ offset++;
+ return b;
+}
+
+public int read(byte[] b, int off, int len) throws IOException {
+ if (chunk == null) throw new IOException();
+ if (offset == length && !checkChunk()) return -1;
+ len = Math.min(len, length - offset);
+ System.arraycopy(chunk.reference, DATA_OFFSET + offset, b, off, len);
+ offset += len;
+ return len;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngLzBlockReader.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngLzBlockReader.java
index 387529dfaa..d05db3742d 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngLzBlockReader.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngLzBlockReader.java
@@ -1,18 +1,18 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.internal.image;
+import java.io.*;
public class PngLzBlockReader {
- boolean readHeader;
boolean isLastBlock;
byte compressionType;
int uncompressedBytesRemaining;
@@ -57,7 +57,6 @@ public class PngLzBlockReader {
PngLzBlockReader(PngDecodingDataStream stream) {
this.stream = stream;
- readHeader = false;
isLastBlock = false;
}
@@ -65,7 +64,7 @@ void setWindowSize(int windowSize) {
window = new byte[windowSize];
}
-void readNextBlockHeader() {
+void readNextBlockHeader() throws IOException {
isLastBlock = stream.getNextIdatBit() != 0;
compressionType = (byte)(stream.getNextIdatBits(2) & 0xFF);
if (compressionType > 2) stream.error();
@@ -84,7 +83,7 @@ void readNextBlockHeader() {
}
}
-byte getNextByte() {
+byte getNextByte() throws IOException {
if (compressionType == UNCOMPRESSED) {
if (uncompressedBytesRemaining == 0) {
readNextBlockHeader();
@@ -104,7 +103,7 @@ byte getNextByte() {
}
}
-private void assertBlockAtEnd() {
+private void assertBlockAtEnd() throws IOException {
if (compressionType == UNCOMPRESSED) {
if (uncompressedBytesRemaining > 0) stream.error();
} else if (copyBytesRemaining > 0 ||
@@ -113,7 +112,7 @@ private void assertBlockAtEnd() {
stream.error();
}
}
-void assertCompressedDataAtEnd() {
+void assertCompressedDataAtEnd() throws IOException {
assertBlockAtEnd();
while (!isLastBlock) {
readNextBlockHeader();
@@ -121,7 +120,7 @@ void assertCompressedDataAtEnd() {
}
}
-private byte getNextCompressedByte() {
+private byte getNextCompressedByte() throws IOException {
if (copyBytesRemaining > 0) {
byte value = window[copyIndex];
window[windowIndex] = value;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngPlteChunk.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngPlteChunk.java
index d6ceace938..421849b730 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngPlteChunk.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngPlteChunk.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -13,19 +13,33 @@ package org.eclipse.swt.internal.image;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.internal.Compatibility;
class PngPlteChunk extends PngChunk {
+
+ int paletteSize;
+
+PngPlteChunk(PaletteData palette) {
+ super(palette.getRGBs().length * 3);
+ paletteSize = length / 3;
+ setType(TYPE_PLTE);
+ setPaletteData(palette);
+ setCRC(computeCRC());
+}
PngPlteChunk(byte[] reference){
super(reference);
+ paletteSize = length / 3;
+}
+
+int getChunkType() {
+ return CHUNK_PLTE;
}
/**
* Get the number of colors in this palette.
*/
int getPaletteSize() {
- return getLength() / 3;
+ return paletteSize;
}
/**
@@ -35,9 +49,9 @@ int getPaletteSize() {
* does not store the palette data created.
*/
PaletteData getPaletteData() {
- RGB[] rgbs = new RGB[getPaletteSize()];
+ RGB[] rgbs = new RGB[paletteSize];
// int start = DATA_OFFSET;
-// int end = DATA_OFFSET + getLength();
+// int end = DATA_OFFSET + length;
for (int i = 0; i < rgbs.length; i++) {
int offset = DATA_OFFSET + (i * 3);
int red = reference[offset] & 0xFF;
@@ -49,6 +63,20 @@ PaletteData getPaletteData() {
}
/**
+ * Set the data of a PLTE chunk to the colors
+ * stored in the specified PaletteData object.
+ */
+void setPaletteData(PaletteData palette) {
+ RGB[] rgbs = palette.getRGBs();
+ for (int i = 0; i < rgbs.length; i++) {
+ int offset = DATA_OFFSET + (i * 3);
+ reference[offset] = (byte) rgbs[i].red;
+ reference[offset + 1] = (byte) rgbs[i].green;
+ reference[offset + 2] = (byte) rgbs[i].blue;
+ }
+}
+
+/**
* Answer whether the chunk is a valid PLTE chunk.
*/
void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
@@ -57,7 +85,6 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
if (!readState.readIHDR
|| readState.readPLTE
|| readState.readTRNS
- || readState.readBKGD
|| readState.readIDAT
|| readState.readIEND)
{
@@ -69,7 +96,9 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
super.validate(readState, headerChunk);
// Palettes cannot be included in grayscale images.
- if (!headerChunk.getCanHavePalette()) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ //
+ // Note: just ignore the palette.
+// if (!headerChunk.getCanHavePalette()) SWT.error(SWT.ERROR_INVALID_IMAGE);
// Palette chunks' data fields must be event multiples
// of 3. Each 3-byte group represents an RGB value.
@@ -78,17 +107,17 @@ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
// Palettes cannot have more entries than 2^bitDepth
// where bitDepth is the bit depth of the image given
// in the IHDR chunk.
- if (Compatibility.pow2(headerChunk.getBitDepth()) < getPaletteSize()) {
+ if (1 << headerChunk.getBitDepth() < paletteSize) {
SWT.error(SWT.ERROR_INVALID_IMAGE);
}
// Palettes cannot have more than 256 entries.
- if (256 < getPaletteSize()) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ if (256 < paletteSize) SWT.error(SWT.ERROR_INVALID_IMAGE);
}
void contributeToString(StringBuffer buffer) {
buffer.append("\n\tPalette size:");
- buffer.append(getPaletteSize());
+ buffer.append(paletteSize);
}
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngTrnsChunk.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngTrnsChunk.java
index 7a9517439f..d659a677d8 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngTrnsChunk.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngTrnsChunk.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -12,15 +12,30 @@ package org.eclipse.swt.internal.image;
import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
public class PngTrnsChunk extends PngChunk {
static final int TRANSPARENCY_TYPE_PIXEL = 0;
static final int TRANSPARENCY_TYPE_ALPHAS = 1;
+ static final int RGB_DATA_LENGTH = 6;
+PngTrnsChunk(RGB rgb) {
+ super(RGB_DATA_LENGTH);
+ setType(TYPE_tRNS);
+ setInt16(DATA_OFFSET, rgb.red);
+ setInt16(DATA_OFFSET + 2, rgb.green);
+ setInt16(DATA_OFFSET + 4, rgb.blue);
+ setCRC(computeCRC());
+}
+
PngTrnsChunk(byte[] reference){
super(reference);
}
+int getChunkType() {
+ return CHUNK_tRNS;
+}
+
void validateLength(PngIhdrChunk header, PngPlteChunk paletteChunk) {
boolean valid;
switch (header.getColorType()) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFDirectory.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFDirectory.java
index e86cc42eca..da5f84cf1f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFDirectory.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFDirectory.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -571,8 +571,8 @@ void writeEntry(short tag, int type, int count, int value) throws IOException {
void writeHeader() throws IOException {
/* little endian */
- out.writeByte((byte)0x49);
- out.writeByte((byte)0x49);
+ out.write(0x49);
+ out.write(0x49);
/* TIFF identifier */
out.writeShort(42);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java
index 7b522feca9..770b34d40f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFFileFormat.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -64,7 +64,10 @@ ImageData[] loadFromByteStream() {
return images;
}
-void unloadIntoByteStream(ImageData image) {
+void unloadIntoByteStream(ImageLoader loader) {
+ /* We do not currently support writing multi-page tiff,
+ * so we use the first image data in the loader's array. */
+ ImageData image = loader.data[0];
TIFFDirectory directory = new TIFFDirectory(image);
try {
directory.writeToStream(outputStream);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFModifiedHuffmanCodec.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFModifiedHuffmanCodec.java
index 893c81b950..6a62184b43 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFModifiedHuffmanCodec.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFModifiedHuffmanCodec.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFRandomFileAccess.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFRandomFileAccess.java
index 167e31f16b..3d00cdb5ae 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFRandomFileAccess.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/TIFFRandomFileAccess.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java
index 40111a1dc0..0a8b8cc656 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinBMPFileFormat.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -16,9 +16,10 @@ import org.eclipse.swt.graphics.*;
import java.io.*;
final class WinBMPFileFormat extends FileFormat {
+ static final int BMPFileHeaderSize = 14;
+ static final int BMPHeaderFixedSize = 40;
int importantColors;
Point pelsPerMeter = new Point(0, 0);
- public static final int BMPHeaderFixedSize = 40;
/**
* Compress numBytes bytes of image data from src, storing in dest
@@ -321,10 +322,11 @@ int decompressRLE8Data(byte[] src, int numBytes, int stride, byte[] dest, int de
}
boolean isFileFormat(LEDataInputStream stream) {
try {
- byte[] header = new byte[2];
+ byte[] header = new byte[18];
stream.read(header);
stream.unread(header);
- return header[0] == 0x42 && header[1] == 0x4D;
+ int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24);
+ return header[0] == 0x42 && header[1] == 0x4D && infoHeaderSize >= BMPHeaderFixedSize;
} catch (Exception e) {
return false;
}
@@ -387,6 +389,9 @@ ImageData[] loadFromByteStream() {
} catch (Exception e) {
SWT.error(SWT.ERROR_IO, e);
}
+ int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
+ int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
+ int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
PaletteData palette = loadPalette(infoHeader);
if (inputStream.getPosition() < fileHeader[4]) {
// Seek to the specified offset
@@ -402,9 +407,6 @@ ImageData[] loadFromByteStream() {
int xPelsPerMeter = (infoHeader[24] & 0xFF) | ((infoHeader[25] & 0xFF) << 8) | ((infoHeader[26] & 0xFF) << 16) | ((infoHeader[27] & 0xFF) << 24);
int yPelsPerMeter = (infoHeader[28] & 0xFF) | ((infoHeader[29] & 0xFF) << 8) | ((infoHeader[30] & 0xFF) << 16) | ((infoHeader[31] & 0xFF) << 24);
this.pelsPerMeter = new Point(xPelsPerMeter, yPelsPerMeter);
- int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
- int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
- int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
int type = (this.compression == 1 /*BMP_RLE8_COMPRESSION*/) || (this.compression == 2 /*BMP_RLE4_COMPRESSION*/) ? SWT.IMAGE_BMP_RLE : SWT.IMAGE_BMP;
return new ImageData[] {
ImageData.internal_new(
@@ -431,7 +433,7 @@ PaletteData loadPalette(byte[] infoHeader) {
if (depth <= 8) {
int numColors = (infoHeader[32] & 0xFF) | ((infoHeader[33] & 0xFF) << 8) | ((infoHeader[34] & 0xFF) << 16) | ((infoHeader[35] & 0xFF) << 24);
if (numColors == 0) {
- numColors = 1 << ((infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8));
+ numColors = 1 << depth;
} else {
if (numColors > 256)
numColors = 256;
@@ -567,7 +569,8 @@ int unloadDataNoCompression(ImageData image, OutputStream out) {
* Unload a DeviceIndependentImage using Windows .BMP format into the given
* byte stream.
*/
-void unloadIntoByteStream(ImageData image) {
+void unloadIntoByteStream(ImageLoader loader) {
+ ImageData image = loader.data[0];
byte[] rgbs;
int numCols;
if (!((image.depth == 1) || (image.depth == 4) || (image.depth == 8) ||
@@ -590,7 +593,7 @@ void unloadIntoByteStream(ImageData image) {
rgbs = paletteToBytes(pal);
}
// Fill in file header, except for bfsize, which is done later.
- int headersSize = 54;
+ int headersSize = BMPFileHeaderSize + BMPHeaderFixedSize;
int[] fileHeader = new int[5];
fileHeader[0] = 0x4D42; // Signature
fileHeader[1] = 0; // File size - filled in later
@@ -605,10 +608,10 @@ void unloadIntoByteStream(ImageData image) {
// the stream and fill in the details later.
ByteArrayOutputStream out = new ByteArrayOutputStream();
unloadData(image, out, comp);
- byte[] compressedData = out.toByteArray();
+ byte[] data = out.toByteArray();
// Calculate file size
- fileHeader[1] = fileHeader[4] + compressedData.length;
+ fileHeader[1] = fileHeader[4] + data.length;
// Write the headers
try {
@@ -621,13 +624,13 @@ void unloadIntoByteStream(ImageData image) {
SWT.error(SWT.ERROR_IO, e);
}
try {
- outputStream.writeInt(WinBMPFileFormat.BMPHeaderFixedSize);
+ outputStream.writeInt(BMPHeaderFixedSize);
outputStream.writeInt(image.width);
outputStream.writeInt(image.height);
outputStream.writeShort(1);
outputStream.writeShort((short)image.depth);
outputStream.writeInt(comp);
- outputStream.writeInt(compressedData.length);
+ outputStream.writeInt(data.length);
outputStream.writeInt(pelsPerMeter.x);
outputStream.writeInt(pelsPerMeter.y);
outputStream.writeInt(numCols);
@@ -647,7 +650,7 @@ void unloadIntoByteStream(ImageData image) {
// Unload the data
try {
- outputStream.write(compressedData);
+ outputStream.write(data);
} catch (IOException e) {
SWT.error(SWT.ERROR_IO, e);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java
index 6731df96a3..ae06872947 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/WinICOFileFormat.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -17,6 +17,14 @@ import java.io.*;
final class WinICOFileFormat extends FileFormat {
+byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
+ // Destructively bit invert data in the given byte array.
+ for (int i = startIndex; i < endIndex; i++) {
+ data[i] = (byte)(255 - data[i - startIndex]);
+ }
+ return data;
+}
+
static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
if (pad == newPad) return data;
int stride = (width * depth + 7) / 8;
@@ -241,8 +249,8 @@ void unloadIconHeader(ImageData i) {
int offset = headerSize + 6;
int iconSize = iconSize(i);
try {
- outputStream.writeByte((byte)i.width);
- outputStream.writeByte((byte)i.height);
+ outputStream.write(i.width);
+ outputStream.write(i.height);
outputStream.writeShort(i.palette.colors != null ? i.palette.colors.length : 0);
outputStream.writeShort(0);
outputStream.writeShort(0);
@@ -252,7 +260,10 @@ void unloadIconHeader(ImageData i) {
SWT.error(SWT.ERROR_IO, e);
}
}
-void unloadIntoByteStream(ImageData image) {
+void unloadIntoByteStream(ImageLoader loader) {
+ /* We do not currently support writing multi-image ico,
+ * so we use the first image data in the loader's array. */
+ ImageData image = loader.data[0];
if (!isValidIcon(image))
SWT.error(SWT.ERROR_INVALID_IMAGE);
try {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/package.html b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/package.html
index 457687f91b..ab7efd4a18 100755
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/package.html
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/package.html
@@ -1,4 +1,4 @@
-<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/CloneableCompatibility.java b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/CloneableCompatibility.java
index 48e3dcc1e9..78e939108f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/CloneableCompatibility.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/CloneableCompatibility.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java
index ba3b062038..226794e42e 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/Compatibility.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -12,8 +12,11 @@ package org.eclipse.swt.internal;
import java.io.*;
+import java.text.MessageFormat;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
+import java.util.zip.InflaterInputStream;
+
import org.eclipse.swt.SWT;
/**
@@ -121,7 +124,7 @@ public static int floor(int p, int q) {
* @return the closest integer to the rational number p / q
*/
public static int round(int p, int q) {
- return (int)Math.round((float)p / q);
+ return Math.round((float)p / q);
}
/**
@@ -166,6 +169,19 @@ public static OutputStream newFileOutputStream(String filename) throws IOExcepti
}
/**
+ * Create an InflaterInputStream if such things are supported.
+ *
+ * @param stream the input stream
+ * @return a inflater stream or <code>null</code>
+ * @exception IOException
+ *
+ * @since 3.2.1
+ */
+public static InputStream newInflaterInputStream(InputStream stream) throws IOException {
+ return new InflaterInputStream(stream);
+}
+
+/**
* Answers whether the character is a letter.
*
* @param c the character
@@ -272,7 +288,30 @@ public static String getMessage(String key) {
}
return answer;
}
+
+public static String getMessage(String key, Object[] args) {
+ String answer = key;
+ if (key == null || args == null) {
+ SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ }
+ if (msgs == null) {
+ try {
+ msgs = ResourceBundle.getBundle("org.eclipse.swt.internal.SWTMessages"); //$NON-NLS-1$
+ } catch (MissingResourceException ex) {
+ answer = key + " (no resource bundle)"; //$NON-NLS-1$
+ }
+ }
+ if (msgs != null) {
+ try {
+ MessageFormat formatter = new MessageFormat("");
+ formatter.applyPattern(msgs.getString(key));
+ answer = formatter.format(args);
+ } catch (MissingResourceException ex2) {}
+ }
+ return answer;
+}
+
/**
* Interrupt the current thread.
* <p>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventListener.java b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventListener.java
index 35dcb2e14e..f7036a3eb5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventListener.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventListener.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventObject.java b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventObject.java
index ccef4c7df4..92ba54f11d 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventObject.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTEventObject.java
@@ -1,10 +1,10 @@
/*******************************************************************************
- * Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
@@ -27,6 +27,8 @@ import java.util.EventObject;
*/
public class SWTEventObject extends EventObject {
+ static final long serialVersionUID = 3258125873411470903L;
+
/**
* Constructs a new instance of this class.
*
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTMessages.properties b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTMessages.properties
index 9d8fb7dc28..e7fdf88e62 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTMessages.properties
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SWTMessages.properties
@@ -1,10 +1,10 @@
###############################################################################
-# Copyright (c) 2000, 2004 IBM Corporation and others.
+# Copyright (c) 2000, 2005 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Common Public License v1.0
+# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
-# http://www.eclipse.org/legal/cpl-v10.html
-#
+# http://www.eclipse.org/legal/epl-v10.html
+#
# Contributors:
# IBM Corporation - initial API and implementation
###############################################################################
@@ -33,6 +33,7 @@ SWT_NewFont=New Font
SWT_Remove=Remove
SWT_Up=Up
SWT_Down=Down
+SWT_Selection=Selection
SWT_Charset_Western=western
SWT_Charset_EastEuropean=eastern
SWT_Charset_SouthEuropean=southern
@@ -57,9 +58,16 @@ SWT_Charset_ASCII=ASCII
SWT_InputMethods=Input Methods
SWT_Password=Password:
SWT_Username=User Name:
-SWT_Prompt=Prompt
+SWT_Switch=Switch
+SWT_Press=Press
+SWT_Open=Open
SWT_Close=Close
SWT_Minimize=Minimize
SWT_Maximize=Maximize
SWT_Restore=Restore
SWT_ShowList=Show List
+SWT_FileDownload=File Download
+SWT_Download_File=Download: {0}
+SWT_Download_Location=Saving {0} from {1}
+SWT_Download_Started=Downloading...
+SWT_Download_Status=Download: {0,number,integer} KB of {1,number,integer} KB
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SerializableCompatibility.java b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SerializableCompatibility.java
index 38cc0b309c..dd5e66ae4f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SerializableCompatibility.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common_j2se/org/eclipse/swt/internal/SerializableCompatibility.java
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/

Back to the top