< 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 >