| /******************************************************************************* |
| * 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; |
| } |
| } |
| |
| |
| |
| } |