696 } |
696 } |
697 |
697 |
698 readHeader(); |
698 readHeader(); |
699 |
699 |
700 /* |
700 /* |
701 * Optimization: We can skip the remaining metadata if the |
701 * Optimization: We can skip reading metadata if ignoreMetadata |
702 * ignoreMetadata flag is set, and only if this is not a palette |
702 * flag is set and colorType is not PNG_COLOR_PALETTE. However, |
703 * image (in that case, we need to read the metadata to get the |
703 * we parse tRNS chunk to retrieve the transparent color from the |
704 * tRNS chunk, which is needed for the getImageTypes() method). |
704 * metadata. Doing so, helps PNGImageReader to appropriately |
|
705 * identify and set transparent pixels in the decoded image for |
|
706 * colorType PNG_COLOR_RGB and PNG_COLOR_GRAY. |
705 */ |
707 */ |
706 int colorType = metadata.IHDR_colorType; |
708 int colorType = metadata.IHDR_colorType; |
707 if (ignoreMetadata && colorType != PNG_COLOR_PALETTE) { |
709 if (ignoreMetadata && colorType != PNG_COLOR_PALETTE) { |
708 try { |
710 try { |
709 while (true) { |
711 while (true) { |
715 } |
717 } |
716 |
718 |
717 int chunkType = stream.readInt(); |
719 int chunkType = stream.readInt(); |
718 |
720 |
719 if (chunkType == IDAT_TYPE) { |
721 if (chunkType == IDAT_TYPE) { |
720 // We've reached the image data |
722 // We've reached the first IDAT chunk position |
721 stream.skipBytes(-8); |
723 stream.skipBytes(-8); |
722 imageStartPosition = stream.getStreamPosition(); |
724 imageStartPosition = stream.getStreamPosition(); |
|
725 /* |
|
726 * According to PNG specification tRNS chunk must |
|
727 * precede the first IDAT chunk. So we can stop |
|
728 * reading metadata. |
|
729 */ |
723 break; |
730 break; |
|
731 } else if (chunkType == tRNS_TYPE) { |
|
732 parse_tRNS_chunk(chunkLength); |
|
733 // After parsing tRNS chunk we will skip 4 CRC bytes |
|
734 stream.skipBytes(4); |
724 } else { |
735 } else { |
725 // Skip the chunk plus the 4 CRC bytes that follow |
736 // Skip the chunk plus the 4 CRC bytes that follow |
726 stream.skipBytes(chunkLength + 4); |
737 stream.skipBytes(chunkLength + 4); |
727 } |
738 } |
728 } |
739 } |
1264 } |
1275 } |
1265 if (dstY > dstMaxY) { |
1276 if (dstY > dstMaxY) { |
1266 break; |
1277 break; |
1267 } |
1278 } |
1268 |
1279 |
1269 if (useSetRect) { |
1280 /* |
|
1281 * For PNG images of color type PNG_COLOR_RGB or PNG_COLOR_GRAY |
|
1282 * that contain a specific transparent color (given by tRNS |
|
1283 * chunk), we compare the decoded pixel color with the color |
|
1284 * given by tRNS chunk to set the alpha on the destination. |
|
1285 */ |
|
1286 boolean tRNSTransparentPixelPresent = |
|
1287 theImage.getSampleModel().getNumBands() == inputBands + 1 && |
|
1288 metadata.hasTransparentColor(); |
|
1289 if (useSetRect && |
|
1290 !tRNSTransparentPixelPresent) { |
1270 imRas.setRect(updateMinX, dstY, passRow); |
1291 imRas.setRect(updateMinX, dstY, passRow); |
1271 } else { |
1292 } else { |
1272 int newSrcX = srcX; |
1293 int newSrcX = srcX; |
1273 |
1294 |
|
1295 /* |
|
1296 * Create intermediate array to fill the extra alpha |
|
1297 * channel when tRNSTransparentPixelPresent is true. |
|
1298 */ |
|
1299 final int[] temp = new int[inputBands + 1]; |
|
1300 final int opaque = (bitDepth < 16) ? 255 : 65535; |
1274 for (int dstX = updateMinX; |
1301 for (int dstX = updateMinX; |
1275 dstX < updateMinX + updateWidth; |
1302 dstX < updateMinX + updateWidth; |
1276 dstX += updateXStep) { |
1303 dstX += updateXStep) { |
1277 |
1304 |
1278 passRow.getPixel(newSrcX, 0, ps); |
1305 passRow.getPixel(newSrcX, 0, ps); |
1279 if (adjustBitDepths) { |
1306 if (adjustBitDepths) { |
1280 for (int b = 0; b < numBands; b++) { |
1307 for (int b = 0; b < numBands; b++) { |
1281 ps[b] = scale[b][ps[b]]; |
1308 ps[b] = scale[b][ps[b]]; |
1282 } |
1309 } |
1283 } |
1310 } |
1284 imRas.setPixel(dstX, dstY, ps); |
1311 if (tRNSTransparentPixelPresent) { |
|
1312 if (metadata.tRNS_colorType == PNG_COLOR_RGB) { |
|
1313 temp[0] = ps[0]; |
|
1314 temp[1] = ps[1]; |
|
1315 temp[2] = ps[2]; |
|
1316 if (ps[0] == metadata.tRNS_red && |
|
1317 ps[1] == metadata.tRNS_green && |
|
1318 ps[2] == metadata.tRNS_blue) { |
|
1319 temp[3] = 0; |
|
1320 } else { |
|
1321 temp[3] = opaque; |
|
1322 } |
|
1323 } else { |
|
1324 // when tRNS_colorType is PNG_COLOR_GRAY |
|
1325 temp[0] = ps[0]; |
|
1326 if (ps[0] == metadata.tRNS_gray) { |
|
1327 temp[1] = 0; |
|
1328 } else { |
|
1329 temp[1] = opaque; |
|
1330 } |
|
1331 } |
|
1332 imRas.setPixel(dstX, dstY, temp); |
|
1333 } else { |
|
1334 imRas.setPixel(dstX, dstY, ps); |
|
1335 } |
1285 newSrcX += srcXStep; |
1336 newSrcX += srcXStep; |
1286 } |
1337 } |
1287 } |
1338 } |
1288 |
1339 |
1289 processImageUpdate(theImage, |
1340 processImageUpdate(theImage, |
1420 |
1471 |
1421 // At this point the header has been read and we know |
1472 // At this point the header has been read and we know |
1422 // how many bands are in the image, so perform checking |
1473 // how many bands are in the image, so perform checking |
1423 // of the read param. |
1474 // of the read param. |
1424 int colorType = metadata.IHDR_colorType; |
1475 int colorType = metadata.IHDR_colorType; |
1425 checkReadParamBandSettings(param, |
1476 if (theImage.getSampleModel().getNumBands() |
1426 inputBandsForColorType[colorType], |
1477 == inputBandsForColorType[colorType] + 1 |
1427 theImage.getSampleModel().getNumBands()); |
1478 && metadata.hasTransparentColor()) { |
|
1479 checkReadParamBandSettings(param, |
|
1480 inputBandsForColorType[colorType] + 1, |
|
1481 theImage.getSampleModel().getNumBands()); |
|
1482 } else { |
|
1483 checkReadParamBandSettings(param, |
|
1484 inputBandsForColorType[colorType], |
|
1485 theImage.getSampleModel().getNumBands()); |
|
1486 } |
1428 |
1487 |
1429 clearAbortRequest(); |
1488 clearAbortRequest(); |
1430 processImageStarted(0); |
1489 processImageStarted(0); |
1431 if (abortRequested()) { |
1490 if (abortRequested()) { |
1432 processReadAborted(); |
1491 processReadAborted(); |
1504 } else { |
1563 } else { |
1505 dataType = DataBuffer.TYPE_USHORT; |
1564 dataType = DataBuffer.TYPE_USHORT; |
1506 } |
1565 } |
1507 |
1566 |
1508 switch (colorType) { |
1567 switch (colorType) { |
|
1568 /* |
|
1569 * For PNG images of color type PNG_COLOR_RGB or PNG_COLOR_GRAY that |
|
1570 * contain a specific transparent color (given by tRNS chunk), we add |
|
1571 * ImageTypeSpecifier(s) that support transparency to the list of |
|
1572 * supported image types. |
|
1573 */ |
1509 case PNG_COLOR_GRAY: |
1574 case PNG_COLOR_GRAY: |
|
1575 readMetadata(); // Need tRNS chunk |
|
1576 |
|
1577 if (metadata.hasTransparentColor()) { |
|
1578 gray = ColorSpace.getInstance(ColorSpace.CS_GRAY); |
|
1579 bandOffsets = new int[2]; |
|
1580 bandOffsets[0] = 0; |
|
1581 bandOffsets[1] = 1; |
|
1582 l.add(ImageTypeSpecifier.createInterleaved(gray, |
|
1583 bandOffsets, |
|
1584 dataType, |
|
1585 true, |
|
1586 false)); |
|
1587 } |
1510 // Packed grayscale |
1588 // Packed grayscale |
1511 l.add(ImageTypeSpecifier.createGrayscale(bitDepth, |
1589 l.add(ImageTypeSpecifier.createGrayscale(bitDepth, |
1512 dataType, |
1590 dataType, |
1513 false)); |
1591 false)); |
1514 break; |
1592 break; |
1515 |
1593 |
1516 case PNG_COLOR_RGB: |
1594 case PNG_COLOR_RGB: |
|
1595 readMetadata(); // Need tRNS chunk |
|
1596 |
1517 if (bitDepth == 8) { |
1597 if (bitDepth == 8) { |
|
1598 if (metadata.hasTransparentColor()) { |
|
1599 l.add(ImageTypeSpecifier.createFromBufferedImageType( |
|
1600 BufferedImage.TYPE_4BYTE_ABGR)); |
|
1601 } |
1518 // some standard types of buffered images |
1602 // some standard types of buffered images |
1519 // which can be used as destination |
1603 // which can be used as destination |
1520 l.add(ImageTypeSpecifier.createFromBufferedImageType( |
1604 l.add(ImageTypeSpecifier.createFromBufferedImageType( |
1521 BufferedImage.TYPE_3BYTE_BGR)); |
1605 BufferedImage.TYPE_3BYTE_BGR)); |
1522 |
1606 |
1524 BufferedImage.TYPE_INT_RGB)); |
1608 BufferedImage.TYPE_INT_RGB)); |
1525 |
1609 |
1526 l.add(ImageTypeSpecifier.createFromBufferedImageType( |
1610 l.add(ImageTypeSpecifier.createFromBufferedImageType( |
1527 BufferedImage.TYPE_INT_BGR)); |
1611 BufferedImage.TYPE_INT_BGR)); |
1528 |
1612 |
|
1613 } |
|
1614 |
|
1615 if (metadata.hasTransparentColor()) { |
|
1616 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB); |
|
1617 bandOffsets = new int[4]; |
|
1618 bandOffsets[0] = 0; |
|
1619 bandOffsets[1] = 1; |
|
1620 bandOffsets[2] = 2; |
|
1621 bandOffsets[3] = 3; |
|
1622 |
|
1623 l.add(ImageTypeSpecifier. |
|
1624 createInterleaved(rgb, bandOffsets, |
|
1625 dataType, true, false)); |
1529 } |
1626 } |
1530 // Component R, G, B |
1627 // Component R, G, B |
1531 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB); |
1628 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB); |
1532 bandOffsets = new int[3]; |
1629 bandOffsets = new int[3]; |
1533 bandOffsets[0] = 0; |
1630 bandOffsets[0] = 0; |