mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 04:25:29 -04:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
5a3945c411
62
README.md
62
README.md
@ -480,12 +480,12 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-jpeg</artifactId>
|
||||
<version>3.3.2</version> <!-- Alternatively, build your own version -->
|
||||
<version>3.4</version> <!-- Alternatively, build your own version -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-tiff</artifactId>
|
||||
<version>3.3.2</version> <!-- Alternatively, build your own version -->
|
||||
<version>3.4</version> <!-- Alternatively, build your own version -->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@ -493,52 +493,52 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
|
||||
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
||||
|
||||
twelvemonkeys-common-lang-3.3.2.jar
|
||||
twelvemonkeys-common-io-3.3.2.jar
|
||||
twelvemonkeys-common-image-3.3.2.jar
|
||||
twelvemonkeys-imageio-core-3.3.2.jar
|
||||
twelvemonkeys-imageio-metadata-3.3.2.jar
|
||||
twelvemonkeys-imageio-jpeg-3.3.2.jar
|
||||
twelvemonkeys-imageio-tiff-3.3.2.jar
|
||||
twelvemonkeys-common-lang-3.4.jar
|
||||
twelvemonkeys-common-io-3.4.jar
|
||||
twelvemonkeys-common-image-3.4.jar
|
||||
twelvemonkeys-imageio-core-3.4.jar
|
||||
twelvemonkeys-imageio-metadata-3.4.jar
|
||||
twelvemonkeys-imageio-jpeg-3.4.jar
|
||||
twelvemonkeys-imageio-tiff-3.4.jar
|
||||
|
||||
### Links to prebuilt binaries
|
||||
|
||||
##### Latest version (3.2.x)
|
||||
##### Latest version (3.4)
|
||||
|
||||
Requires Java 7 or later.
|
||||
|
||||
Common dependencies
|
||||
* [common-lang-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.3.2/common-lang-3.3.2.jar)
|
||||
* [common-io-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.3.2/common-io-3.3.2.jar)
|
||||
* [common-image-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.3.2/common-image-3.3.2.jar)
|
||||
* [common-lang-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.4/common-lang-3.4.jar)
|
||||
* [common-io-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.4/common-io-3.4.jar)
|
||||
* [common-image-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.4/common-image-3.4.jar)
|
||||
|
||||
ImageIO dependencies
|
||||
* [imageio-core-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.3.2/imageio-core-3.3.2.jar)
|
||||
* [imageio-metadata-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.3.2/imageio-metadata-3.3.2.jar)
|
||||
* [imageio-core-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.4/imageio-core-3.4.jar)
|
||||
* [imageio-metadata-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.4/imageio-metadata-3.4.jar)
|
||||
|
||||
ImageIO plugins
|
||||
* [imageio-bmp-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.3.2/imageio-bmp-3.3.2.jar)
|
||||
* [imageio-jpeg-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.3.2/imageio-jpeg-3.3.2.jar)
|
||||
* [imageio-tiff-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.3.2/imageio-tiff-3.3.2.jar)
|
||||
* [imageio-pnm-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.3.2/imageio-pnm-3.3.2.jar)
|
||||
* [imageio-psd-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.3.2/imageio-psd-3.3.2.jar)
|
||||
* [imageio-hdr-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.3.2/imageio-hdr-3.3.2.jar)
|
||||
* [imageio-iff-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.3.2/imageio-iff-3.3.2.jar)
|
||||
* [imageio-pcx-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.3.2/imageio-pcx-3.3.2.jar)
|
||||
* [imageio-pict-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.3.2/imageio-pict-3.3.2.jar)
|
||||
* [imageio-sgi-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.3.2/imageio-sgi-3.3.2.jar)
|
||||
* [imageio-tga-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.3.2/imageio-tga-3.3.2.jar)
|
||||
* [imageio-icns-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.3.2/imageio-icns-3.3.2.jar)
|
||||
* [imageio-thumbsdb-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.3.2/imageio-thumbsdb-3.3.2.jar)
|
||||
* [imageio-bmp-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.4/imageio-bmp-3.4.jar)
|
||||
* [imageio-jpeg-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.4/imageio-jpeg-3.4.jar)
|
||||
* [imageio-tiff-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.4/imageio-tiff-3.4.jar)
|
||||
* [imageio-pnm-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.4/imageio-pnm-3.4.jar)
|
||||
* [imageio-psd-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.4/imageio-psd-3.4.jar)
|
||||
* [imageio-hdr-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.4/imageio-hdr-3.4.jar)
|
||||
* [imageio-iff-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.4/imageio-iff-3.4.jar)
|
||||
* [imageio-pcx-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.4/imageio-pcx-3.4.jar)
|
||||
* [imageio-pict-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.4/imageio-pict-3.4.jar)
|
||||
* [imageio-sgi-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.4/imageio-sgi-3.4.jar)
|
||||
* [imageio-tga-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.4/imageio-tga-3.4.jar)
|
||||
* [imageio-icns-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.4/imageio-icns-3.4.jar)
|
||||
* [imageio-thumbsdb-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.4/imageio-thumbsdb-3.4.jar)
|
||||
|
||||
ImageIO plugins requiring 3rd party libs
|
||||
* [imageio-batik-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.3.2/imageio-batik-3.3.2.jar)
|
||||
* [imageio-batik-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.4/imageio-batik-3.4.jar)
|
||||
|
||||
Photoshop Path support for ImageIO
|
||||
* [imageio-clippath-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.3.2/imageio-clippath-3.3.2.jar)
|
||||
* [imageio-clippath-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.4/imageio-clippath-3.4.jar)
|
||||
|
||||
Servlet support
|
||||
* [servlet-3.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.3.2/servlet-3.3.2.jar)
|
||||
* [servlet-3.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.4/servlet-3.4.jar)
|
||||
|
||||
##### Old version (3.0.x)
|
||||
|
||||
|
@ -45,11 +45,9 @@ import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@ -358,13 +356,21 @@ public final class TIFFUtilities {
|
||||
}
|
||||
}
|
||||
|
||||
int compression = -1;
|
||||
Entry compressionEntry = IFD.getEntryById(TIFF.TAG_COMPRESSION);
|
||||
if (compressionEntry != null && compressionEntry.getValue() instanceof Number) {
|
||||
compression = ((Number) compressionEntry.getValue()).shortValue();
|
||||
}
|
||||
|
||||
boolean rearrangedByteStrips = false;
|
||||
Entry oldJpegData = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||
Entry oldJpegDataLength = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||
long[] jpegByteCounts = null;
|
||||
long[] jpegOffsets = null;
|
||||
if (oldJpegData != null && oldJpegData.valueCount() > 0) {
|
||||
// convert JPEGInterchangeFormat to new-style-JPEG
|
||||
long[] jpegByteCounts = new long[0];
|
||||
long[] jpegOffsets = getValueAsLongArray(oldJpegData);
|
||||
jpegByteCounts = new long[0];
|
||||
jpegOffsets = getValueAsLongArray(oldJpegData);
|
||||
if (oldJpegDataLength != null && oldJpegDataLength.valueCount() > 0) {
|
||||
jpegByteCounts = getValueAsLongArray(oldJpegDataLength);
|
||||
}
|
||||
@ -388,6 +394,20 @@ public final class TIFFUtilities {
|
||||
newIFD.remove(oldJpegDataLength);
|
||||
rearrangedByteStrips = true;
|
||||
}
|
||||
else if (offsets.length == 1 && oldJpegDataLength != null && (jpegOffsets[0] < offsets[0]) && (jpegOffsets[0] + jpegByteCounts[0]) > (offsets[0] + byteCounts[0])) {
|
||||
|
||||
// ByteStrip contains only a part of JPEGInterchangeFormat
|
||||
newOffsets = writeData(jpegOffsets, jpegByteCounts, outputStream);
|
||||
|
||||
newIFD.remove(stripOffsetsEntry);
|
||||
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_OFFSETS : TIFF.TAG_STRIP_OFFSETS, newOffsets));
|
||||
newIFD.remove(stripByteCountsEntry);
|
||||
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_BYTE_COUNTS : TIFF.TAG_STRIP_BYTE_COUNTS, new int[]{(int) (jpegByteCounts[0])}));
|
||||
|
||||
newIFD.remove(oldJpegData);
|
||||
newIFD.remove(oldJpegDataLength);
|
||||
rearrangedByteStrips = true;
|
||||
}
|
||||
else if (oldJpegDataLength != null) {
|
||||
// multiple bytestrips
|
||||
// search for SOF on first strip and copy to each if needed
|
||||
@ -423,7 +443,7 @@ public final class TIFFUtilities {
|
||||
byte[] buffer = new byte[(int) byteCounts[i]];
|
||||
newByteCounts[i] = (int) (jpegInterchangeData.length + byteCounts[i]);
|
||||
stream.readFully(buffer);
|
||||
if (buffer[0] != 0xff && buffer[1] != 0xda) {
|
||||
if (buffer[0] != ((byte) 0xff) || buffer[1] != ((byte) 0xda)) {
|
||||
outputStream.write(sosMarker);
|
||||
newByteCounts[i] += sosMarker.length;
|
||||
}
|
||||
@ -440,7 +460,58 @@ public final class TIFFUtilities {
|
||||
rearrangedByteStrips = true;
|
||||
}
|
||||
}
|
||||
else if (compression == TIFFExtension.COMPRESSION_OLD_JPEG) {
|
||||
// old-style but no JPEGInterchangeFormat
|
||||
|
||||
long[] yCbCrSubSampling = getValueAsLongArray(IFD.getEntryById(TIFF.TAG_YCBCR_SUB_SAMPLING));
|
||||
int subsampling = yCbCrSubSampling != null
|
||||
? (int) ((yCbCrSubSampling[0] & 0xf) << 4 | yCbCrSubSampling[1] & 0xf)
|
||||
: 0x22;
|
||||
int bands = ((Number) IFD.getEntryById(TIFF.TAG_SAMPLES_PER_PIXEL).getValue()).intValue();
|
||||
|
||||
int w = ((Number) IFD.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue()).intValue();
|
||||
int h = ((Number) IFD.getEntryById(TIFF.TAG_IMAGE_HEIGHT).getValue()).intValue();
|
||||
|
||||
int r = ((Number) (useTiles ? IFD.getEntryById(TIFF.TAG_TILE_HEIGTH) : IFD.getEntryById(TIFF.TAG_ROWS_PER_STRIP)).getValue()).intValue();
|
||||
int c = useTiles ? ((Number) IFD.getEntryById(TIFF.TAG_TILE_WIDTH).getValue()).intValue() : w;
|
||||
|
||||
newOffsets = new int[offsets.length];
|
||||
int[] newByteCounts = new int[byteCounts.length];
|
||||
|
||||
// No JPEGInterchangeFormat
|
||||
for (int i = 0; i < offsets.length; i++) {
|
||||
byte[] start = new byte[2];
|
||||
stream.seek(offsets[i]);
|
||||
stream.readFully(start);
|
||||
newOffsets[i] = (int) outputStream.getStreamPosition();
|
||||
if (start[0] == ((byte) 0xff) && start[1] == ((byte) 0xd8)) {
|
||||
// full image stream, nothing to do
|
||||
writeData(stream, outputStream, offsets[i], byteCounts[i]);
|
||||
}
|
||||
else if (start[0] == ((byte) 0xff) && start[1] == ((byte) 0xda)) {
|
||||
// starts with SOS
|
||||
outputStream.writeShort(JPEG.SOI);
|
||||
writeSOF0(outputStream, bands, c, r, subsampling);
|
||||
writeData(stream, outputStream, offsets[i], byteCounts[i]);
|
||||
outputStream.writeShort(JPEG.EOI);
|
||||
}
|
||||
else {
|
||||
// raw data
|
||||
outputStream.writeShort(JPEG.SOI);
|
||||
writeSOF0(outputStream, bands, c, r, subsampling);
|
||||
writeSOS(outputStream, bands);
|
||||
writeData(stream, outputStream, offsets[i], byteCounts[i]);
|
||||
outputStream.writeShort(JPEG.EOI);
|
||||
}
|
||||
newByteCounts[i] = ((int) outputStream.getStreamPosition()) - newOffsets[i];
|
||||
}
|
||||
|
||||
newIFD.remove(stripOffsetsEntry);
|
||||
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_OFFSETS : TIFF.TAG_STRIP_OFFSETS, newOffsets));
|
||||
newIFD.remove(stripByteCountsEntry);
|
||||
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_BYTE_COUNTS : TIFF.TAG_STRIP_BYTE_COUNTS, newByteCounts));
|
||||
rearrangedByteStrips = true;
|
||||
}
|
||||
|
||||
if (!rearrangedByteStrips && stripOffsetsEntry != null && stripByteCountsEntry != null) {
|
||||
newOffsets = writeData(offsets, byteCounts, outputStream);
|
||||
@ -457,12 +528,21 @@ public final class TIFFUtilities {
|
||||
oldJpegTableQ = IFD.getEntryById(TIFF.TAG_OLD_JPEG_Q_TABLES);
|
||||
oldJpegTableDC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_DC_TABLES);
|
||||
oldJpegTableAC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_AC_TABLES);
|
||||
if (oldJpegTableQ != null || oldJpegTableDC != null || oldJpegTableAC != null) {
|
||||
if ((oldJpegTableQ != null) || (oldJpegTableDC != null) || (oldJpegTableAC != null)) {
|
||||
if (IFD.getEntryById(TIFF.TAG_JPEG_TABLES) != null) {
|
||||
throw new IOException("Found old-style and new-style JPEGTables");
|
||||
}
|
||||
|
||||
newIFD.add(mergeTables(oldJpegTableQ, oldJpegTableDC, oldJpegTableAC));
|
||||
boolean tablesInStream = jfifContainsTables(oldJpegTableQ, jpegOffsets, jpegByteCounts);
|
||||
tablesInStream &= jfifContainsTables(oldJpegTableDC, jpegOffsets, jpegByteCounts);
|
||||
tablesInStream &= jfifContainsTables(oldJpegTableAC, jpegOffsets, jpegByteCounts);
|
||||
if (!tablesInStream) {
|
||||
// merge them only to JPEGTables if they are not already contained within the stream
|
||||
Entry jpegTables = mergeTables(oldJpegTableQ, oldJpegTableDC, oldJpegTableAC);
|
||||
if (jpegTables != null) {
|
||||
newIFD.add(jpegTables);
|
||||
}
|
||||
}
|
||||
if (oldJpegTableQ != null) {
|
||||
newIFD.remove(oldJpegTableQ);
|
||||
}
|
||||
@ -474,17 +554,66 @@ public final class TIFFUtilities {
|
||||
}
|
||||
}
|
||||
|
||||
Entry compressionEntry = IFD.getEntryById(TIFF.TAG_COMPRESSION);
|
||||
if(compressionEntry != null) {
|
||||
Number compression = (Number) compressionEntry.getValue();
|
||||
if (compression.shortValue() == TIFFExtension.COMPRESSION_OLD_JPEG) {
|
||||
newIFD.remove(compressionEntry);
|
||||
newIFD.add(new TIFFEntry(TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, TIFFExtension.COMPRESSION_JPEG));
|
||||
}
|
||||
if (compressionEntry != null && compression == TIFFExtension.COMPRESSION_OLD_JPEG) {
|
||||
newIFD.remove(compressionEntry);
|
||||
newIFD.add(new TIFFEntry(TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, TIFFExtension.COMPRESSION_JPEG));
|
||||
}
|
||||
return newIFD;
|
||||
}
|
||||
|
||||
//TODO merge/extract from TIFFReader Jpeg/6 stream reconstruction
|
||||
private void writeSOF0(ImageOutputStream outputStream, int bands, int width, int height, int subsampling) throws IOException {
|
||||
outputStream.writeShort(JPEG.SOF0); // TODO: Use correct process for data
|
||||
outputStream.writeShort(2 + 6 + 3 * bands); // SOF0 len
|
||||
outputStream.writeByte(8); // bits TODO: Consult raster/transfer type or BitsPerSample for 12/16 bits support
|
||||
outputStream.writeShort(height); // height
|
||||
outputStream.writeShort(width); // width
|
||||
outputStream.writeByte(bands); // Number of components
|
||||
|
||||
for (int comp = 0; comp < bands; comp++) {
|
||||
outputStream.writeByte(comp); // Component id
|
||||
outputStream.writeByte(comp == 0 ? subsampling : 0x11); // h/v subsampling
|
||||
outputStream.writeByte(comp); // Q table selector TODO: Consider merging if tables are equal, correct selection if only 1 or 2 valid tables are contained
|
||||
}
|
||||
}
|
||||
|
||||
//TODO merge/extract from TIFFReader Jpeg/6 stream reconstruction
|
||||
private void writeSOS(ImageOutputStream outputStream, int bands) throws IOException {
|
||||
outputStream.writeShort(JPEG.SOS);
|
||||
outputStream.writeShort(6 + 2 * bands); // SOS length
|
||||
outputStream.writeByte(bands); // Num comp
|
||||
|
||||
for (int component = 0; component < bands; component++) {
|
||||
outputStream.writeByte(component); // Comp id
|
||||
outputStream.writeByte(component == 0 ? component : 0x10 + (component & 0xf)); // dc/ac selector TODO: correct selection if only 1 or 2 valid tables are contained
|
||||
}
|
||||
|
||||
outputStream.writeByte(0); // Spectral selection start
|
||||
outputStream.writeByte(0); // Spectral selection end
|
||||
outputStream.writeByte(0); // Approx high & low
|
||||
}
|
||||
|
||||
private void writeData(ImageInputStream input, ImageOutputStream output, long offset, long length) throws IOException {
|
||||
input.seek(offset);
|
||||
byte[] buffer = new byte[(int) length];
|
||||
stream.readFully(buffer);
|
||||
output.write(buffer);
|
||||
}
|
||||
|
||||
private boolean jfifContainsTables(Entry tableEntry, long[] jpegOffsets, long[] jpegLengths) throws IOException {
|
||||
if (jpegLengths == null || jpegOffsets == null || jpegLengths.length == 0) return false;
|
||||
if (tableEntry != null) {
|
||||
long[] tableOffsets = getValueAsLongArray(tableEntry);
|
||||
for (long offset : tableOffsets) {
|
||||
if (offset < jpegOffsets[0] || offset > (jpegOffsets[0] + jpegLengths[0])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO merge/extract from TIFFReader Jpeg/6 stream reconstruction
|
||||
private Entry mergeTables(Entry qEntry, Entry dcEntry, Entry acEntry) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
@ -494,12 +623,16 @@ public final class TIFFUtilities {
|
||||
long[] off = getValueAsLongArray(qEntry);
|
||||
byte[] table = new byte[64];
|
||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||
stream.seek(off[tableId]);
|
||||
stream.readFully(table);
|
||||
dos.writeShort(JPEG.DQT);
|
||||
dos.writeShort(3 + 64);
|
||||
dos.writeByte(tableId);
|
||||
dos.write(table);
|
||||
try {
|
||||
stream.seek(off[tableId]);
|
||||
stream.readFully(table);
|
||||
dos.writeShort(JPEG.DQT);
|
||||
dos.writeShort(3 + 64);
|
||||
dos.writeByte(tableId);
|
||||
dos.write(table);
|
||||
} catch (EOFException e) {
|
||||
// invalid table pointer, ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -507,30 +640,50 @@ public final class TIFFUtilities {
|
||||
if (dcEntry != null && dcEntry.valueCount() > 0) {
|
||||
long[] off = getValueAsLongArray(dcEntry);
|
||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||
stream.seek(off[tableId]);
|
||||
byte[] table = readHUFFTable();
|
||||
dos.writeShort(JPEG.DHT);
|
||||
dos.writeShort(3 + table.length);
|
||||
dos.writeByte(tableId);
|
||||
dos.write(table);
|
||||
try {
|
||||
stream.seek(off[tableId]);
|
||||
byte[] table = readHUFFTable();
|
||||
if (table.length > (16 + 17)) {
|
||||
// to long, table is invalid, just ignoe
|
||||
continue;
|
||||
}
|
||||
dos.writeShort(JPEG.DHT);
|
||||
dos.writeShort(3 + table.length);
|
||||
dos.writeByte(tableId);
|
||||
dos.write(table);
|
||||
} catch (EOFException e) {
|
||||
// invalid table pointer, ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (acEntry != null && acEntry.valueCount() > 0) {
|
||||
long[] off = getValueAsLongArray(acEntry);
|
||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||
stream.seek(off[tableId]);
|
||||
byte[] table = readHUFFTable();
|
||||
dos.writeShort(JPEG.DHT);
|
||||
dos.writeShort(3 + table.length);
|
||||
dos.writeByte(16 | tableId);
|
||||
dos.write(table);
|
||||
try {
|
||||
stream.seek(off[tableId]);
|
||||
byte[] table = readHUFFTable();
|
||||
if (table.length > (16 + 256)) {
|
||||
// to long, table is invalid, just ignoe
|
||||
continue;
|
||||
}
|
||||
dos.writeShort(JPEG.DHT);
|
||||
dos.writeShort(3 + table.length);
|
||||
dos.writeByte(16 | tableId);
|
||||
dos.write(table);
|
||||
} catch (EOFException e) {
|
||||
// invalid table pointer, ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dos.writeShort(JPEG.EOI);
|
||||
|
||||
bos.close();
|
||||
if (bos.size() == 4) {
|
||||
// no valid tables, don't add
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TIFFEntry(TIFF.TAG_JPEG_TABLES, TIFF.TYPE_UNDEFINED, bos.toByteArray());
|
||||
}
|
||||
@ -540,15 +693,11 @@ public final class TIFFUtilities {
|
||||
stream.readFully(lengths);
|
||||
int numCodes = 0;
|
||||
for (int i = 0; i < lengths.length; i++) {
|
||||
numCodes += lengths[i];
|
||||
numCodes += ((int) lengths[i]) & 0xff;
|
||||
}
|
||||
byte table[] = new byte[16 + numCodes];
|
||||
System.arraycopy(lengths, 0, table, 0, 16);
|
||||
int off = 16;
|
||||
for (int i = 0; i < lengths.length; i++) {
|
||||
stream.read(table, off, lengths[i]);
|
||||
off += lengths[i];
|
||||
}
|
||||
stream.readFully(table, 16, numCodes);
|
||||
return table;
|
||||
}
|
||||
|
||||
@ -559,7 +708,11 @@ public final class TIFFUtilities {
|
||||
stream.seek(offsets[i]);
|
||||
|
||||
byte[] buffer = new byte[(int) byteCounts[i]];
|
||||
stream.readFully(buffer);
|
||||
try {
|
||||
stream.readFully(buffer);
|
||||
} catch (EOFException e) {
|
||||
// invalid strip length
|
||||
}
|
||||
outputStream.write(buffer);
|
||||
}
|
||||
return newOffsets;
|
||||
@ -571,7 +724,7 @@ public final class TIFFUtilities {
|
||||
|
||||
if (entry.valueCount() == 1) {
|
||||
// For single entries, this will be a boxed type
|
||||
value = new long[] {((Number) entry.getValue()).longValue()};
|
||||
value = new long[]{((Number) entry.getValue()).longValue()};
|
||||
}
|
||||
else if (entry.getValue() instanceof short[]) {
|
||||
short[] shorts = (short[]) entry.getValue();
|
||||
|
@ -202,36 +202,39 @@ public class TIFFUtilitiesTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeBogusInterchangeFormatLength() throws IOException {
|
||||
String[] testFiles = new String[] {
|
||||
public void testOldStyleJPEGTransform() throws IOException {
|
||||
String[] testFiles = new String[]{
|
||||
"/tiff/old-style-jpeg-bogus-jpeginterchangeformatlength.tif", // InterchangeFormat before StripOffset, length not including StripOffset
|
||||
"/tiff/old-style-jpeg-no-jpeginterchangeformatlength.tif", // missing JPEGInterChangeFormatLength and JPEGInterchangeFormat == StipOffset
|
||||
"/tiff/old-style-jpeg-multiple-strips.tif" // InterchangeFormat with multiple strips
|
||||
"/tiff/old-style-jpeg-multiple-strips.tif", // InterchangeFormat with multiple strips
|
||||
"/contrib/tiff/old-style-jpeg-invalid-tables.tif", // AC/DC Tables are invalid (to long) and lie within the JPEGInterchangeFormat stream
|
||||
"/contrib/tiff/smallliz.tif", // InterchangeFormat contains whole JPEG, ByteStrip only raw ImageData after SOS
|
||||
"/contrib/tiff/WangJPEG.tif", // multiple strips, first strip contains SOS
|
||||
"/contrib/tiff/zackthecat.tif" // No JPEGInterchangeFormat, ByteStrip contains only raw image data
|
||||
};
|
||||
|
||||
for (String testFile : testFiles) {
|
||||
File output = File.createTempFile("imageiotest", ".tif");
|
||||
ImageOutputStream outputStream = ImageIO.createImageOutputStream(output);
|
||||
InputStream inputStream1 = getClassLoaderResource(testFile).openStream();
|
||||
ImageInputStream imageInput1 = ImageIO.createImageInputStream(inputStream1);
|
||||
InputStream inputStream2 = getClassLoaderResource(testFile).openStream();
|
||||
ImageInputStream imageInput2 = ImageIO.createImageInputStream(inputStream2);
|
||||
ArrayList<TIFFUtilities.TIFFPage> pages = new ArrayList<>();
|
||||
pages.addAll(TIFFUtilities.getPages(imageInput1));
|
||||
pages.addAll(TIFFUtilities.getPages(imageInput2));
|
||||
TIFFUtilities.writePages(outputStream, pages);
|
||||
try {
|
||||
File output = File.createTempFile("imageiotest", ".tif");
|
||||
ImageOutputStream outputStream = ImageIO.createImageOutputStream(output);
|
||||
InputStream inputStream = getClassLoaderResource(testFile).openStream();
|
||||
ImageInputStream imageInput = ImageIO.createImageInputStream(inputStream);
|
||||
List<TIFFUtilities.TIFFPage> pages = TIFFUtilities.getPages(imageInput);
|
||||
TIFFUtilities.writePages(outputStream, pages);
|
||||
|
||||
ImageInputStream testOutput = ImageIO.createImageInputStream(output);
|
||||
ImageReader reader = ImageIO.getImageReaders(testOutput).next();
|
||||
reader.setInput(testOutput);
|
||||
int numImages = reader.getNumImages(true);
|
||||
for (int i = 0; i < numImages; i++) {
|
||||
reader.read(i);
|
||||
ImageInputStream testOutput = ImageIO.createImageInputStream(output);
|
||||
ImageReader reader = ImageIO.getImageReaders(testOutput).next();
|
||||
reader.setInput(testOutput);
|
||||
int numImages = reader.getNumImages(true);
|
||||
for (int i = 0; i < numImages; i++) {
|
||||
reader.read(i);
|
||||
}
|
||||
|
||||
imageInput.close();
|
||||
outputStream.close();
|
||||
} catch (Exception exc) {
|
||||
throw new IOException(testFile, exc);
|
||||
}
|
||||
|
||||
imageInput1.close();
|
||||
imageInput2.close();
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
BIN
contrib/src/test/resources/contrib/tiff/WangJPEG.tif
Normal file
BIN
contrib/src/test/resources/contrib/tiff/WangJPEG.tif
Normal file
Binary file not shown.
Binary file not shown.
BIN
contrib/src/test/resources/contrib/tiff/smallliz.tif
Normal file
BIN
contrib/src/test/resources/contrib/tiff/smallliz.tif
Normal file
Binary file not shown.
BIN
contrib/src/test/resources/contrib/tiff/zackthecat.tif
Normal file
BIN
contrib/src/test/resources/contrib/tiff/zackthecat.tif
Normal file
Binary file not shown.
@ -130,7 +130,7 @@ public abstract class AbstractMetadata extends IIOMetadata implements Cloneable
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Bad format name: \"%s\". Expected one of %s", formatName, Arrays.toString(metadataFormatNames))
|
||||
String.format("Unsupported format name: \"%s\". Expected one of %s", formatName, Arrays.toString(metadataFormatNames))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -101,8 +101,16 @@ public final class ColorSpaces {
|
||||
private static final Map<Key, ICC_ColorSpace> cache = new LRUHashMap<>(10);
|
||||
|
||||
static {
|
||||
// Force invocation of ProfileDeferralMgr.activateProfiles() to avoid JDK-6986863
|
||||
ICC_Profile.getInstance(ColorSpace.CS_sRGB).getData();
|
||||
try {
|
||||
// Force invocation of ProfileDeferralMgr.activateProfiles() to avoid JDK-6986863
|
||||
ICC_Profile.getInstance(ColorSpace.CS_sRGB).getData();
|
||||
}
|
||||
catch (Throwable disasters) {
|
||||
System.err.println("ICC Color Profile not properly activated due to the exception below.");
|
||||
System.err.println("Expect to see JDK-6986863 in action, and consider filing a bug report to your JRE provider.");
|
||||
|
||||
disasters.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private ColorSpaces() {}
|
||||
|
@ -68,10 +68,7 @@ final class JPEGLosslessDecoder {
|
||||
private int xLoc;
|
||||
private int yLoc;
|
||||
private int mask;
|
||||
private int[] outputData;
|
||||
private int[] outputRedData;
|
||||
private int[] outputGreenData;
|
||||
private int[] outputBlueData;
|
||||
private int[][] outputData;
|
||||
|
||||
private static final int IDCT_P[] = {
|
||||
0, 5, 40, 16, 45, 2, 7, 42,
|
||||
@ -148,8 +145,6 @@ final class JPEGLosslessDecoder {
|
||||
|
||||
int[][] decode() throws IOException {
|
||||
int current, scanNum = 0;
|
||||
final int pred[] = new int[10];
|
||||
int[][] outputRef;
|
||||
|
||||
xLoc = 0;
|
||||
yLoc = 0;
|
||||
@ -218,32 +213,27 @@ final class JPEGLosslessDecoder {
|
||||
xDim = frame.samplesPerLine;
|
||||
yDim = frame.lines;
|
||||
|
||||
outputRef = new int[numComp][];
|
||||
outputData = new int[numComp][];
|
||||
|
||||
// TODO: Support 4 components (RGBA/YCCA/CMYK/YCCK), others?
|
||||
if (numComp == 1) {
|
||||
outputData = new int[xDim * yDim];
|
||||
outputRef[0] = outputData;
|
||||
for (int componentIndex = 0; componentIndex < numComp; ++componentIndex) {
|
||||
// not a good use of memory, but I had trouble packing bytes into int. some values exceeded 255.
|
||||
outputData[componentIndex] = new int[xDim * yDim];
|
||||
}
|
||||
else {
|
||||
outputRedData = new int[xDim * yDim]; // not a good use of memory, but I had trouble packing bytes into int. some values exceeded 255.
|
||||
outputGreenData = new int[xDim * yDim];
|
||||
outputBlueData = new int[xDim * yDim];
|
||||
|
||||
outputRef[0] = outputRedData;
|
||||
outputRef[1] = outputGreenData;
|
||||
outputRef[2] = outputBlueData;
|
||||
final int firstValue[] = new int[numComp];
|
||||
for (int i = 0; i < numComp; i++) {
|
||||
firstValue[i] = (1 << (precision - 1));
|
||||
}
|
||||
|
||||
final int pred[] = new int[numComp];
|
||||
|
||||
scanNum++;
|
||||
|
||||
while (true) { // Decode one scan
|
||||
int temp[] = new int[1]; // to store remainder bits
|
||||
int index[] = new int[1];
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
pred[i] = (1 << (precision - 1));
|
||||
}
|
||||
System.arraycopy(firstValue, 0, pred, 0, numComp);
|
||||
|
||||
if (restartInterval == 0) {
|
||||
current = decode(pred, temp, index);
|
||||
@ -285,9 +275,10 @@ final class JPEGLosslessDecoder {
|
||||
readNumber();
|
||||
current = input.readUnsignedShort();
|
||||
}
|
||||
// TODO oe: 05.05.2018 Is it correct loop? Content of outputData from previous iteration is always lost.
|
||||
} while ((current != JPEG.EOI) && ((xLoc < xDim) && (yLoc < yDim)) && (scanNum == 0));
|
||||
|
||||
return outputRef;
|
||||
return outputData;
|
||||
}
|
||||
|
||||
private void processWarningOccured(String warning) {
|
||||
@ -341,7 +332,7 @@ final class JPEGLosslessDecoder {
|
||||
return decodeRGB(prev, temp, index);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
return decodeAny(prev, temp, index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,6 +344,7 @@ final class JPEGLosslessDecoder {
|
||||
prev[0] = (1 << (frame.samplePrecision - 1));
|
||||
}
|
||||
else {
|
||||
final int[] outputData = this.outputData[0];
|
||||
switch (selection) {
|
||||
case 2:
|
||||
prev[0] = getPreviousY(outputData);
|
||||
@ -399,6 +391,9 @@ final class JPEGLosslessDecoder {
|
||||
}
|
||||
|
||||
private int decodeRGB(final int prev[], final int temp[], final int index[]) throws IOException {
|
||||
final int[] outputRedData = outputData[0];
|
||||
final int[] outputGreenData = outputData[1];
|
||||
final int[] outputBlueData = outputData[2];
|
||||
switch (selection) {
|
||||
case 2:
|
||||
prev[0] = getPreviousY(outputRedData);
|
||||
@ -437,6 +432,43 @@ final class JPEGLosslessDecoder {
|
||||
break;
|
||||
}
|
||||
|
||||
return decode0(prev, temp, index);
|
||||
}
|
||||
|
||||
private int decodeAny(final int prev[], final int temp[], final int index[]) throws IOException {
|
||||
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
|
||||
final int[] outputData = this.outputData[componentIndex];
|
||||
final int previous;
|
||||
switch (selection) {
|
||||
case 2:
|
||||
previous = getPreviousY(outputData);
|
||||
break;
|
||||
case 3:
|
||||
previous = getPreviousXY(outputData);
|
||||
break;
|
||||
case 4:
|
||||
previous = (getPreviousX(outputData) + getPreviousY(outputData)) - getPreviousXY(outputData);
|
||||
break;
|
||||
case 5:
|
||||
previous = getPreviousX(outputData) + ((getPreviousY(outputData) - getPreviousXY(outputData)) >> 1);
|
||||
break;
|
||||
case 6:
|
||||
previous = getPreviousY(outputData) + ((getPreviousX(outputData) - getPreviousXY(outputData)) >> 1);
|
||||
break;
|
||||
case 7:
|
||||
previous = (int) (((long) getPreviousX(outputData) + getPreviousY(outputData)) / 2);
|
||||
break;
|
||||
default:
|
||||
previous = getPreviousX(outputData);
|
||||
break;
|
||||
}
|
||||
prev[componentIndex] = previous;
|
||||
}
|
||||
|
||||
return decode0(prev, temp, index);
|
||||
}
|
||||
|
||||
private int decode0(int[] prev, int[] temp, int[] index) throws IOException {
|
||||
int value, actab[], dctab[];
|
||||
int qtab[];
|
||||
|
||||
@ -694,14 +726,17 @@ final class JPEGLosslessDecoder {
|
||||
if (numComp == 1) {
|
||||
outputSingle(pred);
|
||||
}
|
||||
else {
|
||||
else if (numComp == 3) {
|
||||
outputRGB(pred);
|
||||
}
|
||||
else {
|
||||
outputAny(pred);
|
||||
}
|
||||
}
|
||||
|
||||
private void outputSingle(final int pred[]) {
|
||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||
outputData[(yLoc * xDim) + xLoc] = mask & pred[0];
|
||||
outputData[0][(yLoc * xDim) + xLoc] = mask & pred[0];
|
||||
xLoc++;
|
||||
|
||||
if (xLoc >= xDim) {
|
||||
@ -713,9 +748,25 @@ final class JPEGLosslessDecoder {
|
||||
|
||||
private void outputRGB(final int pred[]) {
|
||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||
outputRedData[(yLoc * xDim) + xLoc] = pred[0];
|
||||
outputGreenData[(yLoc * xDim) + xLoc] = pred[1];
|
||||
outputBlueData[(yLoc * xDim) + xLoc] = pred[2];
|
||||
final int index = (yLoc * xDim) + xLoc;
|
||||
outputData[0][index] = pred[0];
|
||||
outputData[1][index] = pred[1];
|
||||
outputData[2][index] = pred[2];
|
||||
xLoc++;
|
||||
|
||||
if (xLoc >= xDim) {
|
||||
yLoc++;
|
||||
xLoc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void outputAny(final int pred[]) {
|
||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||
final int index = (yLoc * xDim) + xLoc;
|
||||
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
|
||||
outputData[componentIndex][index] = pred[componentIndex];
|
||||
}
|
||||
xLoc++;
|
||||
|
||||
if (xLoc >= xDim) {
|
||||
|
@ -39,9 +39,12 @@ import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
import static java.lang.String.format;
|
||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* TIFFStreamMetadata.
|
||||
@ -113,7 +116,7 @@ public final class TIFFStreamMetadata extends IIOMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
private ByteOrder getByteOrder(final String value) throws IIOInvalidTreeException {
|
||||
private ByteOrder getByteOrder(final String value) {
|
||||
switch (value) {
|
||||
case "BIG_ENDIAN":
|
||||
return ByteOrder.BIG_ENDIAN;
|
||||
@ -138,6 +141,11 @@ public final class TIFFStreamMetadata extends IIOMetadata {
|
||||
}
|
||||
else if (streamMetadata != null) {
|
||||
TIFFStreamMetadata metadata = new TIFFStreamMetadata();
|
||||
|
||||
Validate.isTrue(asList(streamMetadata.getMetadataFormatNames()).contains(metadata.nativeMetadataFormatName),
|
||||
format("Unsupported stream metadata format, expected %s: %s", metadata.nativeMetadataFormatName,
|
||||
Arrays.toString(streamMetadata.getMetadataFormatNames())));
|
||||
|
||||
// Will throw exception if stream format differs from native
|
||||
metadata.mergeTree(metadata.nativeMetadataFormatName, streamMetadata.getAsTree(metadata.nativeMetadataFormatName));
|
||||
imageOutput.setByteOrder(metadata.byteOrder);
|
||||
|
@ -40,6 +40,7 @@ import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import static com.twelvemonkeys.imageio.plugins.tiff.TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
import static com.twelvemonkeys.imageio.plugins.tiff.TIFFStreamMetadata.SUN_NATIVE_STREAM_METADATA_FORMAT_NAME;
|
||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||
@ -85,9 +86,10 @@ public class TIFFStreamMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureStreamForegin() throws IIOInvalidTreeException {
|
||||
public void testConfigureStreamForeign() throws IIOInvalidTreeException {
|
||||
ImageOutputStream stream = mock(ImageOutputStream.class);
|
||||
IIOMetadata metadata = mock(IIOMetadata.class);
|
||||
when(metadata.getMetadataFormatNames()).thenReturn(new String[]{SUN_NATIVE_STREAM_METADATA_FORMAT_NAME, "com_foo_supertiff_9.42"});
|
||||
when(metadata.getAsTree(eq(SUN_NATIVE_STREAM_METADATA_FORMAT_NAME))).thenReturn(createForeignTree(LITTLE_ENDIAN));
|
||||
|
||||
TIFFStreamMetadata.configureStreamByteOrder(metadata, stream);
|
||||
@ -95,6 +97,24 @@ public class TIFFStreamMetadataTest {
|
||||
verify(stream, only()).setByteOrder(LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigureStreamImageMetadata() throws IIOInvalidTreeException {
|
||||
ImageOutputStream stream = mock(ImageOutputStream.class);
|
||||
IIOMetadata metadata = mock(IIOMetadata.class);
|
||||
when(metadata.getMetadataFormatNames()).thenReturn(new String[]{SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME});
|
||||
|
||||
try {
|
||||
TIFFStreamMetadata.configureStreamByteOrder(metadata, stream);
|
||||
fail("Expected IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertNotNull(expected.getMessage());
|
||||
assertTrue(expected.getMessage().toLowerCase().contains("unsupported stream metadata format"));
|
||||
assertTrue(expected.getMessage().contains("expected " + SUN_NATIVE_STREAM_METADATA_FORMAT_NAME));
|
||||
assertTrue(expected.getMessage().contains(SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
private IIOMetadataNode createForeignTree(ByteOrder order) {
|
||||
IIOMetadataNode root = new IIOMetadataNode(SUN_NATIVE_STREAM_METADATA_FORMAT_NAME);
|
||||
IIOMetadataNode byteOrder = new IIOMetadataNode("ByteOrder");
|
||||
|
Loading…
x
Reference in New Issue
Block a user