/******************************************************************************* * 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 org.eclipse.swt.*; import org.eclipse.swt.graphics.*; class PngIhdrChunk extends PngChunk { 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; static final int BIT_DEPTH_OFFSET = DATA_OFFSET + 8; static final int COLOR_TYPE_OFFSET = DATA_OFFSET + 9; static final int COMPRESSION_METHOD_OFFSET = DATA_OFFSET + 10; static final int FILTER_METHOD_OFFSET = DATA_OFFSET + 11; static final int INTERLACE_METHOD_OFFSET = DATA_OFFSET + 12; 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; static final int FILTER_NONE = 0; static final int FILTER_SUB = 1; static final int FILTER_UP = 2; static final int FILTER_AVERAGE = 3; static final int FILTER_PAETH = 4; 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 width; } /** * Set the image's width in pixels. */ void setWidth(int value) { setInt32(WIDTH_DATA_OFFSET, value); width = value; } /** * Get the image's height in pixels. */ int getHeight() { return height; } /** * Set the image's height in pixels. */ void setHeight(int value) { setInt32(HEIGHT_DATA_OFFSET, value); height = value; } /** * Get the image's bit depth. * This is limited to the values 1, 2, 4, 8, or 16. */ byte getBitDepth() { return bitDepth; } /** * Set the image's bit depth. * This is limited to the values 1, 2, 4, 8, or 16. */ void setBitDepth(byte value) { reference[BIT_DEPTH_OFFSET] = value; bitDepth = value; } /** * Get the image's color type. * This is limited to the values: * 0 - Grayscale image. * 2 - RGB triple. * 3 - Palette. * 4 - Grayscale with Alpha channel. * 6 - RGB with Alpha channel. */ byte getColorType() { return colorType; } /** * Set the image's color type. * This is limited to the values: * 0 - Grayscale image. * 2 - RGB triple. * 3 - Palette. * 4 - Grayscale with Alpha channel. * 6 - RGB with Alpha channel. */ void setColorType(byte value) { reference[COLOR_TYPE_OFFSET] = value; colorType = value; } /** * Get the image's compression method. * This value must be 0. */ byte getCompressionMethod() { return compressionMethod; } /** * Set the image's compression method. * This value must be 0. */ void setCompressionMethod(byte value) { reference[COMPRESSION_METHOD_OFFSET] = value; compressionMethod = value; } /** * Get the image's filter method. * This value must be 0. */ byte getFilterMethod() { return filterMethod; } /** * Set the image's filter method. * This value must be 0. */ void setFilterMethod(byte value) { reference[FILTER_METHOD_OFFSET] = value; filterMethod = value; } /** * Get the image's interlace method. * This value is limited to: * 0 - No interlacing used. * 1 - Adam7 interlacing used. */ byte getInterlaceMethod() { return interlaceMethod; } /** * Set the image's interlace method. * This value is limited to: * 0 - No interlacing used. * 1 - Adam7 interlacing used. */ void setInterlaceMethod(byte value) { reference[INTERLACE_METHOD_OFFSET] = value; interlaceMethod = value; } /** * Answer whether the chunk is a valid IHDR chunk. */ void validate(PngFileReadState readState, PngIhdrChunk headerChunk) { // An IHDR chunk is invalid if any other chunk has // been read. if (readState.readIHDR || readState.readPLTE || readState.readIDAT || readState.readIEND) { SWT.error(SWT.ERROR_INVALID_IMAGE); } else { readState.readIHDR = true; } super.validate(readState, headerChunk); 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; for (int i = 0; i < ValidColorTypes.length; i++) { if (ValidColorTypes[i] == colorType) { colorTypeIsValid = true; break; } } if (!colorTypeIsValid) SWT.error(SWT.ERROR_INVALID_IMAGE); boolean bitDepthIsValid = false; for (int i = 0; i < ValidBitDepths.length; i++) { if (ValidBitDepths[i] == bitDepth) { bitDepthIsValid = true; break; } } if (!bitDepthIsValid) SWT.error(SWT.ERROR_INVALID_IMAGE); if ((colorType == COLOR_TYPE_RGB || colorType == COLOR_TYPE_RGB_WITH_ALPHA || colorType == COLOR_TYPE_GRAYSCALE_WITH_ALPHA) && bitDepth < 8) { SWT.error(SWT.ERROR_INVALID_IMAGE); } if (colorType == COLOR_TYPE_PALETTE && bitDepth > 8) { SWT.error(SWT.ERROR_INVALID_IMAGE); } } String getColorTypeString() { 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 - " + colorType; } } String getFilterMethodString() { switch (filterMethod) { case FILTER_NONE: return "None"; case FILTER_SUB: return "Sub"; case FILTER_UP: return "Up"; case FILTER_AVERAGE: return "Average"; case FILTER_PAETH: return "Paeth"; default: return "Unknown"; } } String getInterlaceMethodString() { switch (interlaceMethod) { case INTERLACE_METHOD_NONE: return "Not Interlaced"; case INTERLACE_METHOD_ADAM7: return "Interlaced - ADAM7"; default: return "Unknown"; } } void contributeToString(StringBuffer buffer) { buffer.append("\n\tWidth: "); buffer.append(width); buffer.append("\n\tHeight: "); buffer.append(height); buffer.append("\n\tBit Depth: "); buffer.append(bitDepth); buffer.append("\n\tColor Type: "); buffer.append(getColorTypeString()); buffer.append("\n\tCompression Method: "); buffer.append(compressionMethod); buffer.append("\n\tFilter Method: "); buffer.append(getFilterMethodString()); buffer.append("\n\tInterlace Method: "); buffer.append(getInterlaceMethodString()); } boolean getMustHavePalette() { return colorType == COLOR_TYPE_PALETTE; } boolean getCanHavePalette() { return colorType != COLOR_TYPE_GRAYSCALE && colorType != COLOR_TYPE_GRAYSCALE_WITH_ALPHA; } /** * Answer the pixel size in bits based on the color type * and bit depth. */ int getBitsPerPixel() { switch (colorType) { case COLOR_TYPE_RGB_WITH_ALPHA: return 4 * bitDepth; case COLOR_TYPE_RGB: return 3 * bitDepth; case COLOR_TYPE_GRAYSCALE_WITH_ALPHA: return 2 * bitDepth; case COLOR_TYPE_GRAYSCALE: case COLOR_TYPE_PALETTE: return bitDepth; default: SWT.error(SWT.ERROR_INVALID_IMAGE); return 0; } } /** * Answer the pixel size in bits based on the color type * and bit depth. */ int getSwtBitsPerPixel() { switch (colorType) { case COLOR_TYPE_RGB_WITH_ALPHA: case COLOR_TYPE_RGB: case COLOR_TYPE_GRAYSCALE_WITH_ALPHA: return 24; case COLOR_TYPE_GRAYSCALE: case COLOR_TYPE_PALETTE: return Math.min(bitDepth, 8); default: SWT.error(SWT.ERROR_INVALID_IMAGE); return 0; } } int getFilterByteOffset() { if (bitDepth < 8) return 1; return getBitsPerPixel() / 8; } boolean usesDirectColor() { switch (colorType) { case COLOR_TYPE_GRAYSCALE: case COLOR_TYPE_GRAYSCALE_WITH_ALPHA: case COLOR_TYPE_RGB: case COLOR_TYPE_RGB_WITH_ALPHA: return true; default: return false; } } PaletteData createGrayscalePalette() { int depth = Math.min(bitDepth, 8); int max = (1 << depth) - 1; int delta = 255 / max; int gray = 0; RGB[] rgbs = new RGB[max + 1]; for (int i = 0; i <= max; i++) { rgbs[i] = new RGB(gray, gray, gray); gray += delta; } return new PaletteData(rgbs); } PaletteData getPaletteData() { switch (colorType) { case COLOR_TYPE_GRAYSCALE: return createGrayscalePalette(); case COLOR_TYPE_GRAYSCALE_WITH_ALPHA: case COLOR_TYPE_RGB: case COLOR_TYPE_RGB_WITH_ALPHA: return new PaletteData(0xFF0000, 0xFF00, 0xFF); default: return null; } } }