diff options
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java')
-rwxr-xr-x | bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PNGFileFormat.java | 573 |
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 |