139 * {@link BaselineTIFFTagSet#COMPRESSION_NONE}, {@link
140 * BaselineTIFFTagSet#COMPRESSION_CCITT_RLE}, {@link
141 * BaselineTIFFTagSet#COMPRESSION_CCITT_T_4}, {@link
142 * BaselineTIFFTagSet#COMPRESSION_CCITT_T_6}, {@link
143 * BaselineTIFFTagSet#COMPRESSION_LZW}, {@link
144 * BaselineTIFFTagSet#COMPRESSION_OLD_JPEG}, {@link
145 * BaselineTIFFTagSet#COMPRESSION_JPEG}, {@link
146 * BaselineTIFFTagSet#COMPRESSION_ZLIB}, {@link
147 * BaselineTIFFTagSet#COMPRESSION_PACKBITS}, {@link
148 * BaselineTIFFTagSet#COMPRESSION_DEFLATE}, or other value
149 * defined by a TIFF extension.
150 */
151 protected int compression;
152
153 /**
154 * {@code true} if the image is encoded using separate planes.
155 */
156 protected boolean planar;
157
158 /**
159 * The value of the {@code SamplesPerPixel} tag.
160 */
161 protected int samplesPerPixel;
162
163 /**
164 * The value of the {@code BitsPerSample} tag.
165 *
166 */
167 protected int[] bitsPerSample;
168
169 /**
170 * The value of the {@code SampleFormat} tag. Legal values
171 * are {@link BaselineTIFFTagSet#SAMPLE_FORMAT_UNSIGNED_INTEGER},
172 * {@link BaselineTIFFTagSet#SAMPLE_FORMAT_SIGNED_INTEGER}, {@link
173 * BaselineTIFFTagSet#SAMPLE_FORMAT_FLOATING_POINT}, {@link
174 * BaselineTIFFTagSet#SAMPLE_FORMAT_UNDEFINED}, or other value
175 * defined by a TIFF extension.
176 */
177 protected int[] sampleFormat =
178 new int[] {BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER};
429 * @return A {@code PixelInterleavedSampleModel}.
430 */
431 static SampleModel createInterleavedSM(int dataType,
432 int numBands) {
433 int[] bandOffsets = new int[numBands];
434 for(int i = 0; i < numBands; i++) {
435 bandOffsets[i] = i;
436 }
437 return new PixelInterleavedSampleModel(dataType,
438 1, // width
439 1, // height
440 numBands, // pixelStride,
441 numBands, // scanlineStride
442 bandOffsets);
443 }
444
445 /**
446 * Create a {@code ComponentColorModel} for use in creating
447 * an {@code ImageTypeSpecifier}.
448 */
449 // This code was copied from javax.imageio.ImageTypeSpecifier.
450 static ColorModel createComponentCM(ColorSpace colorSpace,
451 int numBands,
452 int dataType,
453 boolean hasAlpha,
454 boolean isAlphaPremultiplied) {
455 int transparency =
456 hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
457
458 int[] numBits = new int[numBands];
459 int bits = DataBuffer.getDataTypeSize(dataType);
460
461 for (int i = 0; i < numBands; i++) {
462 numBits[i] = bits;
463 }
464
465 return new ComponentColorModel(colorSpace,
466 numBits,
467 hasAlpha,
468 isAlphaPremultiplied,
469 transparency,
470 dataType);
471 }
472
473 private static int createMask(int[] bitsPerSample, int band) {
474 int mask = (1 << bitsPerSample[band]) - 1;
475 for (int i = band + 1; i < bitsPerSample.length; i++) {
476 mask <<= bitsPerSample[i];
477 }
478
479 return mask;
480 }
481
482 private static int getDataTypeFromNumBits(int numBits, boolean isSigned) {
483 int dataType;
484
485 if (numBits <= 8) {
486 dataType = DataBuffer.TYPE_BYTE;
564 private static boolean areSampleSizesEqual(SampleModel sm) {
565 boolean allSameSize = true;
566 int[] sampleSize = sm.getSampleSize();
567 int sampleSize0 = sampleSize[0];
568 int numBands = sampleSize.length;
569
570 for(int i = 1; i < numBands; i++) {
571 if(sampleSize[i] != sampleSize0) {
572 allSameSize = false;
573 break;
574 }
575 }
576
577 return allSameSize;
578 }
579
580 /**
581 * Determines whether the {@code DataBuffer} is filled without
582 * any interspersed padding bits.
583 */
584 private static boolean isDataBufferBitContiguous(SampleModel sm)
585 throws IIOException {
586 int dataTypeSize = getDataTypeSize(sm.getDataType());
587
588 if(sm instanceof ComponentSampleModel) {
589 int numBands = sm.getNumBands();
590 for(int i = 0; i < numBands; i++) {
591 if(sm.getSampleSize(i) != dataTypeSize) {
592 // Sample does not fill data element.
593 return false;
594 }
595 }
596 } else if(sm instanceof MultiPixelPackedSampleModel) {
597 MultiPixelPackedSampleModel mppsm =
598 (MultiPixelPackedSampleModel)sm;
599 if(dataTypeSize % mppsm.getPixelBitStride() != 0) {
600 // Pixels do not fill the data element.
601 return false;
602 }
603 } else if(sm instanceof SinglePixelPackedSampleModel) {
604 SinglePixelPackedSampleModel sppsm =
605 (SinglePixelPackedSampleModel)sm;
606 int numBands = sm.getNumBands();
607 int numBits = 0;
608 for(int i = 0; i < numBands; i++) {
609 numBits += sm.getSampleSize(i);
610 }
611 if(numBits != dataTypeSize) {
665 int shift = 24;
666 int ival = 0;
667 for(int b = 0; b < numExtraBytes; b++) {
668 ival |= (buf[inOffset++]&0xff) << shift;
669 shift -= 8;
670 }
671 intData[k++] = ival;
672 }
673 outOffset += outStride;
674 }
675 } else {
676 throw new IIOException("shortData == null && intData == null!");
677 }
678 }
679
680 /**
681 * Reformats bit-discontiguous data into the {@code DataBuffer}
682 * of the supplied {@code WritableRaster}.
683 */
684 private static void reformatDiscontiguousData(byte[] buf,
685 int stride,
686 int w,
687 int h,
688 WritableRaster raster)
689 throws IOException {
690
691 // Get SampleModel info.
692 SampleModel sm = raster.getSampleModel();
693 int numBands = sm.getNumBands();
694 int[] sampleSize = sm.getSampleSize();
695
696 // Initialize input stream.
697 ByteArrayInputStream is = new ByteArrayInputStream(buf);
698 ImageInputStream iis = new MemoryCacheImageInputStream(is);
699
700 // Reformat.
701 long iisPosition = 0L;
702 int y = raster.getMinY();
703 for(int j = 0; j < h; j++, y++) {
704 iis.seek(iisPosition);
705 int x = raster.getMinX();
706 for(int i = 0; i < w; i++, x++) {
707 for(int b = 0; b < numBands; b++) {
708 long bits = iis.readBits(sampleSize[b]);
709 raster.setSample(x, y, b, (int)bits);
710 }
711 }
712 iisPosition += stride;
713 }
714 }
715
716 /**
717 * A utility method that returns an
718 * {@code ImageTypeSpecifier} suitable for decoding an image
719 * with the given parameters.
720 *
721 * @param photometricInterpretation the value of the
722 * {@code PhotometricInterpretation} field.
723 * @param compression the value of the {@code Compression} field.
724 * @param samplesPerPixel the value of the
725 * {@code SamplesPerPixel} field.
726 * @param bitsPerSample the value of the {@code BitsPerSample} field.
727 * @param sampleFormat the value of the {@code SampleFormat} field.
728 * @param extraSamples the value of the {@code ExtraSamples} field.
789 }
790
791 return ImageTypeSpecifier.createGrayscale(bitsPerSample[0],
792 dataType,
793 isSigned);
794 } else {
795 // Indexed
796 int mapSize = 1 << bitsPerSample[0];
797 byte[] redLut = new byte[mapSize];
798 byte[] greenLut = new byte[mapSize];
799 byte[] blueLut = new byte[mapSize];
800 byte[] alphaLut = null;
801
802 int idx = 0;
803 for (int i = 0; i < mapSize; i++) {
804 redLut[i] = (byte)((colorMap[i]*255)/65535);
805 greenLut[i] = (byte)((colorMap[mapSize + i]*255)/65535);
806 blueLut[i] = (byte)((colorMap[2*mapSize + i]*255)/65535);
807 }
808
809 int dataType = bitsPerSample[0] == 8 ?
810 DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT;
811 return ImageTypeSpecifier.createIndexed(redLut,
812 greenLut,
813 blueLut,
814 alphaLut,
815 bitsPerSample[0],
816 dataType);
817 }
818 }
819
820 // 8-bit gray-alpha
821 if (samplesPerPixel == 2 &&
822 bitsPerSample[0] == 8 &&
823 bitsPerSample[1] == 8) {
824 int dataType = DataBuffer.TYPE_BYTE;
825 boolean alphaPremultiplied = false;
826 if (extraSamples != null &&
827 extraSamples[0] ==
828 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
829 alphaPremultiplied = true;
830 }
1065 samplesPerPixel);
1066
1067 // Create the ColorModel.
1068 ColorModel cm;
1069 if(samplesPerPixel >= 1 && samplesPerPixel <= 4 &&
1070 (dataType == DataBuffer.TYPE_INT ||
1071 dataType == DataBuffer.TYPE_FLOAT)) {
1072 // Handle the 32-bit cases for 1-4 bands.
1073 ColorSpace cs = samplesPerPixel <= 2 ?
1074 ColorSpace.getInstance(ColorSpace.CS_GRAY) : rgb;
1075 boolean hasAlpha = ((samplesPerPixel % 2) == 0);
1076 boolean alphaPremultiplied = false;
1077 if(hasAlpha && extraSamples != null &&
1078 extraSamples[0] ==
1079 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1080 alphaPremultiplied = true;
1081 }
1082
1083 cm = createComponentCM(cs,
1084 samplesPerPixel,
1085 dataType,
1086 hasAlpha,
1087 alphaPremultiplied);
1088 } else {
1089 ColorSpace cs = new BogusColorSpace(samplesPerPixel);
1090 cm = createComponentCM(cs,
1091 samplesPerPixel,
1092 dataType,
1093 false, // hasAlpha
1094 false); // alphaPremultiplied
1095 }
1096 return new ImageTypeSpecifier(cm, sm);
1097 }
1098 }
1099 }
1100
1101 // Other more bizarre cases including discontiguous DataBuffers
1102 // such as for the image in bug 4918959.
1103
1104 if(colorMap == null &&
1105 sampleFormat[0] !=
1106 BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT) {
1107
1108 // Determine size of largest sample.
1109 int maxBitsPerSample = 0;
1110 for(int i = 0; i < bitsPerSample.length; i++) {
1111 if(bitsPerSample[i] > maxBitsPerSample) {
1112 maxBitsPerSample = bitsPerSample[i];
1113 }
1114 }
1115
1116 // Determine whether data are signed.
1117 boolean isSigned =
1118 (sampleFormat[0] ==
1119 BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER);
1120
1121 // Grayscale
1122 if(samplesPerPixel == 1) {
1123 int dataType =
1124 getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1125
1126 return ImageTypeSpecifier.createGrayscale(maxBitsPerSample,
1127 dataType,
1128 isSigned);
1129 }
1130
1131 // Gray-alpha
1132 if (samplesPerPixel == 2) {
1133 boolean alphaPremultiplied = false;
1134 if (extraSamples != null &&
1135 extraSamples[0] ==
1136 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1137 alphaPremultiplied = true;
1138 }
1139
1140 int dataType =
1141 getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1142
1143 return ImageTypeSpecifier.createGrayscale(maxBitsPerSample,
1144 dataType,
1145 false,
1146 alphaPremultiplied);
1147 }
1148
1149 if (samplesPerPixel == 3 || samplesPerPixel == 4) {
1150 if(totalBits <= 32 && !isSigned) {
1151 // Packed RGB or RGBA
1152 int redMask = createMask(bitsPerSample, 0);
1153 int greenMask = createMask(bitsPerSample, 1);
1154 int blueMask = createMask(bitsPerSample, 2);
1155 int alphaMask = (samplesPerPixel == 4) ?
1156 createMask(bitsPerSample, 3) : 0;
1157 int transferType =
1158 getDataTypeFromNumBits(totalBits, false);
1159 boolean alphaPremultiplied = false;
1160 if (extraSamples != null &&
1161 extraSamples[0] ==
1162 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1163 alphaPremultiplied = true;
1164 }
1165 return ImageTypeSpecifier.createPacked(rgb,
1166 redMask,
1167 greenMask,
1168 blueMask,
1169 alphaMask,
1170 transferType,
1171 alphaPremultiplied);
1172 } else if(samplesPerPixel == 3) {
1173 // Interleaved RGB
1174 int[] bandOffsets = new int[] {0, 1, 2};
1175 int dataType =
1176 getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1177 return ImageTypeSpecifier.createInterleaved(rgb,
1178 bandOffsets,
1179 dataType,
1180 false,
1181 false);
1182 } else if(samplesPerPixel == 4) {
1183 // Interleaved RGBA
1184 int[] bandOffsets = new int[] {0, 1, 2, 3};
1185 int dataType =
1186 getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1187 boolean alphaPremultiplied = false;
1188 if (extraSamples != null &&
1189 extraSamples[0] ==
1190 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1191 alphaPremultiplied = true;
1192 }
1193 return ImageTypeSpecifier.createInterleaved(rgb,
1194 bandOffsets,
1195 dataType,
1196 true,
1197 alphaPremultiplied);
1198 }
1199 } else {
1200 // Arbitrary Interleaved.
1201 int dataType =
1202 getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1203 SampleModel sm = createInterleavedSM(dataType,
1204 samplesPerPixel);
1205 ColorSpace cs = new BogusColorSpace(samplesPerPixel);
1206 ColorModel cm = createComponentCM(cs,
1207 samplesPerPixel,
1208 dataType,
1209 false, // hasAlpha
1210 false); // alphaPremultiplied
1211 return new ImageTypeSpecifier(cm, sm);
1212 }
1213 }
1214
1215 return null;
1216 }
1217
1218 /**
1219 * Sets the value of the {@code reader} field.
1220 *
1221 * <p> If this method is called, the {@code beginDecoding}
1222 * method must be called prior to calling any of the decode
1223 * methods.
1224 *
1225 * @param reader the current {@code ImageReader}.
1226 */
1227 public void setReader(ImageReader reader) {
1228 this.reader = reader;
1229 }
1230
1231 /**
1232 * Sets the value of the {@code metadata} field.
1233 *
1268 */
1269 public void setCompression(int compression) {
1270 this.compression = compression;
1271 }
1272
1273 /**
1274 * Sets the value of the {@code planar} field.
1275 *
1276 * <p> If this method is called, the {@code beginDecoding}
1277 * method must be called prior to calling any of the decode
1278 * methods.
1279 *
1280 * @param planar {@code true} if the image to be decoded is
1281 * stored in planar format.
1282 */
1283 public void setPlanar(boolean planar) {
1284 this.planar = planar;
1285 }
1286
1287 /**
1288 * Sets the value of the {@code samplesPerPixel} field.
1289 *
1290 * <p> If this method is called, the {@code beginDecoding}
1291 * method must be called prior to calling any of the decode
1292 * methods.
1293 *
1294 * @param samplesPerPixel the number of samples in each source
1295 * pixel.
1296 */
1297 public void setSamplesPerPixel(int samplesPerPixel) {
1298 this.samplesPerPixel = samplesPerPixel;
1299 }
1300
1301 /**
1302 * Sets the value of the {@code bitsPerSample} field.
1303 *
1304 * <p> If this method is called, the {@code beginDecoding}
1305 * method must be called prior to calling any of the decode
1306 * methods.
1307 *
2471 isSupportedType = true;
2472 }
2473 }
2474
2475 if(!isSupportedType) {
2476 throw new IIOException
2477 ("Unsupported raw image type: SampleModel = "+sm+
2478 "; DataBuffer = "+db);
2479 }
2480 }
2481
2482 if(isBilevel) {
2483 // Bilevel data are always in a contiguous byte buffer.
2484 decodeRaw(byteData, dstOffset, pixelBitStride, scanlineStride);
2485 } else {
2486 SampleModel sm = ras.getSampleModel();
2487
2488 // Branch based on whether data are bit-contiguous, i.e.,
2489 // data are packaed as tightly as possible leaving no unused
2490 // bits except at the end of a row.
2491 if(isDataBufferBitContiguous(sm)) {
2492 // Use byte or float data directly.
2493 if (byteData != null) {
2494 decodeRaw(byteData, dstOffset,
2495 pixelBitStride, scanlineStride);
2496 } else if (floatData != null) {
2497 decodeRaw(floatData, dstOffset,
2498 pixelBitStride, scanlineStride);
2499 } else if (doubleData != null) {
2500 decodeRaw(doubleData, dstOffset,
2501 pixelBitStride, scanlineStride);
2502 } else {
2503 if (shortData != null) {
2504 if(areSampleSizesEqual(sm) &&
2505 sm.getSampleSize(0) == 16) {
2506 // Decode directly into short data.
2507 decodeRaw(shortData, dstOffset,
2508 pixelBitStride, scanlineStride);
2509 } else {
2510 // Decode into bytes and reformat into shorts.
2511 int bpp = getBitsPerPixel(sm);
2520 if(areSampleSizesEqual(sm) &&
2521 sm.getSampleSize(0) == 32) {
2522 // Decode directly into int data.
2523 decodeRaw(intData, dstOffset,
2524 pixelBitStride, scanlineStride);
2525 } else {
2526 // Decode into bytes and reformat into ints.
2527 int bpp = getBitsPerPixel(sm);
2528 int bytesPerRow = (bpp*srcWidth + 7)/8;
2529 byte[] buf = new byte[bytesPerRow*srcHeight];
2530 decodeRaw(buf, 0, bpp, bytesPerRow);
2531 reformatData(buf, bytesPerRow, srcHeight,
2532 null, intData,
2533 dstOffset, scanlineStride);
2534 }
2535 }
2536 }
2537 } else {
2538 // Read discontiguous data into bytes and set the samples
2539 // into the Raster.
2540 int bpp = getBitsPerPixel(sm);
2541 int bytesPerRow = (bpp*srcWidth + 7)/8;
2542 byte[] buf = new byte[bytesPerRow*srcHeight];
2543 decodeRaw(buf, 0, bpp, bytesPerRow);
2544 reformatDiscontiguousData(buf, bytesPerRow,
2545 srcWidth, srcHeight,
2546 ras);
2547 }
2548 }
2549
2550 if (colorConverter != null) {
2551 float[] rgb = new float[3];
2552
2553 if(byteData != null) {
2554 for (int j = 0; j < dstHeight; j++) {
2555 int idx = dstOffset;
2556 for (int i = 0; i < dstWidth; i++) {
2557 float x0 = (float)(byteData[idx] & 0xff);
2558 float x1 = (float)(byteData[idx + 1] & 0xff);
2559 float x2 = (float)(byteData[idx + 2] & 0xff);
2560
2561 colorConverter.toRGB(x0, x1, x2, rgb);
2562
2563 byteData[idx] = (byte)(rgb[0]);
2564 byteData[idx + 1] = (byte)(rgb[1]);
|
139 * {@link BaselineTIFFTagSet#COMPRESSION_NONE}, {@link
140 * BaselineTIFFTagSet#COMPRESSION_CCITT_RLE}, {@link
141 * BaselineTIFFTagSet#COMPRESSION_CCITT_T_4}, {@link
142 * BaselineTIFFTagSet#COMPRESSION_CCITT_T_6}, {@link
143 * BaselineTIFFTagSet#COMPRESSION_LZW}, {@link
144 * BaselineTIFFTagSet#COMPRESSION_OLD_JPEG}, {@link
145 * BaselineTIFFTagSet#COMPRESSION_JPEG}, {@link
146 * BaselineTIFFTagSet#COMPRESSION_ZLIB}, {@link
147 * BaselineTIFFTagSet#COMPRESSION_PACKBITS}, {@link
148 * BaselineTIFFTagSet#COMPRESSION_DEFLATE}, or other value
149 * defined by a TIFF extension.
150 */
151 protected int compression;
152
153 /**
154 * {@code true} if the image is encoded using separate planes.
155 */
156 protected boolean planar;
157
158 /**
159 * The planar band to decode; ignored for chunky (interleaved) images.
160 */
161 protected int planarBand = 0;
162
163 /**
164 * The value of the {@code SamplesPerPixel} tag.
165 */
166 protected int samplesPerPixel;
167
168 /**
169 * The value of the {@code BitsPerSample} tag.
170 *
171 */
172 protected int[] bitsPerSample;
173
174 /**
175 * The value of the {@code SampleFormat} tag. Legal values
176 * are {@link BaselineTIFFTagSet#SAMPLE_FORMAT_UNSIGNED_INTEGER},
177 * {@link BaselineTIFFTagSet#SAMPLE_FORMAT_SIGNED_INTEGER}, {@link
178 * BaselineTIFFTagSet#SAMPLE_FORMAT_FLOATING_POINT}, {@link
179 * BaselineTIFFTagSet#SAMPLE_FORMAT_UNDEFINED}, or other value
180 * defined by a TIFF extension.
181 */
182 protected int[] sampleFormat =
183 new int[] {BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER};
434 * @return A {@code PixelInterleavedSampleModel}.
435 */
436 static SampleModel createInterleavedSM(int dataType,
437 int numBands) {
438 int[] bandOffsets = new int[numBands];
439 for(int i = 0; i < numBands; i++) {
440 bandOffsets[i] = i;
441 }
442 return new PixelInterleavedSampleModel(dataType,
443 1, // width
444 1, // height
445 numBands, // pixelStride,
446 numBands, // scanlineStride
447 bandOffsets);
448 }
449
450 /**
451 * Create a {@code ComponentColorModel} for use in creating
452 * an {@code ImageTypeSpecifier}.
453 */
454 // This code was inspired by the method of the same name in
455 // javax.imageio.ImageTypeSpecifier
456 static ColorModel createComponentCM(ColorSpace colorSpace,
457 int numBands,
458 int[] bitsPerSample,
459 int dataType,
460 boolean hasAlpha,
461 boolean isAlphaPremultiplied) {
462 int transparency =
463 hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE;
464
465 return new ComponentColorModel(colorSpace,
466 bitsPerSample,
467 hasAlpha,
468 isAlphaPremultiplied,
469 transparency,
470 dataType);
471 }
472
473 private static int createMask(int[] bitsPerSample, int band) {
474 int mask = (1 << bitsPerSample[band]) - 1;
475 for (int i = band + 1; i < bitsPerSample.length; i++) {
476 mask <<= bitsPerSample[i];
477 }
478
479 return mask;
480 }
481
482 private static int getDataTypeFromNumBits(int numBits, boolean isSigned) {
483 int dataType;
484
485 if (numBits <= 8) {
486 dataType = DataBuffer.TYPE_BYTE;
564 private static boolean areSampleSizesEqual(SampleModel sm) {
565 boolean allSameSize = true;
566 int[] sampleSize = sm.getSampleSize();
567 int sampleSize0 = sampleSize[0];
568 int numBands = sampleSize.length;
569
570 for(int i = 1; i < numBands; i++) {
571 if(sampleSize[i] != sampleSize0) {
572 allSameSize = false;
573 break;
574 }
575 }
576
577 return allSameSize;
578 }
579
580 /**
581 * Determines whether the {@code DataBuffer} is filled without
582 * any interspersed padding bits.
583 */
584 private static boolean isDataBufferBitContiguous(SampleModel sm,
585 int[] bitsPerSample)
586 throws IIOException {
587 int dataTypeSize = getDataTypeSize(sm.getDataType());
588
589 if(sm instanceof ComponentSampleModel) {
590 int numBands = sm.getNumBands();
591 for(int i = 0; i < numBands; i++) {
592 if(bitsPerSample[i] != dataTypeSize) {
593 // Sample does not fill data element.
594 return false;
595 }
596 }
597 } else if(sm instanceof MultiPixelPackedSampleModel) {
598 MultiPixelPackedSampleModel mppsm =
599 (MultiPixelPackedSampleModel)sm;
600 if(dataTypeSize % mppsm.getPixelBitStride() != 0) {
601 // Pixels do not fill the data element.
602 return false;
603 }
604 } else if(sm instanceof SinglePixelPackedSampleModel) {
605 SinglePixelPackedSampleModel sppsm =
606 (SinglePixelPackedSampleModel)sm;
607 int numBands = sm.getNumBands();
608 int numBits = 0;
609 for(int i = 0; i < numBands; i++) {
610 numBits += sm.getSampleSize(i);
611 }
612 if(numBits != dataTypeSize) {
666 int shift = 24;
667 int ival = 0;
668 for(int b = 0; b < numExtraBytes; b++) {
669 ival |= (buf[inOffset++]&0xff) << shift;
670 shift -= 8;
671 }
672 intData[k++] = ival;
673 }
674 outOffset += outStride;
675 }
676 } else {
677 throw new IIOException("shortData == null && intData == null!");
678 }
679 }
680
681 /**
682 * Reformats bit-discontiguous data into the {@code DataBuffer}
683 * of the supplied {@code WritableRaster}.
684 */
685 private static void reformatDiscontiguousData(byte[] buf,
686 int[] bitsPerSample,
687 int stride,
688 int w,
689 int h,
690 WritableRaster raster)
691 throws IOException {
692
693 // Get SampleModel info.
694 SampleModel sm = raster.getSampleModel();
695 int numBands = sm.getNumBands();
696
697 // Initialize input stream.
698 ByteArrayInputStream is = new ByteArrayInputStream(buf);
699 ImageInputStream iis = new MemoryCacheImageInputStream(is);
700
701 // Reformat.
702 long iisPosition = 0L;
703 int y = raster.getMinY();
704 for(int j = 0; j < h; j++, y++) {
705 iis.seek(iisPosition);
706 int x = raster.getMinX();
707 for(int i = 0; i < w; i++, x++) {
708 for(int b = 0; b < numBands; b++) {
709 long bits = iis.readBits(bitsPerSample[b]);
710 raster.setSample(x, y, b, (int)bits);
711 }
712 }
713 iisPosition += stride;
714 }
715 }
716
717 /**
718 * A utility method that returns an
719 * {@code ImageTypeSpecifier} suitable for decoding an image
720 * with the given parameters.
721 *
722 * @param photometricInterpretation the value of the
723 * {@code PhotometricInterpretation} field.
724 * @param compression the value of the {@code Compression} field.
725 * @param samplesPerPixel the value of the
726 * {@code SamplesPerPixel} field.
727 * @param bitsPerSample the value of the {@code BitsPerSample} field.
728 * @param sampleFormat the value of the {@code SampleFormat} field.
729 * @param extraSamples the value of the {@code ExtraSamples} field.
790 }
791
792 return ImageTypeSpecifier.createGrayscale(bitsPerSample[0],
793 dataType,
794 isSigned);
795 } else {
796 // Indexed
797 int mapSize = 1 << bitsPerSample[0];
798 byte[] redLut = new byte[mapSize];
799 byte[] greenLut = new byte[mapSize];
800 byte[] blueLut = new byte[mapSize];
801 byte[] alphaLut = null;
802
803 int idx = 0;
804 for (int i = 0; i < mapSize; i++) {
805 redLut[i] = (byte)((colorMap[i]*255)/65535);
806 greenLut[i] = (byte)((colorMap[mapSize + i]*255)/65535);
807 blueLut[i] = (byte)((colorMap[2*mapSize + i]*255)/65535);
808 }
809
810 int dataType;
811 if (bitsPerSample[0] <= 8) {
812 dataType = DataBuffer.TYPE_BYTE;
813 } else if (sampleFormat[0] ==
814 BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) {
815 dataType = DataBuffer.TYPE_SHORT;
816 } else {
817 dataType = DataBuffer.TYPE_USHORT;
818 }
819 return ImageTypeSpecifier.createIndexed(redLut,
820 greenLut,
821 blueLut,
822 alphaLut,
823 bitsPerSample[0],
824 dataType);
825 }
826 }
827
828 // 8-bit gray-alpha
829 if (samplesPerPixel == 2 &&
830 bitsPerSample[0] == 8 &&
831 bitsPerSample[1] == 8) {
832 int dataType = DataBuffer.TYPE_BYTE;
833 boolean alphaPremultiplied = false;
834 if (extraSamples != null &&
835 extraSamples[0] ==
836 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
837 alphaPremultiplied = true;
838 }
1073 samplesPerPixel);
1074
1075 // Create the ColorModel.
1076 ColorModel cm;
1077 if(samplesPerPixel >= 1 && samplesPerPixel <= 4 &&
1078 (dataType == DataBuffer.TYPE_INT ||
1079 dataType == DataBuffer.TYPE_FLOAT)) {
1080 // Handle the 32-bit cases for 1-4 bands.
1081 ColorSpace cs = samplesPerPixel <= 2 ?
1082 ColorSpace.getInstance(ColorSpace.CS_GRAY) : rgb;
1083 boolean hasAlpha = ((samplesPerPixel % 2) == 0);
1084 boolean alphaPremultiplied = false;
1085 if(hasAlpha && extraSamples != null &&
1086 extraSamples[0] ==
1087 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1088 alphaPremultiplied = true;
1089 }
1090
1091 cm = createComponentCM(cs,
1092 samplesPerPixel,
1093 bitsPerSample,
1094 dataType,
1095 hasAlpha,
1096 alphaPremultiplied);
1097 } else {
1098 ColorSpace cs = new BogusColorSpace(samplesPerPixel);
1099 cm = createComponentCM(cs,
1100 samplesPerPixel,
1101 bitsPerSample,
1102 dataType,
1103 false, // hasAlpha
1104 false); // alphaPremultiplied
1105 }
1106 return new ImageTypeSpecifier(cm, sm);
1107 }
1108 }
1109 }
1110
1111 // Other more bizarre cases including discontiguous DataBuffers
1112 // such as for the image in bug 4918959.
1113
1114 if(colorMap == null &&
1115 sampleFormat[0] !=
1116 BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT) {
1117
1118 // Determine size of largest sample.
1119 int maxBitsPerSample = 0;
1120 for(int i = 0; i < bitsPerSample.length; i++) {
1121 if(bitsPerSample[i] > maxBitsPerSample) {
1122 maxBitsPerSample = bitsPerSample[i];
1123 }
1124 }
1125
1126 // Determine whether data are signed.
1127 boolean isSigned =
1128 (sampleFormat[0] ==
1129 BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER);
1130
1131 // Grayscale
1132 if(samplesPerPixel == 1 &&
1133 (bitsPerSample[0] == 1 || bitsPerSample[0] == 2 ||
1134 bitsPerSample[0] == 4 || bitsPerSample[0] == 8 ||
1135 bitsPerSample[0] == 16)) {
1136 int dataType = getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1137
1138 return ImageTypeSpecifier.createGrayscale(bitsPerSample[0],
1139 dataType,
1140 isSigned);
1141 }
1142
1143 // Gray-alpha
1144 if (samplesPerPixel == 2 &&
1145 bitsPerSample[0] == bitsPerSample[1] &&
1146 (bitsPerSample[0] == 1 || bitsPerSample[0] == 2 ||
1147 bitsPerSample[0] == 4 || bitsPerSample[0] == 8 ||
1148 bitsPerSample[0] == 16)) {
1149 boolean alphaPremultiplied = false;
1150 if (extraSamples != null &&
1151 extraSamples[0] ==
1152 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1153 alphaPremultiplied = true;
1154 }
1155
1156 int dataType =
1157 getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1158
1159 return ImageTypeSpecifier.createGrayscale(maxBitsPerSample,
1160 dataType,
1161 false,
1162 alphaPremultiplied);
1163 }
1164
1165 if (samplesPerPixel == 3 || samplesPerPixel == 4) {
1166 int dataType = getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1167 int dataTypeSize;
1168 try {
1169 dataTypeSize = getDataTypeSize(dataType);
1170 } catch (IIOException ignored) {
1171 dataTypeSize = maxBitsPerSample;
1172 }
1173 if(totalBits <= 32 && !isSigned) {
1174 // Packed RGB or RGBA
1175 int redMask = createMask(bitsPerSample, 0);
1176 int greenMask = createMask(bitsPerSample, 1);
1177 int blueMask = createMask(bitsPerSample, 2);
1178 int alphaMask = (samplesPerPixel == 4) ?
1179 createMask(bitsPerSample, 3) : 0;
1180 int transferType =
1181 getDataTypeFromNumBits(totalBits, false);
1182 boolean alphaPremultiplied = false;
1183 if (extraSamples != null &&
1184 extraSamples[0] ==
1185 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1186 alphaPremultiplied = true;
1187 }
1188 return ImageTypeSpecifier.createPacked(rgb,
1189 redMask,
1190 greenMask,
1191 blueMask,
1192 alphaMask,
1193 transferType,
1194 alphaPremultiplied);
1195 } else if(samplesPerPixel == 3 &&
1196 dataTypeSize == bitsPerSample[0] &&
1197 bitsPerSample[0] == bitsPerSample[1] &&
1198 bitsPerSample[1] == bitsPerSample[2]) {
1199 // Interleaved RGB
1200 int[] bandOffsets = new int[] {0, 1, 2};
1201 return ImageTypeSpecifier.createInterleaved(rgb,
1202 bandOffsets,
1203 dataType,
1204 false,
1205 false);
1206 } else if(samplesPerPixel == 4 &&
1207 dataTypeSize == bitsPerSample[0] &&
1208 bitsPerSample[0] == bitsPerSample[1] &&
1209 bitsPerSample[1] == bitsPerSample[2] &&
1210 bitsPerSample[2] == bitsPerSample[3]) {
1211 // Interleaved RGBA
1212 int[] bandOffsets = new int[] {0, 1, 2, 3};
1213 boolean alphaPremultiplied = false;
1214 if (extraSamples != null &&
1215 extraSamples[0] ==
1216 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
1217 alphaPremultiplied = true;
1218 }
1219 return ImageTypeSpecifier.createInterleaved(rgb,
1220 bandOffsets,
1221 dataType,
1222 true,
1223 alphaPremultiplied);
1224 }
1225 }
1226
1227 // Arbitrary Interleaved.
1228 int dataType =
1229 getDataTypeFromNumBits(maxBitsPerSample, isSigned);
1230 SampleModel sm = createInterleavedSM(dataType,
1231 samplesPerPixel);
1232 ColorSpace cs;
1233 if (samplesPerPixel <= 2) {
1234 cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
1235 } else if (samplesPerPixel <= 4) {
1236 cs = rgb;
1237 } else {
1238 cs = new BogusColorSpace(samplesPerPixel);
1239 }
1240 ColorModel cm = createComponentCM(cs,
1241 samplesPerPixel,
1242 bitsPerSample,
1243 dataType,
1244 false, // hasAlpha
1245 false); // alphaPremultiplied
1246 return new ImageTypeSpecifier(cm, sm);
1247 }
1248
1249 return null;
1250 }
1251
1252 /**
1253 * Sets the value of the {@code reader} field.
1254 *
1255 * <p> If this method is called, the {@code beginDecoding}
1256 * method must be called prior to calling any of the decode
1257 * methods.
1258 *
1259 * @param reader the current {@code ImageReader}.
1260 */
1261 public void setReader(ImageReader reader) {
1262 this.reader = reader;
1263 }
1264
1265 /**
1266 * Sets the value of the {@code metadata} field.
1267 *
1302 */
1303 public void setCompression(int compression) {
1304 this.compression = compression;
1305 }
1306
1307 /**
1308 * Sets the value of the {@code planar} field.
1309 *
1310 * <p> If this method is called, the {@code beginDecoding}
1311 * method must be called prior to calling any of the decode
1312 * methods.
1313 *
1314 * @param planar {@code true} if the image to be decoded is
1315 * stored in planar format.
1316 */
1317 public void setPlanar(boolean planar) {
1318 this.planar = planar;
1319 }
1320
1321 /**
1322 * Sets the index of the planar configuration band to be decoded. This value
1323 * is ignored for chunky (interleaved) images.
1324 *
1325 * @param the index of the planar band to decode
1326 */
1327 public void setPlanarBand(int planarBand) { this.planarBand = planarBand; }
1328
1329 /**
1330 * Sets the value of the {@code samplesPerPixel} field.
1331 *
1332 * <p> If this method is called, the {@code beginDecoding}
1333 * method must be called prior to calling any of the decode
1334 * methods.
1335 *
1336 * @param samplesPerPixel the number of samples in each source
1337 * pixel.
1338 */
1339 public void setSamplesPerPixel(int samplesPerPixel) {
1340 this.samplesPerPixel = samplesPerPixel;
1341 }
1342
1343 /**
1344 * Sets the value of the {@code bitsPerSample} field.
1345 *
1346 * <p> If this method is called, the {@code beginDecoding}
1347 * method must be called prior to calling any of the decode
1348 * methods.
1349 *
2513 isSupportedType = true;
2514 }
2515 }
2516
2517 if(!isSupportedType) {
2518 throw new IIOException
2519 ("Unsupported raw image type: SampleModel = "+sm+
2520 "; DataBuffer = "+db);
2521 }
2522 }
2523
2524 if(isBilevel) {
2525 // Bilevel data are always in a contiguous byte buffer.
2526 decodeRaw(byteData, dstOffset, pixelBitStride, scanlineStride);
2527 } else {
2528 SampleModel sm = ras.getSampleModel();
2529
2530 // Branch based on whether data are bit-contiguous, i.e.,
2531 // data are packaed as tightly as possible leaving no unused
2532 // bits except at the end of a row.
2533 if(isDataBufferBitContiguous(sm, bitsPerSample)) {
2534 // Use byte or float data directly.
2535 if (byteData != null) {
2536 decodeRaw(byteData, dstOffset,
2537 pixelBitStride, scanlineStride);
2538 } else if (floatData != null) {
2539 decodeRaw(floatData, dstOffset,
2540 pixelBitStride, scanlineStride);
2541 } else if (doubleData != null) {
2542 decodeRaw(doubleData, dstOffset,
2543 pixelBitStride, scanlineStride);
2544 } else {
2545 if (shortData != null) {
2546 if(areSampleSizesEqual(sm) &&
2547 sm.getSampleSize(0) == 16) {
2548 // Decode directly into short data.
2549 decodeRaw(shortData, dstOffset,
2550 pixelBitStride, scanlineStride);
2551 } else {
2552 // Decode into bytes and reformat into shorts.
2553 int bpp = getBitsPerPixel(sm);
2562 if(areSampleSizesEqual(sm) &&
2563 sm.getSampleSize(0) == 32) {
2564 // Decode directly into int data.
2565 decodeRaw(intData, dstOffset,
2566 pixelBitStride, scanlineStride);
2567 } else {
2568 // Decode into bytes and reformat into ints.
2569 int bpp = getBitsPerPixel(sm);
2570 int bytesPerRow = (bpp*srcWidth + 7)/8;
2571 byte[] buf = new byte[bytesPerRow*srcHeight];
2572 decodeRaw(buf, 0, bpp, bytesPerRow);
2573 reformatData(buf, bytesPerRow, srcHeight,
2574 null, intData,
2575 dstOffset, scanlineStride);
2576 }
2577 }
2578 }
2579 } else {
2580 // Read discontiguous data into bytes and set the samples
2581 // into the Raster.
2582 int bpp;
2583 if (planar) {
2584 bpp = bitsPerSample[planarBand];
2585 } else {
2586 bpp = 0;
2587 for (int bps : bitsPerSample) {
2588 bpp += bps;
2589 }
2590 }
2591 int bytesPerRow = (bpp*srcWidth + 7)/8;
2592 byte[] buf = new byte[bytesPerRow*srcHeight];
2593 decodeRaw(buf, 0, bpp, bytesPerRow);
2594 reformatDiscontiguousData(buf, bitsPerSample, bytesPerRow,
2595 srcWidth, srcHeight,
2596 ras);
2597 }
2598 }
2599
2600 if (colorConverter != null) {
2601 float[] rgb = new float[3];
2602
2603 if(byteData != null) {
2604 for (int j = 0; j < dstHeight; j++) {
2605 int idx = dstOffset;
2606 for (int i = 0; i < dstWidth; i++) {
2607 float x0 = (float)(byteData[idx] & 0xff);
2608 float x1 = (float)(byteData[idx + 1] & 0xff);
2609 float x2 = (float)(byteData[idx + 2] & 0xff);
2610
2611 colorConverter.toRGB(x0, x1, x2, rgb);
2612
2613 byteData[idx] = (byte)(rgb[0]);
2614 byteData[idx + 1] = (byte)(rgb[1]);
|