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 for (int dstX = updateMinX;
1296 dstX < updateMinX + updateWidth;
1297 dstX += updateXStep) {
1298
1299 passRow.getPixel(newSrcX, 0, ps);
1300 if (adjustBitDepths) {
1301 for (int b = 0; b < numBands; b++) {
1302 ps[b] = scale[b][ps[b]];
1303 }
1304 }
1305 if (tRNSTransparentPixelPresent) {
1306 /*
1307 * Create intermediate array to fill the extra
1308 * alpha channel for each pixel.
1309 */
1310 int[] temp = new int[inputBands + 1];
1311
1312 int opaque = (bitDepth < 16) ? 255 : 65535;
1313 if (metadata.tRNS_colorType == PNG_COLOR_RGB) {
1314 temp[0] = ps[0];
1315 temp[1] = ps[1];
1316 temp[2] = ps[2];
1317 if (ps[0] == metadata.tRNS_red &&
1318 ps[1] == metadata.tRNS_green &&
1319 ps[2] == metadata.tRNS_blue) {
1320 temp[3] = 0;
1321 } else {
1322 temp[3] = opaque;
1323 }
1324 } else {
1325 // when tRNS_colorType is PNG_COLOR_GRAY
1326 temp[0] = ps[0];
1327 if (ps[0] == metadata.tRNS_gray) {
1328 temp[1] = 0;
1329 } else {
1330 temp[1] = opaque;
1331 }
1332 }
1333 imRas.setPixel(dstX, dstY, temp);
1334 } else {
1335 imRas.setPixel(dstX, dstY, ps);
1336 }
1337 newSrcX += srcXStep;
1338 }
1339 }
1340
1341 processImageUpdate(theImage,
1342 updateMinX, dstY,
1343 updateWidth, 1,
1344 updateXStep, updateYStep,
1345 destinationBands);
1346 }
1347 }
1348
1349 processPassComplete(theImage);
1350 }
1351
1352 private void decodeImage()
1353 throws IOException, IIOException {
1354 int width = metadata.IHDR_width;
1355 int height = metadata.IHDR_height;
1356
1457 * the level of application, so we will not try to estimate
1458 * the required amount of the memory and/or handle OOM in
1459 * any way.
1460 */
1461 theImage = getDestination(param,
1462 getImageTypes(0),
1463 width,
1464 height);
1465
1466 Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1467 sourceRegion = new Rectangle(0, 0, 0, 0);
1468 computeRegions(param, width, height,
1469 theImage,
1470 sourceRegion, destRegion);
1471 destinationOffset.setLocation(destRegion.getLocation());
1472
1473 // At this point the header has been read and we know
1474 // how many bands are in the image, so perform checking
1475 // of the read param.
1476 int colorType = metadata.IHDR_colorType;
1477 if (theImage.getSampleModel().getNumBands()
1478 == inputBandsForColorType[colorType] + 1
1479 && metadata.hasTransparentColor()) {
1480 checkReadParamBandSettings(param,
1481 inputBandsForColorType[colorType] + 1,
1482 theImage.getSampleModel().getNumBands());
1483 } else {
1484 checkReadParamBandSettings(param,
1485 inputBandsForColorType[colorType],
1486 theImage.getSampleModel().getNumBands());
1487 }
1488
1489 clearAbortRequest();
1490 processImageStarted(0);
1491 if (abortRequested()) {
1492 processReadAborted();
1493 } else {
1494 decodeImage();
1495 if (abortRequested()) {
1496 processReadAborted();
1497 } else {
1498 processImageComplete();
1499 }
1500 }
1501
1502 } catch (IOException e) {
1503 throw new IIOException("Error reading PNG image data", e);
1504 } finally {
1505 if (inf != null) {
1506 inf.end();
1507 }
1549 readHeader();
1550
1551 ArrayList<ImageTypeSpecifier> l =
1552 new ArrayList<ImageTypeSpecifier>(1);
1553
1554 ColorSpace rgb;
1555 ColorSpace gray;
1556 int[] bandOffsets;
1557
1558 int bitDepth = metadata.IHDR_bitDepth;
1559 int colorType = metadata.IHDR_colorType;
1560
1561 int dataType;
1562 if (bitDepth <= 8) {
1563 dataType = DataBuffer.TYPE_BYTE;
1564 } else {
1565 dataType = DataBuffer.TYPE_USHORT;
1566 }
1567
1568 switch (colorType) {
1569 /*
1570 * For PNG images of color type PNG_COLOR_RGB or PNG_COLOR_GRAY that
1571 * contain a specific transparent color (given by tRNS chunk), we add
1572 * ImageTypeSpecifier(s) that support transparency to the list of
1573 * supported image types.
1574 */
1575 case PNG_COLOR_GRAY:
1576 readMetadata(); // Need tRNS chunk
1577
1578 if (metadata.hasTransparentColor()) {
1579 gray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
1580 bandOffsets = new int[2];
1581 bandOffsets[0] = 0;
1582 bandOffsets[1] = 1;
1583 l.add(ImageTypeSpecifier.createInterleaved(gray,
1584 bandOffsets,
1585 dataType,
1586 true,
1587 false));
1588 }
1589 // Packed grayscale
1590 l.add(ImageTypeSpecifier.createGrayscale(bitDepth,
1591 dataType,
1592 false));
1593 break;
1594
1595 case PNG_COLOR_RGB:
1596 readMetadata(); // Need tRNS chunk
1597
1598 if (bitDepth == 8) {
1599 if (metadata.hasTransparentColor()) {
1600 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1601 BufferedImage.TYPE_4BYTE_ABGR));
1602 }
1603 // some standard types of buffered images
1604 // which can be used as destination
1605 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1606 BufferedImage.TYPE_3BYTE_BGR));
1607
1608 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1609 BufferedImage.TYPE_INT_RGB));
1610
1611 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1612 BufferedImage.TYPE_INT_BGR));
1613
1614 }
1615
1616 if (metadata.hasTransparentColor()) {
1617 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
1618 bandOffsets = new int[4];
1619 bandOffsets[0] = 0;
1620 bandOffsets[1] = 1;
1621 bandOffsets[2] = 2;
1622 bandOffsets[3] = 3;
1623
1624 l.add(ImageTypeSpecifier.
1625 createInterleaved(rgb, bandOffsets,
1626 dataType, true, false));
1627 }
1628 // Component R, G, B
1629 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
1630 bandOffsets = new int[3];
1631 bandOffsets[0] = 0;
1632 bandOffsets[1] = 1;
1633 bandOffsets[2] = 2;
1634 l.add(ImageTypeSpecifier.createInterleaved(rgb,
1635 bandOffsets,
1636 dataType,
1637 false,
1638 false));
1639 break;
1640
1641 case PNG_COLOR_PALETTE:
1642 readMetadata(); // Need tRNS chunk
1643
1644 /*
1645 * The PLTE chunk spec says:
1646 *
|