Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java')
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java573
1 files changed, 0 insertions, 573 deletions
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
deleted file mode 100755
index 205d585d2b..0000000000
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java
+++ /dev/null
@@ -1,573 +0,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/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.*;
-import org.eclipse.swt.internal.*;
-
-final class PNGFileFormat extends FileFormat {
- static final int SIGNATURE_LENGTH = 8;
- static final int PRIME = 65521;
- PngIhdrChunk headerChunk;
- PngPlteChunk paletteChunk;
- ImageData imageData;
- byte[] data;
- byte[] alphaPalette;
- byte headerByte1;
- byte headerByte2;
- int adler;
-
-/**
- * Skip over signature data. This has already been
- * verified in isFileFormat().
- */
-void readSignature() throws IOException {
- byte[] signature = new byte[SIGNATURE_LENGTH];
- inputStream.read(signature);
-}
-/**
- * Load the PNG image from the byte stream.
- */
-ImageData[] loadFromByteStream() {
- try {
- readSignature();
- PngChunkReader chunkReader = new PngChunkReader(inputStream);
- headerChunk = chunkReader.getIhdrChunk();
- 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(
- width,
- height,
- headerChunk.getSwtBitsPerPixel(),
- new PaletteData(0, 0, 0),
- 4,
- data,
- 0,
- null,
- null,
- -1,
- -1,
- SWT.IMAGE_PNG,
- 0,
- 0,
- 0,
- 0);
-
- if (headerChunk.usesDirectColor()) {
- imageData.palette = headerChunk.getPaletteData();
- }
-
- // Read and process chunks until the IEND chunk is encountered.
- while (chunkReader.hasMoreChunks()) {
- readNextChunk(chunkReader);
- }
-
- return new ImageData[] {imageData};
- } catch (IOException e) {
- SWT.error(SWT.ERROR_INVALID_IMAGE);
- return null;
- }
-}
-/**
- * Read and handle the next chunk of data from the
- * PNG file.
- */
-void readNextChunk(PngChunkReader chunkReader) throws IOException {
- PngChunk chunk = chunkReader.readNextChunk();
- switch (chunk.getChunkType()) {
- case PngChunk.CHUNK_IEND:
- break;
- case PngChunk.CHUNK_PLTE:
- if (!headerChunk.usesDirectColor()) {
- paletteChunk = (PngPlteChunk) chunk;
- imageData.palette = paletteChunk.getPaletteData();
- }
- break;
- case PngChunk.CHUNK_tRNS:
- PngTrnsChunk trnsChunk = (PngTrnsChunk) chunk;
- if (trnsChunk.getTransparencyType(headerChunk) ==
- PngTrnsChunk.TRANSPARENCY_TYPE_PIXEL)
- {
- imageData.transparentPixel =
- trnsChunk.getSwtTransparentPixel(headerChunk);
- } else {
- alphaPalette = trnsChunk.getAlphaValues(headerChunk, paletteChunk);
- int transparentCount = 0, transparentPixel = -1;
- for (int i = 0; i < alphaPalette.length; i++) {
- if ((alphaPalette[i] & 0xFF) != 255) {
- transparentCount++;
- transparentPixel = i;
- }
- }
- if (transparentCount == 0) {
- alphaPalette = null;
- } else if (transparentCount == 1 && alphaPalette[transparentPixel] == 0) {
- alphaPalette = null;
- imageData.transparentPixel = transparentPixel;
- }
- }
- break;
- case PngChunk.CHUNK_IDAT:
- if (chunkReader.readPixelData()) {
- // All IDAT chunks in an image file must be
- // sequential. If the pixel data has already
- // been read and another IDAT block is encountered,
- // then this is an invalid image.
- SWT.error(SWT.ERROR_INVALID_IMAGE);
- } else {
- // Read in the pixel data for the image. This should
- // go through all the image's IDAT chunks.
- PngIdatChunk dataChunk = (PngIdatChunk) chunk;
- readPixelData(dataChunk, chunkReader);
- }
- break;
- default:
- if (chunk.isCritical()) {
- // All critical chunks must be supported.
- 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 {
- byte[] signature = new byte[SIGNATURE_LENGTH];
- stream.read(signature);
- stream.unread(signature);
- if ((signature[0] & 0xFF) != 137) return false; //137
- if ((signature[1] & 0xFF) != 80) return false; //P
- if ((signature[2] & 0xFF) != 78) return false; //N
- if ((signature[3] & 0xFF) != 71) return false; //G
- if ((signature[4] & 0xFF) != 13) return false; //<RETURN>
- if ((signature[5] & 0xFF) != 10) return false; //<LINEFEED>
- if ((signature[6] & 0xFF) != 26) return false; //<CTRL/Z>
- if ((signature[7] & 0xFF) != 10) return false; //<LINEFEED>
- return true;
- } catch (Exception e) {
- return false;
- }
-}
-/**
- * SWT does not support 16-bit depths. If this image uses
- * 16-bit depths, convert the data to an 8-bit depth.
- */
-byte[] validateBitDepth(byte[] data) {
- if (headerChunk.getBitDepth() > 8) {
- byte[] result = new byte[data.length / 2];
- compress16BitDepthTo8BitDepth(data, 0, result, 0, result.length);
- return result;
- } else {
- return data;
- }
-}
-/**
- * SWT does not support greyscale as a color type. For
- * plain grayscale, we create a palette. For Grayscale
- * with Alpha, however, we need to convert the pixels
- * to use RGB values.
- * Note: This method assumes that the bit depth of the
- * data has already been restricted to 8 or less.
- */
-void setPixelData(byte[] data, ImageData imageData) {
- switch (headerChunk.getColorType()) {
- case PngIhdrChunk.COLOR_TYPE_GRAYSCALE_WITH_ALPHA:
- {
- int width = imageData.width;
- int height = imageData.height;
- int destBytesPerLine = imageData.bytesPerLine;
- /*
- * If the image uses 16-bit depth, it is converted
- * to an 8-bit depth image.
- */
- int srcBytesPerLine = getAlignedBytesPerRow();
- if (headerChunk.getBitDepth() > 8) srcBytesPerLine /= 2;
-
- byte[] rgbData = new byte[destBytesPerLine * height];
- byte[] alphaData = new byte[width * height];
- for (int y = 0; y < height; y++) {
- int srcIndex = srcBytesPerLine * y;
- int destIndex = destBytesPerLine * y;
- int destAlphaIndex = width * y;
- for (int x = 0; x < width; x++) {
- byte grey = data[srcIndex];
- byte alpha = data[srcIndex + 1];
- rgbData[destIndex + 0] = grey;
- rgbData[destIndex + 1] = grey;
- rgbData[destIndex + 2] = grey;
- alphaData[destAlphaIndex] = alpha;
- srcIndex += 2;
- destIndex += 3;
- destAlphaIndex++;
- }
- }
- imageData.data = rgbData;
- imageData.alphaData = alphaData;
- break;
- }
- case PngIhdrChunk.COLOR_TYPE_RGB_WITH_ALPHA:
- {
- int width = imageData.width;
- int height = imageData.height;
- int destBytesPerLine = imageData.bytesPerLine;
- int srcBytesPerLine = getAlignedBytesPerRow();
- /*
- * If the image uses 16-bit depth, it is converted
- * to an 8-bit depth image.
- */
- if (headerChunk.getBitDepth() > 8) srcBytesPerLine /= 2;
-
- byte[] rgbData = new byte[destBytesPerLine * height];
- byte[] alphaData = new byte[width * height];
- for (int y = 0; y < height; y++) {
- int srcIndex = srcBytesPerLine * y;
- int destIndex = destBytesPerLine * y;
- int destAlphaIndex = width * y;
- for (int x = 0; x < width; x++) {
- rgbData[destIndex + 0] = data[srcIndex + 0];
- rgbData[destIndex + 1] = data[srcIndex + 1];
- rgbData[destIndex + 2] = data[srcIndex + 2];
- alphaData[destAlphaIndex] = data[srcIndex + 3];
- srcIndex += 4;
- destIndex += 3;
- destAlphaIndex++;
- }
- }
- imageData.data = rgbData;
- imageData.alphaData = alphaData;
- break;
- }
- case PngIhdrChunk.COLOR_TYPE_RGB:
- imageData.data = data;
- break;
- case PngIhdrChunk.COLOR_TYPE_PALETTE:
- imageData.data = data;
- if (alphaPalette != null) {
- int size = imageData.width * imageData.height;
- byte[] alphaData = new byte[size];
- byte[] pixelData = new byte[size];
- imageData.getPixels(0, 0, size, pixelData, 0);
- for (int i = 0; i < pixelData.length; i++) {
- alphaData[i] = alphaPalette[pixelData[i] & 0xFF];
- }
- imageData.alphaData = alphaData;
- }
- break;
- default:
- imageData.data = data;
- break;
- }
-}
-/**
- * PNG supports some color types and bit depths that are
- * unsupported by SWT. If the image uses an unsupported
- * color type (either of the gray scale types) or bit
- * depth (16), convert the data to an SWT-supported
- * format. Then assign the data into the ImageData given.
- */
-void setImageDataValues(byte[] data, ImageData imageData) {
- byte[] result = validateBitDepth(data);
- setPixelData(result, imageData);
-}
-/**
- * Read the image data from the data stream. This must handle
- * decoding the data, filtering, and interlacing.
- */
-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(stream);
- } else {
- readInterlacedImage(stream);
- }
- /*
- * 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.
- */
-int getAlignedBytesPerRow() {
- return ((getBytesPerRow(headerChunk.getWidth()) + 3) / 4) * 4;
-}
-/**
- * Answer the number of bytes in each row of the image
- * data. Each PNG row is byte-aligned, so images with bit
- * depths less than a byte may have unused bits at the
- * end of each row. The value of these bits is undefined.
- */
-int getBytesPerRow() {
- return getBytesPerRow(headerChunk.getWidth());
-}
-/**
- * Answer the number of bytes needed to represent a pixel.
- * This value depends on the image's color type and bit
- * depth.
- * Note that this method rounds up if an image's pixel size
- * isn't byte-aligned.
- */
-int getBytesPerPixel() {
- int bitsPerPixel = headerChunk.getBitsPerPixel();
- return (bitsPerPixel + 7) / 8;
-}
-/**
- * Answer the number of bytes in a row of the given pixel
- * width. Each row is byte-aligned, so images with bit
- * depths less than a byte may have unused bits at the
- * end of each row. The value of these bits is undefined.
- */
-int getBytesPerRow(int rowWidthInPixels) {
- int bitsPerPixel = headerChunk.getBitsPerPixel();
- int bitsPerRow = bitsPerPixel * rowWidthInPixels;
- int bitsPerByte = 8;
- return (bitsPerRow + (bitsPerByte - 1)) / bitsPerByte;
-}
-/**
- * 1. Read one of the seven frames of interlaced data.
- * 2. Update the imageData.
- * 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) throws IOException
-{
- int width = headerChunk.getWidth();
- int alignedBytesPerRow = getAlignedBytesPerRow();
- int height = headerChunk.getHeight();
- if (startRow >= height || startColumn >= width) return;
-
- int pixelsPerRow = (width - startColumn + columnInterval - 1) / columnInterval;
- int bytesPerRow = getBytesPerRow(pixelsPerRow);
- byte[] row1 = new byte[bytesPerRow];
- byte[] row2 = new byte[bytesPerRow];
- byte[] currentRow = row1;
- byte[] lastRow = row2;
- for (int row = startRow; row < height; row += rowInterval) {
- 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) {
- int bytesPerPixel = getBytesPerPixel();
- int dataOffset = (row * alignedBytesPerRow) + (startColumn * bytesPerPixel);
- for (int rowOffset = 0; rowOffset < currentRow.length; rowOffset += bytesPerPixel) {
- for (int byteOffset = 0; byteOffset < bytesPerPixel; byteOffset++) {
- data[dataOffset + byteOffset] = currentRow[rowOffset + byteOffset];
- }
- dataOffset += (columnInterval * bytesPerPixel);
- }
- } else {
- int bitsPerPixel = headerChunk.getBitDepth();
- int pixelsPerByte = 8 / bitsPerPixel;
- int column = startColumn;
- int rowBase = row * alignedBytesPerRow;
- int valueMask = 0;
- for (int i = 0; i < bitsPerPixel; i++) {
- valueMask <<= 1;
- valueMask |= 1;
- }
- int maxShift = 8 - bitsPerPixel;
- for (int byteOffset = 0; byteOffset < currentRow.length; byteOffset++) {
- for (int bitOffset = maxShift; bitOffset >= 0; bitOffset -= bitsPerPixel) {
- if (column < width) {
- int dataOffset = rowBase + (column * bitsPerPixel / 8);
- int value = (currentRow[byteOffset] >> bitOffset) & valueMask;
- int dataShift = maxShift - (bitsPerPixel * (column % pixelsPerByte));
- data[dataOffset] |= value << dataShift;
- }
- column += columnInterval;
- }
- }
- }
- currentRow = (currentRow == row1) ? row2 : row1;
- lastRow = (lastRow == row1) ? row2 : row1;
- }
- setImageDataValues(data, imageData);
- fireInterlacedFrameEvent(frameCount);
-}
-/**
- * Read the pixel data for an interlaced image from the
- * data stream.
- */
-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
- * frame has been loaded.
- * finalFrame should be true if the image has finished
- * loading, false if there are more frames to come.
- */
-void fireInterlacedFrameEvent(int frameCount) {
- if (loader.hasListeners()) {
- ImageData image = (ImageData) imageData.clone();
- boolean finalFrame = frameCount == 6;
- loader.notifyListeners(new ImageLoaderEvent(loader, image, frameCount, finalFrame));
- }
-}
-/**
- * Read the pixel data for a non-interlaced image from the
- * data stream.
- * Update the imageData to reflect the new data.
- */
-void readNonInterlacedImage(InputStream inputStream) throws IOException {
- int dataOffset = 0;
- int alignedBytesPerRow = getAlignedBytesPerRow();
- int bytesPerRow = getBytesPerRow();
- byte[] row1 = new byte[bytesPerRow];
- byte[] row2 = new byte[bytesPerRow];
- byte[] currentRow = row1;
- byte[] lastRow = row2;
- 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);
- dataOffset += alignedBytesPerRow;
- currentRow = (currentRow == row1) ? row2 : row1;
- lastRow = (lastRow == row1) ? row2 : row1;
- }
- setImageDataValues(data, imageData);
-}
-/**
- * SWT does not support 16-bit depth color formats.
- * Convert the 16-bit data to 8-bit data.
- * The correct way to do this is to multiply each
- * 16 bit value by the value:
- * (2^8 - 1) / (2^16 - 1).
- * The fast way to do this is just to drop the low
- * byte of the 16-bit value.
- */
-static void compress16BitDepthTo8BitDepth(
- byte[] source,
- int sourceOffset,
- byte[] destination,
- int destinationOffset,
- int numberOfValues)
-{
- //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1);
- for (int i = 0; i < numberOfValues; i++) {
- int sourceIndex = sourceOffset + (2 * i);
- int destinationIndex = destinationOffset + i;
- //int value = (source[sourceIndex] << 8) | source[sourceIndex + 1];
- //byte compressedValue = (byte)(value * multiplier);
- byte compressedValue = source[sourceIndex];
- destination[destinationIndex] = compressedValue;
- }
-}
-/**
- * SWT does not support 16-bit depth color formats.
- * Convert the 16-bit data to 8-bit data.
- * The correct way to do this is to multiply each
- * 16 bit value by the value:
- * (2^8 - 1) / (2^16 - 1).
- * The fast way to do this is just to drop the low
- * byte of the 16-bit value.
- */
-static int compress16BitDepthTo8BitDepth(int value) {
- //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1);
- //byte compressedValue = (byte)(value * multiplier);
- return value >> 8;
-}
-/**
- * PNG supports four filtering types. These types are applied
- * per row of image data. This method unfilters the given row
- * based on the filterType.
- */
-void filterRow(byte[] row, byte[] previousRow, int filterType) {
- int byteOffset = headerChunk.getFilterByteOffset();
- switch (filterType) {
- case PngIhdrChunk.FILTER_NONE:
- break;
- case PngIhdrChunk.FILTER_SUB:
- for (int i = byteOffset; i < row.length; i++) {
- int current = row[i] & 0xFF;
- int left = row[i - byteOffset] & 0xFF;
- row[i] = (byte)((current + left) & 0xFF);
- }
- break;
- case PngIhdrChunk.FILTER_UP:
- for (int i = 0; i < row.length; i++) {
- int current = row[i] & 0xFF;
- int above = previousRow[i] & 0xFF;
- row[i] = (byte)((current + above) & 0xFF);
- }
- break;
- case PngIhdrChunk.FILTER_AVERAGE:
- for (int i = 0; i < row.length; i++) {
- int left = (i < byteOffset) ? 0 : row[i - byteOffset] & 0xFF;
- int above = previousRow[i] & 0xFF;
- int current = row[i] & 0xFF;
- row[i] = (byte)((current + ((left + above) / 2)) & 0xFF);
- }
- break;
- case PngIhdrChunk.FILTER_PAETH:
- for (int i = 0; i < row.length; i++) {
- int left = (i < byteOffset) ? 0 : row[i - byteOffset] & 0xFF;
- int aboveLeft = (i < byteOffset) ? 0 : previousRow[i - byteOffset] & 0xFF;
- int above = previousRow[i] & 0xFF;
-
- int a = Math.abs(above - aboveLeft);
- int b = Math.abs(left - aboveLeft);
- int c = Math.abs(left - aboveLeft + above - aboveLeft);
-
- int preductor = 0;
- if (a <= b && a <= c) {
- preductor = left;
- } else if (b <= c) {
- preductor = above;
- } else {
- preductor = aboveLeft;
- }
-
- int currentValue = row[i] & 0xFF;
- row[i] = (byte) ((currentValue + preductor) & 0xFF);
- }
- break;
- }
-}
-
-} \ No newline at end of file

Back to the top