package org.eclipse.swt.internal.image; | |
/* | |
* Copyright (c) 2000, 2002 IBM Corp. All rights reserved. | |
* This file is 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 | |
*/ | |
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 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 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 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}; | |
/** | |
* Construct a PNGChunk using the reference bytes | |
* given. | |
*/ | |
PngIhdrChunk(byte[] reference) { | |
super(reference); | |
} | |
/** | |
* Get the image's width in pixels. | |
*/ | |
int getWidth() { | |
return getInt32(WIDTH_DATA_OFFSET); | |
} | |
/** | |
* Set the image's width in pixels. | |
*/ | |
void setWidth(int value) { | |
setInt32(WIDTH_DATA_OFFSET, value); | |
} | |
/** | |
* Get the image's height in pixels. | |
*/ | |
int getHeight() { | |
return getInt32(HEIGHT_DATA_OFFSET); | |
} | |
/** | |
* Set the image's height in pixels. | |
*/ | |
void setHeight(int value) { | |
setInt32(HEIGHT_DATA_OFFSET, value); | |
} | |
/** | |
* Get the image's bit depth. | |
* This is limited to the values 1, 2, 4, 8, or 16. | |
*/ | |
byte getBitDepth() { | |
return reference[BIT_DEPTH_OFFSET]; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* 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 reference[COLOR_TYPE_OFFSET]; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* Get the image's compression method. | |
* This value must be 0. | |
*/ | |
byte getCompressionMethod() { | |
return reference[COMPRESSION_METHOD_OFFSET]; | |
} | |
/** | |
* Set the image's compression method. | |
* This value must be 0. | |
*/ | |
void setCompressionMethod(byte value) { | |
reference[COMPRESSION_METHOD_OFFSET] = value; | |
} | |
/** | |
* Get the image's filter method. | |
* This value must be 0. | |
*/ | |
byte getFilterMethod() { | |
return reference[FILTER_METHOD_OFFSET]; | |
} | |
/** | |
* Set the image's filter method. | |
* This value must be 0. | |
*/ | |
void setFilterMethod(byte value) { | |
reference[FILTER_METHOD_OFFSET] = value; | |
} | |
/** | |
* Get the image's interlace method. | |
* This value is limited to: | |
* 0 - No interlacing used. | |
* 1 - Adam7 interlacing used. | |
*/ | |
byte getInterlaceMethod() { | |
return reference[INTERLACE_METHOD_OFFSET]; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* 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 (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) { | |
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; | |
break; | |
} | |
} | |
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; | |
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 (getColorType()) { | |
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(); | |
} | |
} | |
String getFilterMethodString() { | |
switch (getFilterMethod()) { | |
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 (getInterlaceMethod()) { | |
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(getWidth()); | |
buffer.append("\n\tHeight: "); | |
buffer.append(getHeight()); | |
buffer.append("\n\tBit Depth: "); | |
buffer.append(getBitDepth()); | |
buffer.append("\n\tColor Type: "); | |
buffer.append(getColorTypeString()); | |
buffer.append("\n\tCompression Method: "); | |
buffer.append(getCompressionMethod()); | |
buffer.append("\n\tFilter Method: "); | |
buffer.append(getFilterMethodString()); | |
buffer.append("\n\tInterlace Method: "); | |
buffer.append(getInterlaceMethodString()); | |
} | |
boolean getMustHavePalette() { | |
return getColorType() == COLOR_TYPE_PALETTE; | |
} | |
boolean getCanHavePalette() { | |
int colorType = getColorType(); | |
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() { | |
int bitDepth = getBitDepth(); | |
switch (getColorType()) { | |
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() { | |
int bitDepth = getBitDepth(); | |
switch (getColorType()) { | |
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 (getBitDepth() < 8) return 1; | |
return getBitsPerPixel() / 8; | |
} | |
boolean usesDirectColor() { | |
switch (getColorType()) { | |
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 bitDepth = Math.min(getBitDepth(), 8); | |
int max = Compatibility.pow2(bitDepth) - 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 (getColorType()) { | |
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; | |
} | |
} | |
} |