681 stream.readFully(b);
682 metadata.zTXt_text.add(new String(inflate(b), "ISO-8859-1"));
683
684 // Check if the text chunk contains image creation time
685 if (keyword.equals(PNGMetadata.tEXt_creationTimeKey)) {
686 // Update Standard/Document/ImageCreationTime from text chunk
687 int index = metadata.zTXt_text.size() - 1;
688 metadata.decodeImageCreationTimeFromTextChunk(
689 metadata.zTXt_text.listIterator(index));
690 }
691 }
692
693 private void readMetadata() throws IIOException {
694 if (gotMetadata) {
695 return;
696 }
697
698 readHeader();
699
700 /*
701 * Optimization: We can skip the remaining metadata if the
702 * ignoreMetadata flag is set, and only if this is not a palette
703 * image (in that case, we need to read the metadata to get the
704 * tRNS chunk, which is needed for the getImageTypes() method).
705 */
706 int colorType = metadata.IHDR_colorType;
707 if (ignoreMetadata && colorType != PNG_COLOR_PALETTE) {
708 try {
709 while (true) {
710 int chunkLength = stream.readInt();
711
712 // verify the chunk length first
713 if (chunkLength < 0 || chunkLength + 4 < 0) {
714 throw new IIOException("Invalid chunk length " + chunkLength);
715 }
716
717 int chunkType = stream.readInt();
718
719 if (chunkType == IDAT_TYPE) {
720 // We've reached the image data
721 stream.skipBytes(-8);
722 imageStartPosition = stream.getStreamPosition();
723 break;
724 } else {
725 // Skip the chunk plus the 4 CRC bytes that follow
726 stream.skipBytes(chunkLength + 4);
727 }
728 }
729 } catch (IOException e) {
730 throw new IIOException("Error skipping PNG metadata", e);
731 }
732
733 gotMetadata = true;
734 return;
735 }
736
737 try {
738 loop: while (true) {
739 int chunkLength = stream.readInt();
740 int chunkType = stream.readInt();
741 int chunkCRC;
742
743 // verify the chunk length
1249 idx += 2;
1250 }
1251 }
1252
1253 // True Y position in source
1254 int sourceY = srcY*yStep + yStart;
1255 if ((sourceY >= sourceRegion.y) &&
1256 (sourceY < sourceRegion.y + sourceRegion.height) &&
1257 (((sourceY - sourceRegion.y) %
1258 sourceYSubsampling) == 0)) {
1259
1260 int dstY = destinationOffset.y +
1261 (sourceY - sourceRegion.y)/sourceYSubsampling;
1262 if (dstY < dstMinY) {
1263 continue;
1264 }
1265 if (dstY > dstMaxY) {
1266 break;
1267 }
1268
1269 if (useSetRect) {
1270 imRas.setRect(updateMinX, dstY, passRow);
1271 } else {
1272 int newSrcX = srcX;
1273
1274 for (int dstX = updateMinX;
1275 dstX < updateMinX + updateWidth;
1276 dstX += updateXStep) {
1277
1278 passRow.getPixel(newSrcX, 0, ps);
1279 if (adjustBitDepths) {
1280 for (int b = 0; b < numBands; b++) {
1281 ps[b] = scale[b][ps[b]];
1282 }
1283 }
1284 imRas.setPixel(dstX, dstY, ps);
1285 newSrcX += srcXStep;
1286 }
1287 }
1288
1289 processImageUpdate(theImage,
1290 updateMinX, dstY,
1291 updateWidth, 1,
1292 updateXStep, updateYStep,
1293 destinationBands);
1294 }
1295 }
1296
1297 processPassComplete(theImage);
1298 }
1299
1300 private void decodeImage()
1301 throws IOException, IIOException {
1302 int width = metadata.IHDR_width;
1303 int height = metadata.IHDR_height;
1304
1405 * the level of application, so we will not try to estimate
1406 * the required amount of the memory and/or handle OOM in
1407 * any way.
1408 */
1409 theImage = getDestination(param,
1410 getImageTypes(0),
1411 width,
1412 height);
1413
1414 Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1415 sourceRegion = new Rectangle(0, 0, 0, 0);
1416 computeRegions(param, width, height,
1417 theImage,
1418 sourceRegion, destRegion);
1419 destinationOffset.setLocation(destRegion.getLocation());
1420
1421 // At this point the header has been read and we know
1422 // how many bands are in the image, so perform checking
1423 // of the read param.
1424 int colorType = metadata.IHDR_colorType;
1425 checkReadParamBandSettings(param,
1426 inputBandsForColorType[colorType],
1427 theImage.getSampleModel().getNumBands());
1428
1429 clearAbortRequest();
1430 processImageStarted(0);
1431 if (abortRequested()) {
1432 processReadAborted();
1433 } else {
1434 decodeImage();
1435 if (abortRequested()) {
1436 processReadAborted();
1437 } else {
1438 processImageComplete();
1439 }
1440 }
1441
1442 } catch (IOException e) {
1443 throw new IIOException("Error reading PNG image data", e);
1444 } finally {
1445 if (inf != null) {
1446 inf.end();
1447 }
1489 readHeader();
1490
1491 ArrayList<ImageTypeSpecifier> l =
1492 new ArrayList<ImageTypeSpecifier>(1);
1493
1494 ColorSpace rgb;
1495 ColorSpace gray;
1496 int[] bandOffsets;
1497
1498 int bitDepth = metadata.IHDR_bitDepth;
1499 int colorType = metadata.IHDR_colorType;
1500
1501 int dataType;
1502 if (bitDepth <= 8) {
1503 dataType = DataBuffer.TYPE_BYTE;
1504 } else {
1505 dataType = DataBuffer.TYPE_USHORT;
1506 }
1507
1508 switch (colorType) {
1509 case PNG_COLOR_GRAY:
1510 // Packed grayscale
1511 l.add(ImageTypeSpecifier.createGrayscale(bitDepth,
1512 dataType,
1513 false));
1514 break;
1515
1516 case PNG_COLOR_RGB:
1517 if (bitDepth == 8) {
1518 // some standard types of buffered images
1519 // which can be used as destination
1520 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1521 BufferedImage.TYPE_3BYTE_BGR));
1522
1523 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1524 BufferedImage.TYPE_INT_RGB));
1525
1526 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1527 BufferedImage.TYPE_INT_BGR));
1528
1529 }
1530 // Component R, G, B
1531 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
1532 bandOffsets = new int[3];
1533 bandOffsets[0] = 0;
1534 bandOffsets[1] = 1;
1535 bandOffsets[2] = 2;
1536 l.add(ImageTypeSpecifier.createInterleaved(rgb,
1537 bandOffsets,
1538 dataType,
1539 false,
1540 false));
1541 break;
1542
1543 case PNG_COLOR_PALETTE:
1544 readMetadata(); // Need tRNS chunk
1545
1546 /*
1547 * The PLTE chunk spec says:
1548 *
|
681 stream.readFully(b);
682 metadata.zTXt_text.add(new String(inflate(b), "ISO-8859-1"));
683
684 // Check if the text chunk contains image creation time
685 if (keyword.equals(PNGMetadata.tEXt_creationTimeKey)) {
686 // Update Standard/Document/ImageCreationTime from text chunk
687 int index = metadata.zTXt_text.size() - 1;
688 metadata.decodeImageCreationTimeFromTextChunk(
689 metadata.zTXt_text.listIterator(index));
690 }
691 }
692
693 private void readMetadata() throws IIOException {
694 if (gotMetadata) {
695 return;
696 }
697
698 readHeader();
699
700 /*
701 * Optimization: We can skip reading metadata if ignoreMetadata
702 * flag is set and colorType is not PNG_COLOR_PALETTE. However,
703 * we parse tRNS chunk to retrieve the transparent color from the
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.
707 */
708 int colorType = metadata.IHDR_colorType;
709 if (ignoreMetadata && colorType != PNG_COLOR_PALETTE) {
710 try {
711 while (true) {
712 int chunkLength = stream.readInt();
713
714 // verify the chunk length first
715 if (chunkLength < 0 || chunkLength + 4 < 0) {
716 throw new IIOException("Invalid chunk length " + chunkLength);
717 }
718
719 int chunkType = stream.readInt();
720
721 if (chunkType == IDAT_TYPE) {
722 // We've reached the first IDAT chunk position
723 stream.skipBytes(-8);
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 */
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);
735 } else {
736 // Skip the chunk plus the 4 CRC bytes that follow
737 stream.skipBytes(chunkLength + 4);
738 }
739 }
740 } catch (IOException e) {
741 throw new IIOException("Error skipping PNG metadata", e);
742 }
743
744 gotMetadata = true;
745 return;
746 }
747
748 try {
749 loop: while (true) {
750 int chunkLength = stream.readInt();
751 int chunkType = stream.readInt();
752 int chunkCRC;
753
754 // verify the chunk length
1260 idx += 2;
1261 }
1262 }
1263
1264 // True Y position in source
1265 int sourceY = srcY*yStep + yStart;
1266 if ((sourceY >= sourceRegion.y) &&
1267 (sourceY < sourceRegion.y + sourceRegion.height) &&
1268 (((sourceY - sourceRegion.y) %
1269 sourceYSubsampling) == 0)) {
1270
1271 int dstY = destinationOffset.y +
1272 (sourceY - sourceRegion.y)/sourceYSubsampling;
1273 if (dstY < dstMinY) {
1274 continue;
1275 }
1276 if (dstY > dstMaxY) {
1277 break;
1278 }
1279
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) {
1291 imRas.setRect(updateMinX, dstY, passRow);
1292 } else {
1293 int newSrcX = srcX;
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;
1301 for (int dstX = updateMinX;
1302 dstX < updateMinX + updateWidth;
1303 dstX += updateXStep) {
1304
1305 passRow.getPixel(newSrcX, 0, ps);
1306 if (adjustBitDepths) {
1307 for (int b = 0; b < numBands; b++) {
1308 ps[b] = scale[b][ps[b]];
1309 }
1310 }
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 }
1336 newSrcX += srcXStep;
1337 }
1338 }
1339
1340 processImageUpdate(theImage,
1341 updateMinX, dstY,
1342 updateWidth, 1,
1343 updateXStep, updateYStep,
1344 destinationBands);
1345 }
1346 }
1347
1348 processPassComplete(theImage);
1349 }
1350
1351 private void decodeImage()
1352 throws IOException, IIOException {
1353 int width = metadata.IHDR_width;
1354 int height = metadata.IHDR_height;
1355
1456 * the level of application, so we will not try to estimate
1457 * the required amount of the memory and/or handle OOM in
1458 * any way.
1459 */
1460 theImage = getDestination(param,
1461 getImageTypes(0),
1462 width,
1463 height);
1464
1465 Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1466 sourceRegion = new Rectangle(0, 0, 0, 0);
1467 computeRegions(param, width, height,
1468 theImage,
1469 sourceRegion, destRegion);
1470 destinationOffset.setLocation(destRegion.getLocation());
1471
1472 // At this point the header has been read and we know
1473 // how many bands are in the image, so perform checking
1474 // of the read param.
1475 int colorType = metadata.IHDR_colorType;
1476 if (theImage.getSampleModel().getNumBands()
1477 == inputBandsForColorType[colorType] + 1
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 }
1487
1488 clearAbortRequest();
1489 processImageStarted(0);
1490 if (abortRequested()) {
1491 processReadAborted();
1492 } else {
1493 decodeImage();
1494 if (abortRequested()) {
1495 processReadAborted();
1496 } else {
1497 processImageComplete();
1498 }
1499 }
1500
1501 } catch (IOException e) {
1502 throw new IIOException("Error reading PNG image data", e);
1503 } finally {
1504 if (inf != null) {
1505 inf.end();
1506 }
1548 readHeader();
1549
1550 ArrayList<ImageTypeSpecifier> l =
1551 new ArrayList<ImageTypeSpecifier>(1);
1552
1553 ColorSpace rgb;
1554 ColorSpace gray;
1555 int[] bandOffsets;
1556
1557 int bitDepth = metadata.IHDR_bitDepth;
1558 int colorType = metadata.IHDR_colorType;
1559
1560 int dataType;
1561 if (bitDepth <= 8) {
1562 dataType = DataBuffer.TYPE_BYTE;
1563 } else {
1564 dataType = DataBuffer.TYPE_USHORT;
1565 }
1566
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 */
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 }
1588 // Packed grayscale
1589 l.add(ImageTypeSpecifier.createGrayscale(bitDepth,
1590 dataType,
1591 false));
1592 break;
1593
1594 case PNG_COLOR_RGB:
1595 readMetadata(); // Need tRNS chunk
1596
1597 if (bitDepth == 8) {
1598 if (metadata.hasTransparentColor()) {
1599 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1600 BufferedImage.TYPE_4BYTE_ABGR));
1601 }
1602 // some standard types of buffered images
1603 // which can be used as destination
1604 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1605 BufferedImage.TYPE_3BYTE_BGR));
1606
1607 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1608 BufferedImage.TYPE_INT_RGB));
1609
1610 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1611 BufferedImage.TYPE_INT_BGR));
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));
1626 }
1627 // Component R, G, B
1628 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
1629 bandOffsets = new int[3];
1630 bandOffsets[0] = 0;
1631 bandOffsets[1] = 1;
1632 bandOffsets[2] = 2;
1633 l.add(ImageTypeSpecifier.createInterleaved(rgb,
1634 bandOffsets,
1635 dataType,
1636 false,
1637 false));
1638 break;
1639
1640 case PNG_COLOR_PALETTE:
1641 readMetadata(); // Need tRNS chunk
1642
1643 /*
1644 * The PLTE chunk spec says:
1645 *
|