< prev index next >
src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java
Print this page
*** 696,709 ****
}
readHeader();
/*
! * Optimization: We can skip the remaining metadata if the
! * ignoreMetadata flag is set, and only if this is not a palette
! * image (in that case, we need to read the metadata to get the
! * tRNS chunk, which is needed for the getImageTypes() method).
*/
int colorType = metadata.IHDR_colorType;
if (ignoreMetadata && colorType != PNG_COLOR_PALETTE) {
try {
while (true) {
--- 696,711 ----
}
readHeader();
/*
! * Optimization: We can skip reading metadata if ignoreMetadata
! * flag is set and colorType is not PNG_COLOR_PALETTE. But we need
! * to parse only the tRNS chunk even in the case where IHDR colortype
! * is not PNG_COLOR_PALETTE, because we need tRNS chunk transparent
! * pixel information for PNG_COLOR_RGB while storing the pixel data
! * in decodePass().
*/
int colorType = metadata.IHDR_colorType;
if (ignoreMetadata && colorType != PNG_COLOR_PALETTE) {
try {
while (true) {
*** 715,728 ****
}
int chunkType = stream.readInt();
if (chunkType == IDAT_TYPE) {
! // We've reached the image data
stream.skipBytes(-8);
imageStartPosition = stream.getStreamPosition();
break;
} else {
// Skip the chunk plus the 4 CRC bytes that follow
stream.skipBytes(chunkLength + 4);
}
}
--- 717,739 ----
}
int chunkType = stream.readInt();
if (chunkType == IDAT_TYPE) {
! // We've reached the first IDAT chunk position
stream.skipBytes(-8);
imageStartPosition = stream.getStreamPosition();
+ /*
+ * According to PNG specification tRNS chunk must
+ * precede the first IDAT chunk. So we can stop
+ * reading metadata.
+ */
break;
+ } else if (chunkType == tRNS_TYPE) {
+ parse_tRNS_chunk(chunkLength);
+ // After parsing tRNS chunk we will skip 4 CRC bytes
+ stream.skipBytes(4);
} else {
// Skip the chunk plus the 4 CRC bytes that follow
stream.skipBytes(chunkLength + 4);
}
}
*** 1072,1081 ****
--- 1083,1118 ----
int bitsPerRow = Math.multiplyExact((inputBands * bitDepth), passWidth);
int bytesPerRow = (bitsPerRow + 7) / 8;
int eltsPerRow = (bitDepth == 16) ? bytesPerRow/2 : bytesPerRow;
+ WritableRaster passRow;
+ if (considerTransparentPixel()) {
+ /*
+ * When we have tRNS chunk for image type PNG_COLOR_RGB, we need
+ * extra alpha channel to represent transparency. In getImageTypes()
+ * we create a 4 channel destination image, so we need to calculate
+ * destEltsPerRow and create appropriate Raster.
+ */
+ int destBands = 4;
+ int destBytesPerPixel = (bitDepth == 16) ? 2 : 1;
+ destBytesPerPixel *= destBands;
+ int destBitsPerRow =
+ Math.multiplyExact((destBands * bitDepth), passWidth);
+ int destBytesPerRow = (destBitsPerRow + 7) / 8;
+ int destEltsPerRow =
+ (bitDepth == 16) ? destBytesPerRow/2 : destBytesPerRow;
+
+ // Create a 1-row tall Raster to hold the data
+ passRow = createRaster(passWidth, 1, destBands,
+ destEltsPerRow, bitDepth);
+ } else {
+ // Create a 1-row tall Raster to hold the data
+ passRow = createRaster(passWidth, 1, inputBands,
+ eltsPerRow, bitDepth);
+ }
+
// If no pixels need updating, just skip the input data
if (updateWidth == 0) {
for (int srcY = 0; srcY < passHeight; srcY++) {
// Update count of pixels read
updateImageProgress(passWidth);
*** 1107,1121 ****
byte[] byteData = null;
short[] shortData = null;
byte[] curr = new byte[bytesPerRow];
byte[] prior = new byte[bytesPerRow];
- // Create a 1-row tall Raster to hold the data
- WritableRaster passRow = createRaster(passWidth, 1, inputBands,
- eltsPerRow,
- bitDepth);
-
// Create an array suitable for holding one pixel
int[] ps = passRow.getPixel(0, 0, (int[])null);
DataBuffer dataBuffer = passRow.getDataBuffer();
int type = dataBuffer.getDataType();
--- 1144,1153 ----
*** 1236,1256 ****
default:
throw new IIOException("Unknown row filter type (= " +
filter + ")!");
}
! // Copy data into passRow byte by byte
if (bitDepth < 16) {
System.arraycopy(curr, 0, byteData, 0, bytesPerRow);
} else {
int idx = 0;
for (int j = 0; j < eltsPerRow; j++) {
shortData[j] =
(short)((curr[idx] << 8) | (curr[idx + 1] & 0xff));
idx += 2;
}
}
// True Y position in source
int sourceY = srcY*yStep + yStart;
if ((sourceY >= sourceRegion.y) &&
(sourceY < sourceRegion.y + sourceRegion.height) &&
--- 1268,1345 ----
default:
throw new IIOException("Unknown row filter type (= " +
filter + ")!");
}
! /*
! * Copy data into passRow byte by byte. In case of colortype
! * PNG_COLOR_RGB if we have transparent pixel information from
! * tRNS chunk we need to consider that and store proper information
! * in alpha channel.
! */
! if (considerTransparentPixel()) {
! if (bitDepth < 16) {
! int srcidx = 0;
! int destidx = 0;
! for (int i = 0; i < passWidth; i++) {
! if (curr[srcidx] == (byte)metadata.tRNS_red &&
! curr[srcidx + 1] == (byte)metadata.tRNS_green &&
! curr[srcidx + 2] == (byte)metadata.tRNS_blue)
! {
! byteData[destidx] = curr[srcidx];
! byteData[destidx + 1] = curr[srcidx + 1];
! byteData[destidx + 2] = curr[srcidx + 2];
! byteData[destidx + 3] = (byte)0;
! } else {
! byteData[destidx] = curr[srcidx];
! byteData[destidx + 1] = curr[srcidx + 1];
! byteData[destidx + 2] = curr[srcidx + 2];
! byteData[destidx + 3] = (byte)255;
! }
! srcidx += 3;
! destidx += 4;
! }
! } else {
! int srcidx = 0;
! int destidx = 0;
! for (int i = 0; i < passWidth; i++) {
! short red = (short)
! ((curr[srcidx] << 8) | (curr[srcidx + 1] & 0xff));
! short green = (short)
! ((curr[srcidx + 2] << 8) | (curr[srcidx + 3] & 0xff));
! short blue = (short)
! ((curr[srcidx + 4] << 8) | (curr[srcidx + 5] & 0xff));
! if (red == (short)metadata.tRNS_red &&
! green == (short)metadata.tRNS_green &&
! blue == (short)metadata.tRNS_blue)
! {
! shortData[destidx] = red;
! shortData[destidx + 1] = green;
! shortData[destidx + 2] = blue;
! shortData[destidx + 3] = (short)0;
! } else {
! shortData[destidx] = red;
! shortData[destidx + 1] = green;
! shortData[destidx + 2] = blue;
! shortData[destidx + 3] = (short)65535;
! }
! srcidx += 6;
! destidx += 4;
! }
! }
! } else {
if (bitDepth < 16) {
System.arraycopy(curr, 0, byteData, 0, bytesPerRow);
} else {
int idx = 0;
for (int j = 0; j < eltsPerRow; j++) {
shortData[j] =
(short)((curr[idx] << 8) | (curr[idx + 1] & 0xff));
idx += 2;
}
}
+ }
// True Y position in source
int sourceY = srcY*yStep + yStart;
if ((sourceY >= sourceRegion.y) &&
(sourceY < sourceRegion.y + sourceRegion.height) &&
*** 1420,1432 ****
--- 1509,1528 ----
// At this point the header has been read and we know
// how many bands are in the image, so perform checking
// of the read param.
int colorType = metadata.IHDR_colorType;
+ if (considerTransparentPixel()) {
+ checkReadParamBandSettings(param,
+ 4,
+ theImage.getSampleModel().getNumBands());
+
+ } else {
checkReadParamBandSettings(param,
inputBandsForColorType[colorType],
theImage.getSampleModel().getNumBands());
+ }
clearAbortRequest();
processImageStarted(0);
if (abortRequested()) {
processReadAborted();
*** 1446,1455 ****
--- 1542,1568 ----
inf.end();
}
}
}
+ private boolean considerTransparentPixel(){
+ /*
+ * In case of non-indexed PNG_COLOR_RGB images if we have tRNS chunk,
+ * we need to consider transparent pixel values and store alpha channel
+ * also. If user explicitly provides ImageReadParam with
+ * destinationBands as 3 when we have tRNS chunk, only then we will
+ * ignore tRNS chunk values.
+ */
+ if ((destinationBands == null ||
+ destinationBands.length == 4) &&
+ metadata.tRNS_colorType == PNG_COLOR_RGB)
+ {
+ return true;
+ }
+ return false;
+ }
+
public int getNumImages(boolean allowSearch) throws IIOException {
if (stream == null) {
throw new IllegalStateException("No input source set!");
}
if (seekForwardOnly && allowSearch) {
*** 1512,1522 ****
--- 1625,1646 ----
dataType,
false));
break;
case PNG_COLOR_RGB:
+ readMetadata(); // Need tRNS chunk
+
+ /*
+ * In case of PNG_COLOR_RGB colortype if we have transparent
+ * pixel information in tRNS chunk we create destination
+ * image with 4 channels.
+ */
if (bitDepth == 8) {
+ if (considerTransparentPixel()) {
+ l.add(ImageTypeSpecifier.createFromBufferedImageType(
+ BufferedImage.TYPE_4BYTE_ABGR));
+ }
// some standard types of buffered images
// which can be used as destination
l.add(ImageTypeSpecifier.createFromBufferedImageType(
BufferedImage.TYPE_3BYTE_BGR));
*** 1525,1534 ****
--- 1649,1670 ----
l.add(ImageTypeSpecifier.createFromBufferedImageType(
BufferedImage.TYPE_INT_BGR));
}
+ if (considerTransparentPixel()) {
+ rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+ bandOffsets = new int[4];
+ bandOffsets[0] = 0;
+ bandOffsets[1] = 1;
+ bandOffsets[2] = 2;
+ bandOffsets[3] = 3;
+
+ l.add(ImageTypeSpecifier.
+ createInterleaved(rgb, bandOffsets,
+ dataType, true, false));
+ }
// Component R, G, B
rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
bandOffsets = new int[3];
bandOffsets[0] = 0;
bandOffsets[1] = 1;
< prev index next >