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
1057 sourceXSubsampling,
1058 sourceYSubsampling,
1059 xStart, yStart,
1060 passWidth, passHeight,
1061 xStep, yStep);
1062 int updateMinX = vals[0];
1063 int updateMinY = vals[1];
1064 int updateWidth = vals[2];
1065 int updateXStep = vals[4];
1066 int updateYStep = vals[5];
1067
1068 int bitDepth = metadata.IHDR_bitDepth;
1069 int inputBands = inputBandsForColorType[metadata.IHDR_colorType];
1070 int bytesPerPixel = (bitDepth == 16) ? 2 : 1;
1071 bytesPerPixel *= inputBands;
1072
1073 int bitsPerRow = Math.multiplyExact((inputBands * bitDepth), passWidth);
1074 int bytesPerRow = (bitsPerRow + 7) / 8;
1075 int eltsPerRow = (bitDepth == 16) ? bytesPerRow/2 : bytesPerRow;
1076
1077 // If no pixels need updating, just skip the input data
1078 if (updateWidth == 0) {
1079 for (int srcY = 0; srcY < passHeight; srcY++) {
1080 // Update count of pixels read
1081 updateImageProgress(passWidth);
1082 /*
1083 * If read has been aborted, just return
1084 * processReadAborted will be called later
1085 */
1086 if (abortRequested()) {
1087 return;
1088 }
1089 // Skip filter byte and the remaining row bytes
1090 pixelStream.skipBytes(1 + bytesPerRow);
1091 }
1092 return;
1093 }
1094
1095 // Backwards map from destination pixels
1096 // (dstX = updateMinX + k*updateXStep)
1097 // to source pixels (sourceX), and then
1098 // to offset and skip in passRow (srcX and srcXStep)
1099 int sourceX =
1100 (updateMinX - destinationOffset.x)*sourceXSubsampling +
1101 sourceRegion.x;
1102 int srcX = (sourceX - xStart)/xStep;
1103
1104 // Compute the step factor in the source
1105 int srcXStep = updateXStep*sourceXSubsampling/xStep;
1106
1107 byte[] byteData = null;
1108 short[] shortData = null;
1109 byte[] curr = new byte[bytesPerRow];
1110 byte[] prior = new byte[bytesPerRow];
1111
1112 // Create a 1-row tall Raster to hold the data
1113 WritableRaster passRow = createRaster(passWidth, 1, inputBands,
1114 eltsPerRow,
1115 bitDepth);
1116
1117 // Create an array suitable for holding one pixel
1118 int[] ps = passRow.getPixel(0, 0, (int[])null);
1119
1120 DataBuffer dataBuffer = passRow.getDataBuffer();
1121 int type = dataBuffer.getDataType();
1122 if (type == DataBuffer.TYPE_BYTE) {
1123 byteData = ((DataBufferByte)dataBuffer).getData();
1124 } else {
1125 shortData = ((DataBufferUShort)dataBuffer).getData();
1126 }
1127
1128 processPassStarted(theImage,
1129 passNum,
1130 sourceMinProgressivePass,
1131 sourceMaxProgressivePass,
1132 updateMinX, updateMinY,
1133 updateXStep, updateYStep,
1134 destinationBands);
1135
1136 // Handle source and destination bands
1221 break;
1222 case PNG_FILTER_SUB:
1223 decodeSubFilter(curr, 0, bytesPerRow, bytesPerPixel);
1224 break;
1225 case PNG_FILTER_UP:
1226 decodeUpFilter(curr, 0, prior, 0, bytesPerRow);
1227 break;
1228 case PNG_FILTER_AVERAGE:
1229 decodeAverageFilter(curr, 0, prior, 0, bytesPerRow,
1230 bytesPerPixel);
1231 break;
1232 case PNG_FILTER_PAETH:
1233 decodePaethFilter(curr, 0, prior, 0, bytesPerRow,
1234 bytesPerPixel);
1235 break;
1236 default:
1237 throw new IIOException("Unknown row filter type (= " +
1238 filter + ")!");
1239 }
1240
1241 // Copy data into passRow byte by byte
1242 if (bitDepth < 16) {
1243 System.arraycopy(curr, 0, byteData, 0, bytesPerRow);
1244 } else {
1245 int idx = 0;
1246 for (int j = 0; j < eltsPerRow; j++) {
1247 shortData[j] =
1248 (short)((curr[idx] << 8) | (curr[idx + 1] & 0xff));
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 {
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 }
1448 }
1449 }
1450
1451 public int getNumImages(boolean allowSearch) throws IIOException {
1452 if (stream == null) {
1453 throw new IllegalStateException("No input source set!");
1454 }
1455 if (seekForwardOnly && allowSearch) {
1456 throw new IllegalStateException
1457 ("seekForwardOnly and allowSearch can't both be true!");
1458 }
1459 return 1;
1460 }
1461
1462 public int getWidth(int imageIndex) throws IIOException {
1463 if (imageIndex != 0) {
1464 throw new IndexOutOfBoundsException("imageIndex != 0!");
1465 }
1466
1467 readHeader();
1468
1469 return metadata.IHDR_width;
1470 }
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. But we need
703 * to parse only the tRNS chunk even in the case where IHDR colortype
704 * is not PNG_COLOR_PALETTE, because we need tRNS chunk transparent
705 * pixel information for PNG_COLOR_RGB while storing the pixel data
706 * in decodePass().
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
1068 sourceXSubsampling,
1069 sourceYSubsampling,
1070 xStart, yStart,
1071 passWidth, passHeight,
1072 xStep, yStep);
1073 int updateMinX = vals[0];
1074 int updateMinY = vals[1];
1075 int updateWidth = vals[2];
1076 int updateXStep = vals[4];
1077 int updateYStep = vals[5];
1078
1079 int bitDepth = metadata.IHDR_bitDepth;
1080 int inputBands = inputBandsForColorType[metadata.IHDR_colorType];
1081 int bytesPerPixel = (bitDepth == 16) ? 2 : 1;
1082 bytesPerPixel *= inputBands;
1083
1084 int bitsPerRow = Math.multiplyExact((inputBands * bitDepth), passWidth);
1085 int bytesPerRow = (bitsPerRow + 7) / 8;
1086 int eltsPerRow = (bitDepth == 16) ? bytesPerRow/2 : bytesPerRow;
1087
1088 WritableRaster passRow;
1089 if (considerTransparentPixel()) {
1090 /*
1091 * When we have tRNS chunk for image type PNG_COLOR_RGB, we need
1092 * extra alpha channel to represent transparency. In getImageTypes()
1093 * we create a 4 channel destination image, so we need to calculate
1094 * destEltsPerRow and create appropriate Raster.
1095 */
1096 int destBands = 4;
1097 int destBytesPerPixel = (bitDepth == 16) ? 2 : 1;
1098 destBytesPerPixel *= destBands;
1099 int destBitsPerRow =
1100 Math.multiplyExact((destBands * bitDepth), passWidth);
1101 int destBytesPerRow = (destBitsPerRow + 7) / 8;
1102 int destEltsPerRow =
1103 (bitDepth == 16) ? destBytesPerRow/2 : destBytesPerRow;
1104
1105 // Create a 1-row tall Raster to hold the data
1106 passRow = createRaster(passWidth, 1, destBands,
1107 destEltsPerRow, bitDepth);
1108 } else {
1109 // Create a 1-row tall Raster to hold the data
1110 passRow = createRaster(passWidth, 1, inputBands,
1111 eltsPerRow, bitDepth);
1112 }
1113
1114 // If no pixels need updating, just skip the input data
1115 if (updateWidth == 0) {
1116 for (int srcY = 0; srcY < passHeight; srcY++) {
1117 // Update count of pixels read
1118 updateImageProgress(passWidth);
1119 /*
1120 * If read has been aborted, just return
1121 * processReadAborted will be called later
1122 */
1123 if (abortRequested()) {
1124 return;
1125 }
1126 // Skip filter byte and the remaining row bytes
1127 pixelStream.skipBytes(1 + bytesPerRow);
1128 }
1129 return;
1130 }
1131
1132 // Backwards map from destination pixels
1133 // (dstX = updateMinX + k*updateXStep)
1134 // to source pixels (sourceX), and then
1135 // to offset and skip in passRow (srcX and srcXStep)
1136 int sourceX =
1137 (updateMinX - destinationOffset.x)*sourceXSubsampling +
1138 sourceRegion.x;
1139 int srcX = (sourceX - xStart)/xStep;
1140
1141 // Compute the step factor in the source
1142 int srcXStep = updateXStep*sourceXSubsampling/xStep;
1143
1144 byte[] byteData = null;
1145 short[] shortData = null;
1146 byte[] curr = new byte[bytesPerRow];
1147 byte[] prior = new byte[bytesPerRow];
1148
1149 // Create an array suitable for holding one pixel
1150 int[] ps = passRow.getPixel(0, 0, (int[])null);
1151
1152 DataBuffer dataBuffer = passRow.getDataBuffer();
1153 int type = dataBuffer.getDataType();
1154 if (type == DataBuffer.TYPE_BYTE) {
1155 byteData = ((DataBufferByte)dataBuffer).getData();
1156 } else {
1157 shortData = ((DataBufferUShort)dataBuffer).getData();
1158 }
1159
1160 processPassStarted(theImage,
1161 passNum,
1162 sourceMinProgressivePass,
1163 sourceMaxProgressivePass,
1164 updateMinX, updateMinY,
1165 updateXStep, updateYStep,
1166 destinationBands);
1167
1168 // Handle source and destination bands
1253 break;
1254 case PNG_FILTER_SUB:
1255 decodeSubFilter(curr, 0, bytesPerRow, bytesPerPixel);
1256 break;
1257 case PNG_FILTER_UP:
1258 decodeUpFilter(curr, 0, prior, 0, bytesPerRow);
1259 break;
1260 case PNG_FILTER_AVERAGE:
1261 decodeAverageFilter(curr, 0, prior, 0, bytesPerRow,
1262 bytesPerPixel);
1263 break;
1264 case PNG_FILTER_PAETH:
1265 decodePaethFilter(curr, 0, prior, 0, bytesPerRow,
1266 bytesPerPixel);
1267 break;
1268 default:
1269 throw new IIOException("Unknown row filter type (= " +
1270 filter + ")!");
1271 }
1272
1273 /*
1274 * Copy data into passRow byte by byte. In case of colortype
1275 * PNG_COLOR_RGB if we have transparent pixel information from
1276 * tRNS chunk we need to consider that and store proper information
1277 * in alpha channel.
1278 */
1279 if (considerTransparentPixel()) {
1280 if (bitDepth < 16) {
1281 int srcidx = 0;
1282 int destidx = 0;
1283 for (int i = 0; i < passWidth; i++) {
1284 if (curr[srcidx] == (byte)metadata.tRNS_red &&
1285 curr[srcidx + 1] == (byte)metadata.tRNS_green &&
1286 curr[srcidx + 2] == (byte)metadata.tRNS_blue)
1287 {
1288 byteData[destidx] = curr[srcidx];
1289 byteData[destidx + 1] = curr[srcidx + 1];
1290 byteData[destidx + 2] = curr[srcidx + 2];
1291 byteData[destidx + 3] = (byte)0;
1292 } else {
1293 byteData[destidx] = curr[srcidx];
1294 byteData[destidx + 1] = curr[srcidx + 1];
1295 byteData[destidx + 2] = curr[srcidx + 2];
1296 byteData[destidx + 3] = (byte)255;
1297 }
1298 srcidx += 3;
1299 destidx += 4;
1300 }
1301 } else {
1302 int srcidx = 0;
1303 int destidx = 0;
1304 for (int i = 0; i < passWidth; i++) {
1305 short red = (short)
1306 ((curr[srcidx] << 8) | (curr[srcidx + 1] & 0xff));
1307 short green = (short)
1308 ((curr[srcidx + 2] << 8) | (curr[srcidx + 3] & 0xff));
1309 short blue = (short)
1310 ((curr[srcidx + 4] << 8) | (curr[srcidx + 5] & 0xff));
1311 if (red == (short)metadata.tRNS_red &&
1312 green == (short)metadata.tRNS_green &&
1313 blue == (short)metadata.tRNS_blue)
1314 {
1315 shortData[destidx] = red;
1316 shortData[destidx + 1] = green;
1317 shortData[destidx + 2] = blue;
1318 shortData[destidx + 3] = (short)0;
1319 } else {
1320 shortData[destidx] = red;
1321 shortData[destidx + 1] = green;
1322 shortData[destidx + 2] = blue;
1323 shortData[destidx + 3] = (short)65535;
1324 }
1325 srcidx += 6;
1326 destidx += 4;
1327 }
1328 }
1329 } else {
1330 if (bitDepth < 16) {
1331 System.arraycopy(curr, 0, byteData, 0, bytesPerRow);
1332 } else {
1333 int idx = 0;
1334 for (int j = 0; j < eltsPerRow; j++) {
1335 shortData[j] =
1336 (short)((curr[idx] << 8) | (curr[idx + 1] & 0xff));
1337 idx += 2;
1338 }
1339 }
1340 }
1341
1342 // True Y position in source
1343 int sourceY = srcY*yStep + yStart;
1344 if ((sourceY >= sourceRegion.y) &&
1345 (sourceY < sourceRegion.y + sourceRegion.height) &&
1346 (((sourceY - sourceRegion.y) %
1347 sourceYSubsampling) == 0)) {
1348
1349 int dstY = destinationOffset.y +
1350 (sourceY - sourceRegion.y)/sourceYSubsampling;
1351 if (dstY < dstMinY) {
1352 continue;
1353 }
1354 if (dstY > dstMaxY) {
1355 break;
1356 }
1357
1358 if (useSetRect) {
1359 imRas.setRect(updateMinX, dstY, passRow);
1360 } else {
1494 * the level of application, so we will not try to estimate
1495 * the required amount of the memory and/or handle OOM in
1496 * any way.
1497 */
1498 theImage = getDestination(param,
1499 getImageTypes(0),
1500 width,
1501 height);
1502
1503 Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1504 sourceRegion = new Rectangle(0, 0, 0, 0);
1505 computeRegions(param, width, height,
1506 theImage,
1507 sourceRegion, destRegion);
1508 destinationOffset.setLocation(destRegion.getLocation());
1509
1510 // At this point the header has been read and we know
1511 // how many bands are in the image, so perform checking
1512 // of the read param.
1513 int colorType = metadata.IHDR_colorType;
1514 if (considerTransparentPixel()) {
1515 checkReadParamBandSettings(param,
1516 4,
1517 theImage.getSampleModel().getNumBands());
1518
1519 } else {
1520 checkReadParamBandSettings(param,
1521 inputBandsForColorType[colorType],
1522 theImage.getSampleModel().getNumBands());
1523 }
1524
1525 clearAbortRequest();
1526 processImageStarted(0);
1527 if (abortRequested()) {
1528 processReadAborted();
1529 } else {
1530 decodeImage();
1531 if (abortRequested()) {
1532 processReadAborted();
1533 } else {
1534 processImageComplete();
1535 }
1536 }
1537
1538 } catch (IOException e) {
1539 throw new IIOException("Error reading PNG image data", e);
1540 } finally {
1541 if (inf != null) {
1542 inf.end();
1543 }
1544 }
1545 }
1546
1547 private boolean considerTransparentPixel(){
1548 /*
1549 * In case of non-indexed PNG_COLOR_RGB images if we have tRNS chunk,
1550 * we need to consider transparent pixel values and store alpha channel
1551 * also. If user explicitly provides ImageReadParam with
1552 * destinationBands as 3 when we have tRNS chunk, only then we will
1553 * ignore tRNS chunk values.
1554 */
1555 if ((destinationBands == null ||
1556 destinationBands.length == 4) &&
1557 metadata.tRNS_colorType == PNG_COLOR_RGB)
1558 {
1559 return true;
1560 }
1561 return false;
1562 }
1563
1564 public int getNumImages(boolean allowSearch) throws IIOException {
1565 if (stream == null) {
1566 throw new IllegalStateException("No input source set!");
1567 }
1568 if (seekForwardOnly && allowSearch) {
1569 throw new IllegalStateException
1570 ("seekForwardOnly and allowSearch can't both be true!");
1571 }
1572 return 1;
1573 }
1574
1575 public int getWidth(int imageIndex) throws IIOException {
1576 if (imageIndex != 0) {
1577 throw new IndexOutOfBoundsException("imageIndex != 0!");
1578 }
1579
1580 readHeader();
1581
1582 return metadata.IHDR_width;
1583 }
1610
1611 int bitDepth = metadata.IHDR_bitDepth;
1612 int colorType = metadata.IHDR_colorType;
1613
1614 int dataType;
1615 if (bitDepth <= 8) {
1616 dataType = DataBuffer.TYPE_BYTE;
1617 } else {
1618 dataType = DataBuffer.TYPE_USHORT;
1619 }
1620
1621 switch (colorType) {
1622 case PNG_COLOR_GRAY:
1623 // Packed grayscale
1624 l.add(ImageTypeSpecifier.createGrayscale(bitDepth,
1625 dataType,
1626 false));
1627 break;
1628
1629 case PNG_COLOR_RGB:
1630 readMetadata(); // Need tRNS chunk
1631
1632 /*
1633 * In case of PNG_COLOR_RGB colortype if we have transparent
1634 * pixel information in tRNS chunk we create destination
1635 * image with 4 channels.
1636 */
1637 if (bitDepth == 8) {
1638 if (considerTransparentPixel()) {
1639 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1640 BufferedImage.TYPE_4BYTE_ABGR));
1641 }
1642 // some standard types of buffered images
1643 // which can be used as destination
1644 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1645 BufferedImage.TYPE_3BYTE_BGR));
1646
1647 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1648 BufferedImage.TYPE_INT_RGB));
1649
1650 l.add(ImageTypeSpecifier.createFromBufferedImageType(
1651 BufferedImage.TYPE_INT_BGR));
1652
1653 }
1654 if (considerTransparentPixel()) {
1655 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
1656 bandOffsets = new int[4];
1657 bandOffsets[0] = 0;
1658 bandOffsets[1] = 1;
1659 bandOffsets[2] = 2;
1660 bandOffsets[3] = 3;
1661
1662 l.add(ImageTypeSpecifier.
1663 createInterleaved(rgb, bandOffsets,
1664 dataType, true, false));
1665 }
1666 // Component R, G, B
1667 rgb = ColorSpace.getInstance(ColorSpace.CS_sRGB);
1668 bandOffsets = new int[3];
1669 bandOffsets[0] = 0;
1670 bandOffsets[1] = 1;
1671 bandOffsets[2] = 2;
1672 l.add(ImageTypeSpecifier.createInterleaved(rgb,
1673 bandOffsets,
1674 dataType,
1675 false,
1676 false));
1677 break;
1678
1679 case PNG_COLOR_PALETTE:
1680 readMetadata(); // Need tRNS chunk
1681
1682 /*
1683 * The PLTE chunk spec says:
1684 *
|