From 1a83e35aad3623011e9691ed224f5639999a1cd4 Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Fri, 18 Aug 2017 11:04:59 +0200 Subject: [PATCH 01/29] fixes constructor of Raster that takes int bitsPerSample to work with more than one samplesPerPixel --- .gitignore | 4 ++++ src/main/java/mil/nga/tiff/Rasters.java | 14 ++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index b83d222..c90e3b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ /target/ + +# IntelliJ +.idea +*.iml \ No newline at end of file diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index 36b56b5..e37a6ab 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -145,6 +145,13 @@ public Rasters(int width, int height, int samplesPerPixel, new Number[samplesPerPixel][width * height]); } + public static List makeBitsPerSampleList(int samplesPerPixel, int bitsPerSample) { + List bitsPerSampleList = new ArrayList(); + for (int i = 0; i < samplesPerPixel; ++i) + bitsPerSampleList.add(bitsPerSample); + return bitsPerSampleList; + } + /** * Constructor * @@ -155,11 +162,11 @@ public Rasters(int width, int height, int samplesPerPixel, * @param samplesPerPixel * samples per pixel * @param bitsPerSample - * single sample bits per sample + * bits per sample for all samples of a pixel */ public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample) { - this(width, height, samplesPerPixel, new ArrayList( - Arrays.asList(bitsPerSample))); + this(width, height, samplesPerPixel, + makeBitsPerSampleList(samplesPerPixel, bitsPerSample)); } /** @@ -593,5 +600,4 @@ private int rowsPerStrip(int bitsPerPixel, int maxBytesPerStrip) { return rowsPerStrip; } - } \ No newline at end of file From e7efe760bf580ee335d0fdb5c6f1d52f4d042d71 Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Fri, 18 Aug 2017 11:28:19 +0200 Subject: [PATCH 02/29] if SamplesPerPixel tag is missing, use length of BitsPerSample list --- src/main/java/mil/nga/tiff/FileDirectory.java | 9 +++++++-- src/test/java/mil/nga/tiff/TiffTestUtils.java | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 4167861..fe68e1a 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -480,8 +480,13 @@ public void setStripOffsets(long stripOffset) { * * @return samples per pixel */ - public Integer getSamplesPerPixel() { - return getIntegerEntryValue(FieldTagType.SamplesPerPixel); + public int getSamplesPerPixel() { + Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); + if (samplesPerPixel != null) + return samplesPerPixel; + + // if SamplesPerPixel tag is missing, use length of BitsPerSample list + return getBitsPerSample().size(); } /** diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index b53ee4b..18573e5 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -93,7 +93,7 @@ private static void compareFileDirectoryAndRastersMetadata( TestCase.assertEquals(fileDirectory.getImageWidth(), rasters.getWidth()); TestCase.assertEquals(fileDirectory.getImageHeight(), rasters.getHeight()); - TestCase.assertEquals(fileDirectory.getSamplesPerPixel().intValue(), + TestCase.assertEquals(fileDirectory.getSamplesPerPixel(), rasters.getSamplesPerPixel()); TestCase.assertEquals(fileDirectory.getBitsPerSample().size(), rasters .getBitsPerSample().size()); From 5b299f5d1c622c5524cc8b08bd86c789d9a14069 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Fri, 18 Aug 2017 06:57:19 -0600 Subject: [PATCH 03/29] pull request changes --- CHANGELOG.md | 3 ++- src/main/java/mil/nga/tiff/FileDirectory.java | 10 +++++---- src/main/java/mil/nga/tiff/Rasters.java | 21 ++++++++++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4900b0f..b16c2d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ Adheres to [Semantic Versioning](http://semver.org/). ## 1.0.4 (TBD) -* TBD +* Rasters constructor support for multiple samples per pixel +* Handle missing samples per pixel values by using length of bits per sample ## [1.0.3](https://github.com/ngageoint/geopackage-tiff-java/releases/tag/1.0.3) (06-27-2017) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index fe68e1a..960862b 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -482,11 +482,13 @@ public void setStripOffsets(long stripOffset) { */ public int getSamplesPerPixel() { Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); - if (samplesPerPixel != null) - return samplesPerPixel; + if (samplesPerPixel == null) { + // if SamplesPerPixel tag is missing, use length of BitsPerSample + // list + samplesPerPixel = getBitsPerSample().size(); + } - // if SamplesPerPixel tag is missing, use length of BitsPerSample list - return getBitsPerSample().size(); + return samplesPerPixel; } /** diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index e37a6ab..b8640b1 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -1,7 +1,6 @@ package mil.nga.tiff; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import mil.nga.tiff.util.TiffConstants; @@ -145,10 +144,22 @@ public Rasters(int width, int height, int samplesPerPixel, new Number[samplesPerPixel][width * height]); } - public static List makeBitsPerSampleList(int samplesPerPixel, int bitsPerSample) { + /** + * Make a bits per sample list where each samples of a pixel has the same + * value + * + * @param samplesPerPixel + * samples per pixel + * @param bitsPerSample + * bits per sample for all samples of a pixel + * @return bits per sample list + */ + public static List makeBitsPerSampleList(int samplesPerPixel, + int bitsPerSample) { List bitsPerSampleList = new ArrayList(); - for (int i = 0; i < samplesPerPixel; ++i) + for (int i = 0; i < samplesPerPixel; ++i) { bitsPerSampleList.add(bitsPerSample); + } return bitsPerSampleList; } @@ -165,8 +176,8 @@ public static List makeBitsPerSampleList(int samplesPerPixel, int bitsP * bits per sample for all samples of a pixel */ public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample) { - this(width, height, samplesPerPixel, - makeBitsPerSampleList(samplesPerPixel, bitsPerSample)); + this(width, height, samplesPerPixel, makeBitsPerSampleList( + samplesPerPixel, bitsPerSample)); } /** From 18ebb70717b4f87f0a94ef2d390f85d1cf6bb055 Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Fri, 18 Aug 2017 16:49:41 +0200 Subject: [PATCH 04/29] gives access to tiff tags --- src/main/java/mil/nga/tiff/FileDirectory.java | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 960862b..8315ccb 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -1440,7 +1440,7 @@ private int getBytesPerPixel() { * field tag type * @return integer value */ - private Integer getIntegerEntryValue(FieldTagType fieldTagType) { + public Integer getIntegerEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); } @@ -1452,7 +1452,7 @@ private Integer getIntegerEntryValue(FieldTagType fieldTagType) { * @param value * unsigned integer value (16 bit) */ - private void setUnsignedIntegerEntryValue(FieldTagType fieldTagType, + public void setUnsignedIntegerEntryValue(FieldTagType fieldTagType, int value) { setEntryValue(fieldTagType, FieldType.SHORT, 1, value); } @@ -1464,7 +1464,7 @@ private void setUnsignedIntegerEntryValue(FieldTagType fieldTagType, * field tag type * @return number value */ - private Number getNumberEntryValue(FieldTagType fieldTagType) { + public Number getNumberEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); } @@ -1476,10 +1476,39 @@ private Number getNumberEntryValue(FieldTagType fieldTagType) { * @param value * unsigned long value (32 bit) */ - private void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { + public void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { setEntryValue(fieldTagType, FieldType.LONG, 1, value); } + /** + * Get a string entry value for the field tag type + * + * @param fieldTagType + * field tag type + * @return number value + */ + public String getStringEntryValue(FieldTagType fieldTagType) { + FileDirectoryEntry entry = fieldTagTypeMapping.get(fieldTagType); + if (entry != null) { + return ((ArrayList) entry.getValues()).get(0); + } + return null; + } + + /** + * Set string value for the field tag type + * + * @param fieldTagType + * @param value + */ + public void setStringEntryValue(FieldTagType fieldTagType, String value) { + List values = new ArrayList<>(); + values.add(value); + FileDirectoryEntry entry = new FileDirectoryEntry(fieldTagType, + FieldType.ASCII, value.length() + 1, values); + addEntry(entry); + } + /** * Get an integer list entry value * @@ -1487,7 +1516,7 @@ private void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { * field tag type * @return integer list value */ - private List getIntegerListEntryValue(FieldTagType fieldTagType) { + public List getIntegerListEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); } @@ -1497,7 +1526,7 @@ private List getIntegerListEntryValue(FieldTagType fieldTagType) { * @param fieldTagType * @param value */ - private void setUnsignedIntegerListEntryValue(FieldTagType fieldTagType, + public void setUnsignedIntegerListEntryValue(FieldTagType fieldTagType, List value) { setEntryValue(fieldTagType, FieldType.SHORT, value.size(), value); } From b257e764d6e622b1bbef03588d089bd2deec6815 Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Fri, 18 Aug 2017 16:33:11 +0200 Subject: [PATCH 05/29] uses int instead of Number for image and tile sizes --- src/main/java/mil/nga/tiff/FileDirectory.java | 49 +++++++++---------- src/main/java/mil/nga/tiff/ImageWindow.java | 4 +- src/main/java/mil/nga/tiff/TiffWriter.java | 20 ++++---- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 960862b..cf6dad4 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -113,7 +113,7 @@ public FileDirectory(SortedSet entries, setCache(cacheData); // Determine if tiled - tiled = getRowsPerStrip() == null; + tiled = getEntryValue(FieldTagType.RowsPerStrip) == null; // Determine and validate the planar configuration Integer pc = getPlanarConfiguration(); @@ -294,8 +294,8 @@ public Map getFieldTagTypeMapping() { * * @return image width */ - public Number getImageWidth() { - return getNumberEntryValue(FieldTagType.ImageWidth); + public int getImageWidth() { + return getNumberEntryValue(FieldTagType.ImageWidth).intValue(); } /** @@ -323,8 +323,8 @@ public void setImageWidthAsLong(long width) { * * @return image height */ - public Number getImageHeight() { - return getNumberEntryValue(FieldTagType.ImageLength); + public int getImageHeight() { + return getNumberEntryValue(FieldTagType.ImageLength).intValue(); } /** @@ -507,8 +507,8 @@ public void setSamplesPerPixel(int samplesPerPixel) { * * @return rows per strip */ - public Number getRowsPerStrip() { - return getNumberEntryValue(FieldTagType.RowsPerStrip); + public int getRowsPerStrip() { + return getNumberEntryValue(FieldTagType.RowsPerStrip).intValue(); } /** @@ -714,8 +714,8 @@ public void setColorMap(int colorMap) { * * @return tile width */ - public Number getTileWidth() { - return tiled ? getNumberEntryValue(FieldTagType.TileWidth) + public int getTileWidth() { + return tiled ? getNumberEntryValue(FieldTagType.TileWidth).intValue() : getImageWidth(); } @@ -744,8 +744,8 @@ public void setTileWidthAsLong(long tileWidth) { * * @return tile height */ - public Number getTileHeight() { - return tiled ? getNumberEntryValue(FieldTagType.TileLength) + public int getTileHeight() { + return tiled ? getNumberEntryValue(FieldTagType.TileLength).intValue() : getRowsPerStrip(); } @@ -1062,8 +1062,8 @@ public Rasters readRasters(int[] samples, boolean sampleValues, public Rasters readRasters(ImageWindow window, int[] samples, boolean sampleValues, boolean interleaveValues) { - int width = getImageWidth().intValue(); - int height = getImageHeight().intValue(); + int width = getImageWidth(); + int height = getImageHeight(); // Validate the image window if (window.getMinX() < 0 || window.getMinY() < 0 @@ -1130,16 +1130,13 @@ public Rasters readRasters(ImageWindow window, int[] samples, */ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { - int tileWidth = getTileWidth().intValue(); - int tileHeight = getTileHeight().intValue(); + int tileWidth = getTileWidth(); + int tileHeight = getTileHeight(); - int minXTile = (int) Math - .floor(window.getMinX() / ((double) tileWidth)); - int maxXTile = (int) Math.ceil(window.getMaxX() / ((double) tileWidth)); - int minYTile = (int) Math.floor(window.getMinY() - / ((double) tileHeight)); - int maxYTile = (int) Math - .ceil(window.getMaxY() / ((double) tileHeight)); + int minXTile = window.getMinX() / tileWidth; + int maxXTile = (window.getMaxX() + tileWidth - 1) / tileWidth; + int minYTile = window.getMinY() / tileHeight; + int maxYTile = (window.getMaxY() + tileHeight - 1) / tileHeight; int windowWidth = window.getMaxX() - window.getMinX(); @@ -1338,10 +1335,10 @@ private byte[] getTileOrStrip(int x, int y, int sample) { byte[] tileOrStrip = null; - int numTilesPerRow = (int) Math.ceil(getImageWidth().doubleValue() - / getTileWidth().doubleValue()); - int numTilesPerCol = (int) Math.ceil(getImageHeight().doubleValue() - / getTileHeight().doubleValue()); + int tileWidth = getTileWidth(); + int tileHeight = getTileHeight(); + int numTilesPerRow = (getImageWidth() + tileWidth - 1) / tileWidth; + int numTilesPerCol = (getImageHeight() + tileHeight - 1) / tileHeight; int index = 0; if (planarConfiguration == TiffConstants.PLANAR_CONFIGURATION_CHUNKY) { diff --git a/src/main/java/mil/nga/tiff/ImageWindow.java b/src/main/java/mil/nga/tiff/ImageWindow.java index eb826a3..2da8726 100644 --- a/src/main/java/mil/nga/tiff/ImageWindow.java +++ b/src/main/java/mil/nga/tiff/ImageWindow.java @@ -67,8 +67,8 @@ public ImageWindow(int x, int y) { public ImageWindow(FileDirectory fileDirectory) { this.minX = 0; this.minY = 0; - this.maxX = fileDirectory.getImageWidth().intValue(); - this.maxY = fileDirectory.getImageHeight().intValue(); + this.maxX = fileDirectory.getImageWidth(); + this.maxY = fileDirectory.getImageHeight(); } /** diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index c6d308c..cb03fe8 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -174,7 +174,7 @@ private static void writeImageFileDirectories(ByteWriter writer, List valueBytesCheck = new ArrayList<>(); // Write the raster bytes to temporary storage - if (fileDirectory.getRowsPerStrip() == null) { + if (fileDirectory.isTiled()) { throw new TiffException("Tiled images are not supported"); } @@ -259,7 +259,7 @@ private static void populateRasterEntries(FileDirectory fileDirectory) { } // Populate the raster entries - if (fileDirectory.getRowsPerStrip() != null) { + if (!fileDirectory.isTiled()) { populateStripEntries(fileDirectory); } else { throw new TiffException("Tiled images are not supported"); @@ -272,14 +272,12 @@ private static void populateRasterEntries(FileDirectory fileDirectory) { * * @param fileDirectory * file directory - * @param strips - * number of strips */ private static void populateStripEntries(FileDirectory fileDirectory) { - int rowsPerStrip = fileDirectory.getRowsPerStrip().intValue(); - int stripsPerSample = (int) Math.ceil(fileDirectory.getImageHeight() - .doubleValue() / rowsPerStrip); + int rowsPerStrip = fileDirectory.getRowsPerStrip(); + int stripsPerSample = (fileDirectory.getImageHeight() + rowsPerStrip - 1) + / rowsPerStrip; int strips = stripsPerSample; if (fileDirectory.getPlanarConfiguration() == TiffConstants.PLANAR_CONFIGURATION_PLANAR) { strips *= fileDirectory.getSamplesPerPixel(); @@ -327,7 +325,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, ByteWriter writer = new ByteWriter(byteOrder); // Write the rasters - if (fileDirectory.getRowsPerStrip() != null) { + if (!fileDirectory.isTiled()) { writeStripRasters(writer, fileDirectory, offset, sampleFieldTypes, encoder); } else { @@ -364,8 +362,8 @@ private static void writeStripRasters(ByteWriter writer, Rasters rasters = fileDirectory.getWriteRasters(); // Get the row and strip counts - int rowsPerStrip = fileDirectory.getRowsPerStrip().intValue(); - int maxY = fileDirectory.getImageHeight().intValue(); + int rowsPerStrip = fileDirectory.getRowsPerStrip(); + int maxY = fileDirectory.getImageHeight(); int stripsPerSample = (int) Math.ceil((double) maxY / (double) rowsPerStrip); int strips = stripsPerSample; @@ -397,7 +395,7 @@ private static void writeStripRasters(ByteWriter writer, ByteWriter rowWriter = new ByteWriter(writer.getByteOrder()); - for (int x = 0; x < fileDirectory.getImageWidth().intValue(); x++) { + for (int x = 0; x < fileDirectory.getImageWidth(); x++) { if (sample != null) { Number value = rasters.getPixelSample(sample, x, y); From bc940b29b30b032b1727e1ed5a019838a6a93848 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Fri, 18 Aug 2017 08:58:48 -0600 Subject: [PATCH 06/29] pull request changes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b16c2d1..fc0fedc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ Adheres to [Semantic Versioning](http://semver.org/). * Rasters constructor support for multiple samples per pixel * Handle missing samples per pixel values by using length of bits per sample +* Public access to tiff tags +* String Entry Value getter and setter ## [1.0.3](https://github.com/ngageoint/geopackage-tiff-java/releases/tag/1.0.3) (06-27-2017) From a315159c228d8e346509608e61d900ed8e5c9fc6 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Mon, 21 Aug 2017 07:19:33 -0600 Subject: [PATCH 07/29] change string entry value to use the common get and set entry value methods --- src/main/java/mil/nga/tiff/FileDirectory.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 8315ccb..1ab9efb 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -1488,11 +1488,12 @@ public void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { * @return number value */ public String getStringEntryValue(FieldTagType fieldTagType) { - FileDirectoryEntry entry = fieldTagTypeMapping.get(fieldTagType); - if (entry != null) { - return ((ArrayList) entry.getValues()).get(0); + String value = null; + List values = getEntryValue(fieldTagType); + if (values != null) { + value = values.get(0); } - return null; + return value; } /** @@ -1504,9 +1505,7 @@ public String getStringEntryValue(FieldTagType fieldTagType) { public void setStringEntryValue(FieldTagType fieldTagType, String value) { List values = new ArrayList<>(); values.add(value); - FileDirectoryEntry entry = new FileDirectoryEntry(fieldTagType, - FieldType.ASCII, value.length() + 1, values); - addEntry(entry); + setEntryValue(fieldTagType, FieldType.ASCII, value.length() + 1, values); } /** From 125563582c77b24740a223276f24495438b35aa8 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Mon, 21 Aug 2017 07:22:18 -0600 Subject: [PATCH 08/29] check for empty --- src/main/java/mil/nga/tiff/FileDirectory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 1ab9efb..3cabec3 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -1490,7 +1490,7 @@ public void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { public String getStringEntryValue(FieldTagType fieldTagType) { String value = null; List values = getEntryValue(fieldTagType); - if (values != null) { + if (values != null && !values.isEmpty()) { value = values.get(0); } return value; From a25e37100faf8ecd0e0332c34dedd2442c7f5303 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Mon, 21 Aug 2017 08:42:54 -0600 Subject: [PATCH 09/29] pull request updates --- src/main/java/mil/nga/tiff/FileDirectory.java | 40 ++++++++++--------- src/main/java/mil/nga/tiff/ImageWindow.java | 4 +- src/main/java/mil/nga/tiff/TiffWriter.java | 17 ++++---- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index ce015ad..c5b8cb4 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -113,7 +113,7 @@ public FileDirectory(SortedSet entries, setCache(cacheData); // Determine if tiled - tiled = getEntryValue(FieldTagType.RowsPerStrip) == null; + tiled = getRowsPerStrip() == null; // Determine and validate the planar configuration Integer pc = getPlanarConfiguration(); @@ -294,8 +294,8 @@ public Map getFieldTagTypeMapping() { * * @return image width */ - public int getImageWidth() { - return getNumberEntryValue(FieldTagType.ImageWidth).intValue(); + public Number getImageWidth() { + return getNumberEntryValue(FieldTagType.ImageWidth); } /** @@ -323,8 +323,8 @@ public void setImageWidthAsLong(long width) { * * @return image height */ - public int getImageHeight() { - return getNumberEntryValue(FieldTagType.ImageLength).intValue(); + public Number getImageHeight() { + return getNumberEntryValue(FieldTagType.ImageLength); } /** @@ -507,8 +507,8 @@ public void setSamplesPerPixel(int samplesPerPixel) { * * @return rows per strip */ - public int getRowsPerStrip() { - return getNumberEntryValue(FieldTagType.RowsPerStrip).intValue(); + public Number getRowsPerStrip() { + return getNumberEntryValue(FieldTagType.RowsPerStrip); } /** @@ -714,8 +714,8 @@ public void setColorMap(int colorMap) { * * @return tile width */ - public int getTileWidth() { - return tiled ? getNumberEntryValue(FieldTagType.TileWidth).intValue() + public Number getTileWidth() { + return tiled ? getNumberEntryValue(FieldTagType.TileWidth) : getImageWidth(); } @@ -744,8 +744,8 @@ public void setTileWidthAsLong(long tileWidth) { * * @return tile height */ - public int getTileHeight() { - return tiled ? getNumberEntryValue(FieldTagType.TileLength).intValue() + public Number getTileHeight() { + return tiled ? getNumberEntryValue(FieldTagType.TileLength) : getRowsPerStrip(); } @@ -1062,8 +1062,8 @@ public Rasters readRasters(int[] samples, boolean sampleValues, public Rasters readRasters(ImageWindow window, int[] samples, boolean sampleValues, boolean interleaveValues) { - int width = getImageWidth(); - int height = getImageHeight(); + int width = getImageWidth().intValue(); + int height = getImageHeight().intValue(); // Validate the image window if (window.getMinX() < 0 || window.getMinY() < 0 @@ -1130,8 +1130,8 @@ public Rasters readRasters(ImageWindow window, int[] samples, */ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { - int tileWidth = getTileWidth(); - int tileHeight = getTileHeight(); + int tileWidth = getTileWidth().intValue(); + int tileHeight = getTileHeight().intValue(); int minXTile = window.getMinX() / tileWidth; int maxXTile = (window.getMaxX() + tileWidth - 1) / tileWidth; @@ -1335,10 +1335,12 @@ private byte[] getTileOrStrip(int x, int y, int sample) { byte[] tileOrStrip = null; - int tileWidth = getTileWidth(); - int tileHeight = getTileHeight(); - int numTilesPerRow = (getImageWidth() + tileWidth - 1) / tileWidth; - int numTilesPerCol = (getImageHeight() + tileHeight - 1) / tileHeight; + int imageWidth = getImageWidth().intValue(); + int imageHeight = getImageHeight().intValue(); + int tileWidth = getTileWidth().intValue(); + int tileHeight = getTileHeight().intValue(); + int numTilesPerRow = (imageWidth + tileWidth - 1) / tileWidth; + int numTilesPerCol = (imageHeight + tileHeight - 1) / tileHeight; int index = 0; if (planarConfiguration == TiffConstants.PLANAR_CONFIGURATION_CHUNKY) { diff --git a/src/main/java/mil/nga/tiff/ImageWindow.java b/src/main/java/mil/nga/tiff/ImageWindow.java index 2da8726..eb826a3 100644 --- a/src/main/java/mil/nga/tiff/ImageWindow.java +++ b/src/main/java/mil/nga/tiff/ImageWindow.java @@ -67,8 +67,8 @@ public ImageWindow(int x, int y) { public ImageWindow(FileDirectory fileDirectory) { this.minX = 0; this.minY = 0; - this.maxX = fileDirectory.getImageWidth(); - this.maxY = fileDirectory.getImageHeight(); + this.maxX = fileDirectory.getImageWidth().intValue(); + this.maxY = fileDirectory.getImageHeight().intValue(); } /** diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index cb03fe8..46f0b70 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -174,7 +174,7 @@ private static void writeImageFileDirectories(ByteWriter writer, List valueBytesCheck = new ArrayList<>(); // Write the raster bytes to temporary storage - if (fileDirectory.isTiled()) { + if (fileDirectory.getRowsPerStrip() == null) { throw new TiffException("Tiled images are not supported"); } @@ -259,7 +259,7 @@ private static void populateRasterEntries(FileDirectory fileDirectory) { } // Populate the raster entries - if (!fileDirectory.isTiled()) { + if (fileDirectory.getRowsPerStrip() != null) { populateStripEntries(fileDirectory); } else { throw new TiffException("Tiled images are not supported"); @@ -275,8 +275,9 @@ private static void populateRasterEntries(FileDirectory fileDirectory) { */ private static void populateStripEntries(FileDirectory fileDirectory) { - int rowsPerStrip = fileDirectory.getRowsPerStrip(); - int stripsPerSample = (fileDirectory.getImageHeight() + rowsPerStrip - 1) + int rowsPerStrip = fileDirectory.getRowsPerStrip().intValue(); + int stripsPerSample = (fileDirectory.getImageHeight().intValue() + + rowsPerStrip - 1) / rowsPerStrip; int strips = stripsPerSample; if (fileDirectory.getPlanarConfiguration() == TiffConstants.PLANAR_CONFIGURATION_PLANAR) { @@ -325,7 +326,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, ByteWriter writer = new ByteWriter(byteOrder); // Write the rasters - if (!fileDirectory.isTiled()) { + if (fileDirectory.getRowsPerStrip() != null) { writeStripRasters(writer, fileDirectory, offset, sampleFieldTypes, encoder); } else { @@ -362,8 +363,8 @@ private static void writeStripRasters(ByteWriter writer, Rasters rasters = fileDirectory.getWriteRasters(); // Get the row and strip counts - int rowsPerStrip = fileDirectory.getRowsPerStrip(); - int maxY = fileDirectory.getImageHeight(); + int rowsPerStrip = fileDirectory.getRowsPerStrip().intValue(); + int maxY = fileDirectory.getImageHeight().intValue(); int stripsPerSample = (int) Math.ceil((double) maxY / (double) rowsPerStrip); int strips = stripsPerSample; @@ -395,7 +396,7 @@ private static void writeStripRasters(ByteWriter writer, ByteWriter rowWriter = new ByteWriter(writer.getByteOrder()); - for (int x = 0; x < fileDirectory.getImageWidth(); x++) { + for (int x = 0; x < fileDirectory.getImageWidth().intValue(); x++) { if (sample != null) { Number value = rasters.getPixelSample(sample, x, y); From 26e90a443106e7409c7feeefe0481150f9569dbe Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Mon, 21 Aug 2017 08:53:14 -0600 Subject: [PATCH 10/29] image height variable --- src/main/java/mil/nga/tiff/TiffWriter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index 46f0b70..d64f919 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -276,9 +276,8 @@ private static void populateRasterEntries(FileDirectory fileDirectory) { private static void populateStripEntries(FileDirectory fileDirectory) { int rowsPerStrip = fileDirectory.getRowsPerStrip().intValue(); - int stripsPerSample = (fileDirectory.getImageHeight().intValue() - + rowsPerStrip - 1) - / rowsPerStrip; + int imageHeight = fileDirectory.getImageHeight().intValue(); + int stripsPerSample = (imageHeight + rowsPerStrip - 1) / rowsPerStrip; int strips = stripsPerSample; if (fileDirectory.getPlanarConfiguration() == TiffConstants.PLANAR_CONFIGURATION_PLANAR) { strips *= fileDirectory.getSamplesPerPixel(); From 137e846d67c34b9d3732f9764753876d9964b14e Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Tue, 22 Aug 2017 10:15:49 +0200 Subject: [PATCH 11/29] reverts getSamplesPerPixel to Integer, fixes getMaxBitsPerSample --- src/main/java/mil/nga/tiff/FileDirectory.java | 12 +++++++----- src/test/java/mil/nga/tiff/TiffTestUtils.java | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index c5b8cb4..7234ad3 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -480,12 +480,14 @@ public void setStripOffsets(long stripOffset) { * * @return samples per pixel */ - public int getSamplesPerPixel() { + public Integer getSamplesPerPixel() { Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); if (samplesPerPixel == null) { - // if SamplesPerPixel tag is missing, use length of BitsPerSample - // list - samplesPerPixel = getBitsPerSample().size(); + // if SamplesPerPixel tag is missing, try using length of + // BitsPerSample list + List bitsPerSampleList = getBitsPerSample(); + if (bitsPerSampleList != null) + samplesPerPixel = bitsPerSampleList.size(); } return samplesPerPixel; @@ -1540,7 +1542,7 @@ private Integer getMaxIntegerEntryValue(FieldTagType fieldTagType) { Integer maxValue = null; List values = getIntegerListEntryValue(fieldTagType); if (values != null) { - maxValue = Collections.max(getSampleFormat()); + maxValue = Collections.max(values); } return maxValue; } diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index 18573e5..b53ee4b 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -93,7 +93,7 @@ private static void compareFileDirectoryAndRastersMetadata( TestCase.assertEquals(fileDirectory.getImageWidth(), rasters.getWidth()); TestCase.assertEquals(fileDirectory.getImageHeight(), rasters.getHeight()); - TestCase.assertEquals(fileDirectory.getSamplesPerPixel(), + TestCase.assertEquals(fileDirectory.getSamplesPerPixel().intValue(), rasters.getSamplesPerPixel()); TestCase.assertEquals(fileDirectory.getBitsPerSample().size(), rasters .getBitsPerSample().size()); From cbf04afeb30c7e9b4d268cf220c2a7e39e494181 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Tue, 22 Aug 2017 07:02:27 -0600 Subject: [PATCH 12/29] pull request --- src/main/java/mil/nga/tiff/FileDirectory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 7234ad3..490111e 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -486,8 +486,9 @@ public Integer getSamplesPerPixel() { // if SamplesPerPixel tag is missing, try using length of // BitsPerSample list List bitsPerSampleList = getBitsPerSample(); - if (bitsPerSampleList != null) + if (bitsPerSampleList != null) { samplesPerPixel = bitsPerSampleList.size(); + } } return samplesPerPixel; From 30f28bc3dfd58a45d331ef4cced65cebfb02c670 Mon Sep 17 00:00:00 2001 From: Jochen Wilhelmy Date: Fri, 25 Aug 2017 10:23:07 +0200 Subject: [PATCH 13/29] replace one more Math.ceil, use .isTiled() --- src/main/java/mil/nga/tiff/TiffWriter.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index d64f919..9c81639 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -174,7 +174,7 @@ private static void writeImageFileDirectories(ByteWriter writer, List valueBytesCheck = new ArrayList<>(); // Write the raster bytes to temporary storage - if (fileDirectory.getRowsPerStrip() == null) { + if (fileDirectory.isTiled()) { throw new TiffException("Tiled images are not supported"); } @@ -259,7 +259,7 @@ private static void populateRasterEntries(FileDirectory fileDirectory) { } // Populate the raster entries - if (fileDirectory.getRowsPerStrip() != null) { + if (!fileDirectory.isTiled()) { populateStripEntries(fileDirectory); } else { throw new TiffException("Tiled images are not supported"); @@ -325,7 +325,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, ByteWriter writer = new ByteWriter(byteOrder); // Write the rasters - if (fileDirectory.getRowsPerStrip() != null) { + if (!fileDirectory.isTiled()) { writeStripRasters(writer, fileDirectory, offset, sampleFieldTypes, encoder); } else { @@ -364,8 +364,7 @@ private static void writeStripRasters(ByteWriter writer, // Get the row and strip counts int rowsPerStrip = fileDirectory.getRowsPerStrip().intValue(); int maxY = fileDirectory.getImageHeight().intValue(); - int stripsPerSample = (int) Math.ceil((double) maxY - / (double) rowsPerStrip); + int stripsPerSample = (maxY + rowsPerStrip - 1) / rowsPerStrip; int strips = stripsPerSample; if (fileDirectory.getPlanarConfiguration() == TiffConstants.PLANAR_CONFIGURATION_PLANAR) { strips *= fileDirectory.getSamplesPerPixel(); From 30d1fa9178d8d9c20e7f13e0041ba4bb766448d8 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Thu, 7 Sep 2017 13:44:09 -0600 Subject: [PATCH 14/29] cleanup and additional public methods --- src/main/java/mil/nga/tiff/FileDirectory.java | 12 +++--- src/main/java/mil/nga/tiff/Rasters.java | 39 ++++++++++--------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 490111e..dd41cde 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -1487,7 +1487,7 @@ public void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { * * @param fieldTagType * field tag type - * @return number value + * @return string value */ public String getStringEntryValue(FieldTagType fieldTagType) { String value = null; @@ -1502,7 +1502,9 @@ public String getStringEntryValue(FieldTagType fieldTagType) { * Set string value for the field tag type * * @param fieldTagType + * field tag type * @param value + * string value */ public void setStringEntryValue(FieldTagType fieldTagType, String value) { List values = new ArrayList<>(); @@ -1539,7 +1541,7 @@ public void setUnsignedIntegerListEntryValue(FieldTagType fieldTagType, * field tag type * @return max integer value */ - private Integer getMaxIntegerEntryValue(FieldTagType fieldTagType) { + public Integer getMaxIntegerEntryValue(FieldTagType fieldTagType) { Integer maxValue = null; List values = getIntegerListEntryValue(fieldTagType); if (values != null) { @@ -1555,7 +1557,7 @@ private Integer getMaxIntegerEntryValue(FieldTagType fieldTagType) { * field tag type * @return long list value */ - private List getNumberListEntryValue(FieldTagType fieldTagType) { + public List getNumberListEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); } @@ -1566,7 +1568,7 @@ private List getNumberListEntryValue(FieldTagType fieldTagType) { * field tag type * @return long list value */ - private List getLongListEntryValue(FieldTagType fieldTagType) { + public List getLongListEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); } @@ -1576,7 +1578,7 @@ private List getLongListEntryValue(FieldTagType fieldTagType) { * @param fieldTagType * @param value */ - private void setUnsignedLongListEntryValue(FieldTagType fieldTagType, + public void setUnsignedLongListEntryValue(FieldTagType fieldTagType, List value) { setEntryValue(fieldTagType, FieldType.LONG, value.size(), value); } diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index b8640b1..99140e0 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -144,25 +144,6 @@ public Rasters(int width, int height, int samplesPerPixel, new Number[samplesPerPixel][width * height]); } - /** - * Make a bits per sample list where each samples of a pixel has the same - * value - * - * @param samplesPerPixel - * samples per pixel - * @param bitsPerSample - * bits per sample for all samples of a pixel - * @return bits per sample list - */ - public static List makeBitsPerSampleList(int samplesPerPixel, - int bitsPerSample) { - List bitsPerSampleList = new ArrayList(); - for (int i = 0; i < samplesPerPixel; ++i) { - bitsPerSampleList.add(bitsPerSample); - } - return bitsPerSampleList; - } - /** * Constructor * @@ -611,4 +592,24 @@ private int rowsPerStrip(int bitsPerPixel, int maxBytesPerStrip) { return rowsPerStrip; } + + /** + * Make a bits per sample list where each samples of a pixel has the same + * value + * + * @param samplesPerPixel + * samples per pixel + * @param bitsPerSample + * bits per sample for all samples of a pixel + * @return bits per sample list + */ + public static List makeBitsPerSampleList(int samplesPerPixel, + int bitsPerSample) { + List bitsPerSampleList = new ArrayList(); + for (int i = 0; i < samplesPerPixel; ++i) { + bitsPerSampleList.add(bitsPerSample); + } + return bitsPerSampleList; + } + } \ No newline at end of file From 955c4a84f1aaef9dc97f5a801f5f9a4fb4f4a382 Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Mon, 18 Sep 2017 16:54:01 +0200 Subject: [PATCH 15/29] Supported deflate compression --- .../tiff/compression/DeflateCompression.java | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/main/java/mil/nga/tiff/compression/DeflateCompression.java b/src/main/java/mil/nga/tiff/compression/DeflateCompression.java index 49d6373..5433f77 100644 --- a/src/main/java/mil/nga/tiff/compression/DeflateCompression.java +++ b/src/main/java/mil/nga/tiff/compression/DeflateCompression.java @@ -1,6 +1,11 @@ package mil.nga.tiff.compression; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.nio.ByteOrder; +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; +import java.util.zip.Inflater; import mil.nga.tiff.util.TiffException; @@ -17,8 +22,25 @@ public class DeflateCompression implements CompressionDecoder, */ @Override public byte[] decode(byte[] bytes, ByteOrder byteOrder) { - throw new TiffException("Deflate decoder is not yet implemented"); - } + try { + Inflater inflater = new Inflater(); + inflater.setInput(bytes); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length); + byte[] buffer = new byte[1024]; + while (!inflater.finished()) { + int count = inflater.inflate(buffer); + outputStream.write(buffer, 0, count); + } + outputStream.close(); + byte[] output = outputStream.toByteArray(); + + return output; + } catch (IOException e) { + throw new TiffException("Failed close decoded byte stream", e); + } catch (DataFormatException e) { + throw new TiffException("Data format error while decoding stream", e); + } + } /** * {@inheritDoc} @@ -33,7 +55,22 @@ public boolean rowEncoding() { */ @Override public byte[] encode(byte[] bytes, ByteOrder byteOrder) { - throw new TiffException("Deflate encoder is not yet implemented"); - } + try { + Deflater deflater = new Deflater(); + deflater.setInput(bytes); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length); + deflater.finish(); + byte[] buffer = new byte[1024]; + while (!deflater.finished()) { + int count = deflater.deflate(buffer); // returns the generated code... index + outputStream.write(buffer, 0, count); + } + outputStream.close(); + byte[] output = outputStream.toByteArray(); + return output; + } catch (IOException e) { + throw new TiffException("Failed close encoded stream", e); + } + } } From c23c742496993d1f0617d854451fa4fbe0ab447b Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Tue, 19 Sep 2017 12:58:38 +0200 Subject: [PATCH 16/29] Supported PKZIP Deflate decoding --- src/main/java/mil/nga/tiff/FileDirectory.java | 1 + src/main/java/mil/nga/tiff/TiffWriter.java | 7 +++++-- src/main/java/mil/nga/tiff/util/TiffConstants.java | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 4167861..62894aa 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -151,6 +151,7 @@ public FileDirectory(SortedSet entries, throw new TiffException("JPEG compression not supported: " + compression); case TiffConstants.COMPRESSION_DEFLATE: + case TiffConstants.COMPRESSION_PKZIP_DEFLATE: decoder = new DeflateCompression(); break; case TiffConstants.COMPRESSION_PACKBITS: diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index c6d308c..c59ba71 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -490,8 +490,11 @@ private static CompressionEncoder getEncoder(FileDirectory fileDirectory) { encoder = new DeflateCompression(); break; case TiffConstants.COMPRESSION_PACKBITS: - encoder = new PackbitsCompression(); - break; + encoder = new PackbitsCompression(); + break; + case TiffConstants.COMPRESSION_PKZIP_DEFLATE: + throw new TiffException("PKZIP Deflate not supported for encoding. " + + "Use Adobe-style instead (COMPRESSION_DEFLATE)"); default: throw new TiffException("Unknown compression method identifier: " + compression); diff --git a/src/main/java/mil/nga/tiff/util/TiffConstants.java b/src/main/java/mil/nga/tiff/util/TiffConstants.java index 69fd54d..2cc0b30 100644 --- a/src/main/java/mil/nga/tiff/util/TiffConstants.java +++ b/src/main/java/mil/nga/tiff/util/TiffConstants.java @@ -56,6 +56,7 @@ public class TiffConstants { public static final int COMPRESSION_JPEG_OLD = 6; public static final int COMPRESSION_JPEG_NEW = 7; public static final int COMPRESSION_DEFLATE = 8; + public static final int COMPRESSION_PKZIP_DEFLATE = 32946; // PKZIP-style Deflate encoding (Obsolete). public static final int COMPRESSION_PACKBITS = 32773; // Extra Samples constants From 43bd952108da3d302163f45fb30ee26d64383f6c Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Tue, 19 Sep 2017 13:14:25 +0200 Subject: [PATCH 17/29] Fixed identation --- src/main/java/mil/nga/tiff/FileDirectory.java | 2 +- src/main/java/mil/nga/tiff/TiffWriter.java | 10 +-- .../tiff/compression/DeflateCompression.java | 70 +++++++++---------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 62894aa..ef9fc65 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -151,7 +151,7 @@ public FileDirectory(SortedSet entries, throw new TiffException("JPEG compression not supported: " + compression); case TiffConstants.COMPRESSION_DEFLATE: - case TiffConstants.COMPRESSION_PKZIP_DEFLATE: + case TiffConstants.COMPRESSION_PKZIP_DEFLATE: decoder = new DeflateCompression(); break; case TiffConstants.COMPRESSION_PACKBITS: diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index c59ba71..5d3480e 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -490,11 +490,11 @@ private static CompressionEncoder getEncoder(FileDirectory fileDirectory) { encoder = new DeflateCompression(); break; case TiffConstants.COMPRESSION_PACKBITS: - encoder = new PackbitsCompression(); - break; - case TiffConstants.COMPRESSION_PKZIP_DEFLATE: - throw new TiffException("PKZIP Deflate not supported for encoding. " + - "Use Adobe-style instead (COMPRESSION_DEFLATE)"); + encoder = new PackbitsCompression(); + break; + case TiffConstants.COMPRESSION_PKZIP_DEFLATE: + throw new TiffException("PKZIP Deflate not supported for encoding. " + + "Use Adobe-style instead (COMPRESSION_DEFLATE)"); default: throw new TiffException("Unknown compression method identifier: " + compression); diff --git a/src/main/java/mil/nga/tiff/compression/DeflateCompression.java b/src/main/java/mil/nga/tiff/compression/DeflateCompression.java index 5433f77..f82b4f4 100644 --- a/src/main/java/mil/nga/tiff/compression/DeflateCompression.java +++ b/src/main/java/mil/nga/tiff/compression/DeflateCompression.java @@ -22,25 +22,25 @@ public class DeflateCompression implements CompressionDecoder, */ @Override public byte[] decode(byte[] bytes, ByteOrder byteOrder) { - try { - Inflater inflater = new Inflater(); - inflater.setInput(bytes); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length); - byte[] buffer = new byte[1024]; - while (!inflater.finished()) { - int count = inflater.inflate(buffer); - outputStream.write(buffer, 0, count); - } - outputStream.close(); - byte[] output = outputStream.toByteArray(); + try { + Inflater inflater = new Inflater(); + inflater.setInput(bytes); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length); + byte[] buffer = new byte[1024]; + while (!inflater.finished()) { + int count = inflater.inflate(buffer); + outputStream.write(buffer, 0, count); + } + outputStream.close(); + byte[] output = outputStream.toByteArray(); - return output; - } catch (IOException e) { - throw new TiffException("Failed close decoded byte stream", e); - } catch (DataFormatException e) { - throw new TiffException("Data format error while decoding stream", e); - } - } + return output; + } catch (IOException e) { + throw new TiffException("Failed close decoded byte stream", e); + } catch (DataFormatException e) { + throw new TiffException("Data format error while decoding stream", e); + } + } /** * {@inheritDoc} @@ -55,22 +55,22 @@ public boolean rowEncoding() { */ @Override public byte[] encode(byte[] bytes, ByteOrder byteOrder) { - try { - Deflater deflater = new Deflater(); - deflater.setInput(bytes); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length); - deflater.finish(); - byte[] buffer = new byte[1024]; - while (!deflater.finished()) { - int count = deflater.deflate(buffer); // returns the generated code... index - outputStream.write(buffer, 0, count); - } + try { + Deflater deflater = new Deflater(); + deflater.setInput(bytes); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(bytes.length); + deflater.finish(); + byte[] buffer = new byte[1024]; + while (!deflater.finished()) { + int count = deflater.deflate(buffer); // returns the generated code... index + outputStream.write(buffer, 0, count); + } - outputStream.close(); - byte[] output = outputStream.toByteArray(); - return output; - } catch (IOException e) { - throw new TiffException("Failed close encoded stream", e); - } - } + outputStream.close(); + byte[] output = outputStream.toByteArray(); + return output; + } catch (IOException e) { + throw new TiffException("Failed close encoded stream", e); + } + } } From 18a5affe8074cdbd7e269a508b3ff4b1d07259c8 Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Tue, 19 Sep 2017 14:54:03 +0200 Subject: [PATCH 18/29] PKZIP_DEFLATE declared as depricated --- src/main/java/mil/nga/tiff/TiffWriter.java | 6 +++--- src/main/java/mil/nga/tiff/util/TiffConstants.java | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index 5d3480e..2cd5071 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -457,6 +457,7 @@ private static void writeStripRasters(ByteWriter writer, * file directory * @return encoder */ + @SuppressWarnings("deprecation") private static CompressionEncoder getEncoder(FileDirectory fileDirectory) { CompressionEncoder encoder = null; @@ -466,6 +467,7 @@ private static CompressionEncoder getEncoder(FileDirectory fileDirectory) { if (compression == null) { compression = TiffConstants.COMPRESSION_NO; } + switch (compression) { case TiffConstants.COMPRESSION_NO: encoder = new RawCompression(); @@ -487,14 +489,12 @@ private static CompressionEncoder getEncoder(FileDirectory fileDirectory) { throw new TiffException("JPEG compression not supported: " + compression); case TiffConstants.COMPRESSION_DEFLATE: + case TiffConstants.COMPRESSION_PKZIP_DEFLATE: encoder = new DeflateCompression(); break; case TiffConstants.COMPRESSION_PACKBITS: encoder = new PackbitsCompression(); break; - case TiffConstants.COMPRESSION_PKZIP_DEFLATE: - throw new TiffException("PKZIP Deflate not supported for encoding. " + - "Use Adobe-style instead (COMPRESSION_DEFLATE)"); default: throw new TiffException("Unknown compression method identifier: " + compression); diff --git a/src/main/java/mil/nga/tiff/util/TiffConstants.java b/src/main/java/mil/nga/tiff/util/TiffConstants.java index 2cc0b30..c8b0879 100644 --- a/src/main/java/mil/nga/tiff/util/TiffConstants.java +++ b/src/main/java/mil/nga/tiff/util/TiffConstants.java @@ -56,6 +56,7 @@ public class TiffConstants { public static final int COMPRESSION_JPEG_OLD = 6; public static final int COMPRESSION_JPEG_NEW = 7; public static final int COMPRESSION_DEFLATE = 8; + @Deprecated public static final int COMPRESSION_PKZIP_DEFLATE = 32946; // PKZIP-style Deflate encoding (Obsolete). public static final int COMPRESSION_PACKBITS = 32773; From aceb15ebe3d988ed965c5902152980d0fb9633ed Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Tue, 26 Sep 2017 10:29:53 +0200 Subject: [PATCH 19/29] Used ByteBuffer instead of arrays --- src/main/java/mil/nga/tiff/FileDirectory.java | 36 +- src/main/java/mil/nga/tiff/Rasters.java | 353 ++++++++++++++++-- src/main/java/mil/nga/tiff/TiffWriter.java | 29 +- src/test/java/mil/nga/tiff/TiffTestUtils.java | 27 +- 4 files changed, 364 insertions(+), 81 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index dd41cde..3fdc269 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -9,6 +9,8 @@ import java.util.SortedSet; import java.util.TreeSet; +import java.nio.ByteBuffer; + import mil.nga.tiff.compression.CompressionDecoder; import mil.nga.tiff.compression.DeflateCompression; import mil.nga.tiff.compression.LZWCompression; @@ -1100,20 +1102,35 @@ public Rasters readRasters(ImageWindow window, int[] samples, } // Create the interleaved result array - Number[] interleave = null; + List bitsPerSample = getBitsPerSample(); + int bytesPerPixel = 0; + for (int i = 0; i < samplesPerPixel; ++i) { + bytesPerPixel += bitsPerSample.get(i) / 8; + } + ByteBuffer interleave = null; if (interleaveValues) { - interleave = new Number[numPixels * samples.length]; + interleave = ByteBuffer.allocate(numPixels * bytesPerPixel); + interleave.order(reader.getByteOrder()); } // Create the sample indexed result double array - Number[][] sample = null; + ByteBuffer[] sample = null; if (sampleValues) { - sample = new Number[samples.length][numPixels]; + sample = new ByteBuffer[samplesPerPixel]; + for (int i = 0; i < sample.length; ++i) { + sample[i] = ByteBuffer.allocate(numPixels * bitsPerSample.get(i) / 8); + sample[i].order(reader.getByteOrder()); + } + } + + FieldType[] sampleFieldTypes = new FieldType[samples.length]; + for (int i = 0; i < samples.length; i++) { + sampleFieldTypes[i] = getFieldTypeForSample(samples[i]); } // Create the rasters results Rasters rasters = new Rasters(windowWidth, windowHeight, - samplesPerPixel, getBitsPerSample(), sample, interleave); + samplesPerPixel, bitsPerSample, sampleFieldTypes, sample, interleave); // Read the rasters readRaster(window, samples, rasters); @@ -1197,10 +1214,8 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { int windowCoordinate = (y + firstLine - window .getMinY()) * windowWidth - * samples.length - + (x + firstCol - window.getMinX()) - * samples.length + sampleIndex; - rasters.addToInterleave(windowCoordinate, value); + + (x + firstCol - window.getMinX()); + rasters.addToInterleave(windowCoordinate, value, sampleIndex); } if (rasters.hasSampleValues()) { @@ -1209,8 +1224,7 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { * windowWidth + x + firstCol - window.getMinX(); - rasters.addToSample(sampleIndex, - windowCoordinate, value); + rasters.addToSample(sampleIndex, windowCoordinate, value); } } diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index 99140e0..62824d1 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -1,5 +1,7 @@ package mil.nga.tiff; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; @@ -16,12 +18,12 @@ public class Rasters { /** * Values separated by sample */ - private Number[][] sampleValues; + private ByteBuffer[] sampleValues; /** * Interleaved pixel sample values */ - private Number[] interleaveValues; + private ByteBuffer interleaveValues; /** * Width of pixels @@ -43,6 +45,11 @@ public class Rasters { */ private final List bitsPerSample; + /** + * Field type for each sample. Can be total samplesPerPixel. + */ + private final FieldType[] sampleFieldTypes; + /** * Constructor * @@ -54,12 +61,14 @@ public class Rasters { * samples per pixel * @param bitsPerSample * bits per sample + * @param sampleFieldTypes + * Field type for each sample * @param sampleValues * empty sample values double array */ public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample, Number[][] sampleValues) { - this(width, height, samplesPerPixel, bitsPerSample, sampleValues, null); + List bitsPerSample, FieldType[] sampleFieldTypes, ByteBuffer[] sampleValues) { + this(width, height, samplesPerPixel, bitsPerSample, sampleFieldTypes, sampleValues, null); } /** @@ -73,12 +82,14 @@ public Rasters(int width, int height, int samplesPerPixel, * samples per pixel * @param bitsPerSample * bits per sample + * @param sampleFieldTypes + * Field type for each sample * @param interleaveValues * empty interleaved values array */ public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample, Number[] interleaveValues) { - this(width, height, samplesPerPixel, bitsPerSample, null, + List bitsPerSample, FieldType[] sampleFieldTypes, ByteBuffer interleaveValues) { + this(width, height, samplesPerPixel, bitsPerSample, sampleFieldTypes, null, interleaveValues); } @@ -93,18 +104,21 @@ public Rasters(int width, int height, int samplesPerPixel, * samples per pixel * @param bitsPerSample * bits per sample + * @param sampleFieldTypes + * Field type for each sample * @param sampleValues * empty sample values double array * @param interleaveValues * empty interleaved values array */ public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample, Number[][] sampleValues, - Number[] interleaveValues) { + List bitsPerSample, FieldType[] sampleFieldTypes, ByteBuffer[] sampleValues, + ByteBuffer interleaveValues) { this.width = width; this.height = height; this.samplesPerPixel = samplesPerPixel; this.bitsPerSample = bitsPerSample; + this.sampleFieldTypes = sampleFieldTypes; this.sampleValues = sampleValues; this.interleaveValues = interleaveValues; validateValues(); @@ -139,9 +153,13 @@ private void validateValues() { * bits per sample */ public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample) { - this(width, height, samplesPerPixel, bitsPerSample, - new Number[samplesPerPixel][width * height]); + List bitsPerSample, FieldType[] sampleFieldTypes, ByteOrder order) { + this(width, height, samplesPerPixel, bitsPerSample, sampleFieldTypes, + new ByteBuffer[samplesPerPixel]); + for (int i = 0; i < sampleValues.length; ++i) { + sampleValues[i] = ByteBuffer.allocate(width * height * sizeSample(i)); + sampleValues[i].order(order); + } } /** @@ -156,9 +174,9 @@ public Rasters(int width, int height, int samplesPerPixel, * @param bitsPerSample * bits per sample for all samples of a pixel */ - public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample) { + public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, FieldType[] sampleFieldTypes, ByteOrder order) { this(width, height, samplesPerPixel, makeBitsPerSampleList( - samplesPerPixel, bitsPerSample)); + samplesPerPixel, bitsPerSample), sampleFieldTypes, order); } /** @@ -179,6 +197,102 @@ public boolean hasInterleaveValues() { return interleaveValues != null; } + /** + * Updates sample to given value in buffer. + * + * @param buffer A buffer to be updated. + * @param bufferIndex Position in buffer where to update. + * @param sampleIndex Sample index in sampleFieldTypes. Needed for determining sample size. + * @param value A Number value to be put in buffer. Has to be same size as sampleFieldTypes[sampleIndex]. + */ + private void updateSampleInByteBuffer(ByteBuffer buffer, int bufferIndex, int sampleIndex, Number value) { + if (bufferIndex < 0 || bufferIndex >= buffer.capacity()) { + throw new IndexOutOfBoundsException("index: " + bufferIndex + ". Buffer capacity: " + buffer.capacity()); + } + + buffer.position(bufferIndex); + + switch (sampleFieldTypes[sampleIndex]) { + case BYTE: + buffer.put(value.byteValue()); + break; + case SHORT: + buffer.putShort(value.shortValue()); + break; + case LONG: + buffer.putInt(value.intValue()); + break; + case SBYTE: + buffer.put(value.byteValue()); + break; + case SSHORT: + buffer.putShort(value.shortValue()); + break; + case SLONG: + buffer.putInt(value.intValue()); + break; + case FLOAT: + buffer.putFloat(value.floatValue()); + break; + case DOUBLE: + buffer.putDouble(value.doubleValue()); + break; + default: + throw new TiffException("Unsupported raster field type: " + + sampleFieldTypes[sampleIndex]); + } + } + + /** + * Reads sample from given buffer. + * + * @param buffer A buffer to read from + * @param index Position in buffer where to read from + * @param sampleIndex Index of sample type to read + * @return Number read from buffer + */ + private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleIndex) { + + if (index < 0 || index >= buffer.capacity()) { + throw new IndexOutOfBoundsException("Requested index: " + index + + ", but size of buffer is: " + buffer.capacity()); + } + + buffer.position(index); + Number sampleValue; + + switch (sampleFieldTypes[sampleIndex]) { + case BYTE: + sampleValue = (short)(buffer.get() & 0xff); + break; + case SHORT: + sampleValue = buffer.getShort() & 0xffff; + break; + case LONG: + sampleValue = buffer.getInt() & 0xffffffffL; + break; + case SBYTE: + sampleValue = buffer.get(); + break; + case SSHORT: + sampleValue = buffer.getShort(); + break; + case SLONG: + sampleValue = buffer.getInt(); + break; + case FLOAT: + sampleValue = buffer.getFloat(); + break; + case DOUBLE: + sampleValue = buffer.getDouble(); + break; + default: + throw new TiffException("Unsupported raster field type: " + + sampleFieldTypes[sampleIndex]); + } + return sampleValue; + } + /** * Add a value to the sample results * @@ -190,7 +304,8 @@ public boolean hasInterleaveValues() { * value */ public void addToSample(int sampleIndex, int coordinate, Number value) { - sampleValues[sampleIndex][coordinate] = value; + updateSampleInByteBuffer(sampleValues[sampleIndex], + coordinate * sizeSample(sampleIndex), sampleIndex, value); } /** @@ -201,8 +316,12 @@ public void addToSample(int sampleIndex, int coordinate, Number value) { * @param value * value */ - public void addToInterleave(int coordinate, Number value) { - interleaveValues[coordinate] = value; + public void addToInterleave(int coordinate, Number value, int sampleIndex) { + int bufferPos = coordinate * sizePixel(); + for (int i = 0; i < sampleIndex; ++i) + bufferPos += sizeSample(i); + + updateSampleInByteBuffer(interleaveValues, bufferPos, sampleIndex, value); } /** @@ -255,7 +374,10 @@ public List getBitsPerSample() { * * @return sample values */ - public Number[][] getSampleValues() { + public ByteBuffer[] getSampleValues() { + for (int i = 0; i < sampleValues.length; ++i) { + sampleValues[i].rewind(); + } return sampleValues; } @@ -265,7 +387,7 @@ public Number[][] getSampleValues() { * @param sampleValues * sample values */ - public void setSampleValues(Number[][] sampleValues) { + public void setSampleValues(ByteBuffer[] sampleValues) { this.sampleValues = sampleValues; validateValues(); } @@ -275,7 +397,8 @@ public void setSampleValues(Number[][] sampleValues) { * * @return interleaved values */ - public Number[] getInterleaveValues() { + public ByteBuffer getInterleaveValues() { + interleaveValues.rewind(); return interleaveValues; } @@ -285,7 +408,7 @@ public Number[] getInterleaveValues() { * @param interleaveValues * interleaved values */ - public void setInterleaveValues(Number[] interleaveValues) { + public void setInterleaveValues(ByteBuffer interleaveValues) { this.interleaveValues = interleaveValues; validateValues(); } @@ -308,14 +431,16 @@ public Number[] getPixel(int x, int y) { // Get the pixel values from each sample if (sampleValues != null) { - int sampleIndex = getSampleIndex(x, y); + int sampleIndex = getSampleIndexInWindow(x, y); for (int i = 0; i < samplesPerPixel; i++) { - pixel[i] = sampleValues[i][sampleIndex]; + int bufferIndex = sampleIndex * sizeSample(i); + pixel[i] = getSampleFromByteBuffer(sampleValues[i], bufferIndex, i); } } else { int interleaveIndex = getInterleaveIndex(x, y); for (int i = 0; i < samplesPerPixel; i++) { - pixel[i] = interleaveValues[interleaveIndex++]; + pixel[i] = getSampleFromByteBuffer(interleaveValues, interleaveIndex, i); + interleaveIndex += sizeSample(i); } } @@ -339,18 +464,162 @@ public void setPixel(int x, int y, Number[] values) { // Set the pixel values from each sample if (sampleValues != null) { - int sampleIndex = getSampleIndex(x, y); for (int i = 0; i < samplesPerPixel; i++) { - sampleValues[i][sampleIndex] = values[i]; + int bufferIndex = getSampleIndexInWindow(x, y) * sizeSample(i); + updateSampleInByteBuffer(sampleValues[i], bufferIndex, i, values[i]); } } else { - int interleaveIndex = getInterleaveIndex(x, y); + int interleaveIndex = getSampleIndexInWindow(x, y) * sizePixel(); for (int i = 0; i < samplesPerPixel; i++) { - interleaveValues[interleaveIndex++] = values[i]; + updateSampleInByteBuffer(interleaveValues, interleaveIndex, i, values[i]); + interleaveIndex += sizeSample(i); } } } + /** + * Returns byte array of pixel row. + * + * @param y Row index + * @param newOrder Desired byte order of result byte array + * @return Byte array of pixel row + */ + public byte[] getPixelRow(int y, ByteOrder newOrder) { + ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * sizePixel()); + outBuffer.order(newOrder); + + if (sampleValues != null) { + for (int i = 0; i < samplesPerPixel; ++i) { + sampleValues[i].position(y * getWidth() * sizeSample(i)); + } + for (int i = 0; i < getWidth(); ++i) { + for (int j = 0; j < samplesPerPixel; ++j) { + switch (sampleFieldTypes[j]) + { + case BYTE: + case SBYTE: + outBuffer.put(sampleValues[j].get()); + break; + case SHORT: + case SSHORT: + outBuffer.putShort(sampleValues[j].getShort()); + break; + case LONG: + case SLONG: + outBuffer.putInt(sampleValues[j].getInt()); + break; + case FLOAT: + outBuffer.putFloat(sampleValues[j].getFloat()); + break; + case DOUBLE: + outBuffer.putDouble(sampleValues[j].getDouble()); + break; + } + } + } + } else { + interleaveValues.position(y * getWidth() * sizePixel()); + + for (int i = 0; i < getWidth(); ++i) { + for (int j = 0; j < samplesPerPixel; ++j) { + switch (sampleFieldTypes[j]) { + case BYTE: + case SBYTE: + outBuffer.put(interleaveValues.get()); + break; + case SHORT: + case SSHORT: + outBuffer.putShort(interleaveValues.getShort()); + break; + case LONG: + case SLONG: + outBuffer.putInt(interleaveValues.getInt()); + break; + case FLOAT: + outBuffer.putFloat(interleaveValues.getFloat()); + break; + case DOUBLE: + outBuffer.putDouble(interleaveValues.getDouble()); + break; + } + } + } + } + + return outBuffer.array(); + } + + /** + * Returns byte array of sample row. + * + * @param y Row index + * @param sample Sample index + * @param newOrder Desired byte order of resulting byte array + * @return Byte array of sample row + */ + public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { + ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * sizeSample(sample)); + outBuffer.order(newOrder); + + if (sampleValues != null) { + sampleValues[sample].position(y * getWidth() * sizeSample(sample)); + for (int x = 0; x < getWidth(); ++x) { + switch (sampleFieldTypes[sample]) { + case BYTE: + case SBYTE: + outBuffer.put(sampleValues[sample].get()); + break; + case SHORT: + case SSHORT: + outBuffer.putShort(sampleValues[sample].getShort()); + break; + case LONG: + case SLONG: + outBuffer.putInt(sampleValues[sample].getInt()); + break; + case FLOAT: + outBuffer.putFloat(sampleValues[sample].getFloat()); + break; + case DOUBLE: + outBuffer.putDouble(sampleValues[sample].getDouble()); + break; + } + } + } else { + int sampleOffset = 0; + for (int i = 0; i < sample; ++i) { + sampleOffset += sizeSample(i); + } + + for (int i = 0; i < getWidth(); ++i) { + interleaveValues.position((y * getWidth() + i) * sizePixel() + sampleOffset); + + switch (sampleFieldTypes[sample]) { + case BYTE: + case SBYTE: + outBuffer.put(interleaveValues.get()); + break; + case SHORT: + case SSHORT: + outBuffer.putShort(interleaveValues.getShort()); + break; + case LONG: + case SLONG: + outBuffer.putInt(interleaveValues.getInt()); + break; + case FLOAT: + outBuffer.putFloat(interleaveValues.getFloat()); + break; + case DOUBLE: + outBuffer.putDouble(interleaveValues.getDouble()); + break; + } + } + } + + return outBuffer.array(); + } + /** * Get a pixel sample value * @@ -372,18 +641,21 @@ public Number getPixelSample(int sample, int x, int y) { // Get the pixel sample if (sampleValues != null) { - int sampleIndex = getSampleIndex(x, y); - pixelSample = sampleValues[sample][sampleIndex]; + int bufferPos = getSampleIndexInWindow(x, y) * sizeSample(sample); + pixelSample = getSampleFromByteBuffer(sampleValues[sample], bufferPos, sample); } else { - int interleaveIndex = getInterleaveIndex(x, y); - pixelSample = interleaveValues[interleaveIndex + sample]; + int bufferPos = getInterleaveIndex(x, y); + for (int i = 0; i < sample; i++) + bufferPos += sizeSample(i); + + pixelSample = getSampleFromByteBuffer(interleaveValues, bufferPos, sample); } return pixelSample; } /** - * Set a pixel vample value + * Set a pixel sample value * * @param sample * sample index (>= 0 && < {@link #getSamplesPerPixel()}) @@ -401,12 +673,15 @@ public void setPixelSample(int sample, int x, int y, Number value) { // Set the pixel sample if (sampleValues != null) { - int sampleIndex = getSampleIndex(x, y); - sampleValues[sample][sampleIndex] = value; + int sampleIndex = getSampleIndexInWindow(x, y) * sizeSample(sample); + updateSampleInByteBuffer(sampleValues[sample], sampleIndex, sample, value); } if (interleaveValues != null) { - int interleaveIndex = getInterleaveIndex(x, y); - interleaveValues[interleaveIndex + sample] = value; + int interleaveIndex = getSampleIndexInWindow(x, y) * sizePixel(); + for (int i = 0; i < sample; ++i) { + interleaveIndex += sizeSample(i); + } + updateSampleInByteBuffer(interleaveValues, interleaveIndex, sample, value); } } @@ -440,7 +715,7 @@ public void setFirstPixelSample(int x, int y, Number value) { } /** - * Get the sample index location + * Get the sample index location in window * * @param x * x coordinate @@ -448,7 +723,7 @@ public void setFirstPixelSample(int x, int y, Number value) { * y coordinate * @return sample index */ - public int getSampleIndex(int x, int y) { + public int getSampleIndexInWindow(int x, int y) { return y * width + x; } @@ -462,7 +737,7 @@ public int getSampleIndex(int x, int y) { * @return interleave index */ public int getInterleaveIndex(int x, int y) { - return (y * width * samplesPerPixel) + (x * samplesPerPixel); + return (y * width * sizePixel()) + (x * sizePixel()); } /** diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index 9c81639..9533e2a 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Collections; @@ -391,28 +392,14 @@ private static void writeStripRasters(ByteWriter writer, int endingY = Math.min(startingY + rowsPerStrip, maxY); for (int y = startingY; y < endingY; y++) { - - ByteWriter rowWriter = new ByteWriter(writer.getByteOrder()); - - for (int x = 0; x < fileDirectory.getImageWidth().intValue(); x++) { - - if (sample != null) { - Number value = rasters.getPixelSample(sample, x, y); - FieldType fieldType = sampleFieldTypes[sample]; - writeValue(rowWriter, fieldType, value); - } else { - Number[] values = rasters.getPixel(x, y); - for (int sampleIndex = 0; sampleIndex < values.length; sampleIndex++) { - Number value = values[sampleIndex]; - FieldType fieldType = sampleFieldTypes[sampleIndex]; - writeValue(rowWriter, fieldType, value); - } - } - } - // Get the row bytes and encode if needed - byte[] rowBytes = rowWriter.getBytes(); - rowWriter.close(); + byte[] rowBytes = null; + if (sample != null) { + rowBytes = rasters.getSampleRow(y, sample, writer.getByteOrder()); + } else { + rowBytes = rasters.getPixelRow(y, writer.getByteOrder()); + } + if (encoder.rowEncoding()) { rowBytes = encoder.encode(rowBytes, writer.getByteOrder()); } diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index b53ee4b..08066fc 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -5,6 +5,7 @@ import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import junit.framework.TestCase; import mil.nga.tiff.util.TiffException; @@ -139,11 +140,13 @@ public static void compareRastersSampleValues(Rasters rasters1, rasters2.getSampleValues().length); for (int i = 0; i < rasters1.getSampleValues().length; i++) { - TestCase.assertEquals(rasters1.getSampleValues()[i].length, - rasters2.getSampleValues()[i].length); - for (int j = 0; j < rasters2.getSampleValues()[i].length; j++) { - compareNumbers(rasters1.getSampleValues()[i][j], - rasters2.getSampleValues()[i][j], exactType); + TestCase.assertEquals(rasters1.getSampleValues()[i].capacity() / rasters1.sizeSample(i), + rasters2.getSampleValues()[i].capacity() / rasters2.sizeSample(i)); + + for (int x = 0; x < rasters1.getWidth(); ++x) { + for (int y = 0; y < rasters1.getHeight(); ++y) { + compareNumbers(rasters1.getPixelSample(i, x, y), rasters2.getPixelSample(i, x, y), exactType); + } } } } @@ -180,12 +183,16 @@ public static void compareRastersInterleaveValues(Rasters rasters1, TestCase.assertNotNull(rasters1.getInterleaveValues()); TestCase.assertNotNull(rasters2.getInterleaveValues()); - TestCase.assertEquals(rasters1.getInterleaveValues().length, - rasters2.getInterleaveValues().length); + TestCase.assertEquals(rasters1.getInterleaveValues().capacity() / rasters1.sizePixel(), + rasters2.getInterleaveValues().capacity() / rasters2.sizePixel()); + - for (int i = 0; i < rasters1.getInterleaveValues().length; i++) { - compareNumbers(rasters1.getInterleaveValues()[i], - rasters2.getInterleaveValues()[i], exactType); + for (int i = 0; i < rasters1.getSamplesPerPixel(); i++) { + for (int x = 0; x < rasters1.getWidth(); ++x) { + for (int y = 0; y < rasters1.getHeight(); ++y) { + compareNumbers(rasters1.getPixelSample(i, x, y), rasters2.getPixelSample(i, x, y), exactType); + } + } } } From 8f965fee58757b51a8898bdd081b04d252a148e8 Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Tue, 26 Sep 2017 11:12:42 +0200 Subject: [PATCH 20/29] Optimized switch use --- src/main/java/mil/nga/tiff/Rasters.java | 259 +++++++++++------------- 1 file changed, 115 insertions(+), 144 deletions(-) diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index 62824d1..4380f60 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import com.sun.javafx.beans.annotations.NonNull; import mil.nga.tiff.util.TiffConstants; import mil.nga.tiff.util.TiffException; @@ -211,36 +212,7 @@ private void updateSampleInByteBuffer(ByteBuffer buffer, int bufferIndex, int sa } buffer.position(bufferIndex); - - switch (sampleFieldTypes[sampleIndex]) { - case BYTE: - buffer.put(value.byteValue()); - break; - case SHORT: - buffer.putShort(value.shortValue()); - break; - case LONG: - buffer.putInt(value.intValue()); - break; - case SBYTE: - buffer.put(value.byteValue()); - break; - case SSHORT: - buffer.putShort(value.shortValue()); - break; - case SLONG: - buffer.putInt(value.intValue()); - break; - case FLOAT: - buffer.putFloat(value.floatValue()); - break; - case DOUBLE: - buffer.putDouble(value.doubleValue()); - break; - default: - throw new TiffException("Unsupported raster field type: " - + sampleFieldTypes[sampleIndex]); - } + writeSample(buffer, sampleFieldTypes[sampleIndex], value); } /** @@ -259,38 +231,7 @@ private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleI } buffer.position(index); - Number sampleValue; - - switch (sampleFieldTypes[sampleIndex]) { - case BYTE: - sampleValue = (short)(buffer.get() & 0xff); - break; - case SHORT: - sampleValue = buffer.getShort() & 0xffff; - break; - case LONG: - sampleValue = buffer.getInt() & 0xffffffffL; - break; - case SBYTE: - sampleValue = buffer.get(); - break; - case SSHORT: - sampleValue = buffer.getShort(); - break; - case SLONG: - sampleValue = buffer.getInt(); - break; - case FLOAT: - sampleValue = buffer.getFloat(); - break; - case DOUBLE: - sampleValue = buffer.getDouble(); - break; - default: - throw new TiffException("Unsupported raster field type: " - + sampleFieldTypes[sampleIndex]); - } - return sampleValue; + return readSample(buffer, sampleFieldTypes[sampleIndex]); } /** @@ -494,27 +435,7 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { } for (int i = 0; i < getWidth(); ++i) { for (int j = 0; j < samplesPerPixel; ++j) { - switch (sampleFieldTypes[j]) - { - case BYTE: - case SBYTE: - outBuffer.put(sampleValues[j].get()); - break; - case SHORT: - case SSHORT: - outBuffer.putShort(sampleValues[j].getShort()); - break; - case LONG: - case SLONG: - outBuffer.putInt(sampleValues[j].getInt()); - break; - case FLOAT: - outBuffer.putFloat(sampleValues[j].getFloat()); - break; - case DOUBLE: - outBuffer.putDouble(sampleValues[j].getDouble()); - break; - } + writeSample(outBuffer, sampleValues[j], sampleFieldTypes[j]); } } } else { @@ -522,26 +443,7 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { for (int i = 0; i < getWidth(); ++i) { for (int j = 0; j < samplesPerPixel; ++j) { - switch (sampleFieldTypes[j]) { - case BYTE: - case SBYTE: - outBuffer.put(interleaveValues.get()); - break; - case SHORT: - case SSHORT: - outBuffer.putShort(interleaveValues.getShort()); - break; - case LONG: - case SLONG: - outBuffer.putInt(interleaveValues.getInt()); - break; - case FLOAT: - outBuffer.putFloat(interleaveValues.getFloat()); - break; - case DOUBLE: - outBuffer.putDouble(interleaveValues.getDouble()); - break; - } + writeSample(outBuffer, interleaveValues, sampleFieldTypes[j]); } } } @@ -564,26 +466,7 @@ public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { if (sampleValues != null) { sampleValues[sample].position(y * getWidth() * sizeSample(sample)); for (int x = 0; x < getWidth(); ++x) { - switch (sampleFieldTypes[sample]) { - case BYTE: - case SBYTE: - outBuffer.put(sampleValues[sample].get()); - break; - case SHORT: - case SSHORT: - outBuffer.putShort(sampleValues[sample].getShort()); - break; - case LONG: - case SLONG: - outBuffer.putInt(sampleValues[sample].getInt()); - break; - case FLOAT: - outBuffer.putFloat(sampleValues[sample].getFloat()); - break; - case DOUBLE: - outBuffer.putDouble(sampleValues[sample].getDouble()); - break; - } + writeSample(outBuffer, sampleValues[sample], sampleFieldTypes[sample]); } } else { int sampleOffset = 0; @@ -593,27 +476,7 @@ public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { for (int i = 0; i < getWidth(); ++i) { interleaveValues.position((y * getWidth() + i) * sizePixel() + sampleOffset); - - switch (sampleFieldTypes[sample]) { - case BYTE: - case SBYTE: - outBuffer.put(interleaveValues.get()); - break; - case SHORT: - case SSHORT: - outBuffer.putShort(interleaveValues.getShort()); - break; - case LONG: - case SLONG: - outBuffer.putInt(interleaveValues.getInt()); - break; - case FLOAT: - outBuffer.putFloat(interleaveValues.getFloat()); - break; - case DOUBLE: - outBuffer.putDouble(interleaveValues.getDouble()); - break; - } + writeSample(outBuffer, interleaveValues, sampleFieldTypes[sample]); } } @@ -887,4 +750,112 @@ public static List makeBitsPerSampleList(int samplesPerPixel, return bitsPerSampleList; } + + /** + * Reads sample from given buffer + * + * @param buffer A buffer to read from. @note Make sure position is set. + * @param fieldType Field type to be read + * @return Sample form buffer + */ + private Number readSample(@NonNull ByteBuffer buffer, @NonNull FieldType fieldType) { + Number sampleValue; + + switch (fieldType) { + case BYTE: + sampleValue = (short)(buffer.get() & 0xff); + break; + case SHORT: + sampleValue = buffer.getShort() & 0xffff; + break; + case LONG: + sampleValue = buffer.getInt() & 0xffffffffL; + break; + case SBYTE: + sampleValue = buffer.get(); + break; + case SSHORT: + sampleValue = buffer.getShort(); + break; + case SLONG: + sampleValue = buffer.getInt(); + break; + case FLOAT: + sampleValue = buffer.getFloat(); + break; + case DOUBLE: + sampleValue = buffer.getDouble(); + break; + default: + throw new TiffException("Unsupported raster field type: " + fieldType); + } + + return sampleValue; + } + + /** + * Writes sample into given buffer. + * + * @param buffer A buffer to write to. @note Make sure buffer position is set. + * @param fieldType Field type to be written. + * @param value Actual value to write. + */ + private void writeSample(@NonNull ByteBuffer buffer, @NonNull FieldType fieldType, @NonNull Number value) { + switch (fieldType) { + case BYTE: + case SBYTE: + buffer.put(value.byteValue()); + break; + case SHORT: + case SSHORT: + buffer.putShort(value.shortValue()); + break; + case LONG: + case SLONG: + buffer.putInt(value.intValue()); + break; + case FLOAT: + buffer.putFloat(value.floatValue()); + break; + case DOUBLE: + buffer.putDouble(value.doubleValue()); + break; + default: + throw new TiffException("Unsupported raster field type: " + fieldType); + } + } + + /** + * Writes sample from input buffer to given output buffer. + * + * @param outBuffer A buffer to write to. @note Make sure buffer position is set. + * @param inBuffer A buffer to read from. @note Make sure buffer position is set. + * @param fieldType Field type to be read. + */ + private void writeSample(@NonNull ByteBuffer outBuffer, @NonNull ByteBuffer inBuffer, + @NonNull FieldType fieldType) { + switch (fieldType) + { + case BYTE: + case SBYTE: + outBuffer.put(inBuffer.get()); + break; + case SHORT: + case SSHORT: + outBuffer.putShort(inBuffer.getShort()); + break; + case LONG: + case SLONG: + outBuffer.putInt(inBuffer.getInt()); + break; + case FLOAT: + outBuffer.putFloat(inBuffer.getFloat()); + break; + case DOUBLE: + outBuffer.putDouble(inBuffer.getDouble()); + break; + default: + throw new TiffException("Unsupported raster field type: " + fieldType); + } + } } \ No newline at end of file From 80e46e82b755d194b2fc9c1b449c31fd4ef0579d Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Tue, 26 Sep 2017 11:19:27 +0200 Subject: [PATCH 21/29] Removed @NonNull annotations --- src/main/java/mil/nga/tiff/Rasters.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index 4380f60..84fdf8c 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.List; -import com.sun.javafx.beans.annotations.NonNull; import mil.nga.tiff.util.TiffConstants; import mil.nga.tiff.util.TiffException; @@ -758,7 +757,7 @@ public static List makeBitsPerSampleList(int samplesPerPixel, * @param fieldType Field type to be read * @return Sample form buffer */ - private Number readSample(@NonNull ByteBuffer buffer, @NonNull FieldType fieldType) { + private Number readSample(ByteBuffer buffer, FieldType fieldType) { Number sampleValue; switch (fieldType) { @@ -800,7 +799,7 @@ private Number readSample(@NonNull ByteBuffer buffer, @NonNull FieldType fieldTy * @param fieldType Field type to be written. * @param value Actual value to write. */ - private void writeSample(@NonNull ByteBuffer buffer, @NonNull FieldType fieldType, @NonNull Number value) { + private void writeSample(ByteBuffer buffer, FieldType fieldType, Number value) { switch (fieldType) { case BYTE: case SBYTE: @@ -832,8 +831,8 @@ private void writeSample(@NonNull ByteBuffer buffer, @NonNull FieldType fieldTyp * @param inBuffer A buffer to read from. @note Make sure buffer position is set. * @param fieldType Field type to be read. */ - private void writeSample(@NonNull ByteBuffer outBuffer, @NonNull ByteBuffer inBuffer, - @NonNull FieldType fieldType) { + private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, + FieldType fieldType) { switch (fieldType) { case BYTE: From bf9494ff645c4f6089d0feeeb7b9a00e1675e9c9 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Thu, 5 Oct 2017 06:34:12 -0600 Subject: [PATCH 22/29] maven-gpg-plugin version 1.6 --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 0d27a0a..0b73f24 100644 --- a/pom.xml +++ b/pom.xml @@ -84,6 +84,7 @@ org.apache.maven.plugins maven-gpg-plugin + 1.6 sign-artifacts From 51b1ba59c06c548649c2947858eb9c2739799c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Neboj=C5=A1a=20Obradovi=C4=87?= Date: Mon, 9 Oct 2017 14:22:43 +0200 Subject: [PATCH 23/29] Introduced sample types in raster (#3) Introduced sample types in raster --- src/main/java/mil/nga/tiff/FileDirectory.java | 72 ++-- src/main/java/mil/nga/tiff/Rasters.java | 353 ++++++++++-------- src/main/java/mil/nga/tiff/TiffWriter.java | 13 +- src/test/java/mil/nga/tiff/TiffTestUtils.java | 4 +- 4 files changed, 233 insertions(+), 209 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index c760c61..e495fae 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -1110,7 +1110,7 @@ public Rasters readRasters(ImageWindow window, int[] samples, } ByteBuffer interleave = null; if (interleaveValues) { - interleave = ByteBuffer.allocate(numPixels * bytesPerPixel); + interleave = ByteBuffer.allocateDirect(numPixels * bytesPerPixel); interleave.order(reader.getByteOrder()); } @@ -1119,19 +1119,19 @@ public Rasters readRasters(ImageWindow window, int[] samples, if (sampleValues) { sample = new ByteBuffer[samplesPerPixel]; for (int i = 0; i < sample.length; ++i) { - sample[i] = ByteBuffer.allocate(numPixels * bitsPerSample.get(i) / 8); + sample[i] = ByteBuffer.allocateDirect(numPixels * bitsPerSample.get(i) / 8); sample[i].order(reader.getByteOrder()); } } - FieldType[] sampleFieldTypes = new FieldType[samples.length]; + Rasters.SampleType[] sampleTypes = new Rasters.SampleType[samples.length]; for (int i = 0; i < samples.length; i++) { - sampleFieldTypes[i] = getFieldTypeForSample(samples[i]); + sampleTypes[i] = getTypeForSample(samples[i]); } // Create the rasters results Rasters rasters = new Rasters(windowWidth, windowHeight, - samplesPerPixel, bitsPerSample, sampleFieldTypes, sample, interleave); + sampleTypes, sample, interleave); // Read the rasters readRaster(window, samples, rasters); @@ -1164,14 +1164,14 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { int bytesPerPixel = getBytesPerPixel(); int[] srcSampleOffsets = new int[samples.length]; - FieldType[] sampleFieldTypes = new FieldType[samples.length]; + Rasters.SampleType[] sampleFieldTypes = new Rasters.SampleType[samples.length]; for (int i = 0; i < samples.length; i++) { int sampleOffset = 0; if (planarConfiguration == TiffConstants.PLANAR_CONFIGURATION_CHUNKY) { sampleOffset = sum(getBitsPerSample(), 0, samples[i]) / 8; } srcSampleOffsets[i] = sampleOffset; - sampleFieldTypes[i] = getFieldTypeForSample(samples[i]); + sampleFieldTypes[i] = getTypeForSample(samples[i]); } for (int yTile = minYTile; yTile < maxYTile; yTile++) { @@ -1236,19 +1236,19 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { } /** - * Read the value from the reader according to the field type + * Read the value from the reader according to the sample type * * @param reader * byte reader - * @param fieldType - * field type + * @param sampleType + * raster sample type * @return value */ - private Number readValue(ByteReader reader, FieldType fieldType) { + private Number readValue(ByteReader reader, Rasters.SampleType sampleType) { Number value = null; - switch (fieldType) { + switch (sampleType) { case BYTE: value = reader.readUnsignedByte(); break; @@ -1258,13 +1258,13 @@ private Number readValue(ByteReader reader, FieldType fieldType) { case LONG: value = reader.readUnsignedInt(); break; - case SBYTE: + case SIGNED_BYTE: value = reader.readByte(); break; - case SSHORT: + case SIGNED_SHORT: value = reader.readShort(); break; - case SLONG: + case SIGNED_LONG: value = reader.readInt(); break; case FLOAT: @@ -1274,68 +1274,72 @@ private Number readValue(ByteReader reader, FieldType fieldType) { value = reader.readDouble(); break; default: - throw new TiffException("Unsupported raster field type: " - + fieldType); + throw new TiffException("Unsupported raster sampleType type: " + + sampleType); } return value; } /** - * Get the field type for the sample - * + * Get the raster sample type for the sample @see Rasters.SampleType + * * @param sampleIndex * sample index - * @return field type + * @return Sample type */ - public FieldType getFieldTypeForSample(int sampleIndex) { + public Rasters.SampleType getTypeForSample(int sampleIndex) { - FieldType fieldType = null; + Rasters.SampleType sampleType = null; - List sampleFormat = getSampleFormat(); - int format = sampleFormat != null && sampleIndex < sampleFormat.size() ? sampleFormat - .get(sampleIndex) : TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT; + List sampleFormatList = getSampleFormat(); + int format = sampleFormatList == null ? TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT + : sampleFormatList.get(sampleIndex < sampleFormatList.size() ? sampleIndex : 0); int bitsPerSample = getBitsPerSample().get(sampleIndex); switch (format) { case TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT: switch (bitsPerSample) { case 8: - fieldType = FieldType.BYTE; + sampleType = Rasters.SampleType.BYTE; break; case 16: - fieldType = FieldType.SHORT; + sampleType = Rasters.SampleType.SHORT; break; case 32: - fieldType = FieldType.LONG; + sampleType = Rasters.SampleType.LONG; break; } break; case TiffConstants.SAMPLE_FORMAT_SIGNED_INT: switch (bitsPerSample) { case 8: - fieldType = FieldType.SBYTE; + sampleType = Rasters.SampleType.SIGNED_BYTE; break; case 16: - fieldType = FieldType.SSHORT; + sampleType = Rasters.SampleType.SIGNED_SHORT; break; case 32: - fieldType = FieldType.SLONG; + sampleType = Rasters.SampleType.SIGNED_LONG; break; } break; case TiffConstants.SAMPLE_FORMAT_FLOAT: switch (bitsPerSample) { case 32: - fieldType = FieldType.FLOAT; + sampleType = Rasters.SampleType.FLOAT; break; case 64: - fieldType = FieldType.DOUBLE; + sampleType = Rasters.SampleType.DOUBLE; break; } break; } - return fieldType; + if (sampleType == null) + throw new TiffException("Unsupported sample type for format: " + format + + ", and bits per sample: " + bitsPerSample); + + return sampleType; } /** diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index 84fdf8c..bfb7a7d 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -3,6 +3,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import mil.nga.tiff.util.TiffConstants; @@ -14,6 +15,29 @@ * @author osbornb */ public class Rasters { + /** + * Sample type for pixel + */ + public enum SampleType { + BYTE(1, TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT), // 8 bits + SIGNED_BYTE(1, TiffConstants.SAMPLE_FORMAT_SIGNED_INT), // 8 bits + SHORT(2, TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT), // 16 bits + SIGNED_SHORT(2, TiffConstants.SAMPLE_FORMAT_SIGNED_INT),// 16 bits + LONG(4, TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT), // 32 bits + SIGNED_LONG(4, TiffConstants.SAMPLE_FORMAT_SIGNED_INT), // 32 bits + FLOAT(4, TiffConstants.SAMPLE_FORMAT_FLOAT) , // 32 bits + DOUBLE(8, TiffConstants.SAMPLE_FORMAT_FLOAT); // 64 bits + + SampleType(int byteSize, int sampleFormat) { + this.byteSize = byteSize; + this.sampleFormat = sampleFormat; + } + + int bitSize() { return byteSize * 8; } + + final int byteSize; + final int sampleFormat; + } /** * Values separated by sample @@ -36,19 +60,26 @@ public class Rasters { private final int height; /** - * Samples per pixel + * Sample type for each sample. */ - private final int samplesPerPixel; + private final SampleType[] sampleTypes; + + // Calculated values /** - * Bits per sample + * Calculated pixel size in bytes */ - private final List bitsPerSample; + private Integer pixelSize; /** - * Field type for each sample. Can be total samplesPerPixel. + * @see getBitsPerSample() */ - private final FieldType[] sampleFieldTypes; + private List bitsPerSample; + + /** + * @see getSampleFormat() + */ + private List sampleFormat; /** * Constructor @@ -57,18 +88,13 @@ public class Rasters { * width of pixels * @param height * height of pixels - * @param samplesPerPixel - * samples per pixel - * @param bitsPerSample - * bits per sample - * @param sampleFieldTypes - * Field type for each sample + * @param sampleTypes + * Sample type for each sample * @param sampleValues * empty sample values double array */ - public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample, FieldType[] sampleFieldTypes, ByteBuffer[] sampleValues) { - this(width, height, samplesPerPixel, bitsPerSample, sampleFieldTypes, sampleValues, null); + public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer[] sampleValues) { + this(width, height, sampleTypes, sampleValues, null); } /** @@ -78,19 +104,13 @@ public Rasters(int width, int height, int samplesPerPixel, * width of pixels * @param height * height of pixels - * @param samplesPerPixel - * samples per pixel - * @param bitsPerSample - * bits per sample - * @param sampleFieldTypes - * Field type for each sample + * @param sampleTypes + * Sample type for each sample * @param interleaveValues * empty interleaved values array */ - public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample, FieldType[] sampleFieldTypes, ByteBuffer interleaveValues) { - this(width, height, samplesPerPixel, bitsPerSample, sampleFieldTypes, null, - interleaveValues); + public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer interleaveValues) { + this(width, height, sampleTypes, null, interleaveValues); } /** @@ -100,34 +120,36 @@ public Rasters(int width, int height, int samplesPerPixel, * width of pixels * @param height * height of pixels - * @param samplesPerPixel - * samples per pixel - * @param bitsPerSample - * bits per sample - * @param sampleFieldTypes - * Field type for each sample + * @param sampleTypes + * Sample type for each sample * @param sampleValues * empty sample values double array * @param interleaveValues * empty interleaved values array */ - public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample, FieldType[] sampleFieldTypes, ByteBuffer[] sampleValues, - ByteBuffer interleaveValues) { + public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer[] sampleValues, + ByteBuffer interleaveValues) { this.width = width; this.height = height; - this.samplesPerPixel = samplesPerPixel; - this.bitsPerSample = bitsPerSample; - this.sampleFieldTypes = sampleFieldTypes; + this.sampleTypes = sampleTypes; this.sampleValues = sampleValues; this.interleaveValues = interleaveValues; validateValues(); - for (int bits : bitsPerSample) { - if ((bits % 8) != 0) { - throw new TiffException("Sample bit-width of " + bits - + " is not supported"); - } - } + } + + /** + * Constructor + * + * Creates Rasters object where given sample type used for each sample. + * + * @param width width of pixels + * @param height height of pixels + * @param samplesPerPixel number of samples per pixel + * @param sampleType type of sample for each sample + */ + public Rasters(int width, int height, int samplesPerPixel, SampleType sampleType) { + this(width, height, createSampleTypeArray(samplesPerPixel, sampleType), + ByteOrder.nativeOrder()); } /** @@ -141,25 +163,13 @@ private void validateValues() { } /** - * Constructor - * - * @param width - * width of pixels - * @param height - * height of pixels - * @param samplesPerPixel - * samples per pixel - * @param bitsPerSample - * bits per sample - */ - public Rasters(int width, int height, int samplesPerPixel, - List bitsPerSample, FieldType[] sampleFieldTypes, ByteOrder order) { - this(width, height, samplesPerPixel, bitsPerSample, sampleFieldTypes, - new ByteBuffer[samplesPerPixel]); - for (int i = 0; i < sampleValues.length; ++i) { - sampleValues[i] = ByteBuffer.allocate(width * height * sizeSample(i)); - sampleValues[i].order(order); - } + * Helper method used to create {@link SampleType} array of given size and + * filled with given values. + */ + private static SampleType[] createSampleTypeArray(int size, SampleType sampleType) { + SampleType[] result = new SampleType[size]; + Arrays.fill(result, sampleType); + return result; } /** @@ -169,14 +179,16 @@ public Rasters(int width, int height, int samplesPerPixel, * width of pixels * @param height * height of pixels - * @param samplesPerPixel - * samples per pixel - * @param bitsPerSample - * bits per sample for all samples of a pixel + * @param sampleTypes + * Sample types per sample */ - public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, FieldType[] sampleFieldTypes, ByteOrder order) { - this(width, height, samplesPerPixel, makeBitsPerSampleList( - samplesPerPixel, bitsPerSample), sampleFieldTypes, order); + public Rasters(int width, int height, SampleType[] sampleTypes, ByteOrder order) { + this(width, height, sampleTypes, new ByteBuffer[sampleTypes.length]); + for (int i = 0; i < sampleValues.length; ++i) { + sampleValues[i] = ByteBuffer + .allocateDirect(width * height * sampleTypes[i].byteSize) + .order(order); + } } /** @@ -211,7 +223,7 @@ private void updateSampleInByteBuffer(ByteBuffer buffer, int bufferIndex, int sa } buffer.position(bufferIndex); - writeSample(buffer, sampleFieldTypes[sampleIndex], value); + writeSample(buffer, sampleTypes[sampleIndex], value); } /** @@ -230,7 +242,7 @@ private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleI } buffer.position(index); - return readSample(buffer, sampleFieldTypes[sampleIndex]); + return readSample(buffer, sampleTypes[sampleIndex]); } /** @@ -245,7 +257,7 @@ private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleI */ public void addToSample(int sampleIndex, int coordinate, Number value) { updateSampleInByteBuffer(sampleValues[sampleIndex], - coordinate * sizeSample(sampleIndex), sampleIndex, value); + coordinate * sampleTypes[sampleIndex].byteSize, sampleIndex, value); } /** @@ -259,7 +271,7 @@ public void addToSample(int sampleIndex, int coordinate, Number value) { public void addToInterleave(int coordinate, Number value, int sampleIndex) { int bufferPos = coordinate * sizePixel(); for (int i = 0; i < sampleIndex; ++i) - bufferPos += sizeSample(i); + bufferPos += sampleTypes[i].byteSize; updateSampleInByteBuffer(interleaveValues, bufferPos, sampleIndex, value); } @@ -297,7 +309,7 @@ public int getNumPixels() { * @return samples per pixel */ public int getSamplesPerPixel() { - return samplesPerPixel; + return sampleTypes.length; } /** @@ -306,7 +318,37 @@ public int getSamplesPerPixel() { * @return bits per sample */ public List getBitsPerSample() { - return bitsPerSample; + if (bitsPerSample != null) { + return bitsPerSample; + } + + List result = new ArrayList<>(sampleTypes.length); + for (SampleType sampleType : sampleTypes) { + result.add(sampleType.bitSize()); + } + bitsPerSample = result; + return result; + } + + /** + * Returns list of sample types constants + * + * Returns list of sample types constants (SAMPLE_FORMAT_UNSIGNED_INT, + * SAMPLE_FORMAT_SIGNED_INT or SAMPLE_FORMAT_FLOAT) for each sample in + * sample list @see getSampleTypes(). @see {@link TiffConstants} + * @return list of sample type constants + */ + public List getSampleFormat() { + if (sampleFormat != null) { + return sampleFormat; + } + + List result = new ArrayList<>(sampleTypes.length); + for (SampleType sampleType : sampleTypes) { + result.add(sampleType.sampleFormat); + } + sampleFormat = result; + return result; } /** @@ -329,6 +371,9 @@ public ByteBuffer[] getSampleValues() { */ public void setSampleValues(ByteBuffer[] sampleValues) { this.sampleValues = sampleValues; + this.sampleFormat = null; + this.bitsPerSample = null; + this.pixelSize = null; validateValues(); } @@ -367,20 +412,20 @@ public Number[] getPixel(int x, int y) { validateCoordinates(x, y); // Pixel with each sample value - Number[] pixel = new Number[samplesPerPixel]; + Number[] pixel = new Number[getSamplesPerPixel()]; // Get the pixel values from each sample if (sampleValues != null) { int sampleIndex = getSampleIndexInWindow(x, y); - for (int i = 0; i < samplesPerPixel; i++) { - int bufferIndex = sampleIndex * sizeSample(i); + for (int i = 0; i < getSamplesPerPixel(); i++) { + int bufferIndex = sampleIndex * sampleTypes[i].byteSize; pixel[i] = getSampleFromByteBuffer(sampleValues[i], bufferIndex, i); } } else { int interleaveIndex = getInterleaveIndex(x, y); - for (int i = 0; i < samplesPerPixel; i++) { + for (int i = 0; i < getSamplesPerPixel(); i++) { pixel[i] = getSampleFromByteBuffer(interleaveValues, interleaveIndex, i); - interleaveIndex += sizeSample(i); + interleaveIndex += sampleTypes[i].byteSize; } } @@ -404,15 +449,15 @@ public void setPixel(int x, int y, Number[] values) { // Set the pixel values from each sample if (sampleValues != null) { - for (int i = 0; i < samplesPerPixel; i++) { - int bufferIndex = getSampleIndexInWindow(x, y) * sizeSample(i); + for (int i = 0; i < getSamplesPerPixel(); i++) { + int bufferIndex = getSampleIndexInWindow(x, y) * sampleTypes[i].byteSize; updateSampleInByteBuffer(sampleValues[i], bufferIndex, i, values[i]); } } else { int interleaveIndex = getSampleIndexInWindow(x, y) * sizePixel(); - for (int i = 0; i < samplesPerPixel; i++) { + for (int i = 0; i < getSamplesPerPixel(); i++) { updateSampleInByteBuffer(interleaveValues, interleaveIndex, i, values[i]); - interleaveIndex += sizeSample(i); + interleaveIndex += sampleTypes[i].byteSize; } } } @@ -429,20 +474,20 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { outBuffer.order(newOrder); if (sampleValues != null) { - for (int i = 0; i < samplesPerPixel; ++i) { - sampleValues[i].position(y * getWidth() * sizeSample(i)); + for (int i = 0; i < getSamplesPerPixel(); ++i) { + sampleValues[i].position(y * getWidth() * sampleTypes[i].byteSize); } for (int i = 0; i < getWidth(); ++i) { - for (int j = 0; j < samplesPerPixel; ++j) { - writeSample(outBuffer, sampleValues[j], sampleFieldTypes[j]); + for (int j = 0; j < getSamplesPerPixel(); ++j) { + writeSample(outBuffer, sampleValues[j], sampleTypes[j]); } } } else { interleaveValues.position(y * getWidth() * sizePixel()); for (int i = 0; i < getWidth(); ++i) { - for (int j = 0; j < samplesPerPixel; ++j) { - writeSample(outBuffer, interleaveValues, sampleFieldTypes[j]); + for (int j = 0; j < getSamplesPerPixel(); ++j) { + writeSample(outBuffer, interleaveValues, sampleTypes[j]); } } } @@ -459,23 +504,23 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { * @return Byte array of sample row */ public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { - ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * sizeSample(sample)); + ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * sampleTypes[sample].byteSize); outBuffer.order(newOrder); if (sampleValues != null) { - sampleValues[sample].position(y * getWidth() * sizeSample(sample)); + sampleValues[sample].position(y * getWidth() * sampleTypes[sample].byteSize); for (int x = 0; x < getWidth(); ++x) { - writeSample(outBuffer, sampleValues[sample], sampleFieldTypes[sample]); + writeSample(outBuffer, sampleValues[sample], sampleTypes[sample]); } } else { int sampleOffset = 0; for (int i = 0; i < sample; ++i) { - sampleOffset += sizeSample(i); + sampleOffset += sampleTypes[sample].byteSize; } for (int i = 0; i < getWidth(); ++i) { interleaveValues.position((y * getWidth() + i) * sizePixel() + sampleOffset); - writeSample(outBuffer, interleaveValues, sampleFieldTypes[sample]); + writeSample(outBuffer, interleaveValues, sampleTypes[sample]); } } @@ -503,12 +548,12 @@ public Number getPixelSample(int sample, int x, int y) { // Get the pixel sample if (sampleValues != null) { - int bufferPos = getSampleIndexInWindow(x, y) * sizeSample(sample); + int bufferPos = getSampleIndexInWindow(x, y) * sampleTypes[sample].byteSize; pixelSample = getSampleFromByteBuffer(sampleValues[sample], bufferPos, sample); } else { int bufferPos = getInterleaveIndex(x, y); for (int i = 0; i < sample; i++) - bufferPos += sizeSample(i); + bufferPos += sampleTypes[sample].byteSize; pixelSample = getSampleFromByteBuffer(interleaveValues, bufferPos, sample); } @@ -535,13 +580,13 @@ public void setPixelSample(int sample, int x, int y, Number value) { // Set the pixel sample if (sampleValues != null) { - int sampleIndex = getSampleIndexInWindow(x, y) * sizeSample(sample); + int sampleIndex = getSampleIndexInWindow(x, y) * sampleTypes[sample].byteSize; updateSampleInByteBuffer(sampleValues[sample], sampleIndex, sample, value); } if (interleaveValues != null) { int interleaveIndex = getSampleIndexInWindow(x, y) * sizePixel(); for (int i = 0; i < sample; ++i) { - interleaveIndex += sizeSample(i); + interleaveIndex += sampleTypes[sample].byteSize; } updateSampleInByteBuffer(interleaveValues, interleaveIndex, sample, value); } @@ -617,24 +662,18 @@ public int size() { * @return bytes */ public int sizePixel() { + if (pixelSize != null) { + return pixelSize; + } + int size = 0; - for (int i = 0; i < samplesPerPixel; i++) { - size += sizeSample(i); + for (int i = 0; i < getSamplesPerPixel(); i++) { + size += sampleTypes[i].byteSize; } + pixelSize = size; return size; } - /** - * Size in bytes of a sample - * - * @param sample - * sample index - * @return bytes - */ - public int sizeSample(int sample) { - return bitsPerSample.get(sample) / 8; - } - /** * Validate the coordinates range * @@ -657,9 +696,9 @@ private void validateCoordinates(int x, int y) { * sample index */ private void validateSample(int sample) { - if (sample < 0 || sample >= samplesPerPixel) { + if (sample < 0 || sample >= getSamplesPerPixel()) { throw new TiffException("Pixel sample out of bounds. sample: " - + sample + ", samples per pixel: " + samplesPerPixel); + + sample + ", samples per pixel: " + getSamplesPerPixel()); } } @@ -690,15 +729,11 @@ public int calculateRowsPerStrip(int planarConfiguration, Integer rowsPerStrip = null; if (planarConfiguration == TiffConstants.PLANAR_CONFIGURATION_CHUNKY) { - int bitsPerPixel = 0; - for (int sampleBits : bitsPerSample) { - bitsPerPixel += sampleBits; - } - rowsPerStrip = rowsPerStrip(bitsPerPixel, maxBytesPerStrip); + rowsPerStrip = rowsPerStrip(sizePixel(), maxBytesPerStrip); } else { - for (int sampleBits : bitsPerSample) { - int rowsPerStripForSample = rowsPerStrip(sampleBits, + for (int sample = 0; sample < getSamplesPerPixel(); ++sample) { + int rowsPerStripForSample = rowsPerStrip(sampleTypes[sample].byteSize, maxBytesPerStrip); if (rowsPerStrip == null || rowsPerStripForSample < rowsPerStrip) { @@ -714,15 +749,14 @@ public int calculateRowsPerStrip(int planarConfiguration, * Get the rows per strip based upon the bits per pixel and max bytes per * strip * - * @param bitsPerPixel - * bits per pixel + * @param bytesPerPixel + * bytes per pixel * @param maxBytesPerStrip * max bytes per strip * @return rows per strip */ - private int rowsPerStrip(int bitsPerPixel, int maxBytesPerStrip) { + private int rowsPerStrip(int bytesPerPixel, int maxBytesPerStrip) { - int bytesPerPixel = (int) Math.ceil(bitsPerPixel / 8.0); int bytesPerRow = bytesPerPixel * width; int rowsPerStrip = Math.max(1, maxBytesPerStrip / bytesPerRow); @@ -730,37 +764,17 @@ private int rowsPerStrip(int bitsPerPixel, int maxBytesPerStrip) { return rowsPerStrip; } - /** - * Make a bits per sample list where each samples of a pixel has the same - * value - * - * @param samplesPerPixel - * samples per pixel - * @param bitsPerSample - * bits per sample for all samples of a pixel - * @return bits per sample list - */ - public static List makeBitsPerSampleList(int samplesPerPixel, - int bitsPerSample) { - List bitsPerSampleList = new ArrayList(); - for (int i = 0; i < samplesPerPixel; ++i) { - bitsPerSampleList.add(bitsPerSample); - } - return bitsPerSampleList; - } - - /** * Reads sample from given buffer * * @param buffer A buffer to read from. @note Make sure position is set. - * @param fieldType Field type to be read + * @param sampleType Sample type to be read * @return Sample form buffer */ - private Number readSample(ByteBuffer buffer, FieldType fieldType) { + private Number readSample(ByteBuffer buffer, SampleType sampleType) { Number sampleValue; - switch (fieldType) { + switch (sampleType) { case BYTE: sampleValue = (short)(buffer.get() & 0xff); break; @@ -770,13 +784,13 @@ private Number readSample(ByteBuffer buffer, FieldType fieldType) { case LONG: sampleValue = buffer.getInt() & 0xffffffffL; break; - case SBYTE: + case SIGNED_BYTE: sampleValue = buffer.get(); break; - case SSHORT: + case SIGNED_SHORT: sampleValue = buffer.getShort(); break; - case SLONG: + case SIGNED_LONG: sampleValue = buffer.getInt(); break; case FLOAT: @@ -786,7 +800,7 @@ private Number readSample(ByteBuffer buffer, FieldType fieldType) { sampleValue = buffer.getDouble(); break; default: - throw new TiffException("Unsupported raster field type: " + fieldType); + throw new TiffException("Unsupported raster sample type: " + sampleType); } return sampleValue; @@ -796,21 +810,21 @@ private Number readSample(ByteBuffer buffer, FieldType fieldType) { * Writes sample into given buffer. * * @param buffer A buffer to write to. @note Make sure buffer position is set. - * @param fieldType Field type to be written. + * @param sampleType Sample type to be written. * @param value Actual value to write. */ - private void writeSample(ByteBuffer buffer, FieldType fieldType, Number value) { - switch (fieldType) { + private void writeSample(ByteBuffer buffer, SampleType sampleType, Number value) { + switch (sampleType) { case BYTE: - case SBYTE: + case SIGNED_BYTE: buffer.put(value.byteValue()); break; case SHORT: - case SSHORT: + case SIGNED_SHORT: buffer.putShort(value.shortValue()); break; case LONG: - case SLONG: + case SIGNED_LONG: buffer.putInt(value.intValue()); break; case FLOAT: @@ -820,7 +834,7 @@ private void writeSample(ByteBuffer buffer, FieldType fieldType, Number value) { buffer.putDouble(value.doubleValue()); break; default: - throw new TiffException("Unsupported raster field type: " + fieldType); + throw new TiffException("Unsupported raster sample type: " + sampleType); } } @@ -829,22 +843,22 @@ private void writeSample(ByteBuffer buffer, FieldType fieldType, Number value) { * * @param outBuffer A buffer to write to. @note Make sure buffer position is set. * @param inBuffer A buffer to read from. @note Make sure buffer position is set. - * @param fieldType Field type to be read. + * @param sampleType Field type to be read. */ private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, - FieldType fieldType) { - switch (fieldType) + SampleType sampleType) { + switch (sampleType) { case BYTE: - case SBYTE: + case SIGNED_BYTE: outBuffer.put(inBuffer.get()); break; case SHORT: - case SSHORT: + case SIGNED_SHORT: outBuffer.putShort(inBuffer.getShort()); break; case LONG: - case SLONG: + case SIGNED_LONG: outBuffer.putInt(inBuffer.getInt()); break; case FLOAT: @@ -854,7 +868,14 @@ private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, outBuffer.putDouble(inBuffer.getDouble()); break; default: - throw new TiffException("Unsupported raster field type: " + fieldType); + throw new TiffException("Unsupported raster sample type: " + sampleType); } } + + /** + * Returns sample types + */ + public SampleType[] getSampleTypes() { + return sampleTypes; + } } \ No newline at end of file diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index 8a526ca..b0790b8 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -3,7 +3,6 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Collections; @@ -312,11 +311,11 @@ private static byte[] writeRasters(ByteOrder byteOrder, } // Get the sample field types - FieldType[] sampleFieldTypes = new FieldType[rasters + Rasters.SampleType[] sampleTypes = new Rasters.SampleType[rasters .getSamplesPerPixel()]; for (int sample = 0; sample < rasters.getSamplesPerPixel(); sample++) { - sampleFieldTypes[sample] = fileDirectory - .getFieldTypeForSample(sample); + sampleTypes[sample] = fileDirectory + .getTypeForSample(sample); } // Get the compression encoder @@ -327,7 +326,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, // Write the rasters if (!fileDirectory.isTiled()) { - writeStripRasters(writer, fileDirectory, offset, sampleFieldTypes, + writeStripRasters(writer, fileDirectory, offset, sampleTypes, encoder); } else { throw new TiffException("Tiled images are not supported"); @@ -349,7 +348,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, * file directory * @param offset * byte offset - * @param sampleFieldTypes + * @param sampleTypes * sample field types * @param encoder * compression encoder @@ -357,7 +356,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, */ private static void writeStripRasters(ByteWriter writer, FileDirectory fileDirectory, long offset, - FieldType[] sampleFieldTypes, CompressionEncoder encoder) + Rasters.SampleType[] sampleTypes, CompressionEncoder encoder) throws IOException { Rasters rasters = fileDirectory.getWriteRasters(); diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index 08066fc..a6b0242 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -140,8 +140,8 @@ public static void compareRastersSampleValues(Rasters rasters1, rasters2.getSampleValues().length); for (int i = 0; i < rasters1.getSampleValues().length; i++) { - TestCase.assertEquals(rasters1.getSampleValues()[i].capacity() / rasters1.sizeSample(i), - rasters2.getSampleValues()[i].capacity() / rasters2.sizeSample(i)); + TestCase.assertEquals(rasters1.getSampleValues()[i].capacity() / rasters1.getSampleTypes()[i].byteSize, + rasters2.getSampleValues()[i].capacity() / rasters2.getSampleTypes()[i].byteSize); for (int x = 0; x < rasters1.getWidth(); ++x) { for (int y = 0; y < rasters1.getHeight(); ++y) { From efbeaddf00af01527475b8fc0c0bc7060d16d13c Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Mon, 9 Oct 2017 16:00:57 +0200 Subject: [PATCH 24/29] getSamplesPerPixel() now returns int --- src/main/java/mil/nga/tiff/FileDirectory.java | 4 ++-- src/test/java/mil/nga/tiff/TiffTestUtils.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index e495fae..7b5e447 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -483,7 +483,7 @@ public void setStripOffsets(long stripOffset) { * * @return samples per pixel */ - public Integer getSamplesPerPixel() { + public int getSamplesPerPixel() { Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); if (samplesPerPixel == null) { // if SamplesPerPixel tag is missing, try using length of @@ -494,7 +494,7 @@ public Integer getSamplesPerPixel() { } } - return samplesPerPixel; + return samplesPerPixel.intValue(); } /** diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index a6b0242..588c220 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -94,7 +94,7 @@ private static void compareFileDirectoryAndRastersMetadata( TestCase.assertEquals(fileDirectory.getImageWidth(), rasters.getWidth()); TestCase.assertEquals(fileDirectory.getImageHeight(), rasters.getHeight()); - TestCase.assertEquals(fileDirectory.getSamplesPerPixel().intValue(), + TestCase.assertEquals(fileDirectory.getSamplesPerPixel(), rasters.getSamplesPerPixel()); TestCase.assertEquals(fileDirectory.getBitsPerSample().size(), rasters .getBitsPerSample().size()); From ddc4bc95df19987d6d09ab2cf5fdc1eb0335e435 Mon Sep 17 00:00:00 2001 From: Nebojsa Obradovic <10four@gmail.com> Date: Mon, 9 Oct 2017 16:00:57 +0200 Subject: [PATCH 25/29] getSamplesPerPixel() now returns int --- src/main/java/mil/nga/tiff/FileDirectory.java | 11 +++-------- src/test/java/mil/nga/tiff/TiffTestUtils.java | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index e495fae..db700c6 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -483,17 +483,12 @@ public void setStripOffsets(long stripOffset) { * * @return samples per pixel */ - public Integer getSamplesPerPixel() { + public int getSamplesPerPixel() { Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); if (samplesPerPixel == null) { - // if SamplesPerPixel tag is missing, try using length of - // BitsPerSample list - List bitsPerSampleList = getBitsPerSample(); - if (bitsPerSampleList != null) { - samplesPerPixel = bitsPerSampleList.size(); - } + // if SamplesPerPixel tag is missing, use default value defined by TIFF standard + return 1; } - return samplesPerPixel; } diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index a6b0242..588c220 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -94,7 +94,7 @@ private static void compareFileDirectoryAndRastersMetadata( TestCase.assertEquals(fileDirectory.getImageWidth(), rasters.getWidth()); TestCase.assertEquals(fileDirectory.getImageHeight(), rasters.getHeight()); - TestCase.assertEquals(fileDirectory.getSamplesPerPixel().intValue(), + TestCase.assertEquals(fileDirectory.getSamplesPerPixel(), rasters.getSamplesPerPixel()); TestCase.assertEquals(fileDirectory.getBitsPerSample().size(), rasters .getBitsPerSample().size()); From 0f2736039d39cc0247eb9c204de1b05614c5cea3 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Thu, 19 Oct 2017 15:33:20 -0600 Subject: [PATCH 26/29] pull request changes --- src/main/java/mil/nga/tiff/FieldType.java | 102 ++++- src/main/java/mil/nga/tiff/FileDirectory.java | 97 ++--- src/main/java/mil/nga/tiff/Rasters.java | 378 +++++++++++------- src/main/java/mil/nga/tiff/TiffWriter.java | 59 +-- src/main/java/mil/nga/tiff/io/ByteReader.java | 2 +- src/main/java/mil/nga/tiff/io/ByteWriter.java | 2 +- src/test/java/mil/nga/tiff/TiffTestUtils.java | 5 +- 7 files changed, 370 insertions(+), 275 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FieldType.java b/src/main/java/mil/nga/tiff/FieldType.java index d9b0ec1..4e31e6e 100644 --- a/src/main/java/mil/nga/tiff/FieldType.java +++ b/src/main/java/mil/nga/tiff/FieldType.java @@ -1,5 +1,8 @@ package mil.nga.tiff; +import mil.nga.tiff.util.TiffConstants; +import mil.nga.tiff.util.TiffException; + /** * Field Types * @@ -104,6 +107,15 @@ public int getBytes() { return bytes; } + /** + * Get the number of bits per value + * + * @return number of bits + */ + public int getBits() { + return bytes * 8; + } + /** * Get the field type * @@ -114,5 +126,93 @@ public int getBytes() { public static FieldType getFieldType(int fieldType) { return FieldType.values()[fieldType - 1]; } - + + /** + * Get the field type of the sample format and bits per sample + * @param sampleFormat sample format + * @param bitsPerSample bits per sample + * @return field type + */ + public static FieldType getFieldType(int sampleFormat, int bitsPerSample){ + + FieldType fieldType = null; + + switch (sampleFormat) { + case TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT: + switch (bitsPerSample) { + case 8: + fieldType = FieldType.BYTE; + break; + case 16: + fieldType = FieldType.SHORT; + break; + case 32: + fieldType = FieldType.LONG; + break; + } + break; + case TiffConstants.SAMPLE_FORMAT_SIGNED_INT: + switch (bitsPerSample) { + case 8: + fieldType = FieldType.SBYTE; + break; + case 16: + fieldType = FieldType.SSHORT; + break; + case 32: + fieldType = FieldType.SLONG; + break; + } + break; + case TiffConstants.SAMPLE_FORMAT_FLOAT: + switch (bitsPerSample) { + case 32: + fieldType = FieldType.FLOAT; + break; + case 64: + fieldType = FieldType.DOUBLE; + break; + } + break; + } + + if (fieldType == null){ + throw new TiffException("Unsupported field type for sample format: " + sampleFormat + + ", bits per sample: " + bitsPerSample); + } + + return fieldType; + } + + /** + * Get the sample format of the field type + * @param fieldType field type + * @return sample format + */ + public static int getSampleFormat(FieldType fieldType){ + + int sampleFormat; + + switch(fieldType){ + case BYTE: + case SHORT: + case LONG: + sampleFormat = TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT; + break; + case SBYTE: + case SSHORT: + case SLONG: + sampleFormat = TiffConstants.SAMPLE_FORMAT_SIGNED_INT; + break; + case FLOAT: + case DOUBLE: + sampleFormat = TiffConstants.SAMPLE_FORMAT_FLOAT; + break; + default: + throw new TiffException("Unsupported sample format for field type: " + fieldType); + } + + return sampleFormat; + } + } diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index db700c6..91dbb2c 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -1,5 +1,6 @@ package mil.nga.tiff; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -9,8 +10,6 @@ import java.util.SortedSet; import java.util.TreeSet; -import java.nio.ByteBuffer; - import mil.nga.tiff.compression.CompressionDecoder; import mil.nga.tiff.compression.DeflateCompression; import mil.nga.tiff.compression.LZWCompression; @@ -487,7 +486,7 @@ public int getSamplesPerPixel() { Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); if (samplesPerPixel == null) { // if SamplesPerPixel tag is missing, use default value defined by TIFF standard - return 1; + samplesPerPixel = 1; } return samplesPerPixel; } @@ -1097,7 +1096,7 @@ public Rasters readRasters(ImageWindow window, int[] samples, } } - // Create the interleaved result array + // Create the interleaved result buffer List bitsPerSample = getBitsPerSample(); int bytesPerPixel = 0; for (int i = 0; i < samplesPerPixel; ++i) { @@ -1109,7 +1108,7 @@ public Rasters readRasters(ImageWindow window, int[] samples, interleave.order(reader.getByteOrder()); } - // Create the sample indexed result double array + // Create the sample indexed result buffer array ByteBuffer[] sample = null; if (sampleValues) { sample = new ByteBuffer[samplesPerPixel]; @@ -1119,14 +1118,14 @@ public Rasters readRasters(ImageWindow window, int[] samples, } } - Rasters.SampleType[] sampleTypes = new Rasters.SampleType[samples.length]; + FieldType[] fieldTypes = new FieldType[samples.length]; for (int i = 0; i < samples.length; i++) { - sampleTypes[i] = getTypeForSample(samples[i]); + fieldTypes[i] = getFieldTypeForSample(samples[i]); } // Create the rasters results Rasters rasters = new Rasters(windowWidth, windowHeight, - sampleTypes, sample, interleave); + fieldTypes, sample, interleave); // Read the rasters readRaster(window, samples, rasters); @@ -1159,14 +1158,14 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { int bytesPerPixel = getBytesPerPixel(); int[] srcSampleOffsets = new int[samples.length]; - Rasters.SampleType[] sampleFieldTypes = new Rasters.SampleType[samples.length]; + FieldType[] sampleFieldTypes = new FieldType[samples.length]; for (int i = 0; i < samples.length; i++) { int sampleOffset = 0; if (planarConfiguration == TiffConstants.PLANAR_CONFIGURATION_CHUNKY) { sampleOffset = sum(getBitsPerSample(), 0, samples[i]) / 8; } srcSampleOffsets[i] = sampleOffset; - sampleFieldTypes[i] = getTypeForSample(samples[i]); + sampleFieldTypes[i] = getFieldTypeForSample(samples[i]); } for (int yTile = minYTile; yTile < maxYTile; yTile++) { @@ -1211,7 +1210,7 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { .getMinY()) * windowWidth + (x + firstCol - window.getMinX()); - rasters.addToInterleave(windowCoordinate, value, sampleIndex); + rasters.addToInterleave(sampleIndex, windowCoordinate, value); } if (rasters.hasSampleValues()) { @@ -1231,19 +1230,19 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { } /** - * Read the value from the reader according to the sample type + * Read the value from the reader according to the field type * * @param reader * byte reader - * @param sampleType - * raster sample type + * @param fieldType + * field type * @return value */ - private Number readValue(ByteReader reader, Rasters.SampleType sampleType) { + private Number readValue(ByteReader reader, FieldType fieldType) { Number value = null; - switch (sampleType) { + switch (fieldType) { case BYTE: value = reader.readUnsignedByte(); break; @@ -1253,13 +1252,13 @@ private Number readValue(ByteReader reader, Rasters.SampleType sampleType) { case LONG: value = reader.readUnsignedInt(); break; - case SIGNED_BYTE: + case SBYTE: value = reader.readByte(); break; - case SIGNED_SHORT: + case SSHORT: value = reader.readShort(); break; - case SIGNED_LONG: + case SLONG: value = reader.readInt(); break; case FLOAT: @@ -1269,72 +1268,30 @@ private Number readValue(ByteReader reader, Rasters.SampleType sampleType) { value = reader.readDouble(); break; default: - throw new TiffException("Unsupported raster sampleType type: " - + sampleType); + throw new TiffException("Unsupported raster field type: " + + fieldType); } return value; } /** - * Get the raster sample type for the sample @see Rasters.SampleType + * Get the field type for the sample * * @param sampleIndex * sample index - * @return Sample type + * @return field type */ - public Rasters.SampleType getTypeForSample(int sampleIndex) { - - Rasters.SampleType sampleType = null; + public FieldType getFieldTypeForSample(int sampleIndex) { List sampleFormatList = getSampleFormat(); - int format = sampleFormatList == null ? TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT + int sampleFormat = sampleFormatList == null ? TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT : sampleFormatList.get(sampleIndex < sampleFormatList.size() ? sampleIndex : 0); int bitsPerSample = getBitsPerSample().get(sampleIndex); - switch (format) { - case TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT: - switch (bitsPerSample) { - case 8: - sampleType = Rasters.SampleType.BYTE; - break; - case 16: - sampleType = Rasters.SampleType.SHORT; - break; - case 32: - sampleType = Rasters.SampleType.LONG; - break; - } - break; - case TiffConstants.SAMPLE_FORMAT_SIGNED_INT: - switch (bitsPerSample) { - case 8: - sampleType = Rasters.SampleType.SIGNED_BYTE; - break; - case 16: - sampleType = Rasters.SampleType.SIGNED_SHORT; - break; - case 32: - sampleType = Rasters.SampleType.SIGNED_LONG; - break; - } - break; - case TiffConstants.SAMPLE_FORMAT_FLOAT: - switch (bitsPerSample) { - case 32: - sampleType = Rasters.SampleType.FLOAT; - break; - case 64: - sampleType = Rasters.SampleType.DOUBLE; - break; - } - break; - } - - if (sampleType == null) - throw new TiffException("Unsupported sample type for format: " + format + - ", and bits per sample: " + bitsPerSample); + + FieldType fieldType = FieldType.getFieldType(sampleFormat, bitsPerSample); - return sampleType; + return fieldType; } /** diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index bfb7a7d..8407276 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -15,29 +15,6 @@ * @author osbornb */ public class Rasters { - /** - * Sample type for pixel - */ - public enum SampleType { - BYTE(1, TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT), // 8 bits - SIGNED_BYTE(1, TiffConstants.SAMPLE_FORMAT_SIGNED_INT), // 8 bits - SHORT(2, TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT), // 16 bits - SIGNED_SHORT(2, TiffConstants.SAMPLE_FORMAT_SIGNED_INT),// 16 bits - LONG(4, TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT), // 32 bits - SIGNED_LONG(4, TiffConstants.SAMPLE_FORMAT_SIGNED_INT), // 32 bits - FLOAT(4, TiffConstants.SAMPLE_FORMAT_FLOAT) , // 32 bits - DOUBLE(8, TiffConstants.SAMPLE_FORMAT_FLOAT); // 64 bits - - SampleType(int byteSize, int sampleFormat) { - this.byteSize = byteSize; - this.sampleFormat = sampleFormat; - } - - int bitSize() { return byteSize * 8; } - - final int byteSize; - final int sampleFormat; - } /** * Values separated by sample @@ -60,9 +37,9 @@ public enum SampleType { private final int height; /** - * Sample type for each sample. + * Field type for each sample */ - private final SampleType[] sampleTypes; + private final FieldType[] fieldTypes; // Calculated values @@ -72,12 +49,12 @@ public enum SampleType { private Integer pixelSize; /** - * @see getBitsPerSample() + * @see #getBitsPerSample() */ private List bitsPerSample; /** - * @see getSampleFormat() + * @see #getSampleFormat() */ private List sampleFormat; @@ -88,13 +65,13 @@ public enum SampleType { * width of pixels * @param height * height of pixels - * @param sampleTypes - * Sample type for each sample + * @param fieldTypes + * field type for each sample * @param sampleValues - * empty sample values double array + * empty sample values buffer array */ - public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer[] sampleValues) { - this(width, height, sampleTypes, sampleValues, null); + public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampleValues) { + this(width, height, fieldTypes, sampleValues, null); } /** @@ -104,13 +81,13 @@ public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer[] sam * width of pixels * @param height * height of pixels - * @param sampleTypes - * Sample type for each sample + * @param fieldTypes + * field type for each sample * @param interleaveValues - * empty interleaved values array + * empty interleaved values buffer */ - public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer interleaveValues) { - this(width, height, sampleTypes, null, interleaveValues); + public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer interleaveValues) { + this(width, height, fieldTypes, null, interleaveValues); } /** @@ -120,18 +97,18 @@ public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer inter * width of pixels * @param height * height of pixels - * @param sampleTypes - * Sample type for each sample + * @param fieldTypes + * Field type for each sample * @param sampleValues - * empty sample values double array + * empty sample values buffer array * @param interleaveValues - * empty interleaved values array + * empty interleaved values buffer */ - public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer[] sampleValues, + public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampleValues, ByteBuffer interleaveValues) { this.width = width; this.height = height; - this.sampleTypes = sampleTypes; + this.fieldTypes = fieldTypes; this.sampleValues = sampleValues; this.interleaveValues = interleaveValues; validateValues(); @@ -140,38 +117,106 @@ public Rasters(int width, int height, SampleType[] sampleTypes, ByteBuffer[] sam /** * Constructor * - * Creates Rasters object where given sample type used for each sample. + * Creates Rasters object where given field type used for each sample. * * @param width width of pixels * @param height height of pixels * @param samplesPerPixel number of samples per pixel - * @param sampleType type of sample for each sample + * @param fieldType type of field for each sample */ - public Rasters(int width, int height, int samplesPerPixel, SampleType sampleType) { - this(width, height, createSampleTypeArray(samplesPerPixel, sampleType), - ByteOrder.nativeOrder()); + public Rasters(int width, int height, int samplesPerPixel, FieldType fieldType) { + this(width, height, createFieldTypeArray(samplesPerPixel, fieldType)); } - + /** - * Validate that either sample or interleave values exist + * Constructor + * + * Creates Rasters object where given field type used for each sample. + * + * @param width width of pixels + * @param height height of pixels + * @param samplesPerPixel number of samples per pixel + * @param fieldType type of field for each sample + * @param order byte order */ - private void validateValues() { - if (sampleValues == null && interleaveValues == null) { - throw new TiffException( - "Results must be sample and/or interleave based"); - } + public Rasters(int width, int height, int samplesPerPixel, FieldType fieldType, ByteOrder order) { + this(width, height, createFieldTypeArray(samplesPerPixel, fieldType), order); } - + + /** + * Constructor + * + * Creates Rasters object where one bits per sample and sample format is provided for each sample + * + * @param width width of pixels + * @param height height of pixels + * @param bitsPerSamples bits per samples + * @param sampleFormats sample formats + */ + public Rasters(int width, int height, int[] bitsPerSamples, int[] sampleFormats) { + this(width, height, createFieldTypeArray(bitsPerSamples, sampleFormats)); + } + /** - * Helper method used to create {@link SampleType} array of given size and - * filled with given values. + * Constructor + * + * Creates Rasters object where one bits per sample and sample format is provided for each sample + * + * @param width width of pixels + * @param height height of pixels + * @param bitsPerSamples bits per samples + * @param sampleFormats sample formats + * @param order byte order */ - private static SampleType[] createSampleTypeArray(int size, SampleType sampleType) { - SampleType[] result = new SampleType[size]; - Arrays.fill(result, sampleType); - return result; + public Rasters(int width, int height, int[] bitsPerSamples, int[] sampleFormats, ByteOrder order) { + this(width, height, createFieldTypeArray(bitsPerSamples, sampleFormats), order); + } + + /** + * Constructor + * + * Creates Rasters object where given bits per sample and sample format is used for each sample + * + * @param width width of pixels + * @param height height of pixels + * @param samplesPerPixel number of samples per pixel + * @param bitsPerSample bits per each sample + * @param sampleFormat format for each sample + */ + public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, int sampleFormat) { + this(width, height, samplesPerPixel, FieldType.getFieldType(sampleFormat, bitsPerSample)); } + /** + * Constructor + * + * Creates Rasters object where given bits per sample and sample format is used for each sample + * + * @param width width of pixels + * @param height height of pixels + * @param samplesPerPixel number of samples per pixel + * @param bitsPerSample bits per each sample + * @param sampleFormat format for each sample + * @param order byte order + */ + public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, int sampleFormat, ByteOrder order) { + this(width, height, samplesPerPixel, FieldType.getFieldType(sampleFormat, bitsPerSample), order); + } + + /** + * Constructor + * + * @param width + * width of pixels + * @param height + * height of pixels + * @param fieldTypes + * field types per sample + */ + public Rasters(int width, int height, FieldType[] fieldTypes) { + this(width, height, fieldTypes, ByteOrder.nativeOrder()); + } + /** * Constructor * @@ -179,18 +224,63 @@ private static SampleType[] createSampleTypeArray(int size, SampleType sampleTyp * width of pixels * @param height * height of pixels - * @param sampleTypes - * Sample types per sample + * @param fieldTypes + * field types per sample + * @param order + * byte order */ - public Rasters(int width, int height, SampleType[] sampleTypes, ByteOrder order) { - this(width, height, sampleTypes, new ByteBuffer[sampleTypes.length]); + public Rasters(int width, int height, FieldType[] fieldTypes, ByteOrder order) { + this(width, height, fieldTypes, new ByteBuffer[fieldTypes.length]); for (int i = 0; i < sampleValues.length; ++i) { sampleValues[i] = ByteBuffer - .allocateDirect(width * height * sampleTypes[i].byteSize) + .allocateDirect(width * height * fieldTypes[i].getBytes()) .order(order); } } + /** + * Validate that either sample or interleave values exist + */ + private void validateValues() { + if (sampleValues == null && interleaveValues == null) { + throw new TiffException( + "Results must be sample and/or interleave based"); + } + } + + /** + * Create {@link FieldType} filled array for samples per pixel size + * + * @param samplesPerPixel number of samples per pixel + * @param fieldType type of field for each sample + * @return field type array + */ + private static FieldType[] createFieldTypeArray(int samplesPerPixel, FieldType fieldType) { + FieldType[] result = new FieldType[samplesPerPixel]; + Arrays.fill(result, fieldType); + return result; + } + + /** + * Create {@link FieldType} array for the bits per samples and sample formats + * + * @param bitsPerSamples bits per samples + * @param sampleFormats sample formats + * @return field type array + */ + private static FieldType[] createFieldTypeArray(int[] bitsPerSamples, int[] sampleFormats) { + if(bitsPerSamples.length != sampleFormats.length){ + throw new TiffException( + "Equal number of bits per samples and sample formats expected. " + + "Bits Per Samples: " + bitsPerSamples + ", Sample Formats: " + sampleFormats); + } + FieldType[] result = new FieldType[bitsPerSamples.length]; + for(int i = 0; i < bitsPerSamples.length; i++){ + result[i] = FieldType.getFieldType(sampleFormats[i], bitsPerSamples[i]); + } + return result; + } + /** * True if the results are stored by samples * @@ -223,7 +313,7 @@ private void updateSampleInByteBuffer(ByteBuffer buffer, int bufferIndex, int sa } buffer.position(bufferIndex); - writeSample(buffer, sampleTypes[sampleIndex], value); + writeSample(buffer, fieldTypes[sampleIndex], value); } /** @@ -242,7 +332,7 @@ private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleI } buffer.position(index); - return readSample(buffer, sampleTypes[sampleIndex]); + return readSample(buffer, fieldTypes[sampleIndex]); } /** @@ -257,21 +347,24 @@ private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleI */ public void addToSample(int sampleIndex, int coordinate, Number value) { updateSampleInByteBuffer(sampleValues[sampleIndex], - coordinate * sampleTypes[sampleIndex].byteSize, sampleIndex, value); + coordinate * fieldTypes[sampleIndex].getBytes(), sampleIndex, value); } /** * Add a value to the interleaved results * + * @param sampleIndex + * sample index * @param coordinate * coordinate location * @param value * value */ - public void addToInterleave(int coordinate, Number value, int sampleIndex) { + public void addToInterleave(int sampleIndex, int coordinate, Number value) { int bufferPos = coordinate * sizePixel(); - for (int i = 0; i < sampleIndex; ++i) - bufferPos += sampleTypes[i].byteSize; + for (int i = 0; i < sampleIndex; ++i){ + bufferPos += fieldTypes[i].getBytes(); + } updateSampleInByteBuffer(interleaveValues, bufferPos, sampleIndex, value); } @@ -309,7 +402,7 @@ public int getNumPixels() { * @return samples per pixel */ public int getSamplesPerPixel() { - return sampleTypes.length; + return fieldTypes.length; } /** @@ -318,15 +411,14 @@ public int getSamplesPerPixel() { * @return bits per sample */ public List getBitsPerSample() { - if (bitsPerSample != null) { - return bitsPerSample; - } - - List result = new ArrayList<>(sampleTypes.length); - for (SampleType sampleType : sampleTypes) { - result.add(sampleType.bitSize()); + List result = bitsPerSample; + if(result == null){ + result = new ArrayList<>(fieldTypes.length); + for (FieldType fieldType : fieldTypes) { + result.add(fieldType.getBits()); + } + bitsPerSample = result; } - bitsPerSample = result; return result; } @@ -335,22 +427,21 @@ public List getBitsPerSample() { * * Returns list of sample types constants (SAMPLE_FORMAT_UNSIGNED_INT, * SAMPLE_FORMAT_SIGNED_INT or SAMPLE_FORMAT_FLOAT) for each sample in - * sample list @see getSampleTypes(). @see {@link TiffConstants} + * sample list @see getFieldTypes(). @see {@link TiffConstants} * @return list of sample type constants */ public List getSampleFormat() { - if (sampleFormat != null) { - return sampleFormat; - } - - List result = new ArrayList<>(sampleTypes.length); - for (SampleType sampleType : sampleTypes) { - result.add(sampleType.sampleFormat); + List result = sampleFormat; + if(result == null){ + result = new ArrayList<>(fieldTypes.length); + for (FieldType fieldType : fieldTypes) { + result.add(FieldType.getSampleFormat(fieldType)); + } + sampleFormat = result; } - sampleFormat = result; return result; } - + /** * Get the results stored by samples * @@ -416,16 +507,16 @@ public Number[] getPixel(int x, int y) { // Get the pixel values from each sample if (sampleValues != null) { - int sampleIndex = getSampleIndexInWindow(x, y); + int sampleIndex = getSampleIndex(x, y); for (int i = 0; i < getSamplesPerPixel(); i++) { - int bufferIndex = sampleIndex * sampleTypes[i].byteSize; + int bufferIndex = sampleIndex * fieldTypes[i].getBytes(); pixel[i] = getSampleFromByteBuffer(sampleValues[i], bufferIndex, i); } } else { int interleaveIndex = getInterleaveIndex(x, y); for (int i = 0; i < getSamplesPerPixel(); i++) { pixel[i] = getSampleFromByteBuffer(interleaveValues, interleaveIndex, i); - interleaveIndex += sampleTypes[i].byteSize; + interleaveIndex += fieldTypes[i].getBytes(); } } @@ -450,14 +541,14 @@ public void setPixel(int x, int y, Number[] values) { // Set the pixel values from each sample if (sampleValues != null) { for (int i = 0; i < getSamplesPerPixel(); i++) { - int bufferIndex = getSampleIndexInWindow(x, y) * sampleTypes[i].byteSize; + int bufferIndex = getSampleIndex(x, y) * fieldTypes[i].getBytes(); updateSampleInByteBuffer(sampleValues[i], bufferIndex, i, values[i]); } } else { - int interleaveIndex = getSampleIndexInWindow(x, y) * sizePixel(); + int interleaveIndex = getSampleIndex(x, y) * sizePixel(); for (int i = 0; i < getSamplesPerPixel(); i++) { updateSampleInByteBuffer(interleaveValues, interleaveIndex, i, values[i]); - interleaveIndex += sampleTypes[i].byteSize; + interleaveIndex += fieldTypes[i].getBytes(); } } } @@ -475,11 +566,11 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { if (sampleValues != null) { for (int i = 0; i < getSamplesPerPixel(); ++i) { - sampleValues[i].position(y * getWidth() * sampleTypes[i].byteSize); + sampleValues[i].position(y * getWidth() * fieldTypes[i].getBytes()); } for (int i = 0; i < getWidth(); ++i) { for (int j = 0; j < getSamplesPerPixel(); ++j) { - writeSample(outBuffer, sampleValues[j], sampleTypes[j]); + writeSample(outBuffer, sampleValues[j], fieldTypes[j]); } } } else { @@ -487,7 +578,7 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { for (int i = 0; i < getWidth(); ++i) { for (int j = 0; j < getSamplesPerPixel(); ++j) { - writeSample(outBuffer, interleaveValues, sampleTypes[j]); + writeSample(outBuffer, interleaveValues, fieldTypes[j]); } } } @@ -504,23 +595,23 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { * @return Byte array of sample row */ public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { - ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * sampleTypes[sample].byteSize); + ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * fieldTypes[sample].getBytes()); outBuffer.order(newOrder); if (sampleValues != null) { - sampleValues[sample].position(y * getWidth() * sampleTypes[sample].byteSize); + sampleValues[sample].position(y * getWidth() * fieldTypes[sample].getBytes()); for (int x = 0; x < getWidth(); ++x) { - writeSample(outBuffer, sampleValues[sample], sampleTypes[sample]); + writeSample(outBuffer, sampleValues[sample], fieldTypes[sample]); } } else { int sampleOffset = 0; for (int i = 0; i < sample; ++i) { - sampleOffset += sampleTypes[sample].byteSize; + sampleOffset += fieldTypes[sample].getBytes(); } for (int i = 0; i < getWidth(); ++i) { interleaveValues.position((y * getWidth() + i) * sizePixel() + sampleOffset); - writeSample(outBuffer, interleaveValues, sampleTypes[sample]); + writeSample(outBuffer, interleaveValues, fieldTypes[sample]); } } @@ -548,12 +639,13 @@ public Number getPixelSample(int sample, int x, int y) { // Get the pixel sample if (sampleValues != null) { - int bufferPos = getSampleIndexInWindow(x, y) * sampleTypes[sample].byteSize; + int bufferPos = getSampleIndex(x, y) * fieldTypes[sample].getBytes(); pixelSample = getSampleFromByteBuffer(sampleValues[sample], bufferPos, sample); } else { int bufferPos = getInterleaveIndex(x, y); - for (int i = 0; i < sample; i++) - bufferPos += sampleTypes[sample].byteSize; + for (int i = 0; i < sample; i++){ + bufferPos += fieldTypes[sample].getBytes(); + } pixelSample = getSampleFromByteBuffer(interleaveValues, bufferPos, sample); } @@ -580,13 +672,13 @@ public void setPixelSample(int sample, int x, int y, Number value) { // Set the pixel sample if (sampleValues != null) { - int sampleIndex = getSampleIndexInWindow(x, y) * sampleTypes[sample].byteSize; + int sampleIndex = getSampleIndex(x, y) * fieldTypes[sample].getBytes(); updateSampleInByteBuffer(sampleValues[sample], sampleIndex, sample, value); } if (interleaveValues != null) { - int interleaveIndex = getSampleIndexInWindow(x, y) * sizePixel(); + int interleaveIndex = getSampleIndex(x, y) * sizePixel(); for (int i = 0; i < sample; ++i) { - interleaveIndex += sampleTypes[sample].byteSize; + interleaveIndex += fieldTypes[sample].getBytes(); } updateSampleInByteBuffer(interleaveValues, interleaveIndex, sample, value); } @@ -622,7 +714,7 @@ public void setFirstPixelSample(int x, int y, Number value) { } /** - * Get the sample index location in window + * Get the sample index location * * @param x * x coordinate @@ -630,7 +722,7 @@ public void setFirstPixelSample(int x, int y, Number value) { * y coordinate * @return sample index */ - public int getSampleIndexInWindow(int x, int y) { + public int getSampleIndex(int x, int y) { return y * width + x; } @@ -668,7 +760,7 @@ public int sizePixel() { int size = 0; for (int i = 0; i < getSamplesPerPixel(); i++) { - size += sampleTypes[i].byteSize; + size += fieldTypes[i].getBytes(); } pixelSize = size; return size; @@ -733,7 +825,7 @@ public int calculateRowsPerStrip(int planarConfiguration, } else { for (int sample = 0; sample < getSamplesPerPixel(); ++sample) { - int rowsPerStripForSample = rowsPerStrip(sampleTypes[sample].byteSize, + int rowsPerStripForSample = rowsPerStrip(fieldTypes[sample].getBytes(), maxBytesPerStrip); if (rowsPerStrip == null || rowsPerStripForSample < rowsPerStrip) { @@ -768,13 +860,13 @@ private int rowsPerStrip(int bytesPerPixel, int maxBytesPerStrip) { * Reads sample from given buffer * * @param buffer A buffer to read from. @note Make sure position is set. - * @param sampleType Sample type to be read - * @return Sample form buffer + * @param fieldType field type to be read + * @return Sample from buffer */ - private Number readSample(ByteBuffer buffer, SampleType sampleType) { + private Number readSample(ByteBuffer buffer, FieldType fieldType) { Number sampleValue; - switch (sampleType) { + switch (fieldType) { case BYTE: sampleValue = (short)(buffer.get() & 0xff); break; @@ -784,13 +876,13 @@ private Number readSample(ByteBuffer buffer, SampleType sampleType) { case LONG: sampleValue = buffer.getInt() & 0xffffffffL; break; - case SIGNED_BYTE: + case SBYTE: sampleValue = buffer.get(); break; - case SIGNED_SHORT: + case SSHORT: sampleValue = buffer.getShort(); break; - case SIGNED_LONG: + case SLONG: sampleValue = buffer.getInt(); break; case FLOAT: @@ -800,7 +892,7 @@ private Number readSample(ByteBuffer buffer, SampleType sampleType) { sampleValue = buffer.getDouble(); break; default: - throw new TiffException("Unsupported raster sample type: " + sampleType); + throw new TiffException("Unsupported raster field type: " + fieldType); } return sampleValue; @@ -810,21 +902,21 @@ private Number readSample(ByteBuffer buffer, SampleType sampleType) { * Writes sample into given buffer. * * @param buffer A buffer to write to. @note Make sure buffer position is set. - * @param sampleType Sample type to be written. + * @param fieldType field type to be written. * @param value Actual value to write. */ - private void writeSample(ByteBuffer buffer, SampleType sampleType, Number value) { - switch (sampleType) { + private void writeSample(ByteBuffer buffer, FieldType fieldType, Number value) { + switch (fieldType) { case BYTE: - case SIGNED_BYTE: + case SBYTE: buffer.put(value.byteValue()); break; case SHORT: - case SIGNED_SHORT: + case SSHORT: buffer.putShort(value.shortValue()); break; case LONG: - case SIGNED_LONG: + case SLONG: buffer.putInt(value.intValue()); break; case FLOAT: @@ -834,7 +926,7 @@ private void writeSample(ByteBuffer buffer, SampleType sampleType, Number value) buffer.putDouble(value.doubleValue()); break; default: - throw new TiffException("Unsupported raster sample type: " + sampleType); + throw new TiffException("Unsupported raster field type: " + fieldType); } } @@ -843,22 +935,21 @@ private void writeSample(ByteBuffer buffer, SampleType sampleType, Number value) * * @param outBuffer A buffer to write to. @note Make sure buffer position is set. * @param inBuffer A buffer to read from. @note Make sure buffer position is set. - * @param sampleType Field type to be read. + * @param fieldType Field type to be read. */ private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, - SampleType sampleType) { - switch (sampleType) - { + FieldType fieldType) { + switch (fieldType) { case BYTE: - case SIGNED_BYTE: + case SBYTE: outBuffer.put(inBuffer.get()); break; case SHORT: - case SIGNED_SHORT: + case SSHORT: outBuffer.putShort(inBuffer.getShort()); break; case LONG: - case SIGNED_LONG: + case SLONG: outBuffer.putInt(inBuffer.getInt()); break; case FLOAT: @@ -868,14 +959,17 @@ private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, outBuffer.putDouble(inBuffer.getDouble()); break; default: - throw new TiffException("Unsupported raster sample type: " + sampleType); + throw new TiffException("Unsupported raster field type: " + fieldType); } } /** - * Returns sample types + * Returns field types + * + * @return field types */ - public SampleType[] getSampleTypes() { - return sampleTypes; + public FieldType[] getFieldTypes() { + return fieldTypes; } + } \ No newline at end of file diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index b0790b8..a78f05d 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -310,14 +310,6 @@ private static byte[] writeRasters(ByteOrder byteOrder, "File Directory Writer Rasters is required to create a TIFF"); } - // Get the sample field types - Rasters.SampleType[] sampleTypes = new Rasters.SampleType[rasters - .getSamplesPerPixel()]; - for (int sample = 0; sample < rasters.getSamplesPerPixel(); sample++) { - sampleTypes[sample] = fileDirectory - .getTypeForSample(sample); - } - // Get the compression encoder CompressionEncoder encoder = getEncoder(fileDirectory); @@ -326,8 +318,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, // Write the rasters if (!fileDirectory.isTiled()) { - writeStripRasters(writer, fileDirectory, offset, sampleTypes, - encoder); + writeStripRasters(writer, fileDirectory, offset, encoder); } else { throw new TiffException("Tiled images are not supported"); } @@ -348,15 +339,13 @@ private static byte[] writeRasters(ByteOrder byteOrder, * file directory * @param offset * byte offset - * @param sampleTypes - * sample field types * @param encoder * compression encoder * @throws IOException */ private static void writeStripRasters(ByteWriter writer, FileDirectory fileDirectory, long offset, - Rasters.SampleType[] sampleTypes, CompressionEncoder encoder) + CompressionEncoder encoder) throws IOException { Rasters rasters = fileDirectory.getWriteRasters(); @@ -486,50 +475,6 @@ private static CompressionEncoder getEncoder(FileDirectory fileDirectory) { return encoder; } - /** - * Write the value according to the field type - * - * @param writer - * byte writer - * @param fieldType - * field type - * @throws IOException - */ - private static void writeValue(ByteWriter writer, FieldType fieldType, - Number value) throws IOException { - - switch (fieldType) { - case BYTE: - writer.writeUnsignedByte(value.shortValue()); - break; - case SHORT: - writer.writeUnsignedShort(value.intValue()); - break; - case LONG: - writer.writeUnsignedInt(value.longValue()); - break; - case SBYTE: - writer.writeByte(value.byteValue()); - break; - case SSHORT: - writer.writeShort(value.shortValue()); - break; - case SLONG: - writer.writeInt(value.intValue()); - break; - case FLOAT: - writer.writeFloat(value.floatValue()); - break; - case DOUBLE: - writer.writeDouble(value.doubleValue()); - break; - default: - throw new TiffException("Unsupported raster field type: " - + fieldType); - } - - } - /** * Write filler 0 bytes * diff --git a/src/main/java/mil/nga/tiff/io/ByteReader.java b/src/main/java/mil/nga/tiff/io/ByteReader.java index 2e8c507..0b76b72 100644 --- a/src/main/java/mil/nga/tiff/io/ByteReader.java +++ b/src/main/java/mil/nga/tiff/io/ByteReader.java @@ -35,7 +35,7 @@ public class ByteReader { * bytes */ public ByteReader(byte[] bytes) { - this(bytes, ByteOrder.BIG_ENDIAN); + this(bytes, ByteOrder.nativeOrder()); } /** diff --git a/src/main/java/mil/nga/tiff/io/ByteWriter.java b/src/main/java/mil/nga/tiff/io/ByteWriter.java index cfb3c6b..8a2a037 100644 --- a/src/main/java/mil/nga/tiff/io/ByteWriter.java +++ b/src/main/java/mil/nga/tiff/io/ByteWriter.java @@ -26,7 +26,7 @@ public class ByteWriter { * Constructor */ public ByteWriter() { - this(ByteOrder.BIG_ENDIAN); + this(ByteOrder.nativeOrder()); } /** diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index 588c220..de60f67 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -5,7 +5,6 @@ import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.List; import junit.framework.TestCase; import mil.nga.tiff.util.TiffException; @@ -140,8 +139,8 @@ public static void compareRastersSampleValues(Rasters rasters1, rasters2.getSampleValues().length); for (int i = 0; i < rasters1.getSampleValues().length; i++) { - TestCase.assertEquals(rasters1.getSampleValues()[i].capacity() / rasters1.getSampleTypes()[i].byteSize, - rasters2.getSampleValues()[i].capacity() / rasters2.getSampleTypes()[i].byteSize); + TestCase.assertEquals(rasters1.getSampleValues()[i].capacity() / rasters1.getFieldTypes()[i].getBytes(), + rasters2.getSampleValues()[i].capacity() / rasters2.getFieldTypes()[i].getBytes()); for (int x = 0; x < rasters1.getWidth(); ++x) { for (int y = 0; y < rasters1.getHeight(); ++y) { From 0b0e03bb5096ef36aa93f3869c07b08e70064a91 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Thu, 19 Oct 2017 15:42:10 -0600 Subject: [PATCH 27/29] formatting --- src/main/java/mil/nga/tiff/FieldType.java | 45 +- src/main/java/mil/nga/tiff/FileDirectory.java | 25 +- src/main/java/mil/nga/tiff/Rasters.java | 486 +++++++++++------- src/main/java/mil/nga/tiff/TiffWriter.java | 8 +- src/test/java/mil/nga/tiff/TiffTestUtils.java | 19 +- 5 files changed, 351 insertions(+), 232 deletions(-) diff --git a/src/main/java/mil/nga/tiff/FieldType.java b/src/main/java/mil/nga/tiff/FieldType.java index 4e31e6e..d98526b 100644 --- a/src/main/java/mil/nga/tiff/FieldType.java +++ b/src/main/java/mil/nga/tiff/FieldType.java @@ -126,17 +126,20 @@ public int getBits() { public static FieldType getFieldType(int fieldType) { return FieldType.values()[fieldType - 1]; } - + /** * Get the field type of the sample format and bits per sample - * @param sampleFormat sample format - * @param bitsPerSample bits per sample + * + * @param sampleFormat + * sample format + * @param bitsPerSample + * bits per sample * @return field type */ - public static FieldType getFieldType(int sampleFormat, int bitsPerSample){ - + public static FieldType getFieldType(int sampleFormat, int bitsPerSample) { + FieldType fieldType = null; - + switch (sampleFormat) { case TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT: switch (bitsPerSample) { @@ -176,24 +179,27 @@ public static FieldType getFieldType(int sampleFormat, int bitsPerSample){ break; } - if (fieldType == null){ - throw new TiffException("Unsupported field type for sample format: " + sampleFormat + - ", bits per sample: " + bitsPerSample); + if (fieldType == null) { + throw new TiffException( + "Unsupported field type for sample format: " + sampleFormat + + ", bits per sample: " + bitsPerSample); } - + return fieldType; } - + /** * Get the sample format of the field type - * @param fieldType field type + * + * @param fieldType + * field type * @return sample format */ - public static int getSampleFormat(FieldType fieldType){ - + public static int getSampleFormat(FieldType fieldType) { + int sampleFormat; - - switch(fieldType){ + + switch (fieldType) { case BYTE: case SHORT: case LONG: @@ -209,10 +215,11 @@ public static int getSampleFormat(FieldType fieldType){ sampleFormat = TiffConstants.SAMPLE_FORMAT_FLOAT; break; default: - throw new TiffException("Unsupported sample format for field type: " + fieldType); + throw new TiffException( + "Unsupported sample format for field type: " + fieldType); } - + return sampleFormat; } - + } diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 91dbb2c..872f357 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -485,7 +485,8 @@ public void setStripOffsets(long stripOffset) { public int getSamplesPerPixel() { Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); if (samplesPerPixel == null) { - // if SamplesPerPixel tag is missing, use default value defined by TIFF standard + // if SamplesPerPixel tag is missing, use default value defined by + // TIFF standard samplesPerPixel = 1; } return samplesPerPixel; @@ -1113,7 +1114,8 @@ public Rasters readRasters(ImageWindow window, int[] samples, if (sampleValues) { sample = new ByteBuffer[samplesPerPixel]; for (int i = 0; i < sample.length; ++i) { - sample[i] = ByteBuffer.allocateDirect(numPixels * bitsPerSample.get(i) / 8); + sample[i] = ByteBuffer.allocateDirect(numPixels + * bitsPerSample.get(i) / 8); sample[i].order(reader.getByteOrder()); } } @@ -1124,8 +1126,8 @@ public Rasters readRasters(ImageWindow window, int[] samples, } // Create the rasters results - Rasters rasters = new Rasters(windowWidth, windowHeight, - fieldTypes, sample, interleave); + Rasters rasters = new Rasters(windowWidth, windowHeight, fieldTypes, + sample, interleave); // Read the rasters readRaster(window, samples, rasters); @@ -1210,7 +1212,8 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { .getMinY()) * windowWidth + (x + firstCol - window.getMinX()); - rasters.addToInterleave(sampleIndex, windowCoordinate, value); + rasters.addToInterleave(sampleIndex, + windowCoordinate, value); } if (rasters.hasSampleValues()) { @@ -1219,7 +1222,8 @@ private void readRaster(ImageWindow window, int[] samples, Rasters rasters) { * windowWidth + x + firstCol - window.getMinX(); - rasters.addToSample(sampleIndex, windowCoordinate, value); + rasters.addToSample(sampleIndex, + windowCoordinate, value); } } @@ -1286,10 +1290,13 @@ public FieldType getFieldTypeForSample(int sampleIndex) { List sampleFormatList = getSampleFormat(); int sampleFormat = sampleFormatList == null ? TiffConstants.SAMPLE_FORMAT_UNSIGNED_INT - : sampleFormatList.get(sampleIndex < sampleFormatList.size() ? sampleIndex : 0); + : sampleFormatList + .get(sampleIndex < sampleFormatList.size() ? sampleIndex + : 0); int bitsPerSample = getBitsPerSample().get(sampleIndex); - - FieldType fieldType = FieldType.getFieldType(sampleFormat, bitsPerSample); + + FieldType fieldType = FieldType.getFieldType(sampleFormat, + bitsPerSample); return fieldType; } diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index 8407276..5fb01c7 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -70,7 +70,8 @@ public class Rasters { * @param sampleValues * empty sample values buffer array */ - public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampleValues) { + public Rasters(int width, int height, FieldType[] fieldTypes, + ByteBuffer[] sampleValues) { this(width, height, fieldTypes, sampleValues, null); } @@ -86,7 +87,8 @@ public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampl * @param interleaveValues * empty interleaved values buffer */ - public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer interleaveValues) { + public Rasters(int width, int height, FieldType[] fieldTypes, + ByteBuffer interleaveValues) { this(width, height, fieldTypes, null, interleaveValues); } @@ -104,8 +106,8 @@ public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer interle * @param interleaveValues * empty interleaved values buffer */ - public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampleValues, - ByteBuffer interleaveValues) { + public Rasters(int width, int height, FieldType[] fieldTypes, + ByteBuffer[] sampleValues, ByteBuffer interleaveValues) { this.width = width; this.height = height; this.fieldTypes = fieldTypes; @@ -115,94 +117,137 @@ public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampl } /** - * Constructor + * Constructor * - * Creates Rasters object where given field type used for each sample. + * Creates Rasters object where given field type used for each sample. * - * @param width width of pixels - * @param height height of pixels - * @param samplesPerPixel number of samples per pixel - * @param fieldType type of field for each sample + * @param width + * width of pixels + * @param height + * height of pixels + * @param samplesPerPixel + * number of samples per pixel + * @param fieldType + * type of field for each sample */ - public Rasters(int width, int height, int samplesPerPixel, FieldType fieldType) { + public Rasters(int width, int height, int samplesPerPixel, + FieldType fieldType) { this(width, height, createFieldTypeArray(samplesPerPixel, fieldType)); } - + /** - * Constructor + * Constructor * - * Creates Rasters object where given field type used for each sample. + * Creates Rasters object where given field type used for each sample. * - * @param width width of pixels - * @param height height of pixels - * @param samplesPerPixel number of samples per pixel - * @param fieldType type of field for each sample - * @param order byte order + * @param width + * width of pixels + * @param height + * height of pixels + * @param samplesPerPixel + * number of samples per pixel + * @param fieldType + * type of field for each sample + * @param order + * byte order */ - public Rasters(int width, int height, int samplesPerPixel, FieldType fieldType, ByteOrder order) { - this(width, height, createFieldTypeArray(samplesPerPixel, fieldType), order); + public Rasters(int width, int height, int samplesPerPixel, + FieldType fieldType, ByteOrder order) { + this(width, height, createFieldTypeArray(samplesPerPixel, fieldType), + order); } - + /** * Constructor * - * Creates Rasters object where one bits per sample and sample format is provided for each sample + * Creates Rasters object where one bits per sample and sample format is + * provided for each sample * - * @param width width of pixels - * @param height height of pixels - * @param bitsPerSamples bits per samples - * @param sampleFormats sample formats + * @param width + * width of pixels + * @param height + * height of pixels + * @param bitsPerSamples + * bits per samples + * @param sampleFormats + * sample formats */ - public Rasters(int width, int height, int[] bitsPerSamples, int[] sampleFormats) { + public Rasters(int width, int height, int[] bitsPerSamples, + int[] sampleFormats) { this(width, height, createFieldTypeArray(bitsPerSamples, sampleFormats)); } - + /** * Constructor * - * Creates Rasters object where one bits per sample and sample format is provided for each sample + * Creates Rasters object where one bits per sample and sample format is + * provided for each sample * - * @param width width of pixels - * @param height height of pixels - * @param bitsPerSamples bits per samples - * @param sampleFormats sample formats - * @param order byte order + * @param width + * width of pixels + * @param height + * height of pixels + * @param bitsPerSamples + * bits per samples + * @param sampleFormats + * sample formats + * @param order + * byte order */ - public Rasters(int width, int height, int[] bitsPerSamples, int[] sampleFormats, ByteOrder order) { - this(width, height, createFieldTypeArray(bitsPerSamples, sampleFormats), order); + public Rasters(int width, int height, int[] bitsPerSamples, + int[] sampleFormats, ByteOrder order) { + this(width, height, + createFieldTypeArray(bitsPerSamples, sampleFormats), order); } - + /** * Constructor * - * Creates Rasters object where given bits per sample and sample format is used for each sample + * Creates Rasters object where given bits per sample and sample format is + * used for each sample * - * @param width width of pixels - * @param height height of pixels - * @param samplesPerPixel number of samples per pixel - * @param bitsPerSample bits per each sample - * @param sampleFormat format for each sample + * @param width + * width of pixels + * @param height + * height of pixels + * @param samplesPerPixel + * number of samples per pixel + * @param bitsPerSample + * bits per each sample + * @param sampleFormat + * format for each sample */ - public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, int sampleFormat) { - this(width, height, samplesPerPixel, FieldType.getFieldType(sampleFormat, bitsPerSample)); + public Rasters(int width, int height, int samplesPerPixel, + int bitsPerSample, int sampleFormat) { + this(width, height, samplesPerPixel, FieldType.getFieldType( + sampleFormat, bitsPerSample)); } /** * Constructor * - * Creates Rasters object where given bits per sample and sample format is used for each sample + * Creates Rasters object where given bits per sample and sample format is + * used for each sample * - * @param width width of pixels - * @param height height of pixels - * @param samplesPerPixel number of samples per pixel - * @param bitsPerSample bits per each sample - * @param sampleFormat format for each sample - * @param order byte order + * @param width + * width of pixels + * @param height + * height of pixels + * @param samplesPerPixel + * number of samples per pixel + * @param bitsPerSample + * bits per each sample + * @param sampleFormat + * format for each sample + * @param order + * byte order */ - public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, int sampleFormat, ByteOrder order) { - this(width, height, samplesPerPixel, FieldType.getFieldType(sampleFormat, bitsPerSample), order); + public Rasters(int width, int height, int samplesPerPixel, + int bitsPerSample, int sampleFormat, ByteOrder order) { + this(width, height, samplesPerPixel, FieldType.getFieldType( + sampleFormat, bitsPerSample), order); } - + /** * Constructor * @@ -216,7 +261,7 @@ public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, in public Rasters(int width, int height, FieldType[] fieldTypes) { this(width, height, fieldTypes, ByteOrder.nativeOrder()); } - + /** * Constructor * @@ -229,12 +274,12 @@ public Rasters(int width, int height, FieldType[] fieldTypes) { * @param order * byte order */ - public Rasters(int width, int height, FieldType[] fieldTypes, ByteOrder order) { + public Rasters(int width, int height, FieldType[] fieldTypes, + ByteOrder order) { this(width, height, fieldTypes, new ByteBuffer[fieldTypes.length]); for (int i = 0; i < sampleValues.length; ++i) { - sampleValues[i] = ByteBuffer - .allocateDirect(width * height * fieldTypes[i].getBytes()) - .order(order); + sampleValues[i] = ByteBuffer.allocateDirect( + width * height * fieldTypes[i].getBytes()).order(order); } } @@ -251,36 +296,45 @@ private void validateValues() { /** * Create {@link FieldType} filled array for samples per pixel size * - * @param samplesPerPixel number of samples per pixel - * @param fieldType type of field for each sample + * @param samplesPerPixel + * number of samples per pixel + * @param fieldType + * type of field for each sample * @return field type array */ - private static FieldType[] createFieldTypeArray(int samplesPerPixel, FieldType fieldType) { + private static FieldType[] createFieldTypeArray(int samplesPerPixel, + FieldType fieldType) { FieldType[] result = new FieldType[samplesPerPixel]; Arrays.fill(result, fieldType); return result; } - + /** - * Create {@link FieldType} array for the bits per samples and sample formats + * Create {@link FieldType} array for the bits per samples and sample + * formats * - * @param bitsPerSamples bits per samples - * @param sampleFormats sample formats + * @param bitsPerSamples + * bits per samples + * @param sampleFormats + * sample formats * @return field type array */ - private static FieldType[] createFieldTypeArray(int[] bitsPerSamples, int[] sampleFormats) { - if(bitsPerSamples.length != sampleFormats.length){ + private static FieldType[] createFieldTypeArray(int[] bitsPerSamples, + int[] sampleFormats) { + if (bitsPerSamples.length != sampleFormats.length) { throw new TiffException( "Equal number of bits per samples and sample formats expected. " - + "Bits Per Samples: " + bitsPerSamples + ", Sample Formats: " + sampleFormats); + + "Bits Per Samples: " + bitsPerSamples + + ", Sample Formats: " + sampleFormats); } FieldType[] result = new FieldType[bitsPerSamples.length]; - for(int i = 0; i < bitsPerSamples.length; i++){ - result[i] = FieldType.getFieldType(sampleFormats[i], bitsPerSamples[i]); + for (int i = 0; i < bitsPerSamples.length; i++) { + result[i] = FieldType.getFieldType(sampleFormats[i], + bitsPerSamples[i]); } return result; } - + /** * True if the results are stored by samples * @@ -302,14 +356,22 @@ public boolean hasInterleaveValues() { /** * Updates sample to given value in buffer. * - * @param buffer A buffer to be updated. - * @param bufferIndex Position in buffer where to update. - * @param sampleIndex Sample index in sampleFieldTypes. Needed for determining sample size. - * @param value A Number value to be put in buffer. Has to be same size as sampleFieldTypes[sampleIndex]. + * @param buffer + * A buffer to be updated. + * @param bufferIndex + * Position in buffer where to update. + * @param sampleIndex + * Sample index in sampleFieldTypes. Needed for determining + * sample size. + * @param value + * A Number value to be put in buffer. Has to be same size as + * sampleFieldTypes[sampleIndex]. */ - private void updateSampleInByteBuffer(ByteBuffer buffer, int bufferIndex, int sampleIndex, Number value) { + private void updateSampleInByteBuffer(ByteBuffer buffer, int bufferIndex, + int sampleIndex, Number value) { if (bufferIndex < 0 || bufferIndex >= buffer.capacity()) { - throw new IndexOutOfBoundsException("index: " + bufferIndex + ". Buffer capacity: " + buffer.capacity()); + throw new IndexOutOfBoundsException("index: " + bufferIndex + + ". Buffer capacity: " + buffer.capacity()); } buffer.position(bufferIndex); @@ -319,16 +381,20 @@ private void updateSampleInByteBuffer(ByteBuffer buffer, int bufferIndex, int sa /** * Reads sample from given buffer. * - * @param buffer A buffer to read from - * @param index Position in buffer where to read from - * @param sampleIndex Index of sample type to read + * @param buffer + * A buffer to read from + * @param index + * Position in buffer where to read from + * @param sampleIndex + * Index of sample type to read * @return Number read from buffer */ - private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleIndex) { + private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, + int sampleIndex) { if (index < 0 || index >= buffer.capacity()) { - throw new IndexOutOfBoundsException("Requested index: " + index + - ", but size of buffer is: " + buffer.capacity()); + throw new IndexOutOfBoundsException("Requested index: " + index + + ", but size of buffer is: " + buffer.capacity()); } buffer.position(index); @@ -346,8 +412,8 @@ private Number getSampleFromByteBuffer(ByteBuffer buffer, int index, int sampleI * value */ public void addToSample(int sampleIndex, int coordinate, Number value) { - updateSampleInByteBuffer(sampleValues[sampleIndex], - coordinate * fieldTypes[sampleIndex].getBytes(), sampleIndex, value); + updateSampleInByteBuffer(sampleValues[sampleIndex], coordinate + * fieldTypes[sampleIndex].getBytes(), sampleIndex, value); } /** @@ -362,11 +428,12 @@ public void addToSample(int sampleIndex, int coordinate, Number value) { */ public void addToInterleave(int sampleIndex, int coordinate, Number value) { int bufferPos = coordinate * sizePixel(); - for (int i = 0; i < sampleIndex; ++i){ + for (int i = 0; i < sampleIndex; ++i) { bufferPos += fieldTypes[i].getBytes(); } - updateSampleInByteBuffer(interleaveValues, bufferPos, sampleIndex, value); + updateSampleInByteBuffer(interleaveValues, bufferPos, sampleIndex, + value); } /** @@ -412,7 +479,7 @@ public int getSamplesPerPixel() { */ public List getBitsPerSample() { List result = bitsPerSample; - if(result == null){ + if (result == null) { result = new ArrayList<>(fieldTypes.length); for (FieldType fieldType : fieldTypes) { result.add(fieldType.getBits()); @@ -428,11 +495,12 @@ public List getBitsPerSample() { * Returns list of sample types constants (SAMPLE_FORMAT_UNSIGNED_INT, * SAMPLE_FORMAT_SIGNED_INT or SAMPLE_FORMAT_FLOAT) for each sample in * sample list @see getFieldTypes(). @see {@link TiffConstants} + * * @return list of sample type constants */ public List getSampleFormat() { List result = sampleFormat; - if(result == null){ + if (result == null) { result = new ArrayList<>(fieldTypes.length); for (FieldType fieldType : fieldTypes) { result.add(FieldType.getSampleFormat(fieldType)); @@ -441,7 +509,7 @@ public List getSampleFormat() { } return result; } - + /** * Get the results stored by samples * @@ -510,12 +578,14 @@ public Number[] getPixel(int x, int y) { int sampleIndex = getSampleIndex(x, y); for (int i = 0; i < getSamplesPerPixel(); i++) { int bufferIndex = sampleIndex * fieldTypes[i].getBytes(); - pixel[i] = getSampleFromByteBuffer(sampleValues[i], bufferIndex, i); + pixel[i] = getSampleFromByteBuffer(sampleValues[i], + bufferIndex, i); } } else { int interleaveIndex = getInterleaveIndex(x, y); for (int i = 0; i < getSamplesPerPixel(); i++) { - pixel[i] = getSampleFromByteBuffer(interleaveValues, interleaveIndex, i); + pixel[i] = getSampleFromByteBuffer(interleaveValues, + interleaveIndex, i); interleaveIndex += fieldTypes[i].getBytes(); } } @@ -541,13 +611,16 @@ public void setPixel(int x, int y, Number[] values) { // Set the pixel values from each sample if (sampleValues != null) { for (int i = 0; i < getSamplesPerPixel(); i++) { - int bufferIndex = getSampleIndex(x, y) * fieldTypes[i].getBytes(); - updateSampleInByteBuffer(sampleValues[i], bufferIndex, i, values[i]); + int bufferIndex = getSampleIndex(x, y) + * fieldTypes[i].getBytes(); + updateSampleInByteBuffer(sampleValues[i], bufferIndex, i, + values[i]); } } else { int interleaveIndex = getSampleIndex(x, y) * sizePixel(); for (int i = 0; i < getSamplesPerPixel(); i++) { - updateSampleInByteBuffer(interleaveValues, interleaveIndex, i, values[i]); + updateSampleInByteBuffer(interleaveValues, interleaveIndex, i, + values[i]); interleaveIndex += fieldTypes[i].getBytes(); } } @@ -556,8 +629,10 @@ public void setPixel(int x, int y, Number[] values) { /** * Returns byte array of pixel row. * - * @param y Row index - * @param newOrder Desired byte order of result byte array + * @param y + * Row index + * @param newOrder + * Desired byte order of result byte array * @return Byte array of pixel row */ public byte[] getPixelRow(int y, ByteOrder newOrder) { @@ -566,7 +641,8 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { if (sampleValues != null) { for (int i = 0; i < getSamplesPerPixel(); ++i) { - sampleValues[i].position(y * getWidth() * fieldTypes[i].getBytes()); + sampleValues[i].position(y * getWidth() + * fieldTypes[i].getBytes()); } for (int i = 0; i < getWidth(); ++i) { for (int j = 0; j < getSamplesPerPixel(); ++j) { @@ -589,17 +665,22 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { /** * Returns byte array of sample row. * - * @param y Row index - * @param sample Sample index - * @param newOrder Desired byte order of resulting byte array + * @param y + * Row index + * @param sample + * Sample index + * @param newOrder + * Desired byte order of resulting byte array * @return Byte array of sample row */ public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { - ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * fieldTypes[sample].getBytes()); + ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() + * fieldTypes[sample].getBytes()); outBuffer.order(newOrder); if (sampleValues != null) { - sampleValues[sample].position(y * getWidth() * fieldTypes[sample].getBytes()); + sampleValues[sample].position(y * getWidth() + * fieldTypes[sample].getBytes()); for (int x = 0; x < getWidth(); ++x) { writeSample(outBuffer, sampleValues[sample], fieldTypes[sample]); } @@ -610,7 +691,8 @@ public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { } for (int i = 0; i < getWidth(); ++i) { - interleaveValues.position((y * getWidth() + i) * sizePixel() + sampleOffset); + interleaveValues.position((y * getWidth() + i) * sizePixel() + + sampleOffset); writeSample(outBuffer, interleaveValues, fieldTypes[sample]); } } @@ -639,15 +721,18 @@ public Number getPixelSample(int sample, int x, int y) { // Get the pixel sample if (sampleValues != null) { - int bufferPos = getSampleIndex(x, y) * fieldTypes[sample].getBytes(); - pixelSample = getSampleFromByteBuffer(sampleValues[sample], bufferPos, sample); + int bufferPos = getSampleIndex(x, y) + * fieldTypes[sample].getBytes(); + pixelSample = getSampleFromByteBuffer(sampleValues[sample], + bufferPos, sample); } else { int bufferPos = getInterleaveIndex(x, y); - for (int i = 0; i < sample; i++){ + for (int i = 0; i < sample; i++) { bufferPos += fieldTypes[sample].getBytes(); } - pixelSample = getSampleFromByteBuffer(interleaveValues, bufferPos, sample); + pixelSample = getSampleFromByteBuffer(interleaveValues, bufferPos, + sample); } return pixelSample; @@ -672,15 +757,18 @@ public void setPixelSample(int sample, int x, int y, Number value) { // Set the pixel sample if (sampleValues != null) { - int sampleIndex = getSampleIndex(x, y) * fieldTypes[sample].getBytes(); - updateSampleInByteBuffer(sampleValues[sample], sampleIndex, sample, value); + int sampleIndex = getSampleIndex(x, y) + * fieldTypes[sample].getBytes(); + updateSampleInByteBuffer(sampleValues[sample], sampleIndex, sample, + value); } if (interleaveValues != null) { int interleaveIndex = getSampleIndex(x, y) * sizePixel(); for (int i = 0; i < sample; ++i) { interleaveIndex += fieldTypes[sample].getBytes(); } - updateSampleInByteBuffer(interleaveValues, interleaveIndex, sample, value); + updateSampleInByteBuffer(interleaveValues, interleaveIndex, sample, + value); } } @@ -825,8 +913,8 @@ public int calculateRowsPerStrip(int planarConfiguration, } else { for (int sample = 0; sample < getSamplesPerPixel(); ++sample) { - int rowsPerStripForSample = rowsPerStrip(fieldTypes[sample].getBytes(), - maxBytesPerStrip); + int rowsPerStripForSample = rowsPerStrip( + fieldTypes[sample].getBytes(), maxBytesPerStrip); if (rowsPerStrip == null || rowsPerStripForSample < rowsPerStrip) { rowsPerStrip = rowsPerStripForSample; @@ -859,40 +947,43 @@ private int rowsPerStrip(int bytesPerPixel, int maxBytesPerStrip) { /** * Reads sample from given buffer * - * @param buffer A buffer to read from. @note Make sure position is set. - * @param fieldType field type to be read + * @param buffer + * A buffer to read from. @note Make sure position is set. + * @param fieldType + * field type to be read * @return Sample from buffer */ private Number readSample(ByteBuffer buffer, FieldType fieldType) { Number sampleValue; switch (fieldType) { - case BYTE: - sampleValue = (short)(buffer.get() & 0xff); - break; - case SHORT: - sampleValue = buffer.getShort() & 0xffff; - break; - case LONG: - sampleValue = buffer.getInt() & 0xffffffffL; - break; - case SBYTE: - sampleValue = buffer.get(); - break; - case SSHORT: - sampleValue = buffer.getShort(); - break; - case SLONG: - sampleValue = buffer.getInt(); - break; - case FLOAT: - sampleValue = buffer.getFloat(); - break; - case DOUBLE: - sampleValue = buffer.getDouble(); - break; - default: - throw new TiffException("Unsupported raster field type: " + fieldType); + case BYTE: + sampleValue = (short) (buffer.get() & 0xff); + break; + case SHORT: + sampleValue = buffer.getShort() & 0xffff; + break; + case LONG: + sampleValue = buffer.getInt() & 0xffffffffL; + break; + case SBYTE: + sampleValue = buffer.get(); + break; + case SSHORT: + sampleValue = buffer.getShort(); + break; + case SLONG: + sampleValue = buffer.getInt(); + break; + case FLOAT: + sampleValue = buffer.getFloat(); + break; + case DOUBLE: + sampleValue = buffer.getDouble(); + break; + default: + throw new TiffException("Unsupported raster field type: " + + fieldType); } return sampleValue; @@ -901,65 +992,74 @@ private Number readSample(ByteBuffer buffer, FieldType fieldType) { /** * Writes sample into given buffer. * - * @param buffer A buffer to write to. @note Make sure buffer position is set. - * @param fieldType field type to be written. - * @param value Actual value to write. + * @param buffer + * A buffer to write to. @note Make sure buffer position is set. + * @param fieldType + * field type to be written. + * @param value + * Actual value to write. */ - private void writeSample(ByteBuffer buffer, FieldType fieldType, Number value) { + private void writeSample(ByteBuffer buffer, FieldType fieldType, + Number value) { switch (fieldType) { - case BYTE: - case SBYTE: - buffer.put(value.byteValue()); - break; - case SHORT: - case SSHORT: - buffer.putShort(value.shortValue()); - break; - case LONG: - case SLONG: - buffer.putInt(value.intValue()); - break; - case FLOAT: - buffer.putFloat(value.floatValue()); - break; - case DOUBLE: - buffer.putDouble(value.doubleValue()); - break; - default: - throw new TiffException("Unsupported raster field type: " + fieldType); + case BYTE: + case SBYTE: + buffer.put(value.byteValue()); + break; + case SHORT: + case SSHORT: + buffer.putShort(value.shortValue()); + break; + case LONG: + case SLONG: + buffer.putInt(value.intValue()); + break; + case FLOAT: + buffer.putFloat(value.floatValue()); + break; + case DOUBLE: + buffer.putDouble(value.doubleValue()); + break; + default: + throw new TiffException("Unsupported raster field type: " + + fieldType); } } /** * Writes sample from input buffer to given output buffer. * - * @param outBuffer A buffer to write to. @note Make sure buffer position is set. - * @param inBuffer A buffer to read from. @note Make sure buffer position is set. - * @param fieldType Field type to be read. + * @param outBuffer + * A buffer to write to. @note Make sure buffer position is set. + * @param inBuffer + * A buffer to read from. @note Make sure buffer position is set. + * @param fieldType + * Field type to be read. */ private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, - FieldType fieldType) { + FieldType fieldType) { switch (fieldType) { - case BYTE: - case SBYTE: - outBuffer.put(inBuffer.get()); - break; - case SHORT: - case SSHORT: - outBuffer.putShort(inBuffer.getShort()); - break; - case LONG: - case SLONG: - outBuffer.putInt(inBuffer.getInt()); - break; - case FLOAT: - outBuffer.putFloat(inBuffer.getFloat()); - break; - case DOUBLE: - outBuffer.putDouble(inBuffer.getDouble()); - break; - default: - throw new TiffException("Unsupported raster field type: " + fieldType); + case BYTE: + case SBYTE: + outBuffer.put(inBuffer.get()); + break; + case SHORT: + case SSHORT: + outBuffer.putShort(inBuffer.getShort()); + break; + case LONG: + case SLONG: + outBuffer.putInt(inBuffer.getInt()); + break; + case FLOAT: + outBuffer.putFloat(inBuffer.getFloat()); + break; + case DOUBLE: + outBuffer.putDouble(inBuffer.getDouble()); + break; + default: + throw new TiffException("Unsupported raster field type: " + + fieldType); } } @@ -971,5 +1071,5 @@ private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, public FieldType[] getFieldTypes() { return fieldTypes; } - + } \ No newline at end of file diff --git a/src/main/java/mil/nga/tiff/TiffWriter.java b/src/main/java/mil/nga/tiff/TiffWriter.java index a78f05d..50b5bdb 100644 --- a/src/main/java/mil/nga/tiff/TiffWriter.java +++ b/src/main/java/mil/nga/tiff/TiffWriter.java @@ -344,8 +344,7 @@ private static byte[] writeRasters(ByteOrder byteOrder, * @throws IOException */ private static void writeStripRasters(ByteWriter writer, - FileDirectory fileDirectory, long offset, - CompressionEncoder encoder) + FileDirectory fileDirectory, long offset, CompressionEncoder encoder) throws IOException { Rasters rasters = fileDirectory.getWriteRasters(); @@ -383,11 +382,12 @@ private static void writeStripRasters(ByteWriter writer, // Get the row bytes and encode if needed byte[] rowBytes = null; if (sample != null) { - rowBytes = rasters.getSampleRow(y, sample, writer.getByteOrder()); + rowBytes = rasters.getSampleRow(y, sample, + writer.getByteOrder()); } else { rowBytes = rasters.getPixelRow(y, writer.getByteOrder()); } - + if (encoder.rowEncoding()) { rowBytes = encoder.encode(rowBytes, writer.getByteOrder()); } diff --git a/src/test/java/mil/nga/tiff/TiffTestUtils.java b/src/test/java/mil/nga/tiff/TiffTestUtils.java index de60f67..cbbaf33 100644 --- a/src/test/java/mil/nga/tiff/TiffTestUtils.java +++ b/src/test/java/mil/nga/tiff/TiffTestUtils.java @@ -139,12 +139,16 @@ public static void compareRastersSampleValues(Rasters rasters1, rasters2.getSampleValues().length); for (int i = 0; i < rasters1.getSampleValues().length; i++) { - TestCase.assertEquals(rasters1.getSampleValues()[i].capacity() / rasters1.getFieldTypes()[i].getBytes(), - rasters2.getSampleValues()[i].capacity() / rasters2.getFieldTypes()[i].getBytes()); + TestCase.assertEquals( + rasters1.getSampleValues()[i].capacity() + / rasters1.getFieldTypes()[i].getBytes(), + rasters2.getSampleValues()[i].capacity() + / rasters2.getFieldTypes()[i].getBytes()); for (int x = 0; x < rasters1.getWidth(); ++x) { for (int y = 0; y < rasters1.getHeight(); ++y) { - compareNumbers(rasters1.getPixelSample(i, x, y), rasters2.getPixelSample(i, x, y), exactType); + compareNumbers(rasters1.getPixelSample(i, x, y), + rasters2.getPixelSample(i, x, y), exactType); } } } @@ -182,14 +186,15 @@ public static void compareRastersInterleaveValues(Rasters rasters1, TestCase.assertNotNull(rasters1.getInterleaveValues()); TestCase.assertNotNull(rasters2.getInterleaveValues()); - TestCase.assertEquals(rasters1.getInterleaveValues().capacity() / rasters1.sizePixel(), - rasters2.getInterleaveValues().capacity() / rasters2.sizePixel()); - + TestCase.assertEquals(rasters1.getInterleaveValues().capacity() + / rasters1.sizePixel(), rasters2.getInterleaveValues() + .capacity() / rasters2.sizePixel()); for (int i = 0; i < rasters1.getSamplesPerPixel(); i++) { for (int x = 0; x < rasters1.getWidth(); ++x) { for (int y = 0; y < rasters1.getHeight(); ++y) { - compareNumbers(rasters1.getPixelSample(i, x, y), rasters2.getPixelSample(i, x, y), exactType); + compareNumbers(rasters1.getPixelSample(i, x, y), + rasters2.getPixelSample(i, x, y), exactType); } } } From 5541bfb42a004258e0dae5cebfc870d792f4ca7a Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Mon, 23 Oct 2017 06:39:41 -0600 Subject: [PATCH 28/29] change next version to 2.0.0 --- CHANGELOG.md | 9 ++++++--- pom.xml | 2 +- src/main/java/mil/nga/tiff/FieldType.java | 3 +++ src/main/java/mil/nga/tiff/FileDirectory.java | 17 ++++++++++++++++ src/main/java/mil/nga/tiff/Rasters.java | 20 +++++++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc0fedc..fce250c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,15 @@ Adheres to [Semantic Versioning](http://semver.org/). --- -## 1.0.4 (TBD) +## 2.0.0 (TBD) -* Rasters constructor support for multiple samples per pixel -* Handle missing samples per pixel values by using length of bits per sample +* Rasters modified to use buffers in place of arrays +* Deflate compression support +* Additional Rasters constructor options +* Handle missing samples per pixel with default value of 1 * Public access to tiff tags * String Entry Value getter and setter +* maven-gpg-plugin version 1.6 ## [1.0.3](https://github.com/ngageoint/geopackage-tiff-java/releases/tag/1.0.3) (06-27-2017) diff --git a/pom.xml b/pom.xml index 0b73f24..b5c97cf 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 mil.nga tiff - 1.0.4 + 2.0.0 jar Tagged Image File Format https://github.com/ngageoint/geopackage-tiff-java diff --git a/src/main/java/mil/nga/tiff/FieldType.java b/src/main/java/mil/nga/tiff/FieldType.java index d98526b..a2a551d 100644 --- a/src/main/java/mil/nga/tiff/FieldType.java +++ b/src/main/java/mil/nga/tiff/FieldType.java @@ -111,6 +111,7 @@ public int getBytes() { * Get the number of bits per value * * @return number of bits + * @since 2.0.0 */ public int getBits() { return bytes * 8; @@ -135,6 +136,7 @@ public static FieldType getFieldType(int fieldType) { * @param bitsPerSample * bits per sample * @return field type + * @since 2.0.0 */ public static FieldType getFieldType(int sampleFormat, int bitsPerSample) { @@ -194,6 +196,7 @@ public static FieldType getFieldType(int sampleFormat, int bitsPerSample) { * @param fieldType * field type * @return sample format + * @since 2.0.0 */ public static int getSampleFormat(FieldType fieldType) { diff --git a/src/main/java/mil/nga/tiff/FileDirectory.java b/src/main/java/mil/nga/tiff/FileDirectory.java index 872f357..cb31cc7 100644 --- a/src/main/java/mil/nga/tiff/FileDirectory.java +++ b/src/main/java/mil/nga/tiff/FileDirectory.java @@ -481,6 +481,7 @@ public void setStripOffsets(long stripOffset) { * Get the samples per pixel * * @return samples per pixel + * @since 2.0.0 */ public int getSamplesPerPixel() { Integer samplesPerPixel = getIntegerEntryValue(FieldTagType.SamplesPerPixel); @@ -1419,6 +1420,7 @@ private int getBytesPerPixel() { * @param fieldTagType * field tag type * @return integer value + * @since 2.0.0 */ public Integer getIntegerEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); @@ -1431,6 +1433,7 @@ public Integer getIntegerEntryValue(FieldTagType fieldTagType) { * field tag type * @param value * unsigned integer value (16 bit) + * @since 2.0.0 */ public void setUnsignedIntegerEntryValue(FieldTagType fieldTagType, int value) { @@ -1443,6 +1446,7 @@ public void setUnsignedIntegerEntryValue(FieldTagType fieldTagType, * @param fieldTagType * field tag type * @return number value + * @since 2.0.0 */ public Number getNumberEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); @@ -1455,6 +1459,7 @@ public Number getNumberEntryValue(FieldTagType fieldTagType) { * field tag type * @param value * unsigned long value (32 bit) + * @since 2.0.0 */ public void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { setEntryValue(fieldTagType, FieldType.LONG, 1, value); @@ -1466,6 +1471,7 @@ public void setUnsignedLongEntryValue(FieldTagType fieldTagType, long value) { * @param fieldTagType * field tag type * @return string value + * @since 2.0.0 */ public String getStringEntryValue(FieldTagType fieldTagType) { String value = null; @@ -1483,6 +1489,7 @@ public String getStringEntryValue(FieldTagType fieldTagType) { * field tag type * @param value * string value + * @since 2.0.0 */ public void setStringEntryValue(FieldTagType fieldTagType, String value) { List values = new ArrayList<>(); @@ -1496,6 +1503,7 @@ public void setStringEntryValue(FieldTagType fieldTagType, String value) { * @param fieldTagType * field tag type * @return integer list value + * @since 2.0.0 */ public List getIntegerListEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); @@ -1505,7 +1513,10 @@ public List getIntegerListEntryValue(FieldTagType fieldTagType) { * Set an unsigned integer list of values for the field tag type * * @param fieldTagType + * field tag type * @param value + * integer list value + * @since 2.0.0 */ public void setUnsignedIntegerListEntryValue(FieldTagType fieldTagType, List value) { @@ -1518,6 +1529,7 @@ public void setUnsignedIntegerListEntryValue(FieldTagType fieldTagType, * @param fieldTagType * field tag type * @return max integer value + * @since 2.0.0 */ public Integer getMaxIntegerEntryValue(FieldTagType fieldTagType) { Integer maxValue = null; @@ -1534,6 +1546,7 @@ public Integer getMaxIntegerEntryValue(FieldTagType fieldTagType) { * @param fieldTagType * field tag type * @return long list value + * @since 2.0.0 */ public List getNumberListEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); @@ -1545,6 +1558,7 @@ public List getNumberListEntryValue(FieldTagType fieldTagType) { * @param fieldTagType * field tag type * @return long list value + * @since 2.0.0 */ public List getLongListEntryValue(FieldTagType fieldTagType) { return getEntryValue(fieldTagType); @@ -1554,7 +1568,10 @@ public List getLongListEntryValue(FieldTagType fieldTagType) { * Set an unsigned long list of values for the field tag type * * @param fieldTagType + * field tag type * @param value + * long list value + * @since 2.0.0 */ public void setUnsignedLongListEntryValue(FieldTagType fieldTagType, List value) { diff --git a/src/main/java/mil/nga/tiff/Rasters.java b/src/main/java/mil/nga/tiff/Rasters.java index 5fb01c7..5a00e0f 100644 --- a/src/main/java/mil/nga/tiff/Rasters.java +++ b/src/main/java/mil/nga/tiff/Rasters.java @@ -69,6 +69,7 @@ public class Rasters { * field type for each sample * @param sampleValues * empty sample values buffer array + * @since 2.0.0 */ public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampleValues) { @@ -86,6 +87,7 @@ public Rasters(int width, int height, FieldType[] fieldTypes, * field type for each sample * @param interleaveValues * empty interleaved values buffer + * @since 2.0.0 */ public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer interleaveValues) { @@ -105,6 +107,7 @@ public Rasters(int width, int height, FieldType[] fieldTypes, * empty sample values buffer array * @param interleaveValues * empty interleaved values buffer + * @since 2.0.0 */ public Rasters(int width, int height, FieldType[] fieldTypes, ByteBuffer[] sampleValues, ByteBuffer interleaveValues) { @@ -129,6 +132,7 @@ public Rasters(int width, int height, FieldType[] fieldTypes, * number of samples per pixel * @param fieldType * type of field for each sample + * @since 2.0.0 */ public Rasters(int width, int height, int samplesPerPixel, FieldType fieldType) { @@ -150,6 +154,7 @@ public Rasters(int width, int height, int samplesPerPixel, * type of field for each sample * @param order * byte order + * @since 2.0.0 */ public Rasters(int width, int height, int samplesPerPixel, FieldType fieldType, ByteOrder order) { @@ -171,6 +176,7 @@ public Rasters(int width, int height, int samplesPerPixel, * bits per samples * @param sampleFormats * sample formats + * @since 2.0.0 */ public Rasters(int width, int height, int[] bitsPerSamples, int[] sampleFormats) { @@ -193,6 +199,7 @@ public Rasters(int width, int height, int[] bitsPerSamples, * sample formats * @param order * byte order + * @since 2.0.0 */ public Rasters(int width, int height, int[] bitsPerSamples, int[] sampleFormats, ByteOrder order) { @@ -216,6 +223,7 @@ public Rasters(int width, int height, int[] bitsPerSamples, * bits per each sample * @param sampleFormat * format for each sample + * @since 2.0.0 */ public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, int sampleFormat) { @@ -241,6 +249,7 @@ public Rasters(int width, int height, int samplesPerPixel, * format for each sample * @param order * byte order + * @since 2.0.0 */ public Rasters(int width, int height, int samplesPerPixel, int bitsPerSample, int sampleFormat, ByteOrder order) { @@ -257,6 +266,7 @@ public Rasters(int width, int height, int samplesPerPixel, * height of pixels * @param fieldTypes * field types per sample + * @since 2.0.0 */ public Rasters(int width, int height, FieldType[] fieldTypes) { this(width, height, fieldTypes, ByteOrder.nativeOrder()); @@ -273,6 +283,7 @@ public Rasters(int width, int height, FieldType[] fieldTypes) { * field types per sample * @param order * byte order + * @since 2.0.0 */ public Rasters(int width, int height, FieldType[] fieldTypes, ByteOrder order) { @@ -425,6 +436,7 @@ public void addToSample(int sampleIndex, int coordinate, Number value) { * coordinate location * @param value * value + * @since 2.0.0 */ public void addToInterleave(int sampleIndex, int coordinate, Number value) { int bufferPos = coordinate * sizePixel(); @@ -497,6 +509,7 @@ public List getBitsPerSample() { * sample list @see getFieldTypes(). @see {@link TiffConstants} * * @return list of sample type constants + * @since 2.0.0 */ public List getSampleFormat() { List result = sampleFormat; @@ -514,6 +527,7 @@ public List getSampleFormat() { * Get the results stored by samples * * @return sample values + * @since 2.0.0 */ public ByteBuffer[] getSampleValues() { for (int i = 0; i < sampleValues.length; ++i) { @@ -527,6 +541,7 @@ public ByteBuffer[] getSampleValues() { * * @param sampleValues * sample values + * @since 2.0.0 */ public void setSampleValues(ByteBuffer[] sampleValues) { this.sampleValues = sampleValues; @@ -540,6 +555,7 @@ public void setSampleValues(ByteBuffer[] sampleValues) { * Get the results stored as interleaved pixel samples * * @return interleaved values + * @since 2.0.0 */ public ByteBuffer getInterleaveValues() { interleaveValues.rewind(); @@ -551,6 +567,7 @@ public ByteBuffer getInterleaveValues() { * * @param interleaveValues * interleaved values + * @since 2.0.0 */ public void setInterleaveValues(ByteBuffer interleaveValues) { this.interleaveValues = interleaveValues; @@ -634,6 +651,7 @@ public void setPixel(int x, int y, Number[] values) { * @param newOrder * Desired byte order of result byte array * @return Byte array of pixel row + * @since 2.0.0 */ public byte[] getPixelRow(int y, ByteOrder newOrder) { ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() * sizePixel()); @@ -672,6 +690,7 @@ public byte[] getPixelRow(int y, ByteOrder newOrder) { * @param newOrder * Desired byte order of resulting byte array * @return Byte array of sample row + * @since 2.0.0 */ public byte[] getSampleRow(int y, int sample, ByteOrder newOrder) { ByteBuffer outBuffer = ByteBuffer.allocate(getWidth() @@ -1067,6 +1086,7 @@ private void writeSample(ByteBuffer outBuffer, ByteBuffer inBuffer, * Returns field types * * @return field types + * @since 2.0.0 */ public FieldType[] getFieldTypes() { return fieldTypes; From ed304e7dd049e0da589f60894aa09b2f418a9747 Mon Sep 17 00:00:00 2001 From: Brian Osborn Date: Mon, 20 Nov 2017 10:17:48 -0700 Subject: [PATCH 29/29] release version 2.0.0 --- CHANGELOG.md | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fce250c..0747c0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Adheres to [Semantic Versioning](http://semver.org/). --- -## 2.0.0 (TBD) +## [2.0.0](https://github.com/ngageoint/geopackage-tiff-java/releases/tag/2.0.0) (11-20-2017) * Rasters modified to use buffers in place of arrays * Deflate compression support diff --git a/README.md b/README.md index 2363f7f..6455d09 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ TIFFImage tiffImage = TiffReader.readTiff(input); List directories = tiffImage.getFileDirectories(); FileDirectory directory = directories.get(0); Rasters rasters = directory.readRasters(); - + ``` #### Write #### @@ -76,12 +76,12 @@ TiffWriter.writeTiff(file, tiffImage); ### Installation ### -Pull from the [Maven Central Repository](http://search.maven.org/#artifactdetails|mil.nga|tiff|1.0.3|jar) (JAR, POM, Source, Javadoc) +Pull from the [Maven Central Repository](http://search.maven.org/#artifactdetails|mil.nga|tiff|2.0.0|jar) (JAR, POM, Source, Javadoc) mil.nga tiff - 1.0.3 + 2.0.0 ### Build ###