This is an automated email from the ASF dual-hosted git repository.

kinow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-imaging.git

commit 263dddeb92204f840a4136c351b5f2631d646a17
Author: gwlucastrig <contact.tinf...@gmail.com>
AuthorDate: Wed Sep 8 22:02:03 2021 -0400

    [IMAGING-266] Read numeric data from GeoTIFFs
---
 src/conf/spotbugs-exclude-filter.xml               |  18 ++
 .../imaging/formats/tiff/TiffDirectory.java        |  67 ++++--
 .../imaging/formats/tiff/TiffImageParser.java      | 118 ++++++----
 .../imaging/formats/tiff/TiffRasterData.java       | 163 +++++++------
 ...iffRasterData.java => TiffRasterDataFloat.java} | 130 +++++++----
 ...{TiffRasterData.java => TiffRasterDataInt.java} | 134 +++++++----
 .../imaging/formats/tiff/TiffRasterDataType.java}  |  38 ++-
 .../formats/tiff/constants/TiffTagConstants.java   |   2 +-
 .../formats/tiff/datareaders/DataReaderStrips.java |  84 ++++++-
 .../formats/tiff/datareaders/DataReaderTiled.java  |  82 ++++++-
 .../formats/tiff/datareaders/ImageDataReader.java  | 190 +++++++++++++--
 .../commons/imaging/TestImageReadException.java    |  24 +-
 .../commons/imaging/TestImageWriteException.java   |  68 +++---
 .../tiff/ExampleReadFloatingPointData.java         |   2 +-
 .../imaging/examples/tiff/SurveyTiffFile.java      |   3 +-
 .../formats/tiff/TiffFloatingPointReadTest.java    |   2 +-
 ...terDataTest.java => TiffRasterDataIntTest.java} |  91 ++++----
 .../imaging/formats/tiff/TiffRasterDataTest.java   |  55 ++++-
 .../formats/tiff/TiffRasterStatisticsTest.java     |   4 +-
 .../formats/tiff/TiffShortIntRoundTripTest.java    | 255 +++++++++++++++++++++
 20 files changed, 1126 insertions(+), 404 deletions(-)

diff --git a/src/conf/spotbugs-exclude-filter.xml 
b/src/conf/spotbugs-exclude-filter.xml
index 2f99342..0cfc7cb 100644
--- a/src/conf/spotbugs-exclude-filter.xml
+++ b/src/conf/spotbugs-exclude-filter.xml
@@ -72,6 +72,24 @@
     <Bug pattern="EI_EXPOSE_REP2" />
   </Match>
   <Match>
+    <Class name="org.apache.commons.imaging.formats.tiff.TiffRasterDataFloat" 
/>
+    <Method name="getData" />
+    <Bug pattern="EI_EXPOSE_REP" />
+  </Match>
+  <Match>
+    <Class name="org.apache.commons.imaging.formats.tiff.TiffRasterDataFloat" 
/>
+    <Bug pattern="EI_EXPOSE_REP2" />
+  </Match>
+    <Match>
+    <Class name="org.apache.commons.imaging.formats.tiff.TiffRasterDataInt" />
+    <Method name="getIntData" />
+    <Bug pattern="EI_EXPOSE_REP" />
+  </Match>
+  <Match>
+    <Class name="org.apache.commons.imaging.formats.tiff.TiffRasterDataInt" />
+    <Bug pattern="EI_EXPOSE_REP2" />
+  </Match>
+  <Match>
     <Class 
name="org.apache.commons.imaging.formats.tiff.datareaders.ImageDataReader" />
     <Bug pattern="EI_EXPOSE_REP2" />
   </Match>
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java
index e84f780..d548365 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffDirectory.java
@@ -92,6 +92,16 @@ public class TiffDirectory extends TiffElement {
         this.headerByteOrder = byteOrder;
     }
 
+    /**
+     * Gets the byte order used by the source file for storing this directory
+     * and its content.
+     *
+     * @return A valid byte order instance.
+     */
+    public ByteOrder getByteOrder() {
+        return headerByteOrder;
+    }
+
     public String description() {
         return TiffDirectory.description(type);
     }
@@ -845,11 +855,11 @@ public class TiffDirectory extends TiffElement {
     }
 
     /**
-     * Reads the floating-point data stored in this TIFF directory, if
-     * available. Note that this method is defined only for TIFF directories
-     * that contain floating-point data.
+     * Reads the numerical data stored in this TIFF directory, if available.
+     * Note that this method is defined only for TIFF directories that contain
+     * floating-point data or two-byte signed integer data.
      * <p>
-     * TIFF directories that provide floating-point data do not directly 
specify
+     * TIFF directories that provide numerical data do not directly specify
      * images, though it is possible to interpret the data as an image using
      * this library. TIFF files may contain multiple directories which are
      * allowed to have different formats. Thus it is possible for a TIFF file 
to
@@ -872,37 +882,62 @@ public class TiffDirectory extends TiffElement {
      *   TiffRasterData raster =
      *        directory.readFloatingPointRasterData(params);
      * </pre>
-
+     *
      * @param params an optional parameter map instance
      * @return a valid instance
      * @throws ImageReadException in the event of incompatible or malformed 
data
      * @throws IOException in the event of an I/O error
      */
-    public TiffRasterData getFloatingPointRasterData(
-        final Map<String, Object> params)
-        throws ImageReadException, IOException {
+    public TiffRasterData getRasterData(
+            final Map<String, Object> params)
+            throws ImageReadException, IOException {
 
         final TiffImageParser parser = new TiffImageParser();
-        return parser.getFloatingPointRasterData(this, headerByteOrder, 
params);
+        return parser.getRasterData(this, headerByteOrder, params);
     }
 
     /**
      * Indicates whether the directory definition specifies a float-point data
      * format.
      *
-     * @return true if the directory contains floating point data; otherwise,
-     * false
+     * @return {@code true} if the directory contains floating point data;
+     * otherwise, {@code false}
+     *
      * @throws ImageReadException in the event of an invalid or malformed
      * specification.
      */
     public boolean hasTiffFloatingPointRasterData() throws ImageReadException {
-        if (this.hasTiffImageData()) {
-            final short[] sSampleFmt = getFieldValue(
+        if (!this.hasTiffImageData()) {
+            return false;
+        }
+        final short[] s = getFieldValue(
                 TiffTagConstants.TIFF_TAG_SAMPLE_FORMAT, false);
-            return sSampleFmt != null && sSampleFmt.length > 0
-                && sSampleFmt[0] == 
TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT;
+        return s != null
+                && s.length > 0
+                && s[0] == 
TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT;
+
+    }
 
+    /**
+     * Indicates whether the content associated with the directory is given in 
a
+     * supported numerical-data format. If this method returns {@code true}, 
the
+     * Imaging API will be able to extract a TiffRasterData instance from the
+     * associated TIFF file using this directory.
+     *
+     * @return {@code true} if the directory contains a supported raster data
+     * format; otherwise, {@code false}.
+     * @throws ImageReadException in the event of an invalid or malformed
+     * specification.
+     */
+    public boolean hasTiffRasterData() throws ImageReadException {
+        if (!this.hasTiffImageData()) {
+            return false;
         }
-        return false;
+        final short[] s = getFieldValue(
+                TiffTagConstants.TIFF_TAG_SAMPLE_FORMAT, false);
+        return s != null
+                && s.length > 0
+                && (s[0] == 
TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT
+                || s[0] == 
TiffTagConstants.SAMPLE_FORMAT_VALUE_TWOS_COMPLEMENT_SIGNED_INTEGER);
     }
 }
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java
index 1418b4f..4a8279f 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffImageParser.java
@@ -34,6 +34,7 @@ import java.io.PrintWriter;
 import java.nio.ByteOrder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -762,12 +763,12 @@ public class TiffImageParser extends ImageParser 
implements XmpEmbeddable {
     }
 
     /**
-     * Reads the content of a TIFF file that contains floating-point data
-     * samples.
+     * Reads the content of a TIFF file that contains numerical data samples
+     * rather than image-related pixels.
      * <p>
-     * If desired, sub-image data can be read from the file by using a Java Map
-     * instance to specify the subsection of the image that is required. The
-     * following code illustrates the approach:
+     * If desired, sub-image data can be read from the file by using a Java
+     * {@code Map} instance to specify the subsection of the image that
+     * is required. The following code illustrates the approach:
      * <pre>
      *   int x; // coordinate (column) of corner of sub-image
      *   int y; // coordinate (row) of corner of sub-image
@@ -791,62 +792,57 @@ public class TiffImageParser extends ImageParser 
implements XmpEmbeddable {
      * @throws ImageReadException in the event of incompatible or malformed 
data
      * @throws IOException in the event of an I/O error
      */
-    TiffRasterData getFloatingPointRasterData(
-        final TiffDirectory directory,
-        final ByteOrder byteOrder,
-        final Map<String, Object> params)
-        throws ImageReadException, IOException {
+    TiffRasterData getRasterData(
+            final TiffDirectory directory,
+            final ByteOrder byteOrder,
+            Map<String, Object> params)
+            throws ImageReadException, IOException {
         final List<TiffField> entries = directory.entries;
 
         if (entries == null) {
             throw new ImageReadException("TIFF missing entries");
         }
 
+        if (params == null) {
+            params = new HashMap<>();
+        }
+
         final short[] sSampleFmt = directory.getFieldValue(
-            TiffTagConstants.TIFF_TAG_SAMPLE_FORMAT, true);
-        if (sSampleFmt[0] != 
TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT) {
-            throw new ImageReadException("TIFF does not provide floating-point 
data");
+                TiffTagConstants.TIFF_TAG_SAMPLE_FORMAT, true);
+        if (sSampleFmt == null || sSampleFmt.length < 1) {
+            throw new ImageReadException(
+                    "Directory does not specify numeric raster data");
         }
 
         int samplesPerPixel = 1;
         final TiffField samplesPerPixelField = directory.findField(
-            TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL);
+                TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL);
         if (samplesPerPixelField != null) {
             samplesPerPixel = samplesPerPixelField.getIntValue();
         }
-        if (samplesPerPixel != 1) {
-            throw new ImageReadException(
-                "TIFF floating-point data uses unsupported samples per pixel: "
-                + samplesPerPixel);
-        }
 
         int[] bitsPerSample = {1};
         int bitsPerPixel = samplesPerPixel;
         final TiffField bitsPerSampleField = directory.findField(
-            TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE);
+                TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE);
         if (bitsPerSampleField != null) {
             bitsPerSample = bitsPerSampleField.getIntArrayValue();
             bitsPerPixel = bitsPerSampleField.getIntValueOrArraySum();
         }
 
-        if (bitsPerPixel != 32 && bitsPerPixel != 64) {
-            throw new ImageReadException(
-                "TIFF floating-point data uses unsupported bits-per-pixel: "
-                + bitsPerPixel);
-        }
-
         final short compressionFieldValue;
         if (directory.findField(TiffTagConstants.TIFF_TAG_COMPRESSION) != 
null) {
             compressionFieldValue
-                = 
directory.getFieldValue(TiffTagConstants.TIFF_TAG_COMPRESSION);
+                    = 
directory.getFieldValue(TiffTagConstants.TIFF_TAG_COMPRESSION);
         } else {
             compressionFieldValue = TIFF_COMPRESSION_UNCOMPRESSED_1;
         }
         final int compression = 0xffff & compressionFieldValue;
+
         final int width
-            = 
directory.getSingleFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH);
+                = 
directory.getSingleFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH);
         final int height
-            = 
directory.getSingleFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH);
+                = 
directory.getSingleFieldValue(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH);
 
         Rectangle subImage = checkForSubImage(params);
         if (subImage != null) {
@@ -874,9 +870,9 @@ public class TiffImageParser extends ImageParser implements 
XmpEmbeddable {
             // if the subimage is just the same thing as the whole
             // image, suppress the subimage processing
             if (subImage.x == 0
-                && subImage.y == 0
-                && subImage.width == width
-                && subImage.height == height) {
+                    && subImage.y == 0
+                    && subImage.width == width
+                    && subImage.height == height) {
                 subImage = null;
             }
         }
@@ -891,32 +887,70 @@ public class TiffImageParser extends ImageParser 
implements XmpEmbeddable {
             // dumpOptionalNumberTag(entries, TIFF_TAG_ORIENTATION);
             // dumpOptionalNumberTag(entries, TIFF_TAG_PLANAR_CONFIGURATION);
             final TiffField predictorField = directory.findField(
-                TiffTagConstants.TIFF_TAG_PREDICTOR);
+                    TiffTagConstants.TIFF_TAG_PREDICTOR);
             if (null != predictorField) {
                 predictor = predictorField.getIntValueOrArraySum();
             }
         }
 
-        if (predictor == 
TiffTagConstants.PREDICTOR_VALUE_HORIZONTAL_DIFFERENCING) {
-            throw new ImageReadException(
-                "TIFF floating-point data uses unsupported 
horizontal-differencing predictor");
+        if (sSampleFmt[0] == 
TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT) {
+
+            if (samplesPerPixel != 1) {
+                throw new ImageReadException(
+                        "TIFF floating-point data uses unsupported samples per 
pixel: "
+                        + samplesPerPixel);
+            }
+
+            if (bitsPerPixel != 32 && bitsPerPixel != 64) {
+                throw new ImageReadException(
+                        "TIFF floating-point data uses unsupported 
bits-per-pixel: "
+                        + bitsPerPixel);
+            }
+
+            if (predictor != -1
+                    && predictor != TiffTagConstants.PREDICTOR_VALUE_NONE
+                    && predictor != 
TiffTagConstants.PREDICTOR_VALUE_FLOATING_POINT_DIFFERENCING) {
+                throw new ImageReadException(
+                        "TIFF floating-point data uses unsupported 
horizontal-differencing predictor");
+            }
+        } else if (sSampleFmt[0] == 
TiffTagConstants.SAMPLE_FORMAT_VALUE_TWOS_COMPLEMENT_SIGNED_INTEGER) {
+
+            if (samplesPerPixel != 1) {
+                throw new ImageReadException(
+                        "TIFF integer data uses unsupported samples per pixel: 
"
+                        + samplesPerPixel);
+            }
+
+            if (bitsPerPixel != 16) {
+                throw new ImageReadException(
+                        "TIFF integer data uses unsupported bits-per-pixel: "
+                        + bitsPerPixel);
+            }
+
+            if (predictor != -1
+                    && predictor != TiffTagConstants.PREDICTOR_VALUE_NONE
+                    && predictor != 
TiffTagConstants.PREDICTOR_VALUE_HORIZONTAL_DIFFERENCING) {
+                throw new ImageReadException(
+                        "TIFF integer data uses unsupported 
horizontal-differencing predictor");
+            }
+        } else {
+            throw new ImageReadException("TIFF does not provide a supported 
raster-data format");
         }
 
         // The photometric interpreter is not used, but the image-based
         // data reader classes require one.  So we create a dummy interpreter.
         final PhotometricInterpreter photometricInterpreter
-            = new PhotometricInterpreterBiLevel(samplesPerPixel,
-                bitsPerSample, predictor, width, height, false);
+                = new PhotometricInterpreterBiLevel(samplesPerPixel,
+                        bitsPerSample, predictor, width, height, false);
 
         final TiffImageData imageData = directory.getTiffImageData();
 
         final ImageDataReader dataReader = imageData.getDataReader(directory,
-          photometricInterpreter, bitsPerPixel, bitsPerSample, predictor,
-          samplesPerPixel, width, height, compression,
-          TiffPlanarConfiguration.CHUNKY, byteOrder);
+                photometricInterpreter, bitsPerPixel, bitsPerSample, predictor,
+                samplesPerPixel, width, height, compression,
+                TiffPlanarConfiguration.CHUNKY, byteOrder);
 
         return dataReader.readRasterData(subImage);
     }
 
-
 }
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java
index 9574d59..1966034 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java
+++ b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java
@@ -17,16 +17,21 @@
 package org.apache.commons.imaging.formats.tiff;
 
 /**
- * Provides a simple container for floating-point data. Some TIFF files are 
used
- * to store floating-point data rather than images. This class is intended to
- * support access to those TIFF files.
+ * Provides a simple container for numeric-raster data. Some TIFF files are 
used
+ * to store floating-point or integer data rather than images. This class is
+ * intended to support access to those TIFF files.
+ * <p>
+ * <strong>Note:</strong> The getData() and getIntData() methods can return
+ * direct references to the internal arrays stored in instances of this class.
+ * Because these are not safe copies of the data, an application that
+ * modified the arrays returned by these methods will change the content
+ * of the associated instance. This approach is used for purposes of efficiency
+ * when dealing with very large TIFF images.
  */
-public class TiffRasterData {
+public abstract class TiffRasterData {
 
-
-    private final int width;
-    private final int height;
-    private final float[] data;
+    protected final int width;
+    protected final int height;
 
     /**
      * Construct an instance allocating memory for the specified dimensions.
@@ -37,38 +42,46 @@ public class TiffRasterData {
     public TiffRasterData(final int width, final int height) {
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException(
-                "Raster dimensions less than or equal to zero are not 
supported");
+                    "Raster dimensions less than or equal to zero are not 
supported");
         }
-        final int nCells = width * height;
-        data = new float[nCells];
         this.width = width;
         this.height = height;
+    }
 
+    protected final int checkCoordinatesAndComputeIndex(final int x, final int 
y) {
+        if (x < 0 || x >= width || y < 0 || y >= height) {
+            throw new IllegalArgumentException(
+                    "Coordinates out of range (" + x + ", " + y + ")");
+        }
+        return y * width + x;
     }
 
     /**
-     * Construct an instance allocating memory for the specified dimensions.
+     * Gets the width (number of columns) of the raster.
      *
-     * @param width a value of 1 or greater
-     * @param height a value of 1 or greater
-     * @param data the data to be stored in the raster.
+     * @return the width of the raster
      */
-    public TiffRasterData(final int width, final int height, final float[] 
data) {
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException(
-                "Raster dimensions less than or equal to zero are not 
supported");
-        }
-        if (data == null || data.length < width * height) {
-            throw new IllegalArgumentException(
-                "Specified data does not contain sufficient elements");
-        }
-        this.width = width;
-        this.height = height;
-        this.data = data;
+    public final int getWidth() {
+        return width;
+    }
 
+    /**
+     * Gets the height (number of rows) of the raster.
+     *
+     * @return the height of the raster.
+     */
+    public final int getHeight() {
+        return height;
     }
 
     /**
+     * Gets the raster data type from the instance.
+     *
+     * @return a valid enumeration value.
+     */
+    public abstract TiffRasterDataType getDataType();
+
+    /**
      * Sets the value stored at the specified raster coordinates.
      *
      * @param x integer coordinate in the columnar direction
@@ -76,13 +89,7 @@ public class TiffRasterData {
      * @param value the value to be stored at the specified location;
      * potentially a Float&#46;NaN.
      */
-    public void setValue(final int x, final int y, final float value) {
-        if (x < 0 || x >= width || y < 0 || y >= height) {
-            throw new IllegalArgumentException(
-                "Coordinates out of range (" + x + ", " + y + ")");
-        }
-        data[y * width + x] = value;
-    }
+    public abstract void setValue(int x, int y, float value);
 
     /**
      * Gets the value stored at the specified raster coordinates.
@@ -92,23 +99,34 @@ public class TiffRasterData {
      * @return the value stored at the specified location; potentially a
      * Float&#46;NaN.
      */
-    public float getValue(final int x, final int y) {
-        if (x < 0 || x >= width || y < 0 || y >= height) {
-            throw new IllegalArgumentException(
-                "Coordinates out of range (" + x + ", " + y + ")");
-        }
-        return data[y * width + x];
-    }
+    public abstract float getValue(int x, int y);
+
+    /**
+     * Sets the value stored at the specified raster coordinates.
+     *
+     * @param x integer coordinate in the columnar direction
+     * @param y integer coordinate in the row direction
+     * @param value the value to be stored at the specified location.
+     */
+    public abstract void setIntValue(int x, int y, int value);
+
+    /**
+     * Gets the value stored at the specified raster coordinates.
+     *
+     * @param x integer coordinate in the columnar direction
+     * @param y integer coordinate in the row direction
+     * @return the value stored at the specified location
+     */
+    public abstract int getIntValue(int x, int y);
 
     /**
      * Tabulates simple statistics for the raster and returns an instance
      * containing general metadata.
      *
      * @return a valid instance containing a safe copy of the current simple
-   * statistics for the raster.     */
-    public TiffRasterStatistics getSimpleStatistics() {
-        return new TiffRasterStatistics(this, Float.NaN);
-    }
+     * statistics for the raster.
+     */
+    public abstract TiffRasterStatistics getSimpleStatistics();
 
     /**
      * Tabulates simple statistics for the raster excluding the specified value
@@ -117,42 +135,37 @@ public class TiffRasterData {
      * @param valueToExclude exclude samples with this specified value.
      * @return a valid instance.
      */
-    public TiffRasterStatistics getSimpleStatistics(final float 
valueToExclude) {
-        return new TiffRasterStatistics(this, valueToExclude);
-    }
+    public abstract TiffRasterStatistics getSimpleStatistics(float 
valueToExclude);
 
     /**
-     * Gets the width (number of columns) of the raster.
+     * Returns the content stored as an array in this instance. Note that in
+     * many cases, the returned array is <strong>not</strong> a safe copy of 
the
+     * data but a direct reference to the member element. In such cases,
+     * modifying it would directly affect the content of the instance. While
+     * this design approach carries some risk in terms of data security, it was
+     * chosen for reasons of performance and memory conservation. TIFF images
+     * that contain floating-point data are often quite large. Sizes of 100
+     * million raster cells are common. Making a redundant copy of such a large
+     * in-memory object might exceed the resources available to a Java
+     * application.
      *
-     * @return the width of the raster
+     * @return the data content stored in this instance.
      */
-    public int getWidth() {
-        return width;
-    }
+    public abstract float[] getData();
 
     /**
-     * Gets the height (number of rows) of the raster.
+     * Returns the content stored as an array in this instance. Note that in
+     * many cases, the returned array is <strong>not</strong> a safe copy of 
the
+     * data but a direct reference to the member element. In such cases,
+     * modifying it would directly affect the content of the instance. While
+     * this design approach carries some risk in terms of data security, it was
+     * chosen for reasons of performance and memory conservation. TIFF images
+     * that contain floating-point data are often quite large. Sizes of 100
+     * million raster cells are common. Making a redundant copy of such a large
+     * in-memory object might exceed the resources available to a Java
+     * application.
      *
-     * @return the height of the raster.
+     * @return the data content stored in this instance.
      */
-    public int getHeight() {
-        return height;
-    }
-
-    /**
-     * Returns a reference to the data array stored in this instance. Note that
-     * value is <strong>not</strong> a safe copy and that modifying it would
-     * directly affect the content of the instance. While this design approach
-     * carries some risk in terms of data security, it was chosen for reasons 
of
-     * performance and memory conservation. TIFF images that contain
-     * floating-point data are often quite large. Sizes of 100 million raster
-     * cells are common. Making a redundant copy of such a large in-memory 
object
-     * might exceed the resources available to a Java application.
-     *
-     * @return a direct reference to the data array stored in this instance.
-     */
-    public float[] getData() {
-        return data;
-    }
-
+    public abstract int[] getIntData();
 }
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataFloat.java
similarity index 59%
copy from 
src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java
copy to 
src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataFloat.java
index 9574d59..e7454ea 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java
+++ 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataFloat.java
@@ -16,16 +16,23 @@
  */
 package org.apache.commons.imaging.formats.tiff;
 
+import java.util.stream.IntStream;
+
 /**
  * Provides a simple container for floating-point data. Some TIFF files are 
used
  * to store floating-point data rather than images. This class is intended to
  * support access to those TIFF files.
+ * <p>
+ * <strong>Note:</strong> The getData() and getIntData() methods can return
+ * direct references to the internal arrays stored in instances of this class.
+ * Because these are not safe copies of the data, an application that
+ * modified the arrays returned by these methods will change the content
+ * of the associated instance. This approach is used for purposes of efficiency
+ * when dealing with very large TIFF images.
  */
-public class TiffRasterData {
+public class TiffRasterDataFloat extends TiffRasterData {
 
 
-    private final int width;
-    private final int height;
     private final float[] data;
 
     /**
@@ -34,16 +41,10 @@ public class TiffRasterData {
      * @param width a value of 1 or greater
      * @param height a value of 1 or greater
      */
-    public TiffRasterData(final int width, final int height) {
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException(
-                "Raster dimensions less than or equal to zero are not 
supported");
-        }
+    public TiffRasterDataFloat(final int width, final int height) {
+        super(width, height);
         final int nCells = width * height;
         data = new float[nCells];
-        this.width = width;
-        this.height = height;
-
     }
 
     /**
@@ -53,21 +54,27 @@ public class TiffRasterData {
      * @param height a value of 1 or greater
      * @param data the data to be stored in the raster.
      */
-    public TiffRasterData(final int width, final int height, final float[] 
data) {
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException(
-                "Raster dimensions less than or equal to zero are not 
supported");
-        }
+    public TiffRasterDataFloat(final int width, final int height, final 
float[] data) {
+        super(width, height);
+
         if (data == null || data.length < width * height) {
             throw new IllegalArgumentException(
                 "Specified data does not contain sufficient elements");
         }
-        this.width = width;
-        this.height = height;
         this.data = data;
+    }
 
+     /**
+     * Gets the raster data type from the instance.
+     *
+     * @return a value of TiffRasterDataType&#46;FLOAT.
+     */
+    @Override
+    public TiffRasterDataType getDataType() {
+        return TiffRasterDataType.FLOAT;
     }
 
+
     /**
      * Sets the value stored at the specified raster coordinates.
      *
@@ -76,12 +83,10 @@ public class TiffRasterData {
      * @param value the value to be stored at the specified location;
      * potentially a Float&#46;NaN.
      */
+    @Override
     public void setValue(final int x, final int y, final float value) {
-        if (x < 0 || x >= width || y < 0 || y >= height) {
-            throw new IllegalArgumentException(
-                "Coordinates out of range (" + x + ", " + y + ")");
-        }
-        data[y * width + x] = value;
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        data[index] = value;
     }
 
     /**
@@ -92,12 +97,37 @@ public class TiffRasterData {
      * @return the value stored at the specified location; potentially a
      * Float&#46;NaN.
      */
+    @Override
     public float getValue(final int x, final int y) {
-        if (x < 0 || x >= width || y < 0 || y >= height) {
-            throw new IllegalArgumentException(
-                "Coordinates out of range (" + x + ", " + y + ")");
-        }
-        return data[y * width + x];
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        return data[index];
+    }
+
+
+    /**
+     * Sets the value stored at the specified raster coordinates.
+     *
+     * @param x integer coordinate in the columnar direction
+     * @param y integer coordinate in the row direction
+     * @param value the value to be stored at the specified location
+     */
+    @Override
+    public void setIntValue(final int x, final int y, final int value) {
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        data[index] = value;
+    }
+
+    /**
+     * Gets the value stored at the specified raster coordinates.
+     *
+     * @param x integer coordinate in the columnar direction
+     * @param y integer coordinate in the row direction
+     * @return the value stored at the specified location
+     */
+    @Override
+    public int getIntValue(final int x, final int y) {
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        return (int)data[index];
     }
 
     /**
@@ -105,7 +135,9 @@ public class TiffRasterData {
      * containing general metadata.
      *
      * @return a valid instance containing a safe copy of the current simple
-   * statistics for the raster.     */
+     * statistics for the raster.
+     */
+    @Override
     public TiffRasterStatistics getSimpleStatistics() {
         return new TiffRasterStatistics(this, Float.NaN);
     }
@@ -117,32 +149,15 @@ public class TiffRasterData {
      * @param valueToExclude exclude samples with this specified value.
      * @return a valid instance.
      */
+    @Override
     public TiffRasterStatistics getSimpleStatistics(final float 
valueToExclude) {
         return new TiffRasterStatistics(this, valueToExclude);
     }
 
     /**
-     * Gets the width (number of columns) of the raster.
-     *
-     * @return the width of the raster
-     */
-    public int getWidth() {
-        return width;
-    }
-
-    /**
-     * Gets the height (number of rows) of the raster.
-     *
-     * @return the height of the raster.
-     */
-    public int getHeight() {
-        return height;
-    }
-
-    /**
      * Returns a reference to the data array stored in this instance. Note that
-     * value is <strong>not</strong> a safe copy and that modifying it would
-     * directly affect the content of the instance. While this design approach
+     * the array returned is <strong>not</strong> a safe copy and that 
modifying
+     * it directly affects the content of the instance. While this design 
approach
      * carries some risk in terms of data security, it was chosen for reasons 
of
      * performance and memory conservation. TIFF images that contain
      * floating-point data are often quite large. Sizes of 100 million raster
@@ -151,8 +166,25 @@ public class TiffRasterData {
      *
      * @return a direct reference to the data array stored in this instance.
      */
+    @Override
     public float[] getData() {
         return data;
     }
 
+    /**
+     * Returns an array of integer approximations for the floating-point 
content
+     * stored as an array in this instance.
+     *
+     * @return the integer equivalents to the data content stored
+     * in this instance.
+     */
+    @Override
+    public int[] getIntData() {
+        final int nCells = width * height;
+        return IntStream.range(0, nCells)
+                .map(i -> (int) data[i])
+                .toArray();
+    }
+
+
 }
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataInt.java
similarity index 58%
copy from 
src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java
copy to 
src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataInt.java
index 9574d59..913b2a1 100644
--- a/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterData.java
+++ 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataInt.java
@@ -20,13 +20,18 @@ package org.apache.commons.imaging.formats.tiff;
  * Provides a simple container for floating-point data. Some TIFF files are 
used
  * to store floating-point data rather than images. This class is intended to
  * support access to those TIFF files.
+ * <p>
+ * <strong>Note:</strong> The getData() and getIntData() methods can return
+ * direct references to the internal arrays stored in instances of this class.
+ * Because these are not safe copies of the data, an application that
+ * modified the arrays returned by these methods will change the content
+ * of the associated instance. This approach is used for purposes of efficiency
+ * when dealing with very large TIFF images.
  */
-public class TiffRasterData {
+public class TiffRasterDataInt extends TiffRasterData {
 
 
-    private final int width;
-    private final int height;
-    private final float[] data;
+    private final int[] data;
 
     /**
      * Construct an instance allocating memory for the specified dimensions.
@@ -34,16 +39,10 @@ public class TiffRasterData {
      * @param width a value of 1 or greater
      * @param height a value of 1 or greater
      */
-    public TiffRasterData(final int width, final int height) {
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException(
-                "Raster dimensions less than or equal to zero are not 
supported");
-        }
+    public TiffRasterDataInt(final int width, final int height) {
+        super(width, height);
         final int nCells = width * height;
-        data = new float[nCells];
-        this.width = width;
-        this.height = height;
-
+        data = new int[nCells];
     }
 
     /**
@@ -53,21 +52,27 @@ public class TiffRasterData {
      * @param height a value of 1 or greater
      * @param data the data to be stored in the raster.
      */
-    public TiffRasterData(final int width, final int height, final float[] 
data) {
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException(
-                "Raster dimensions less than or equal to zero are not 
supported");
-        }
+    public TiffRasterDataInt(final int width, final int height, final int[] 
data) {
+        super(width, height);
+
         if (data == null || data.length < width * height) {
             throw new IllegalArgumentException(
                 "Specified data does not contain sufficient elements");
         }
-        this.width = width;
-        this.height = height;
         this.data = data;
+    }
 
+     /**
+     * Gets the raster data type from the instance.
+     *
+     * @return a value of TiffRasterDataType&#46;FLOAT.
+     */
+    @Override
+    public TiffRasterDataType getDataType() {
+        return TiffRasterDataType.INTEGER;
     }
 
+
     /**
      * Sets the value stored at the specified raster coordinates.
      *
@@ -76,12 +81,10 @@ public class TiffRasterData {
      * @param value the value to be stored at the specified location;
      * potentially a Float&#46;NaN.
      */
+    @Override
     public void setValue(final int x, final int y, final float value) {
-        if (x < 0 || x >= width || y < 0 || y >= height) {
-            throw new IllegalArgumentException(
-                "Coordinates out of range (" + x + ", " + y + ")");
-        }
-        data[y * width + x] = value;
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        data[index] = (int)value;
     }
 
     /**
@@ -92,20 +95,48 @@ public class TiffRasterData {
      * @return the value stored at the specified location; potentially a
      * Float&#46;NaN.
      */
+    @Override
     public float getValue(final int x, final int y) {
-        if (x < 0 || x >= width || y < 0 || y >= height) {
-            throw new IllegalArgumentException(
-                "Coordinates out of range (" + x + ", " + y + ")");
-        }
-        return data[y * width + x];
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        return data[index];
+    }
+
+
+    /**
+     * Sets the value stored at the specified raster coordinates.
+     *
+     * @param x integer coordinate in the columnar direction
+     * @param y integer coordinate in the row direction
+     * @param value the value to be stored at the specified location
+     */
+    @Override
+    public void setIntValue(final int x, final int y, final int value) {
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        data[index] = value;
+    }
+
+    /**
+     * Gets the value stored at the specified raster coordinates.
+     *
+     * @param x integer coordinate in the columnar direction
+     * @param y integer coordinate in the row direction
+     * @return the value stored at the specified location
+     */
+    @Override
+    public int getIntValue(final int x, final int y) {
+        int index = checkCoordinatesAndComputeIndex(x, y);
+        return data[index];
     }
 
+
+
     /**
      * Tabulates simple statistics for the raster and returns an instance
      * containing general metadata.
      *
      * @return a valid instance containing a safe copy of the current simple
    * statistics for the raster.     */
+    @Override
     public TiffRasterStatistics getSimpleStatistics() {
         return new TiffRasterStatistics(this, Float.NaN);
     }
@@ -117,32 +148,16 @@ public class TiffRasterData {
      * @param valueToExclude exclude samples with this specified value.
      * @return a valid instance.
      */
+    @Override
     public TiffRasterStatistics getSimpleStatistics(final float 
valueToExclude) {
         return new TiffRasterStatistics(this, valueToExclude);
     }
 
-    /**
-     * Gets the width (number of columns) of the raster.
-     *
-     * @return the width of the raster
-     */
-    public int getWidth() {
-        return width;
-    }
-
-    /**
-     * Gets the height (number of rows) of the raster.
-     *
-     * @return the height of the raster.
-     */
-    public int getHeight() {
-        return height;
-    }
 
     /**
      * Returns a reference to the data array stored in this instance. Note that
-     * value is <strong>not</strong> a safe copy and that modifying it would
-     * directly affect the content of the instance. While this design approach
+     * the array returned is <strong>not</strong> a safe copy and that 
modifying
+     * it directly affects the content of the instance. While this design 
approach
      * carries some risk in terms of data security, it was chosen for reasons 
of
      * performance and memory conservation. TIFF images that contain
      * floating-point data are often quite large. Sizes of 100 million raster
@@ -151,8 +166,27 @@ public class TiffRasterData {
      *
      * @return a direct reference to the data array stored in this instance.
      */
-    public float[] getData() {
+    @Override
+    public int [] getIntData() {
         return data;
     }
 
+    /**
+     * Returns an array of floating-point equivalents to the integer
+     * values stored in this instance.  To do so, a float array is
+     * allocated and each integer value in the source
+     * data is cast to a float.
+     *
+     * @return the floating-point equivalents of the content stored
+     * in this instance.
+     */
+    @Override
+    public float[] getData() {
+        final int nCells = width * height;
+        final float[] result = new float[nCells];
+        for (int i = 0; i < nCells; i++) {
+            result[i] = (int) data[i];
+        }
+        return result;
+    }
 }
diff --git 
a/src/test/java/org/apache/commons/imaging/TestImageReadException.java 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataType.java
similarity index 50%
copy from src/test/java/org/apache/commons/imaging/TestImageReadException.java
copy to 
src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataType.java
index f0adf5c..21ca2ec 100644
--- a/src/test/java/org/apache/commons/imaging/TestImageReadException.java
+++ 
b/src/main/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataType.java
@@ -14,30 +14,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.commons.imaging;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-
-import org.junit.jupiter.api.Test;
+package org.apache.commons.imaging.formats.tiff;
 
 /**
- * Tests for {@link ImageReadException}.
+ * Provides an enumeration indicating the type of data for
+ * an instance of a TiffRasterData class.
  */
-public class TestImageReadException {
-
-       @Test
-       public void testCreateExceptionWithMessage() {
-               final ImageReadException exception = new 
ImageReadException("imaging");
-               assertEquals("imaging", exception.getMessage());
-               assertNull(exception.getCause());
-       }
+public enum TiffRasterDataType {
+    /**
+     * Indicates that the raster contains integer data.
+     * Attempts to access floating-point data from the raster
+     * will result in the nearest floating point value.
+     */
+    INTEGER,
 
-       @Test
-       public void testCreateExceptionWithMessageAndCause() {
-               final ImageReadException exception = new 
ImageReadException("imaging", new Exception("cause"));
-               assertEquals("imaging", exception.getMessage());
-               assertNotNull(exception.getCause());
-       }
+    /**
+     * Indicates that the raster contains single-precision floating-point
+     * data.  Attempts to access integer data from the raster
+     * may result in a truncated value.
+     */
+    FLOAT;
 }
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffTagConstants.java
 
b/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffTagConstants.java
index 27eeabb..7b3bf89 100644
--- 
a/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffTagConstants.java
+++ 
b/src/main/java/org/apache/commons/imaging/formats/tiff/constants/TiffTagConstants.java
@@ -358,7 +358,7 @@ public final class TiffTagConstants {
     public static final int SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT = 3;
     public static final int SAMPLE_FORMAT_VALUE_UNDEFINED = 4;
     public static final int SAMPLE_FORMAT_VALUE_COMPLEX_INTEGER = 5;
-    public static final int SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT_1 = 6;
+    public static final int SAMPLE_FORMAT_VALUE_IEEE_COMPLEX_FLOAT = 6;
 
     public static final TagInfoAny TIFF_TAG_SMIN_SAMPLE_VALUE = new TagInfoAny(
             "SMinSampleValue", 0x154, -1,
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java
 
b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java
index 6f3a159..e235754 100644
--- 
a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java
+++ 
b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderStrips.java
@@ -27,6 +27,8 @@ import org.apache.commons.imaging.common.ImageBuilder;
 import org.apache.commons.imaging.formats.tiff.TiffRasterData;
 import org.apache.commons.imaging.formats.tiff.TiffDirectory;
 import org.apache.commons.imaging.formats.tiff.TiffImageData;
+import org.apache.commons.imaging.formats.tiff.TiffRasterDataFloat;
+import org.apache.commons.imaging.formats.tiff.TiffRasterDataInt;
 import 
org.apache.commons.imaging.formats.tiff.constants.TiffPlanarConfiguration;
 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
 import 
org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreter;
@@ -352,8 +354,20 @@ public final class DataReaderStrips extends 
ImageDataReader {
 
     @Override
     public TiffRasterData readRasterData(final Rectangle subImage)
-        throws ImageReadException, IOException {
+            throws ImageReadException, IOException {
+        switch(sampleFormat){
+            case TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT:
+                return readRasterDataFloat(subImage);
+            case 
TiffTagConstants.SAMPLE_FORMAT_VALUE_TWOS_COMPLEMENT_SIGNED_INTEGER:
+                 return readRasterDataInt(subImage);
+            default:
+                throw new ImageReadException("Unsupported sample format, 
value="
+                        +sampleFormat);
+        }
+    }
 
+    private TiffRasterData readRasterDataFloat(final Rectangle subImage)
+            throws ImageReadException, IOException {
         int xRaster;
         int yRaster;
         int rasterWidth;
@@ -369,7 +383,8 @@ public final class DataReaderStrips extends ImageDataReader 
{
             rasterWidth = width;
             rasterHeight = height;
         }
-        final float[] rasterData = new float[rasterWidth * rasterHeight];
+
+        float[] rasterDataFloat = new float[rasterWidth * rasterHeight];
 
         // the legacy code is optimized to the reading of whole
         // strips (except for the last strip in the image, which can
@@ -390,16 +405,69 @@ public final class DataReaderStrips extends 
ImageDataReader {
 
             final byte[] compressed = imageData.getImageData(strip).getData();
             final byte[] decompressed = decompress(compressed, compression,
-                bytesPerStrip, width, rowsInThisStrip);
+                    bytesPerStrip, width, rowsInThisStrip);
 
             final int[] blockData = unpackFloatingPointSamples(
-                width, (int) rowsInThisStrip, width,
-                decompressed,
-                predictor, bitsPerPixel, byteOrder);
+                    width,
+                    rowsInThisStrip,
+                    width,
+                    decompressed,
+                    predictor, bitsPerPixel, byteOrder);
             transferBlockToRaster(0, yStrip, width, (int) rowsInThisStrip, 
blockData,
-                xRaster, yRaster, rasterWidth, rasterHeight, rasterData);
+                    xRaster, yRaster, rasterWidth, rasterHeight, 
rasterDataFloat);
         }
-        return new TiffRasterData(rasterWidth, rasterHeight, rasterData);
+        return new TiffRasterDataFloat(rasterWidth, rasterHeight, 
rasterDataFloat);
     }
 
+    private TiffRasterData readRasterDataInt(final Rectangle subImage)
+            throws ImageReadException, IOException {
+        int xRaster;
+        int yRaster;
+        int rasterWidth;
+        int rasterHeight;
+        if (subImage != null) {
+            xRaster = subImage.x;
+            yRaster = subImage.y;
+            rasterWidth = subImage.width;
+            rasterHeight = subImage.height;
+        } else {
+            xRaster = 0;
+            yRaster = 0;
+            rasterWidth = width;
+            rasterHeight = height;
+        }
+
+        int[] rasterDataInt = new int[rasterWidth * rasterHeight];
+
+        // the legacy code is optimized to the reading of whole
+        // strips (except for the last strip in the image, which can
+        // be a partial).  So create a working image with compatible
+        // dimensions and read that.  Later on, the working image
+        // will be sub-imaged to the proper size.
+        // strip0 and strip1 give the indices of the strips containing
+        // the first and last rows of pixels in the subimage
+        final int strip0 = yRaster / rowsPerStrip;
+        final int strip1 = (yRaster + rasterHeight - 1) / rowsPerStrip;
+
+        for (int strip = strip0; strip <= strip1; strip++) {
+            final int yStrip = strip * rowsPerStrip;
+            final int rowsRemaining = height - yStrip;
+            final int rowsInThisStrip = Math.min(rowsRemaining, rowsPerStrip);
+            final int bytesPerRow = (bitsPerPixel * width + 7) / 8;
+            final int bytesPerStrip = rowsInThisStrip * bytesPerRow;
+
+            final byte[] compressed = imageData.getImageData(strip).getData();
+            final byte[] decompressed = decompress(compressed, compression,
+                    bytesPerStrip, width, rowsInThisStrip);
+            final int[] blockData = unpackIntSamples(
+                    width,
+                    rowsInThisStrip,
+                    width,
+                    decompressed,
+                    predictor, bitsPerPixel, byteOrder);
+            transferBlockToRaster(0, yStrip, width, rowsInThisStrip, blockData,
+                    xRaster, yRaster, rasterWidth, rasterHeight, 
rasterDataInt);
+        }
+        return new TiffRasterDataInt(rasterWidth, rasterHeight, rasterDataInt);
+    }
 }
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderTiled.java
 
b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderTiled.java
index d745301..8912589 100644
--- 
a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderTiled.java
+++ 
b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/DataReaderTiled.java
@@ -33,6 +33,8 @@ import org.apache.commons.imaging.common.ImageBuilder;
 import org.apache.commons.imaging.formats.tiff.TiffRasterData;
 import org.apache.commons.imaging.formats.tiff.TiffDirectory;
 import org.apache.commons.imaging.formats.tiff.TiffImageData;
+import org.apache.commons.imaging.formats.tiff.TiffRasterDataFloat;
+import org.apache.commons.imaging.formats.tiff.TiffRasterDataInt;
 import 
org.apache.commons.imaging.formats.tiff.constants.TiffPlanarConfiguration;
 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
 import 
org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreter;
@@ -286,7 +288,20 @@ public final class DataReaderTiled extends ImageDataReader 
{
 
     @Override
     public TiffRasterData readRasterData(final Rectangle subImage)
-        throws ImageReadException, IOException {
+            throws ImageReadException, IOException {
+        switch (sampleFormat) {
+            case TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT:
+                return readRasterDataFloat(subImage);
+            case 
TiffTagConstants.SAMPLE_FORMAT_VALUE_TWOS_COMPLEMENT_SIGNED_INTEGER:
+                return readRasterDataInt(subImage);
+            default:
+                throw new ImageReadException("Unsupported sample format, 
value="
+                        + sampleFormat);
+        }
+    }
+
+    private TiffRasterData readRasterDataFloat(final Rectangle subImage)
+            throws ImageReadException, IOException {
         final int bitsPerRow = tileWidth * bitsPerPixel;
         final int bytesPerRow = (bitsPerRow + 7) / 8;
         final int bytesPerTile = bytesPerRow * tileLength;
@@ -305,7 +320,7 @@ public final class DataReaderTiled extends ImageDataReader {
             rasterWidth = width;
             rasterHeight = height;
         }
-        final float[] rasterData = new float[rasterWidth * rasterHeight];
+        float[] rasterDataFloat = new float[rasterWidth * rasterHeight];
 
         // tileWidth is the width of the tile
         // tileLength is the height of the tile
@@ -321,19 +336,68 @@ public final class DataReaderTiled extends 
ImageDataReader {
                 final int tile = iRow * nColumnsOfTiles + iCol;
                 final byte[] compressed = imageData.tiles[tile].getData();
                 final byte[] decompressed = decompress(compressed, compression,
-                    bytesPerTile, tileWidth, tileLength);
+                        bytesPerTile, tileWidth, tileLength);
                 final int x = iCol * tileWidth;
                 final int y = iRow * tileLength;
+
                 final int[] blockData = unpackFloatingPointSamples(
-                    tileWidth, tileLength, tileWidth,
-                    decompressed,
-                    predictor, bitsPerPixel, byteOrder);
+                        tileWidth, tileLength, tileWidth,
+                        decompressed,
+                        predictor, bitsPerPixel, byteOrder);
                 transferBlockToRaster(x, y, tileWidth, tileLength, blockData,
-                    xRaster, yRaster, rasterWidth, rasterHeight, rasterData);
+                        xRaster, yRaster, rasterWidth, rasterHeight, 
rasterDataFloat);
             }
         }
-
-        return new TiffRasterData(rasterWidth, rasterHeight, rasterData);
+        return new TiffRasterDataFloat(rasterWidth, rasterHeight, 
rasterDataFloat);
     }
 
+    private TiffRasterData readRasterDataInt(final Rectangle subImage)
+            throws ImageReadException, IOException {
+        final int bitsPerRow = tileWidth * bitsPerPixel;
+        final int bytesPerRow = (bitsPerRow + 7) / 8;
+        final int bytesPerTile = bytesPerRow * tileLength;
+        int xRaster;
+        int yRaster;
+        int rasterWidth;
+        int rasterHeight;
+        if (subImage != null) {
+            xRaster = subImage.x;
+            yRaster = subImage.y;
+            rasterWidth = subImage.width;
+            rasterHeight = subImage.height;
+        } else {
+            xRaster = 0;
+            yRaster = 0;
+            rasterWidth = width;
+            rasterHeight = height;
+        }
+        int[] rasterDataInt = new int[rasterWidth * rasterHeight];
+
+        // tileWidth is the width of the tile
+        // tileLength is the height of the tile
+        final int col0 = xRaster / tileWidth;
+        final int col1 = (xRaster + rasterWidth - 1) / tileWidth;
+        final int row0 = yRaster / tileLength;
+        final int row1 = (yRaster + rasterHeight - 1) / tileLength;
+
+        final int nColumnsOfTiles = (width + tileWidth - 1) / tileWidth;
+
+        for (int iRow = row0; iRow <= row1; iRow++) {
+            for (int iCol = col0; iCol <= col1; iCol++) {
+                final int tile = iRow * nColumnsOfTiles + iCol;
+                final byte[] compressed = imageData.tiles[tile].getData();
+                final byte[] decompressed = decompress(compressed, compression,
+                        bytesPerTile, tileWidth, tileLength);
+                final int x = iCol * tileWidth;
+                final int y = iRow * tileLength;
+                final int[] blockData = unpackIntSamples(
+                        tileWidth, tileLength, tileWidth,
+                        decompressed,
+                        predictor, bitsPerPixel, byteOrder);
+                transferBlockToRaster(x, y, tileWidth, tileLength, blockData,
+                        xRaster, yRaster, rasterWidth, rasterHeight, 
rasterDataInt);
+            }
+        }
+        return new TiffRasterDataInt(rasterWidth, rasterHeight, rasterDataInt);
+    }
 }
diff --git 
a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/ImageDataReader.java
 
b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/ImageDataReader.java
index ba6df5a..d6ab52e 100644
--- 
a/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/ImageDataReader.java
+++ 
b/src/main/java/org/apache/commons/imaging/formats/tiff/datareaders/ImageDataReader.java
@@ -142,7 +142,6 @@ import 
org.apache.commons.imaging.formats.tiff.photometricinterpreters.Photometr
  * is implemented, it should get their own block of code so as not to interfere
  * with the processing of the more common non-interleaved variations.
  */
-@SuppressWarnings("PMD.TooManyStaticImports")
 public abstract class ImageDataReader {
     protected final TiffDirectory directory;
     protected final PhotometricInterpreter photometricInterpreter;
@@ -172,7 +171,6 @@ public abstract class ImageDataReader {
         last = new int[samplesPerPixel];
     }
 
-
     /**
      * Read the image data from the IFD associated with this
      * instance of ImageDataReader using the optional sub-image specification
@@ -211,11 +209,9 @@ public abstract class ImageDataReader {
     /**
      * Reads samples and returns them in an int array.
      *
-     * @param bis
-     *            the stream to read from
-     * @param result
-     *            the samples array to populate, must be the same length as
-     *            bitsPerSample.length
+     * @param bis the stream to read from
+     * @param result the samples array to populate, must be the same length as
+     * bitsPerSample.length
      * @throws IOException
      */
     void getSamplesAsBytes(final BitInputStream bis, final int[] result) 
throws IOException {
@@ -371,7 +367,7 @@ public abstract class ImageDataReader {
      *
      * @param width the width of the data block to be extracted
      * @param height the height of the data block to be extracted
-     * @param scansize the number of pixels in a single row of the block
+     * @param scanSize the number of pixels in a single row of the block
      * @param bytes the raw bytes
      * @param predictor the predictor specified by the source, only predictor 3
      * is supported.
@@ -384,16 +380,17 @@ public abstract class ImageDataReader {
     protected int[] unpackFloatingPointSamples(
         final int width,
         final int height,
-        final int scansize,
+        final int scanSize,
         final byte[] bytes,
         final int predictor,
-        final int bitsPerSample, final ByteOrder byteOrder)
+        final int bitsPerSample,
+        final ByteOrder byteOrder)
         throws ImageReadException {
         final int bytesPerSample = bitsPerSample / 8;
-        final int nBytes = bytesPerSample * scansize * height;
-        final int length = bytes.length < nBytes ? nBytes / scansize : height;
+        final int nBytes = bytesPerSample * scanSize * height;
+        final int length = bytes.length < nBytes ? nBytes / scanSize : height;
 
-        final int[] samples = new int[scansize * height];
+        final int[] samples = new int[scanSize * height];
         // floating-point differencing is indicated by a predictor value of 3.
         if (predictor == 
TiffTagConstants.PREDICTOR_VALUE_FLOATING_POINT_DIFFERENCING) {
             // at this time, this class supports the 32-bit format.  The
@@ -405,12 +402,12 @@ public abstract class ImageDataReader {
                     + " with predictor type 3 for "
                     + bitsPerSample + " bits per sample");
             }
-            final int bytesInRow = scansize * 4;
+            final int bytesInRow = scanSize * 4;
             for (int i = 0; i < length; i++) {
                 final int aOffset = i * bytesInRow;
-                final int bOffset = aOffset + scansize;
-                final int cOffset = bOffset + scansize;
-                final int dOffset = cOffset + scansize;
+                final int bOffset = aOffset + scanSize;
+                final int cOffset = bOffset + scanSize;
+                final int dOffset = cOffset + scanSize;
                 // in this loop, the source bytes give delta values.
                 // we adjust them to give true values.  This operation is
                 // done on a row-by-row basis.
@@ -419,7 +416,7 @@ public abstract class ImageDataReader {
                 }
                 // pack the bytes into the integer bit-equivalent of
                 // floating point values
-                int index = i * scansize;
+                int index = i * scanSize;
                 for (int j = 0; j < width; j++) {
                     final int a = bytes[aOffset + j];
                     final int b = bytes[bOffset + j];
@@ -441,7 +438,7 @@ public abstract class ImageDataReader {
             int k = 0;
             int index = 0;
             for (int i = 0; i < length; i++) {
-                for (int j = 0; j < scansize; j++) {
+                for (int j = 0; j < scanSize; j++) {
                     final long b0 = bytes[k++] & 0xffL;
                     final long b1 = bytes[k++] & 0xffL;
                     final long b2 = bytes[k++] & 0xffL;
@@ -483,7 +480,7 @@ public abstract class ImageDataReader {
             int k = 0;
             int index = 0;
             for (int i = 0; i < length; i++) {
-                for (int j = 0; j < scansize; j++) {
+                for (int j = 0; j < scanSize; j++) {
                     final int b0 = bytes[k++] & 0xff;
                     final int b1 = bytes[k++] & 0xff;
                     final int b2 = bytes[k++] & 0xff;
@@ -519,8 +516,80 @@ public abstract class ImageDataReader {
         return samples;
     }
 
+
     /**
+     * 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 of integers.
+     * <p>
+     * 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 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 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 columns of tiles, the second column
+     * having only one column of pixels that were worth extracting.
      *
+     * @param width the width of the data block to be extracted
+     * @param height the height of the data block to be extracted
+     * @param scanSize the number of pixels in a single row of the block
+     * @param bytes the raw bytes
+     * @param predictor the predictor specified by the source, only predictor 3
+     * is supported.
+     * @param bitsPerSample the number of bits per sample, 32 or 64.
+     * @param byteOrder the byte order for the source data
+     * @return a valid array of integers in row major order, dimensions
+     * scan-size wide and height height.
+     */
+    protected int[] unpackIntSamples(
+        final int width,
+        final int height,
+        final int scanSize,
+        final byte[] bytes,
+        final int predictor,
+        final int bitsPerSample,
+        final ByteOrder byteOrder) {
+        final int bytesPerSample = bitsPerSample / 8;
+        final int nBytes = bytesPerSample * scanSize * height;
+        final int length = bytes.length < nBytes ? nBytes / scanSize : height;
+
+        final int[] samples = new int[scanSize * height];
+        // At this time, Commons Imaging only supports two-byte
+        // two's complement short integers.  It is assumed that
+        // the calling module already checked the arguments for
+        // compliance, so this method simply assumes that they are correct.
+
+        // The logic that follows is simplified by the fact that
+        // the existing API only supports two-byte signed integers.
+        boolean useDifferencing
+                = predictor == 
TiffTagConstants.PREDICTOR_VALUE_HORIZONTAL_DIFFERENCING;
+
+        for (int i = 0; i < length; i++) {
+            int index = i * scanSize;
+            int offset = index * 2;
+            if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
+                for (int j = 0; j < width; j++, offset += 2) {
+                    samples[index + j] = (bytes[offset + 1] << 8) | 
(bytes[offset] & 0xff);
+                }
+            } else {
+                for (int j = 0; j < width; j++, offset += 2) {
+                    samples[index + j] = (bytes[offset] << 8) | (bytes[offset 
+ 1] & 0xff);
+                }
+            }
+            if (useDifferencing) {
+                for (int j = 1; j < width; j++) {
+                    samples[index + j] += samples[index + j - 1];
+                }
+            }
+        }
+
+        return samples;
+    }
+
+    /**
+     * Transfer samples obtained from the TIFF file to a floating-point
+     * raster.
      * @param xBlock coordinate of block relative to source data
      * @param yBlock coordinate of block relative to source data
      * @param blockWidth width of block, in pixels
@@ -603,6 +672,87 @@ public abstract class ImageDataReader {
     }
 
     /**
+     * Transfer samples obtained from the TIFF file to an integer raster.
+     * @param xBlock coordinate of block relative to source data
+     * @param yBlock coordinate of block relative to source data
+     * @param blockWidth width of block, in pixels
+     * @param blockHeight height of block in pixels
+     * @param blockData the data for the block
+     * @param xRaster coordinate of raster relative to source data
+     * @param yRaster coordinate of raster relative to source data
+     * @param rasterWidth width of the raster (always smaller than source data)
+     * @param rasterHeight height of the raster (always smaller than source
+     * data)
+     * @param rasterData the raster data.
+     */
+    void transferBlockToRaster(final int xBlock, final int yBlock,
+        final int blockWidth, final int blockHeight, final int[] blockData,
+        final int xRaster, final int yRaster,
+        final int rasterWidth, final int rasterHeight, final int[] rasterData) 
{
+
+        // xR0, yR0 are the coordinates within the raster (upper-left corner)
+        // xR1, yR1 are ONE PAST the coordinates of the lower-right corner
+        int xR0 = xBlock - xRaster;  // xR0, yR0 coordinates relative to
+        int yR0 = yBlock - yRaster; // the raster
+        int xR1 = xR0 + blockWidth;
+        int yR1 = yR0 + blockHeight;
+        if (xR0 < 0) {
+            xR0 = 0;
+        }
+        if (yR0 < 0) {
+            yR0 = 0;
+        }
+        if (xR1 > rasterWidth) {
+            xR1 = rasterWidth;
+        }
+        if (yR1 > rasterHeight) {
+            yR1 = rasterHeight;
+        }
+
+        // Recall that the above logic may have adjusted xR0, xY0 so that
+        // they are not necessarily point to the source pixel at xRaster, 
yRaster
+        // we compute xSource = xR0+xRaster.
+        //            xOffset = xSource-xBlock
+        // since the block cannot be accessed with a negative offset,
+        // we check for negatives and adjust xR0, yR0 upward as necessary
+        int xB0 = xR0 + xRaster - xBlock;
+        int yB0 = yR0 + yRaster - yBlock;
+        if (xB0 < 0) {
+            xR0 -= xB0;
+            xB0 = 0;
+        }
+        if (yB0 < 0) {
+            yR0 -= yB0;
+            yB0 = 0;
+        }
+
+        int w = xR1 - xR0;
+        int h = yR1 - yR0;
+        if (w <= 0 || h <= 0) {
+            // The call to this method puts the block outside the
+            // bounds of the raster.  There is nothing to do.  Ideally,
+            // this situation never arises, because it would mean that
+            // the data was read from the file unnecessarily.
+            return;
+        }
+        // see if the xR1, yR1 would extend past the limits of the block
+        if (w > blockWidth) {
+            w = blockWidth;
+        }
+        if (h > blockHeight) {
+            h = blockHeight;
+        }
+
+        for (int i = 0; i < h; i++) {
+            final int yR = yR0 + i;
+            final int yB = yB0 + i;
+            final int rOffset = yR * rasterWidth + xR0;
+            final int bOffset = yB * blockWidth + xB0;
+            System.arraycopy(blockData, bOffset, rasterData, rOffset, w);
+        }
+    }
+
+    /**
      * Defines a method for accessing the floating-point raster data in a TIFF
      * image. These implementations of this method in DataReaderStrips and
      * DataReaderTiled assume that this instance is of a compatible data type
diff --git 
a/src/test/java/org/apache/commons/imaging/TestImageReadException.java 
b/src/test/java/org/apache/commons/imaging/TestImageReadException.java
index f0adf5c..59b50e2 100644
--- a/src/test/java/org/apache/commons/imaging/TestImageReadException.java
+++ b/src/test/java/org/apache/commons/imaging/TestImageReadException.java
@@ -27,17 +27,17 @@ import org.junit.jupiter.api.Test;
  */
 public class TestImageReadException {
 
-       @Test
-       public void testCreateExceptionWithMessage() {
-               final ImageReadException exception = new 
ImageReadException("imaging");
-               assertEquals("imaging", exception.getMessage());
-               assertNull(exception.getCause());
-       }
+    @Test
+    public void testCreateExceptionWithMessage() {
+        final ImageReadException exception = new ImageReadException("imaging");
+        assertEquals("imaging", exception.getMessage());
+        assertNull(exception.getCause());
+    }
 
-       @Test
-       public void testCreateExceptionWithMessageAndCause() {
-               final ImageReadException exception = new 
ImageReadException("imaging", new Exception("cause"));
-               assertEquals("imaging", exception.getMessage());
-               assertNotNull(exception.getCause());
-       }
+    @Test
+    public void testCreateExceptionWithMessageAndCause() {
+        final ImageReadException exception = new ImageReadException("imaging", 
new Exception("cause"));
+        assertEquals("imaging", exception.getMessage());
+        assertNotNull(exception.getCause());
+    }
 }
diff --git 
a/src/test/java/org/apache/commons/imaging/TestImageWriteException.java 
b/src/test/java/org/apache/commons/imaging/TestImageWriteException.java
index 6781681..b830f54 100644
--- a/src/test/java/org/apache/commons/imaging/TestImageWriteException.java
+++ b/src/test/java/org/apache/commons/imaging/TestImageWriteException.java
@@ -31,41 +31,41 @@ import org.junit.jupiter.params.provider.MethodSource;
  */
 public class TestImageWriteException {
 
-       public static Stream<Object[]> data() {
-               final ImageWriteException exception = new 
ImageWriteException(null);
-               return Stream.of(
-                               new Object[] {null, "null"},
-                               new Object[] {new Object[] 
{Integer.valueOf(1)}, "[Object[]: 1]"},
-                               new Object[] {new char[] {'a', 'b', 'c'}, 
"[char[]: 3]"},
-                               new Object[] {new byte[] {0, 1}, "[byte[]: 2]"},
-                               new Object[] {new short[] {0}, "[short[]: 1]"},
-                               new Object[] {new int[] {-1, -2, 4, 100}, 
"[int[]: 4]"},
-                               new Object[] {new long[] {-1, -2, 4, 100}, 
"[long[]: 4]"},
-                               new Object[] {new float[] {-1.0f, 2.0f}, 
"[float[]: 2]"},
-                               new Object[] {new double[] {-1.0d, 2.0d}, 
"[double[]: 2]"},
-                               new Object[] {new boolean[] {true, false, 
true}, "[boolean[]: 3]"},
-                               new Object[] {exception, 
exception.getClass().getName()}
-                               );
-       }
+    public static Stream<Object[]> data() {
+        final ImageWriteException exception = new ImageWriteException(null);
+        return Stream.of(
+                new Object[] {null, "null"},
+                new Object[] {new Object[] {Integer.valueOf(1)}, "[Object[]: 
1]"},
+                new Object[] {new char[] {'a', 'b', 'c'}, "[char[]: 3]"},
+                new Object[] {new byte[] {0, 1}, "[byte[]: 2]"},
+                new Object[] {new short[] {0}, "[short[]: 1]"},
+                new Object[] {new int[] {-1, -2, 4, 100}, "[int[]: 4]"},
+                new Object[] {new long[] {-1, -2, 4, 100}, "[long[]: 4]"},
+                new Object[] {new float[] {-1.0f, 2.0f}, "[float[]: 2]"},
+                new Object[] {new double[] {-1.0d, 2.0d}, "[double[]: 2]"},
+                new Object[] {new boolean[] {true, false, true}, "[boolean[]: 
3]"},
+                new Object[] {exception, exception.getClass().getName()}
+                );
+    }
 
-       @Test
-       public void testCreateExceptionWithMessage() {
-               final ImageWriteException exception = new 
ImageWriteException("imaging");
-               assertEquals("imaging", exception.getMessage());
-               assertNull(exception.getCause());
-       }
+    @Test
+    public void testCreateExceptionWithMessage() {
+        final ImageWriteException exception = new 
ImageWriteException("imaging");
+        assertEquals("imaging", exception.getMessage());
+        assertNull(exception.getCause());
+    }
 
-       @Test
-       public void testCreateExceptionWithMessageAndCause() {
-               final ImageWriteException exception = new 
ImageWriteException("imaging", new Exception("cause"));
-               assertEquals("imaging", exception.getMessage());
-               assertNotNull(exception.getCause());
-       }
+    @Test
+    public void testCreateExceptionWithMessageAndCause() {
+        final ImageWriteException exception = new 
ImageWriteException("imaging", new Exception("cause"));
+        assertEquals("imaging", exception.getMessage());
+        assertNotNull(exception.getCause());
+    }
 
-       @ParameterizedTest
-       @MethodSource("data")
-       public void testCreateExceptionWithData(final Object data, final String 
expectedType) {
-               final ImageWriteException exception = new 
ImageWriteException("imaging", data);
-               assertEquals(String.format("imaging: %s (%s)", data, 
expectedType), exception.getMessage());
-       }
+    @ParameterizedTest
+    @MethodSource("data")
+    public void testCreateExceptionWithData(final Object data, final String 
expectedType) {
+        final ImageWriteException exception = new 
ImageWriteException("imaging", data);
+        assertEquals(String.format("imaging: %s (%s)", data, expectedType), 
exception.getMessage());
+    }
 }
diff --git 
a/src/test/java/org/apache/commons/imaging/examples/tiff/ExampleReadFloatingPointData.java
 
b/src/test/java/org/apache/commons/imaging/examples/tiff/ExampleReadFloatingPointData.java
index 4756f96..0e1aa51 100644
--- 
a/src/test/java/org/apache/commons/imaging/examples/tiff/ExampleReadFloatingPointData.java
+++ 
b/src/test/java/org/apache/commons/imaging/examples/tiff/ExampleReadFloatingPointData.java
@@ -117,7 +117,7 @@ public class ExampleReadFloatingPointData {
         final long time0Nanos = System.nanoTime();
         final HashMap<String, Object> params = new HashMap<>();
         final TiffRasterData rasterData
-            = directory.getFloatingPointRasterData(params);
+            = directory.getRasterData(params);
         final long time1Nanos = System.nanoTime();
         System.out.println("Data read in " + ((time1Nanos - time0Nanos) / 
1.0e+6) + " ms");
 
diff --git 
a/src/test/java/org/apache/commons/imaging/examples/tiff/SurveyTiffFile.java 
b/src/test/java/org/apache/commons/imaging/examples/tiff/SurveyTiffFile.java
index 8e2499a..bcedb65 100644
--- a/src/test/java/org/apache/commons/imaging/examples/tiff/SurveyTiffFile.java
+++ b/src/test/java/org/apache/commons/imaging/examples/tiff/SurveyTiffFile.java
@@ -237,8 +237,9 @@ public class SurveyTiffFile {
             case TiffTagConstants.SAMPLE_FORMAT_VALUE_COMPLEX_INTEGER:
                 return "Comp I" + heterogeneous;
             case TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT:
-            case TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_FLOATING_POINT_1:
                 return "Float" + heterogeneous;
+            case TiffTagConstants.SAMPLE_FORMAT_VALUE_IEEE_COMPLEX_FLOAT:
+                return "Comp F" + heterogeneous;
             case 
TiffTagConstants.SAMPLE_FORMAT_VALUE_TWOS_COMPLEMENT_SIGNED_INTEGER:
                 return "Sgn Int" + heterogeneous;
             case TiffTagConstants.SAMPLE_FORMAT_VALUE_UNSIGNED_INTEGER:
diff --git 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffFloatingPointReadTest.java
 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffFloatingPointReadTest.java
index ab6b3c9..b9aebb6 100644
--- 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffFloatingPointReadTest.java
+++ 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffFloatingPointReadTest.java
@@ -121,7 +121,7 @@ public class TiffFloatingPointReadTest {
             true, // indicates that application should read image data, if 
present
             FormatCompliance.getDefault());
         final TiffDirectory directory = contents.directories.get(0);
-        return directory.getFloatingPointRasterData(params);
+        return directory.getRasterData(params);
     }
 
     @Test
diff --git 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataTest.java 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataIntTest.java
similarity index 66%
copy from 
src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataTest.java
copy to 
src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataIntTest.java
index eccaf96..7ff6bfe 100644
--- 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataTest.java
+++ 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataIntTest.java
@@ -18,6 +18,8 @@ package org.apache.commons.imaging.formats.tiff;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import org.junit.jupiter.api.Test;
@@ -25,17 +27,17 @@ import org.junit.jupiter.api.Test;
 /**
  * Provides unit test for the raster-data class.
  */
-public class TiffRasterDataTest {
+public class TiffRasterDataIntTest {
 
     int width = 11;
     int height = 10;
-    float[] data;
+    int[] data;
     TiffRasterData raster;
     float meanValue;
 
-    public TiffRasterDataTest() {
+    public TiffRasterDataIntTest() {
         double sum = 0;
-        data = new float[width * height];
+        data = new int[width * height];
         int k = 0;
         for (int i = 0; i < width; i++) {
             for (int j = 0; j < height; j++) {
@@ -44,7 +46,7 @@ public class TiffRasterDataTest {
                 k++;
             }
         }
-        raster = new TiffRasterData(width, height, data);
+        raster = new TiffRasterDataInt(width, height, data);
         meanValue = (float) (sum / k);
     }
 
@@ -53,13 +55,16 @@ public class TiffRasterDataTest {
      */
     @Test
     public void testSetValue() {
-        final TiffRasterData instance = new TiffRasterData(width, height);
+        final TiffRasterData instance = new TiffRasterDataInt(width, height);
         for (int y = 0; y < height; y++) {
             for (int x = 0; x < width; x++) {
                 final int index = y * width + height;
-                instance.setValue(x, y, index);
-                final int test = (int) instance.getValue(x, y);
+                instance.setValue(x, y, index+0.4f);
+                int test = (int) instance.getValue(x, y);
                 assertEquals(index, test, "Set/get value test failed");
+                instance.setIntValue(x, y, index);
+                test = instance.getIntValue(x, y);
+                assertEquals(index, test, "Set/get int value test failed");
             }
         }
     }
@@ -72,7 +77,9 @@ public class TiffRasterDataTest {
         for (int y = 0; y < height; y++) {
             for (int x = 0; x < width; x++) {
                 final int index = y * width + x;
-                final int test = (int) raster.getValue(x, y);
+                int test = (int) raster.getValue(x, y);
+                assertEquals(index, test, "Get into source data test failed at 
(" + x + "," + y + ")");
+                test = raster.getIntValue(x, y);
                 assertEquals(index, test, "Get into source data test failed at 
(" + x + "," + y + ")");
             }
         }
@@ -123,7 +130,20 @@ public class TiffRasterDataTest {
     @Test
     public void testGetData() {
         final float[] result = raster.getData();
-        assertArrayEquals(data, result);
+        for(int i=0; i<result.length; i++){
+            assertEquals((int)result[i], data[i]);
+        }
+        final int []iResult = raster.getIntData();
+        assertArrayEquals(data, iResult);
+    }
+
+    /**
+     * Test of getData method, of class TiffRasterData.
+     */
+    @Test
+    public void testGetDataType() {
+        TiffRasterDataType dataType = raster.getDataType();
+        assertTrue(dataType == TiffRasterDataType.INTEGER, "Unexpected data 
type "+dataType.name());
     }
 
 
@@ -132,39 +152,12 @@ public class TiffRasterDataTest {
      */
     @Test
     public void testBadConstructor() {
-        try{
-            final TiffRasterData raster = new TiffRasterData(-1, 10);
-            fail("Constructor did not detect bad width");
-        }catch(final IllegalArgumentException illArgEx){
-            // success!
-        }
-        try{
-            final TiffRasterData raster = new TiffRasterData(10, -1);
-            fail("Constructor did not detect bad height");
-        }catch(final IllegalArgumentException illArgEx){
-            // success!
-        }
-        try{
-            final float []f = new float[10];
-            final TiffRasterData raster = new TiffRasterData(2, 10, f);
-            fail("Constructor did not detect insufficient input array size");
-        }catch(final IllegalArgumentException illArgEx){
-            // success!
-        }
-        try{
-            final float []f = new float[10];
-            final TiffRasterData raster = new TiffRasterData(-1, 10, f);
-            fail("Constructor did not detect bad width");
-        }catch(final IllegalArgumentException illArgEx){
-            // success!
-        }
-        try{
-            final float []f = new float[10];
-            final TiffRasterData raster = new TiffRasterData(10, -1, f);
-            fail("Constructor did not detect bad height");
-        }catch(final IllegalArgumentException illArgEx){
-            // success!
-        }
+        final int []sample = new int[10];
+        assertThrows(IllegalArgumentException.class, ()-> new 
TiffRasterDataInt(-1, 10));
+        assertThrows(IllegalArgumentException.class, ()-> new 
TiffRasterDataInt(10, -1));
+        assertThrows(IllegalArgumentException.class, ()-> new 
TiffRasterDataInt(2, 10, sample));
+        assertThrows(IllegalArgumentException.class, ()-> new 
TiffRasterDataInt(-1, 10, sample));
+        assertThrows(IllegalArgumentException.class, ()-> new 
TiffRasterDataInt(10, -1, sample));
     }
 
     /**
@@ -174,18 +167,18 @@ public class TiffRasterDataTest {
     public void testBadCoordinates() {
 
         try{
-            final float []f = new float[100];
-            final TiffRasterData raster = new TiffRasterData(10, 10, f);
-            raster.getValue(11, 11);
+            final int []sample = new int[100];
+            final TiffRasterData raster = new TiffRasterDataInt(10, 10, 
sample);
+            raster.getIntValue(11, 11);
             fail("Access method getValue() did not detect bad coordinates");
         }catch(final IllegalArgumentException illArgEx){
             // success!
         }
         try{
-            final float []f = new float[100];
-            final TiffRasterData raster = new TiffRasterData(10, 10, f);
+            final int []sample = new int[100];
+            final TiffRasterData raster = new TiffRasterDataInt(10, 10, 
sample);
             raster.setValue(11, 11, 5.0f);
-            fail("Access method getValue() did not detect bad coordinates");
+            fail("Access method setValue() did not detect bad coordinates");
         }catch(final IllegalArgumentException illArgEx){
             // success!
         }
diff --git 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataTest.java 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataTest.java
index eccaf96..797c93b 100644
--- 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataTest.java
+++ 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterDataTest.java
@@ -18,6 +18,7 @@ package org.apache.commons.imaging.formats.tiff;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import org.junit.jupiter.api.Test;
@@ -44,7 +45,7 @@ public class TiffRasterDataTest {
                 k++;
             }
         }
-        raster = new TiffRasterData(width, height, data);
+        raster = new TiffRasterDataFloat(width, height, data);
         meanValue = (float) (sum / k);
     }
 
@@ -53,13 +54,16 @@ public class TiffRasterDataTest {
      */
     @Test
     public void testSetValue() {
-        final TiffRasterData instance = new TiffRasterData(width, height);
+        final TiffRasterData instance = new TiffRasterDataFloat(width, height);
         for (int y = 0; y < height; y++) {
             for (int x = 0; x < width; x++) {
                 final int index = y * width + height;
                 instance.setValue(x, y, index);
                 final int test = (int) instance.getValue(x, y);
-                assertEquals(index, test, "Set/get value test failed");
+                assertEquals(index, test, "Set/get value test failed at (" + x 
+ "," + y + ")");
+                instance.setIntValue(x, y, index);
+                final int iTest = instance.getIntValue(x, y);
+                assertEquals(index, iTest, "Get/set value test failed at (" + 
x + "," + y + ")");
             }
         }
     }
@@ -74,6 +78,8 @@ public class TiffRasterDataTest {
                 final int index = y * width + x;
                 final int test = (int) raster.getValue(x, y);
                 assertEquals(index, test, "Get into source data test failed at 
(" + x + "," + y + ")");
+                final int iTest = raster.getIntValue(x, y);
+                assertEquals(index, iTest, "Get into source data test failed 
at (" + x + "," + y + ")");
             }
         }
     }
@@ -126,41 +132,66 @@ public class TiffRasterDataTest {
         assertArrayEquals(data, result);
     }
 
+    /**
+     * Test of getData method, of class TiffRasterData.
+     */
+    @Test
+    public void testGetIntData() {
+        final int[] result = raster.getIntData();
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x++) {
+                final int index = y * width + x;
+                final int test = (int) data[index];
+                assertEquals(index, test, "Integer array access test failed at 
(" + x + "," + y + ")");
+            }
+        }
+    }
 
-     /**
+
+    /**
+     * Test of getData method, of class TiffRasterData.
+     */
+    @Test
+    public void testGetDataType() {
+        TiffRasterDataType dataType = raster.getDataType();
+        assertTrue(dataType == TiffRasterDataType.FLOAT, "Unexpected data type 
"+dataType.name());
+    }
+
+
+    /**
      * Test of constructors with bad arguments, of class TiffRasterData.
      */
     @Test
     public void testBadConstructor() {
         try{
-            final TiffRasterData raster = new TiffRasterData(-1, 10);
+            final TiffRasterData raster = new TiffRasterDataFloat(-1, 10);
             fail("Constructor did not detect bad width");
         }catch(final IllegalArgumentException illArgEx){
             // success!
         }
         try{
-            final TiffRasterData raster = new TiffRasterData(10, -1);
+            final TiffRasterData raster = new TiffRasterDataFloat(10, -1);
             fail("Constructor did not detect bad height");
         }catch(final IllegalArgumentException illArgEx){
             // success!
         }
         try{
             final float []f = new float[10];
-            final TiffRasterData raster = new TiffRasterData(2, 10, f);
+            final TiffRasterData raster = new TiffRasterDataFloat(2, 10, f);
             fail("Constructor did not detect insufficient input array size");
         }catch(final IllegalArgumentException illArgEx){
             // success!
         }
         try{
             final float []f = new float[10];
-            final TiffRasterData raster = new TiffRasterData(-1, 10, f);
+            final TiffRasterData raster = new TiffRasterDataFloat(-1, 10, f);
             fail("Constructor did not detect bad width");
         }catch(final IllegalArgumentException illArgEx){
             // success!
         }
         try{
             final float []f = new float[10];
-            final TiffRasterData raster = new TiffRasterData(10, -1, f);
+            final TiffRasterData raster = new TiffRasterDataFloat(10, -1, f);
             fail("Constructor did not detect bad height");
         }catch(final IllegalArgumentException illArgEx){
             // success!
@@ -175,7 +206,7 @@ public class TiffRasterDataTest {
 
         try{
             final float []f = new float[100];
-            final TiffRasterData raster = new TiffRasterData(10, 10, f);
+            final TiffRasterData raster = new TiffRasterDataFloat(10, 10, f);
             raster.getValue(11, 11);
             fail("Access method getValue() did not detect bad coordinates");
         }catch(final IllegalArgumentException illArgEx){
@@ -183,9 +214,9 @@ public class TiffRasterDataTest {
         }
         try{
             final float []f = new float[100];
-            final TiffRasterData raster = new TiffRasterData(10, 10, f);
+            final TiffRasterData raster = new TiffRasterDataFloat(10, 10, f);
             raster.setValue(11, 11, 5.0f);
-            fail("Access method getValue() did not detect bad coordinates");
+            fail("Access method setValue() did not detect bad coordinates");
         }catch(final IllegalArgumentException illArgEx){
             // success!
         }
diff --git 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterStatisticsTest.java
 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterStatisticsTest.java
index 458f0a1..7721f9e 100644
--- 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterStatisticsTest.java
+++ 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffRasterStatisticsTest.java
@@ -50,7 +50,7 @@ public class TiffRasterStatisticsTest {
             }
         }
         data[width * height / 2] = Float.NaN;
-        raster = new TiffRasterData(width, height, data);
+        raster = new TiffRasterDataFloat(width, height, data);
         meanValue = (float) (sum / k);
         stat0 = raster.getSimpleStatistics();
         stat1 = raster.getSimpleStatistics(stat0.getMaxValue());
@@ -101,7 +101,7 @@ public class TiffRasterStatisticsTest {
 
         final float[] zero = new float[100];
         Arrays.fill(zero, 10);
-        final TiffRasterData zeroData = new TiffRasterData(10, 10, zero);
+        final TiffRasterData zeroData = new TiffRasterDataFloat(10, 10, zero);
         final TiffRasterStatistics zeroStat = zeroData.getSimpleStatistics(10);
         assertEquals(0.0f, zeroStat.getMeanValue(),
             "Invalid mean data for excluded value");
diff --git 
a/src/test/java/org/apache/commons/imaging/formats/tiff/TiffShortIntRoundTripTest.java
 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffShortIntRoundTripTest.java
new file mode 100644
index 0000000..dfaf878
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/imaging/formats/tiff/TiffShortIntRoundTripTest.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.imaging.formats.tiff;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteOrder;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.imaging.FormatCompliance;
+import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.ImageWriteException;
+import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
+import org.apache.commons.imaging.formats.tiff.constants.TiffConstants;
+import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
+import org.apache.commons.imaging.formats.tiff.write.TiffImageWriterLossy;
+import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;
+import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+/**
+ * Performs a test in which a TIFF file with the special-purpose short-integer
+ * sample type is used to store data to a file. The file is then read to see if
+ * it matches the original values. The primary purpose of this test is to 
verify
+ * that the TIFF data reader classes behave correctly when reading raster data
+ * in various formats.
+ */
+public class TiffShortIntRoundTripTest extends TiffBaseTest {
+
+    @TempDir
+    Path tempDir;
+
+    int width = 48;
+    int height = 23;
+
+    short[] sample = new short[width * height];
+
+    public TiffShortIntRoundTripTest() {
+        // populate the image data
+        for (int iCol = 0; iCol < width; iCol++) {
+            for (int iRow = 0; iRow < height; iRow++) {
+                final int index = iRow * width + iCol;
+                sample[index] = (short)(index-10);  // -10 so at least some 
are negative
+            }
+        }
+    }
+
+
+
+    @Test
+    public void test() throws Exception {
+        final File[] testFile = new File[4];
+        testFile[0] = writeFile(16, ByteOrder.LITTLE_ENDIAN, false);
+        testFile[1] = writeFile(16, ByteOrder.BIG_ENDIAN, false);
+        testFile[2] = writeFile(16, ByteOrder.LITTLE_ENDIAN, true);
+        testFile[3] = writeFile(16, ByteOrder.BIG_ENDIAN, true);
+        for (int i = 0; i < testFile.length; i++) {
+            final String name = testFile[i].getName();
+            final ByteSourceFile byteSource = new ByteSourceFile(testFile[i]);
+            final TiffReader tiffReader = new TiffReader(true);
+            final TiffContents contents = tiffReader.readDirectories(
+                byteSource,
+                true, // indicates that application should read image data, if 
present
+                FormatCompliance.getDefault());
+            final TiffDirectory directory = contents.directories.get(0);
+            TiffRasterData rdInt = directory.getRasterData(null);
+            int []test = rdInt.getIntData();
+            for(int j=0; j<sample.length; j++){
+                  assertEquals(sample[j], test[j],
+                "Extracted data does not match original, test "+name+": "
+                + i + ", index " + j);
+            }
+            final Map<String, Object> params = new HashMap<>();
+            params.put(TiffConstants.PARAM_KEY_SUBIMAGE_X, 2);
+            params.put(TiffConstants.PARAM_KEY_SUBIMAGE_Y, 2);
+            params.put(TiffConstants.PARAM_KEY_SUBIMAGE_WIDTH, width-4);
+            params.put(TiffConstants.PARAM_KEY_SUBIMAGE_HEIGHT, height-4);
+            TiffRasterData rdSub = directory.getRasterData(params);
+            assertEquals(width-4, rdSub.getWidth(), "Invalid sub-image width");
+            assertEquals(height-4, rdSub.getHeight(), "Invalid sub-image 
height");
+            for(int x = 2; x<width-2; x++){
+                for(int y=2; y<height-2; y++){
+                    final int a = rdInt.getIntValue(x, y);
+                    final int b = rdSub.getIntValue(x-2, y-2);
+                    assertEquals(a, b, "Sub Image test failed at (" + x + "," 
+ y + ")");
+                }
+            }
+            final Map<String, Object> xparams = new HashMap<>();
+            xparams.put(TiffConstants.PARAM_KEY_SUBIMAGE_X, 2);
+            xparams.put(TiffConstants.PARAM_KEY_SUBIMAGE_Y, 2);
+            xparams.put(TiffConstants.PARAM_KEY_SUBIMAGE_WIDTH, width);
+            xparams.put(TiffConstants.PARAM_KEY_SUBIMAGE_HEIGHT, height);
+            assertThrows(ImageReadException.class, 
()->directory.getRasterData(xparams),
+                "Failed to catch bad subimage for test "+name);
+        }
+    }
+
+    private File writeFile(final int bitsPerSample, final ByteOrder byteOrder, 
final boolean useTiles)
+        throws IOException, ImageWriteException {
+        final String name = String.format("ShortIntRoundTrip_%2d_%s_%s.tiff",
+            bitsPerSample,
+            byteOrder == ByteOrder.LITTLE_ENDIAN ? "LE" : "BE",
+            useTiles ? "Tiles" : "Strips");
+        final File outputFile = new File(tempDir.toFile(), name);
+
+        final int bytesPerSample = bitsPerSample / 8;
+        int nRowsInBlock;
+        int nColsInBlock;
+        int nBytesInBlock;
+        if (useTiles) {
+            // Define the tiles so that they will not evenly subdivide
+            // the image.  This will allow the test to evaluate how the
+            // data reader processes tiles that are only partially used.
+            nRowsInBlock = 12;
+            nColsInBlock = 20;
+        } else {
+            // Define the strips so that they will not evenly subdivide
+            // the image.  This will allow the test to evaluate how the
+            // data reader processes strips that are only partially used.
+            nRowsInBlock = 2;
+            nColsInBlock = width;
+        }
+        nBytesInBlock = nRowsInBlock * nColsInBlock * bytesPerSample;
+
+        byte[][] blocks;
+        blocks = this.getBytesForOutput16(sample, width, height, nRowsInBlock, 
nColsInBlock, byteOrder);
+
+
+        // NOTE:  At this time, Tile format is not supported.
+        // When it is, modify the tags below to populate
+        // TIFF_TAG_TILE_* appropriately.
+        final TiffOutputSet outputSet = new TiffOutputSet(byteOrder);
+        final TiffOutputDirectory outDir = outputSet.addRootDirectory();
+        outDir.add(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, width);
+        outDir.add(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, height);
+        outDir.add(TiffTagConstants.TIFF_TAG_SAMPLE_FORMAT,
+            (short) 
TiffTagConstants.SAMPLE_FORMAT_VALUE_TWOS_COMPLEMENT_SIGNED_INTEGER);
+        outDir.add(TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL, (short) 1);
+        outDir.add(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE, (short) 
bitsPerSample);
+        outDir.add(TiffTagConstants.TIFF_TAG_PHOTOMETRIC_INTERPRETATION,
+            (short) 
TiffTagConstants.PHOTOMETRIC_INTERPRETATION_VALUE_BLACK_IS_ZERO);
+        outDir.add(TiffTagConstants.TIFF_TAG_COMPRESSION,
+            (short) TiffTagConstants.COMPRESSION_VALUE_UNCOMPRESSED);
+
+        outDir.add(TiffTagConstants.TIFF_TAG_PLANAR_CONFIGURATION,
+            (short) TiffTagConstants.PLANAR_CONFIGURATION_VALUE_CHUNKY);
+
+        if (useTiles) {
+            outDir.add(TiffTagConstants.TIFF_TAG_TILE_WIDTH, nColsInBlock);
+            outDir.add(TiffTagConstants.TIFF_TAG_TILE_LENGTH, nRowsInBlock);
+            outDir.add(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS, 
nBytesInBlock);
+        } else {
+            outDir.add(TiffTagConstants.TIFF_TAG_ROWS_PER_STRIP, 2);
+            outDir.add(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS, 
nBytesInBlock);
+        }
+
+        final TiffElement.DataElement[] imageData = new 
TiffElement.DataElement[blocks.length];
+        for (int i = 0; i < blocks.length; i++) {
+            imageData[i] = new TiffImageData.Data(0, blocks[i].length, 
blocks[i]);
+        }
+
+        TiffImageData tiffImageData;
+        if (useTiles) {
+            tiffImageData
+                = new TiffImageData.Tiles(imageData, nColsInBlock, 
nRowsInBlock);
+        } else {
+            tiffImageData
+                = new TiffImageData.Strips(imageData, nRowsInBlock);
+        }
+        outDir.setTiffImageData(tiffImageData);
+
+        try (FileOutputStream fos = new FileOutputStream(outputFile);
+            BufferedOutputStream bos = new BufferedOutputStream(fos)) {
+            final TiffImageWriterLossy writer = new 
TiffImageWriterLossy(byteOrder);
+            writer.write(bos, outputSet);
+            bos.flush();
+        }
+        return outputFile;
+    }
+
+    /**
+     * Gets the bytes for output for a 16 bit floating point format. Note that
+     * this method operates over "blocks" of data which may represent either
+     * TIFF Strips or Tiles. When processing strips, there is always one column
+     * of blocks and each strip is exactly the full width of the image. When
+     * processing tiles, there may be one or more columns of blocks and the
+     * block coverage may extend beyond both the last row and last column.
+     *
+     * @param s an array of the grid of output values in row major order
+     * @param width the width of the overall image
+     * @param height the height of the overall image
+     * @param nRowsInBlock the number of rows in the Strip or Tile
+     * @param nColsInBlock the number of columns in the Strip or Tile
+     * @param byteOrder little endian or big endian
+     * @return a two-dimensional array of bytes dimensioned by the number of 
blocks and samples
+     */
+    private byte[][] getBytesForOutput16(
+        final short[] s,
+        final int width, final int height,
+        final int nRowsInBlock, final int nColsInBlock,
+        final ByteOrder byteOrder) {
+        final int nColsOfBlocks = (width + nColsInBlock - 1) / nColsInBlock;
+        final int nRowsOfBlocks = (height + nRowsInBlock + 1) / nRowsInBlock;
+        final int bytesPerPixel = 2;
+        final int nBlocks = nRowsOfBlocks * nColsOfBlocks;
+        final int nBytesInBlock = bytesPerPixel * nRowsInBlock * nColsInBlock;
+        final byte[][] blocks = new byte[nBlocks][nBytesInBlock];
+        for (int i = 0; i < height; i++) {
+            final int blockRow = i / nRowsInBlock;
+            final int rowInBlock = i - blockRow * nRowsInBlock;
+            final int blockOffset = rowInBlock * nColsInBlock;
+            for (int j = 0; j < width; j++) {
+                final int value = s[i * width + j];
+                final int blockCol = j / nColsInBlock;
+                final int colInBlock = j - blockCol * nColsInBlock;
+                final int index = blockOffset + colInBlock;
+                final int offset = index * bytesPerPixel;
+                final byte[] b = blocks[blockRow * nColsOfBlocks + blockCol];
+                if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
+                    b[offset] = (byte) (value & 0xff);
+                    b[offset + 1] = (byte) ((value >> 8) & 0xff);
+                } else {
+                    b[offset] = (byte) ((value >> 8) & 0xff);
+                    b[offset + 1] = (byte) (value & 0xff);
+                }
+            }
+        }
+
+        return blocks;
+    }
+
+
+}

Reply via email to