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