View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.imaging.formats.tiff.datareaders;
18  
19  import java.awt.Rectangle;
20  import java.io.ByteArrayInputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.nio.ByteOrder;
24  import java.util.Arrays;
25  
26  import org.apache.commons.imaging.ImagingException;
27  import org.apache.commons.imaging.common.Allocator;
28  import org.apache.commons.imaging.common.ImageBuilder;
29  import org.apache.commons.imaging.common.PackBits;
30  import org.apache.commons.imaging.common.ZlibDeflate;
31  import org.apache.commons.imaging.formats.tiff.AbstractTiffRasterData;
32  import org.apache.commons.imaging.formats.tiff.TiffDirectory;
33  import org.apache.commons.imaging.formats.tiff.TiffField;
34  import org.apache.commons.imaging.formats.tiff.constants.TiffConstants;
35  import org.apache.commons.imaging.formats.tiff.constants.TiffPlanarConfiguration;
36  import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
37  import org.apache.commons.imaging.formats.tiff.itu_t4.T4AndT6Compression;
38  import org.apache.commons.imaging.formats.tiff.photometricinterpreters.AbstractPhotometricInterpreter;
39  import org.apache.commons.imaging.mylzw.MyLzwDecompressor;
40  
41  /**
42   * Defines the base class for the TIFF file reader classes. The TIFF format defines two broad organizations for image pixel storage: strips and tiles. This
43   * class defines common elements for both representations.
44   * <p>
45   * <strong>The TIFF Floating-Point Formats </strong>
46   * <p>
47   * In addition to providing images, TIFF files can supply data in the form of numerical values. As of March 2020 the Commons Imaging library was extended to
48   * support some floating-point data formats.
49   * <p>
50   * Unfortunately, the TIFF floating-point format allows for a lot of different variations. At this time, only the most widely used of these are supported. When
51   * this code was written, only a small set of test data products were available. Thus it is likely that developers will wish to extend the range of
52   * floating-point data that can be processed as additional test data become available. When implementing extensions to this logic, developers are reminded that
53   * image processing requires the handling of literally millions of pixels, so attention to performance is essential to a successful implementation (please see
54   * the notes in {@link DataReaderStrips} for more information).
55   * <p>
56   * The TIFF floating-point specification is poorly documented. So these notes are included to provide clarification on at least some aspects of the format. Some
57   * documentation and C-code examples are available in "TIFF Technical Note 3, April 8, 2005)".
58   * <p>
59   * <strong>The Predictor==3 Case</strong>
60   * <p>
61   * TIFF specifies an extension for a predictor that is intended to improve data compression ratios for floating-point values. This predictor is specified using
62   * the TIFF predictor TAG with a value of 3 (see TIFF Technical Note 3). Consider a 4-byte floating point value given in IEEE-754 format. Let f3 be the
63   * high-order byte, with f2 the next highest, followed by f1, and f0 for the low-order byte. This designation should not be confused with the in-memory layout
64   * of the bytes (little-endian versus big-endian), but rather their numerical values. The sign bit and upper 7 bits of the exponent are given in the high-order
65   * byte, followed by the one remaining exponent bit and the mantissa in the lower-order bytes.
66   * <p>
67   * In many real-valued raster data sets, the sign and magnitude (exponent) of the values change slowly. But the bits in the mantissa vary rapidly in a
68   * semi-random manner. The information entropy in the mantissa tends to increase in the lowest ordered bytes. Thus, the high-order bytes have more redundancy
69   * than the low-order bytes and can compress more efficiently. To exploit this, the TIFF format splits the bytes into groups based on their order-of-magnitude.
70   * This splitting process takes place on a ROW-BY-ROW basis (note the emphasis, this point is not clearly documented in the spec). For example, for a row of
71   * length 3 pixels -- A, B, and C -- the data for two rows would be given as shown below (again, ignoring endian issues):
72   *
73   * <pre>
74   *   Original:
75   *      A3 A2 A1 A0   B3 B2 B1 B0   C3 C2 C1 C0
76   *      D3 D3 D1 D0   E3 E2 E2 E0   F3 F2 F1 F0
77   *
78   *   Bytes split into groups by order-of-magnitude:
79   *      A3 B3 C3   A2 B2 C2   A1 B1 C1   A0 B0 C0
80   *      D3 E3 F3   D2 E2 F2   D1 E1 F1   D0 E0 F0
81   * </pre>
82   *
83   * To further improve the compression, the predictor takes the difference of each subsequent bytes. Again, the differences (deltas) are computed on a
84   * row-byte-row basis. For the most part, the differences combine bytes associated with the same order-of-magnitude, though there is a special transition at the
85   * end of each order-of-magnitude set (shown in parentheses):
86   *
87   * <pre>
88   *      A3, B3-A3, C3-B3, (A2-C3), B2-A2, C2-B2, (A1-C2), etc.
89   *      D3, E3-D3, F3-D3, (D2-F3), E3-D2, etc.
90   * </pre>
91   *
92   * Once the predictor transform is complete, the data is stored using conventional data compression techniques such as Deflate or LZW. In practice, floating
93   * point data does not compress especially well, but using the above technique, the TIFF process typically reduces the overall storage size by 20 to 30 percent
94   * (depending on the data). The TIFF Technical Note 3 specifies 3 data size formats for storing floating point values:
95   *
96   * <pre>
97   *     32 bits    IEEE-754 single-precision standard
98   *     16 bits    IEEE-754 half-precision standard
99   *     24 bits    A non-standard representation
100  * </pre>
101  *
102  * At this time, we have not obtained data samples for the smaller representations used in combination with a predictor.
103  * <p>
104  * <strong>Interleaved formats</strong>
105  * <p>
106  * TIFF Technical Note 3 also provides example code for cases where each pixel (or raster cell) in the image is associated with more than one floating-point
107  * samples. Data in this format might be used for real-valued vector data, complex-valued pairs, or other numerical applications).
108  * <p>
109  * At this time, we have encountered only a limited selection of the possible configurations for multi-variable data. The code below only supports those
110  * configurations for which we had actual images that could be used to verify our implementation. The implementation supports the following formats:
111  * <ul>
112  * <li>32-bit floating-point data</li>
113  * <li>Uncompressed, Deflate, or LZW compression</li>
114  * <li>Optional horizontal predictors used with compression</li>
115  * <li>PlanarConfiguration interleaved (CHUNKY) or non-interleaved (PLANAR)</li>
116  * </ul>
117  * <p>
118  * Note that integer formats are not supported at this time.
119  * <p>
120  * Often, the TIFF files store multi-variable data in so that samples are interleaved. For example, a configuration that gave two samples per pixel (or cell)
121  * would give the two values for the first pixel in order followed by the two values for the second pixel, etc. If a differencing approach were used for data
122  * compression, the byte-stream would begin with the high-order byte for each of the two samples for the first pixel, followed by the high-order byte for each
123  * of the next two samples, and so forth for the remainder of the row of pixels. It would then follow with the second-highest-order bytes for the first two
124  * samples, etc.
125  * <p>
126  * This implementation also supports the non-interleaved (PLANAR) configuration. One consideration in implementing this feature was that TIFF Technical Note 3
127  * does not address the case where a TIFF image uses the alternate planar configuration. For conventional images, the TIFF specification (Revision 6.0)
128  * recommends that the planar configuration should be avoided (see pg. 38). But for numerical data products, the planar configuration may yield better data
129  * compression in the case where different sample sets have different statistical properties. Because separated groups often have more uniformity and
130  * predictability than interleaved data sets, they sometimes lead to a small improvement in storage-size reduction when data compression is used.
131  */
132 public abstract class AbstractImageDataReader {
133 
134     protected final TiffDirectory directory;
135     protected final AbstractPhotometricInterpreter photometricInterpreter;
136     private final int[] bitsPerSample;
137     protected final int bitsPerSampleLength;
138     private final int[] last;
139 
140     protected final int predictor;
141     protected final int samplesPerPixel;
142     protected final int width;
143     protected final int height;
144     protected final int sampleFormat;
145 
146     protected final TiffPlanarConfiguration planarConfiguration;
147 
148     public AbstractImageDataReader(final TiffDirectory directory, final AbstractPhotometricInterpreter photometricInterpreter, final int[] bitsPerSample,
149             final int predictor, final int samplesPerPixel, final int sampleFormat, final int width, final int height,
150             final TiffPlanarConfiguration planarConfiguration) {
151         this.directory = directory;
152         this.photometricInterpreter = photometricInterpreter;
153         this.bitsPerSample = bitsPerSample;
154         this.bitsPerSampleLength = bitsPerSample.length;
155         this.samplesPerPixel = samplesPerPixel;
156         this.sampleFormat = sampleFormat;
157         this.predictor = predictor;
158         this.width = width;
159         this.height = height;
160         this.planarConfiguration = planarConfiguration;
161         last = Allocator.intArray(samplesPerPixel);
162     }
163 
164     protected int[] applyPredictor(final int[] samples) {
165         if (predictor == 2) {
166             // Horizontal differencing.
167             for (int i = 0; i < samples.length; i++) {
168                 samples[i] = 0xff & samples[i] + last[i];
169                 last[i] = samples[i];
170             }
171         }
172 
173         return samples;
174     }
175 
176     protected void applyPredictorToBlock(final int width, final int height, final int nSamplesPerPixel, final byte[] p) {
177         final int k = width * nSamplesPerPixel;
178         for (int i = 0; i < height; i++) {
179             final int j0 = i * k + nSamplesPerPixel;
180             final int j1 = (i + 1) * k;
181             for (int j = j0; j < j1; j++) {
182                 p[j] += p[j - nSamplesPerPixel];
183             }
184         }
185     }
186 
187     protected byte[] decompress(final byte[] compressedInput, final int compression, final int expectedSize, final int tileWidth, final int tileHeight)
188             throws ImagingException, IOException {
189         final TiffField fillOrderField = directory.findField(TiffTagConstants.TIFF_TAG_FILL_ORDER);
190         int fillOrder = TiffTagConstants.FILL_ORDER_VALUE_NORMAL;
191         if (fillOrderField != null) {
192             fillOrder = fillOrderField.getIntValue();
193         }
194         final byte[] compressedOrdered; // re-ordered bytes (if necessary)
195         if (fillOrder == TiffTagConstants.FILL_ORDER_VALUE_NORMAL) {
196             compressedOrdered = compressedInput;
197             // good
198         } else if (fillOrder == TiffTagConstants.FILL_ORDER_VALUE_REVERSED) {
199             compressedOrdered = new byte[compressedInput.length];
200             for (int i = 0; i < compressedInput.length; i++) {
201                 compressedOrdered[i] = (byte) (Integer.reverse(0xff & compressedInput[i]) >>> 24);
202             }
203         } else {
204             throw new ImagingException("TIFF FillOrder=" + fillOrder + " is invalid");
205         }
206 
207         switch (compression) {
208         case TiffConstants.COMPRESSION_UNCOMPRESSED:
209             // None;
210             return compressedOrdered;
211         case TiffConstants.COMPRESSION_CCITT_1D:
212             // CCITT Group 3 1-Dimensional Modified Huffman run-length encoding.
213             return T4AndT6Compression.decompressModifiedHuffman(compressedOrdered, tileWidth, tileHeight);
214         case TiffConstants.COMPRESSION_CCITT_GROUP_3: {
215             int t4Options = 0;
216             final TiffField field = directory.findField(TiffTagConstants.TIFF_TAG_T4_OPTIONS);
217             if (field != null) {
218                 t4Options = field.getIntValue();
219             }
220             final boolean is2D = (t4Options & TiffConstants.FLAG_T4_OPTIONS_2D) != 0;
221             final boolean usesUncompressedMode = (t4Options & TiffConstants.FLAG_T4_OPTIONS_UNCOMPRESSED_MODE) != 0;
222             if (usesUncompressedMode) {
223                 throw new ImagingException("T.4 compression with the uncompressed mode extension is not yet supported");
224             }
225             final boolean hasFillBitsBeforeEOL = (t4Options & TiffConstants.FLAG_T4_OPTIONS_FILL) != 0;
226             if (is2D) {
227                 return T4AndT6Compression.decompressT4_2D(compressedOrdered, tileWidth, tileHeight, hasFillBitsBeforeEOL);
228             }
229             return T4AndT6Compression.decompressT4_1D(compressedOrdered, tileWidth, tileHeight, hasFillBitsBeforeEOL);
230         }
231         case TiffConstants.COMPRESSION_CCITT_GROUP_4: {
232             int t6Options = 0;
233             final TiffField field = directory.findField(TiffTagConstants.TIFF_TAG_T6_OPTIONS);
234             if (field != null) {
235                 t6Options = field.getIntValue();
236             }
237             final boolean usesUncompressedMode = (t6Options & TiffConstants.FLAG_T6_OPTIONS_UNCOMPRESSED_MODE) != 0;
238             if (usesUncompressedMode) {
239                 throw new ImagingException("T.6 compression with the uncompressed mode extension is not yet supported");
240             }
241             return T4AndT6Compression.decompressT6(compressedOrdered, tileWidth, tileHeight);
242         }
243         case TiffConstants.COMPRESSION_LZW: {
244             final InputStream is = new ByteArrayInputStream(compressedOrdered);
245             final int lzwMinimumCodeSize = 8;
246             return new MyLzwDecompressor(lzwMinimumCodeSize, ByteOrder.BIG_ENDIAN, true).decompress(is, expectedSize);
247         }
248 
249         // Packbits
250         case TiffConstants.COMPRESSION_PACKBITS: {
251             return PackBits.decompress(compressedOrdered, expectedSize);
252         }
253 
254         // deflate
255         case TiffConstants.COMPRESSION_DEFLATE_ADOBE:
256         case TiffConstants.COMPRESSION_DEFLATE_PKZIP: {
257             return ZlibDeflate.decompress(compressedInput, expectedSize);
258         }
259 
260         default:
261             throw new ImagingException("Tiff: unknown/unsupported compression: " + compression);
262         }
263     }
264 
265     /**
266      * Reads samples and returns them in an int array.
267      *
268      * @param bis    the stream to read from
269      * @param result the samples array to populate, must be the same length as bitsPerSample.length
270      * @throws IOException
271      */
272     void getSamplesAsBytes(final BitInputStream bis, final int[] result) throws IOException {
273         for (int i = 0; i < bitsPerSample.length; i++) {
274             final int bits = bitsPerSample[i];
275             int sample = bis.readBits(bits);
276             if (bits < 8) {
277                 final int sign = sample & 1;
278                 sample = sample << 8 - bits; // scale to byte.
279                 if (sign > 0) {
280                     sample = sample | (1 << 8 - bits) - 1; // extend to byte
281                 }
282             } else if (bits > 8) {
283                 sample = sample >> bits - 8; // extend to byte.
284             }
285             result[i] = sample;
286         }
287     }
288 
289     /**
290      * Checks if all the bits per sample entries are the same size
291      *
292      * @param size the size to check
293      * @return true if all the bits per sample entries are the same
294      */
295     protected boolean isHomogenous(final int size) {
296         for (final int element : bitsPerSample) {
297             if (element != size) {
298                 return false;
299             }
300         }
301         return true;
302     }
303 
304     /**
305      * Reads the image data from the IFD associated with this instance of ImageDataReader using the optional sub-image specification if desired.
306      *
307      * @param subImageSpecification a rectangle describing a sub-region of the image for reading, or a null if the whole image is to be read.
308      * @param hasAlpha              indicates that the image has an alpha (transparency) channel (RGB color model only).
309      * @param isAlphaPremultiplied  indicates that the image uses the associated alpha channel format (pre-multiplied alpha).
310      * @return a valid instance containing the pixel data from the image.
311      * @throws IOException      in the event of an unrecoverable I/O error.
312      * @throws ImagingException TODO
313      */
314     public abstract ImageBuilder readImageData(Rectangle subImageSpecification, boolean hasAlpha, boolean isAlphaPremultiplied)
315             throws IOException, ImagingException;
316 
317     /**
318      * Defines a method for accessing the floating-point raster data in a TIFF image. These implementations of this method in DataReaderStrips and
319      * DataReaderTiled assume that this instance is of a compatible data type (floating-point) and that all access checks have already been performed.
320      *
321      * @param subImage if non-null, instructs the access method to retrieve only a sub-section of the image data.
322      * @return a valid instance
323      * @throws ImagingException in the event of an incompatible data form.
324      * @throws IOException      in the event of I/O error.
325      */
326     public abstract AbstractTiffRasterData readRasterData(Rectangle subImage) throws ImagingException, IOException;
327 
328     protected void resetPredictor() {
329         Arrays.fill(last, 0);
330     }
331 
332     /**
333      * Transfer samples obtained from the TIFF file to a floating-point raster.
334      *
335      * @param xBlock       coordinate of block relative to source data
336      * @param yBlock       coordinate of block relative to source data
337      * @param blockWidth   width of block, in pixels
338      * @param blockHeight  height of block in pixels
339      * @param blockData    the data for the block
340      * @param xRaster      coordinate of raster relative to source data
341      * @param yRaster      coordinate of raster relative to source data
342      * @param rasterWidth  width of the raster (always smaller than source data)
343      * @param rasterHeight height of the raster (always smaller than source data)
344      * @param rasterData   the raster data.
345      */
346     void transferBlockToRaster(final int xBlock, final int yBlock, final int blockWidth, final int blockHeight, final int[] blockData, final int xRaster,
347             final int yRaster, final int rasterWidth, final int rasterHeight, final int samplesPerPixel, final float[] rasterData) {
348 
349         // xR0, yR0 are the coordinates within the raster (upper-left corner)
350         // xR1, yR1 are ONE PAST the coordinates of the lower-right corner
351         int xR0 = xBlock - xRaster; // xR0, yR0 coordinates relative to
352         int yR0 = yBlock - yRaster; // the raster
353         int xR1 = xR0 + blockWidth;
354         int yR1 = yR0 + blockHeight;
355         if (xR0 < 0) {
356             xR0 = 0;
357         }
358         if (yR0 < 0) {
359             yR0 = 0;
360         }
361         if (xR1 > rasterWidth) {
362             xR1 = rasterWidth;
363         }
364         if (yR1 > rasterHeight) {
365             yR1 = rasterHeight;
366         }
367 
368         // Recall that the above logic may have adjusted xR0, xY0 so that
369         // they are not necessarily point to the source pixel at xRaster, yRaster
370         // we compute xSource = xR0+xRaster.
371         // xOffset = xSource-xBlock
372         // since the block cannot be accessed with a negative offset,
373         // we check for negatives and adjust xR0, yR0 upward as necessary
374         int xB0 = xR0 + xRaster - xBlock;
375         int yB0 = yR0 + yRaster - yBlock;
376         if (xB0 < 0) {
377             xR0 -= xB0;
378             xB0 = 0;
379         }
380         if (yB0 < 0) {
381             yR0 -= yB0;
382             yB0 = 0;
383         }
384 
385         int w = xR1 - xR0;
386         int h = yR1 - yR0;
387         if (w <= 0 || h <= 0) {
388             // The call to this method put the block outside the
389             // bounds of the raster. There is nothing to do. Ideally,
390             // this situation never arises, because it would mean that
391             // the data was read from the file unnecessarily.
392             return;
393         }
394         // see if the xR1, yR1 would extend past the limits of the block
395         if (w > blockWidth) {
396             w = blockWidth;
397         }
398         if (h > blockHeight) {
399             h = blockHeight;
400         }
401 
402         // The TiffRasterData class expects data to be in the order
403         // corresponding to TiffPlanarConfiguration.PLANAR. So for the
404         // multivariable case, we must convert CHUNKY data to PLANAR.
405         if (samplesPerPixel == 1) {
406             for (int i = 0; i < h; i++) {
407                 final int yR = yR0 + i;
408                 final int yB = yB0 + i;
409                 final int rOffset = yR * rasterWidth + xR0;
410                 final int bOffset = yB * blockWidth + xB0;
411                 for (int j = 0; j < w; j++) {
412                     rasterData[rOffset + j] = Float.intBitsToFloat(blockData[bOffset + j]);
413                 }
414             }
415         } else if (this.planarConfiguration == TiffPlanarConfiguration.CHUNKY) {
416             // The source data is in the interleaved (Chunky) order,
417             // but the TiffRasterData class expects non-interleaved order.
418             // So we transcribe the elements as appropriate.
419             final int pixelsPerPlane = rasterWidth * rasterHeight;
420             for (int i = 0; i < h; i++) {
421                 final int yR = yR0 + i;
422                 final int yB = yB0 + i;
423                 final int rOffset = yR * rasterWidth + xR0;
424                 final int bOffset = yB * blockWidth + xB0;
425                 for (int j = 0; j < w; j++) {
426                     for (int k = 0; k < samplesPerPixel; k++) {
427                         rasterData[k * pixelsPerPlane + rOffset + j] = Float.intBitsToFloat(blockData[(bOffset + j) * samplesPerPixel + k]);
428                     }
429                 }
430             }
431         } else {
432             for (int iPlane = 0; iPlane < samplesPerPixel; iPlane++) {
433                 final int rPlanarOffset = iPlane * rasterWidth * rasterHeight;
434                 final int bPlanarOffset = iPlane * blockWidth * blockHeight;
435                 for (int i = 0; i < h; i++) {
436                     final int yR = yR0 + i;
437                     final int yB = yB0 + i;
438                     final int rOffset = rPlanarOffset + yR * rasterWidth + xR0;
439                     final int bOffset = bPlanarOffset + yB * blockWidth + xB0;
440                     for (int j = 0; j < w; j++) {
441                         rasterData[rOffset + j] = Float.intBitsToFloat(blockData[bOffset + j]);
442                     }
443                 }
444             }
445         }
446 
447     }
448 
449     /**
450      * Transfer samples obtained from the TIFF file to an integer raster.
451      *
452      * @param xBlock       coordinate of block relative to source data
453      * @param yBlock       coordinate of block relative to source data
454      * @param blockWidth   width of block, in pixels
455      * @param blockHeight  height of block in pixels
456      * @param blockData    the data for the block
457      * @param xRaster      coordinate of raster relative to source data
458      * @param yRaster      coordinate of raster relative to source data
459      * @param rasterWidth  width of the raster (always smaller than source data)
460      * @param rasterHeight height of the raster (always smaller than source data)
461      * @param rasterData   the raster data.
462      */
463     void transferBlockToRaster(final int xBlock, final int yBlock, final int blockWidth, final int blockHeight, final int[] blockData, final int xRaster,
464             final int yRaster, final int rasterWidth, final int rasterHeight, final int[] rasterData) {
465 
466         // xR0, yR0 are the coordinates within the raster (upper-left corner)
467         // xR1, yR1 are ONE PAST the coordinates of the lower-right corner
468         int xR0 = xBlock - xRaster; // xR0, yR0 coordinates relative to
469         int yR0 = yBlock - yRaster; // the raster
470         int xR1 = xR0 + blockWidth;
471         int yR1 = yR0 + blockHeight;
472         if (xR0 < 0) {
473             xR0 = 0;
474         }
475         if (yR0 < 0) {
476             yR0 = 0;
477         }
478         if (xR1 > rasterWidth) {
479             xR1 = rasterWidth;
480         }
481         if (yR1 > rasterHeight) {
482             yR1 = rasterHeight;
483         }
484 
485         // Recall that the above logic may have adjusted xR0, xY0 so that
486         // they are not necessarily point to the source pixel at xRaster, yRaster
487         // we compute xSource = xR0+xRaster.
488         // xOffset = xSource-xBlock
489         // since the block cannot be accessed with a negative offset,
490         // we check for negatives and adjust xR0, yR0 upward as necessary
491         int xB0 = xR0 + xRaster - xBlock;
492         int yB0 = yR0 + yRaster - yBlock;
493         if (xB0 < 0) {
494             xR0 -= xB0;
495             xB0 = 0;
496         }
497         if (yB0 < 0) {
498             yR0 -= yB0;
499             yB0 = 0;
500         }
501 
502         int w = xR1 - xR0;
503         int h = yR1 - yR0;
504         if (w <= 0 || h <= 0) {
505             // The call to this method puts the block outside the
506             // bounds of the raster. There is nothing to do. Ideally,
507             // this situation never arises, because it would mean that
508             // the data was read from the file unnecessarily.
509             return;
510         }
511         // see if the xR1, yR1 would extend past the limits of the block
512         if (w > blockWidth) {
513             w = blockWidth;
514         }
515         if (h > blockHeight) {
516             h = blockHeight;
517         }
518 
519         for (int i = 0; i < h; i++) {
520             final int yR = yR0 + i;
521             final int yB = yB0 + i;
522             final int rOffset = yR * rasterWidth + xR0;
523             final int bOffset = yB * blockWidth + xB0;
524             System.arraycopy(blockData, bOffset, rasterData, rOffset, w);
525         }
526     }
527 
528     /**
529      * Given a source file that specifies the floating-point data format, unpack the raw bytes obtained from the source file and organize them into an array of
530      * integers containing the bit-equivalent of IEEE-754 32-bit floats. Source files containing 64 bit doubles are downcast to floats.
531      * <p>
532      * This method supports either the tile format or the strip format of TIFF source files. The scan size indicates the number of columns to be extracted. For
533      * strips, the width and the scan size are always the full width of the image. For tiles, the scan size is the full width of the tile, but the width may be
534      * smaller in the cases where the tiles do not evenly divide the width (for example, a 256 pixel wide tile in a 257 pixel wide image would result in two
535      * columns of tiles, the second column having only one column of pixels that were worth extracting.
536      *
537      * @param width        the width of the data block to be extracted
538      * @param height       the height of the data block to be extracted
539      * @param scanSize     the number of pixels in a single row of the block
540      * @param bytes        the raw bytes
541      * @param bitsPerPixel the number of bits per sample, 32 or 64.
542      * @param byteOrder    the byte order for the source data
543      * @return a valid array of integers in row major order, dimensions scan-size wide and height.
544      * @throws ImagingException in the event of an invalid format.
545      */
546     protected int[] unpackFloatingPointSamples(final int width, final int height, final int scanSize, final byte[] bytes, final int bitsPerPixel,
547             final ByteOrder byteOrder) throws ImagingException {
548         final int bitsPerSample = bitsPerPixel / samplesPerPixel;
549         final int bytesPerSample = bitsPerSample / 8;
550         final int bytesPerScan = scanSize * samplesPerPixel * bytesPerSample;
551         final int nBytes = bytesPerScan * height;
552         final int length = bytes.length < nBytes ? nBytes / bytesPerScan : height;
553         final int[] samples = Allocator.intArray(scanSize * samplesPerPixel * height);
554         // floating-point differencing is indicated by a predictor value of 3.
555         if (predictor == TiffTagConstants.PREDICTOR_VALUE_FLOATING_POINT_DIFFERENCING) {
556             // at this time, this class supports the 32-bit format. The
557             // main reason for this is that we have not located sample data
558             // that can be used for testing and analysis.
559             if (bitsPerPixel / samplesPerPixel != 32) {
560                 throw new ImagingException(
561                         "Imaging does not yet support floating-point data" + " with predictor type 3 for " + bitsPerPixel + " bits per sample");
562             }
563 
564             if (planarConfiguration == TiffPlanarConfiguration.CHUNKY) {
565                 final int bytesInRow = scanSize * 4 * samplesPerPixel;
566                 for (int i = 0; i < length; i++) {
567                     final int aOffset = i * bytesInRow;
568                     final int bOffset = aOffset + scanSize * samplesPerPixel;
569                     final int cOffset = bOffset + scanSize * samplesPerPixel;
570                     final int dOffset = cOffset + scanSize * samplesPerPixel;
571                     // in this loop, the source bytes give delta values.
572                     // we adjust them to give true values. This operation is
573                     // done on a row-by-row basis.
574                     for (int j = 1; j < bytesInRow; j++) {
575                         bytes[aOffset + j] += bytes[aOffset + j - 1];
576                     }
577                     // pack the bytes into the integer bit-equivalent of
578                     // floating point values
579                     int index = i * scanSize;
580                     for (int j = 0; j < width * samplesPerPixel; j++) {
581                         final int a = bytes[aOffset + j];
582                         final int b = bytes[bOffset + j];
583                         final int c = bytes[cOffset + j];
584                         final int d = bytes[dOffset + j];
585                         // Pack the 4 byte components into a single integer
586                         // in the byte order used by the TIFF standard
587                         samples[index++] = (a & 0xff) << 24 | (b & 0xff) << 16 | (c & 0xff) << 8 | d & 0xff;
588                     }
589                 }
590             } else {
591                 final int bytesInRow = scanSize * 4;
592                 for (int iPlane = 0; iPlane < samplesPerPixel; iPlane++) {
593                     final int planarIntOffset = iPlane * length * scanSize;
594                     final int planarByteOffset = planarIntOffset * 4;
595 
596                     for (int i = 0; i < length; i++) {
597                         final int aOffset = i * bytesInRow + planarByteOffset;
598                         final int bOffset = aOffset + scanSize;
599                         final int cOffset = bOffset + scanSize;
600                         final int dOffset = cOffset + scanSize;
601                         // in this loop, the source bytes give delta values.
602                         // we adjust them to give true values. This operation is
603                         // done on a row-by-row basis.
604                         for (int j = 1; j < bytesInRow; j++) {
605                             bytes[aOffset + j] += bytes[aOffset + j - 1];
606                         }
607                         // pack the bytes into the integer bit-equivalent of
608                         // floating point values
609                         int index = planarIntOffset + i * scanSize;
610                         for (int j = 0; j < width; j++) {
611                             final int a = bytes[aOffset + j];
612                             final int b = bytes[bOffset + j];
613                             final int c = bytes[cOffset + j];
614                             final int d = bytes[dOffset + j];
615                             // Pack the 4 byte components into a single integer
616                             // in the byte order used by the TIFF standard
617                             samples[index++] = (a & 0xff) << 24 | (b & 0xff) << 16 | (c & 0xff) << 8 | d & 0xff;
618                         }
619                     }
620                 }
621 
622             }
623             return samples;
624         } // end of predictor==3 case.
625 
626         // simple packing case, 64 or 32 bits --------------------------
627         if (bitsPerSample == 64) {
628             int k = 0;
629             int index = 0;
630             for (int i = 0; i < length; i++) {
631                 for (int j = 0; j < scanSize; j++) {
632                     final long b0 = bytes[k++] & 0xffL;
633                     final long b1 = bytes[k++] & 0xffL;
634                     final long b2 = bytes[k++] & 0xffL;
635                     final long b3 = bytes[k++] & 0xffL;
636                     final long b4 = bytes[k++] & 0xffL;
637                     final long b5 = bytes[k++] & 0xffL;
638                     final long b6 = bytes[k++] & 0xffL;
639                     final long b7 = bytes[k++] & 0xffL;
640                     final long sbits;
641                     if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
642                         sbits = b7 << 56 | b6 << 48 | b5 << 40 | b4 << 32 | b3 << 24 | b2 << 16 | b1 << 8 | b0;
643 
644                     } else {
645                         sbits = b0 << 56 | b1 << 48 | b2 << 40 | b3 << 32 | b4 << 24 | b5 << 16 | b6 << 8 | b7;
646                     }
647                     // since the photometric interpreter does not
648                     // currently support doubles, we need to replace this
649                     // element with a float. This action is inefficient and
650                     // should be improved.
651                     final float f = (float) Double.longBitsToDouble(sbits);
652                     samples[index++] = Float.floatToRawIntBits(f);
653                 }
654             }
655         } else if (bitsPerSample == 32) {
656             int k = 0;
657             int index = 0;
658             for (int i = 0; i < length; i++) {
659                 for (int j = 0; j < scanSize * samplesPerPixel; j++) {
660                     final int b0 = bytes[k++] & 0xff;
661                     final int b1 = bytes[k++] & 0xff;
662                     final int b2 = bytes[k++] & 0xff;
663                     final int b3 = bytes[k++] & 0xff;
664                     final int sbits;
665                     if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
666                         sbits = b3 << 24 | b2 << 16 | b1 << 8 | b0;
667 
668                     } else {
669                         sbits = b0 << 24 | b1 << 16 | b2 << 8 | b3;
670                     }
671                     // since the photometric interpreter does not
672                     // currently support doubles, we need to replace this
673                     // element with a float. This action is inefficient and
674                     // should be improved.
675                     samples[index++] = sbits;
676                 }
677             }
678         } else {
679             throw new ImagingException("Imaging does not support floating-point samples with " + bitsPerPixel + " bits per sample");
680         }
681 
682         return samples;
683     }
684 
685     /**
686      * Given a source file that specifies numerical data as short integers, unpack the raw bytes obtained from the source file and organize them into an array
687      * of integers.
688      * <p>
689      * This method supports either the tile format or the strip format of TIFF source files. The scan size indicates the number of columns to be extracted. For
690      * strips, the width and the scan size are always the full width of the image. For tiles, the scan size is the full width of the tile, but the "width"
691      * parameter may be smaller in the cases where the tiles do not evenly divide the width (for example, a 256 pixel wide tile in a 257 pixel wide image would
692      * result in two columns of tiles, the second column having only one column of pixels that were worth extracting.
693      *
694      * @param width         the width of the data block to be extracted
695      * @param height        the height of the data block to be extracted
696      * @param scanSize      the number of pixels in a single row of the block
697      * @param bytes         the raw bytes
698      * @param predictor     the predictor specified by the source, only predictor 3 is supported.
699      * @param bitsPerSample the number of bits per sample, 32 or 64.
700      * @param byteOrder     the byte order for the source data
701      * @return a valid array of integers in row major order, dimensions scan-size wide and height.
702      */
703     protected int[] unpackIntSamples(final int width, final int height, final int scanSize, final byte[] bytes, final int predictor, final int bitsPerSample,
704             final ByteOrder byteOrder) {
705         final int bytesPerSample = bitsPerSample / 8;
706         final int nBytes = bytesPerSample * scanSize * height;
707         final int length = bytes.length < nBytes ? nBytes / scanSize : height;
708 
709         final int[] samples = Allocator.intArray(scanSize * height);
710         // At this time, Commons Imaging only supports two-byte
711         // two's complement short integers. It is assumed that
712         // the calling module already checked the arguments for
713         // compliance, so this method simply assumes that they are correct.
714 
715         // The logic that follows is simplified by the fact that
716         // the existing API only supports two-byte signed integers.
717         final boolean useDifferencing = predictor == TiffTagConstants.PREDICTOR_VALUE_HORIZONTAL_DIFFERENCING;
718 
719         for (int i = 0; i < length; i++) {
720             final int index = i * scanSize;
721             int offset = index * bytesPerSample;
722             if (bitsPerSample == 16) {
723                 if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
724                     for (int j = 0; j < width; j++, offset += 2) {
725                         samples[index + j] = bytes[offset + 1] << 8 | bytes[offset] & 0xff;
726                     }
727                 } else {
728                     for (int j = 0; j < width; j++, offset += 2) {
729                         samples[index + j] = bytes[offset] << 8 | bytes[offset + 1] & 0xff;
730                     }
731                 }
732             } else if (bitsPerSample == 32) {
733                 if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
734                     for (int j = 0; j < width; j++, offset += 4) {
735                         samples[index + j] = bytes[offset + 3] << 24 | (bytes[offset + 2] & 0xff) << 16 | (bytes[offset + 1] & 0xff) << 8
736                                 | bytes[offset] & 0xff;
737                     }
738                 } else {
739                     for (int j = 0; j < width; j++, offset += 4) {
740                         samples[index + j] = bytes[offset] << 24 | (bytes[offset + 1] & 0xff) << 16 | (bytes[offset + 2] & 0xff) << 8
741                                 | bytes[offset + 3] & 0xff;
742                     }
743                 }
744             }
745             if (useDifferencing) {
746                 for (int j = 1; j < width; j++) {
747                     samples[index + j] += samples[index + j - 1];
748                 }
749             }
750         }
751 
752         return samples;
753     }
754 }