001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.imaging.formats.tiff.datareaders;
018
019import java.awt.Rectangle;
020import java.io.ByteArrayInputStream;
021import java.io.IOException;
022import java.io.InputStream;
023import java.nio.ByteOrder;
024import java.util.Arrays;
025
026import org.apache.commons.imaging.ImagingException;
027import org.apache.commons.imaging.common.Allocator;
028import org.apache.commons.imaging.common.ImageBuilder;
029import org.apache.commons.imaging.common.PackBits;
030import org.apache.commons.imaging.common.ZlibDeflate;
031import org.apache.commons.imaging.formats.tiff.AbstractTiffRasterData;
032import org.apache.commons.imaging.formats.tiff.TiffDirectory;
033import org.apache.commons.imaging.formats.tiff.TiffField;
034import org.apache.commons.imaging.formats.tiff.constants.TiffConstants;
035import org.apache.commons.imaging.formats.tiff.constants.TiffPlanarConfiguration;
036import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
037import org.apache.commons.imaging.formats.tiff.itu_t4.T4AndT6Compression;
038import org.apache.commons.imaging.formats.tiff.photometricinterpreters.AbstractPhotometricInterpreter;
039import org.apache.commons.imaging.mylzw.MyLzwDecompressor;
040
041/**
042 * 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
043 * class defines common elements for both representations.
044 * <p>
045 * <strong>The TIFF Floating-Point Formats </strong>
046 * <p>
047 * 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
048 * support some floating-point data formats.
049 * <p>
050 * 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
051 * 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
052 * floating-point data that can be processed as additional test data become available. When implementing extensions to this logic, developers are reminded that
053 * image processing requires the handling of literally millions of pixels, so attention to performance is essential to a successful implementation (please see
054 * the notes in {@link DataReaderStrips} for more information).
055 * <p>
056 * 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
057 * documentation and C-code examples are available in "TIFF Technical Note 3, April 8, 2005)".
058 * <p>
059 * <strong>The Predictor==3 Case</strong>
060 * <p>
061 * TIFF specifies an extension for a predictor that is intended to improve data compression ratios for floating-point values. This predictor is specified using
062 * 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
063 * 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
064 * 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
065 * byte, followed by the one remaining exponent bit and the mantissa in the lower-order bytes.
066 * <p>
067 * 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
068 * 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
069 * 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.
070 * 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
071 * length 3 pixels -- A, B, and C -- the data for two rows would be given as shown below (again, ignoring endian issues):
072 *
073 * <pre>
074 *   Original:
075 *      A3 A2 A1 A0   B3 B2 B1 B0   C3 C2 C1 C0
076 *      D3 D3 D1 D0   E3 E2 E2 E0   F3 F2 F1 F0
077 *
078 *   Bytes split into groups by order-of-magnitude:
079 *      A3 B3 C3   A2 B2 C2   A1 B1 C1   A0 B0 C0
080 *      D3 E3 F3   D2 E2 F2   D1 E1 F1   D0 E0 F0
081 * </pre>
082 *
083 * To further improve the compression, the predictor takes the difference of each subsequent bytes. Again, the differences (deltas) are computed on a
084 * 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
085 * end of each order-of-magnitude set (shown in parentheses):
086 *
087 * <pre>
088 *      A3, B3-A3, C3-B3, (A2-C3), B2-A2, C2-B2, (A1-C2), etc.
089 *      D3, E3-D3, F3-D3, (D2-F3), E3-D2, etc.
090 * </pre>
091 *
092 * Once the predictor transform is complete, the data is stored using conventional data compression techniques such as Deflate or LZW. In practice, floating
093 * 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
094 * (depending on the data). The TIFF Technical Note 3 specifies 3 data size formats for storing floating point values:
095 *
096 * <pre>
097 *     32 bits    IEEE-754 single-precision standard
098 *     16 bits    IEEE-754 half-precision standard
099 *     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 */
132public 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}