mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 20:15:28 -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>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<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>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<version>3.3.2</version> <!-- Alternatively, build your own version -->
|
<version>3.4</version> <!-- Alternatively, build your own version -->
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</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:
|
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-lang-3.4.jar
|
||||||
twelvemonkeys-common-io-3.3.2.jar
|
twelvemonkeys-common-io-3.4.jar
|
||||||
twelvemonkeys-common-image-3.3.2.jar
|
twelvemonkeys-common-image-3.4.jar
|
||||||
twelvemonkeys-imageio-core-3.3.2.jar
|
twelvemonkeys-imageio-core-3.4.jar
|
||||||
twelvemonkeys-imageio-metadata-3.3.2.jar
|
twelvemonkeys-imageio-metadata-3.4.jar
|
||||||
twelvemonkeys-imageio-jpeg-3.3.2.jar
|
twelvemonkeys-imageio-jpeg-3.4.jar
|
||||||
twelvemonkeys-imageio-tiff-3.3.2.jar
|
twelvemonkeys-imageio-tiff-3.4.jar
|
||||||
|
|
||||||
### Links to prebuilt binaries
|
### Links to prebuilt binaries
|
||||||
|
|
||||||
##### Latest version (3.2.x)
|
##### Latest version (3.4)
|
||||||
|
|
||||||
Requires Java 7 or later.
|
Requires Java 7 or later.
|
||||||
|
|
||||||
Common dependencies
|
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-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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.3.2/common-io-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.3.2/common-image-3.3.2.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 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-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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.3.2/imageio-metadata-3.3.2.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 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-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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.3.2/imageio-jpeg-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.3.2/imageio-tiff-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.3.2/imageio-pnm-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.3.2/imageio-psd-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.3.2/imageio-hdr-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.3.2/imageio-iff-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.3.2/imageio-pcx-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.3.2/imageio-pict-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.3.2/imageio-sgi-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.3.2/imageio-tga-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.3.2/imageio-icns-3.3.2.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.3.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.3.2/imageio-thumbsdb-3.3.2.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 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
|
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 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)
|
##### Old version (3.0.x)
|
||||||
|
|
||||||
|
@ -45,11 +45,9 @@ import javax.imageio.stream.ImageInputStream;
|
|||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.*;
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
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;
|
boolean rearrangedByteStrips = false;
|
||||||
Entry oldJpegData = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
Entry oldJpegData = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||||
Entry oldJpegDataLength = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
Entry oldJpegDataLength = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||||
|
long[] jpegByteCounts = null;
|
||||||
|
long[] jpegOffsets = null;
|
||||||
if (oldJpegData != null && oldJpegData.valueCount() > 0) {
|
if (oldJpegData != null && oldJpegData.valueCount() > 0) {
|
||||||
// convert JPEGInterchangeFormat to new-style-JPEG
|
// convert JPEGInterchangeFormat to new-style-JPEG
|
||||||
long[] jpegByteCounts = new long[0];
|
jpegByteCounts = new long[0];
|
||||||
long[] jpegOffsets = getValueAsLongArray(oldJpegData);
|
jpegOffsets = getValueAsLongArray(oldJpegData);
|
||||||
if (oldJpegDataLength != null && oldJpegDataLength.valueCount() > 0) {
|
if (oldJpegDataLength != null && oldJpegDataLength.valueCount() > 0) {
|
||||||
jpegByteCounts = getValueAsLongArray(oldJpegDataLength);
|
jpegByteCounts = getValueAsLongArray(oldJpegDataLength);
|
||||||
}
|
}
|
||||||
@ -388,6 +394,20 @@ public final class TIFFUtilities {
|
|||||||
newIFD.remove(oldJpegDataLength);
|
newIFD.remove(oldJpegDataLength);
|
||||||
rearrangedByteStrips = true;
|
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) {
|
else if (oldJpegDataLength != null) {
|
||||||
// multiple bytestrips
|
// multiple bytestrips
|
||||||
// search for SOF on first strip and copy to each if needed
|
// 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]];
|
byte[] buffer = new byte[(int) byteCounts[i]];
|
||||||
newByteCounts[i] = (int) (jpegInterchangeData.length + byteCounts[i]);
|
newByteCounts[i] = (int) (jpegInterchangeData.length + byteCounts[i]);
|
||||||
stream.readFully(buffer);
|
stream.readFully(buffer);
|
||||||
if (buffer[0] != 0xff && buffer[1] != 0xda) {
|
if (buffer[0] != ((byte) 0xff) || buffer[1] != ((byte) 0xda)) {
|
||||||
outputStream.write(sosMarker);
|
outputStream.write(sosMarker);
|
||||||
newByteCounts[i] += sosMarker.length;
|
newByteCounts[i] += sosMarker.length;
|
||||||
}
|
}
|
||||||
@ -440,7 +460,58 @@ public final class TIFFUtilities {
|
|||||||
rearrangedByteStrips = true;
|
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) {
|
if (!rearrangedByteStrips && stripOffsetsEntry != null && stripByteCountsEntry != null) {
|
||||||
newOffsets = writeData(offsets, byteCounts, outputStream);
|
newOffsets = writeData(offsets, byteCounts, outputStream);
|
||||||
@ -457,12 +528,21 @@ public final class TIFFUtilities {
|
|||||||
oldJpegTableQ = IFD.getEntryById(TIFF.TAG_OLD_JPEG_Q_TABLES);
|
oldJpegTableQ = IFD.getEntryById(TIFF.TAG_OLD_JPEG_Q_TABLES);
|
||||||
oldJpegTableDC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_DC_TABLES);
|
oldJpegTableDC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_DC_TABLES);
|
||||||
oldJpegTableAC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_AC_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) {
|
if (IFD.getEntryById(TIFF.TAG_JPEG_TABLES) != null) {
|
||||||
throw new IOException("Found old-style and new-style JPEGTables");
|
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) {
|
if (oldJpegTableQ != null) {
|
||||||
newIFD.remove(oldJpegTableQ);
|
newIFD.remove(oldJpegTableQ);
|
||||||
}
|
}
|
||||||
@ -474,17 +554,66 @@ public final class TIFFUtilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry compressionEntry = IFD.getEntryById(TIFF.TAG_COMPRESSION);
|
if (compressionEntry != null && compression == TIFFExtension.COMPRESSION_OLD_JPEG) {
|
||||||
if(compressionEntry != null) {
|
|
||||||
Number compression = (Number) compressionEntry.getValue();
|
|
||||||
if (compression.shortValue() == TIFFExtension.COMPRESSION_OLD_JPEG) {
|
|
||||||
newIFD.remove(compressionEntry);
|
newIFD.remove(compressionEntry);
|
||||||
newIFD.add(new TIFFEntry(TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, TIFFExtension.COMPRESSION_JPEG));
|
newIFD.add(new TIFFEntry(TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, TIFFExtension.COMPRESSION_JPEG));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return newIFD;
|
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 {
|
private Entry mergeTables(Entry qEntry, Entry dcEntry, Entry acEntry) throws IOException {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
DataOutputStream dos = new DataOutputStream(bos);
|
DataOutputStream dos = new DataOutputStream(bos);
|
||||||
@ -494,12 +623,16 @@ public final class TIFFUtilities {
|
|||||||
long[] off = getValueAsLongArray(qEntry);
|
long[] off = getValueAsLongArray(qEntry);
|
||||||
byte[] table = new byte[64];
|
byte[] table = new byte[64];
|
||||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||||
|
try {
|
||||||
stream.seek(off[tableId]);
|
stream.seek(off[tableId]);
|
||||||
stream.readFully(table);
|
stream.readFully(table);
|
||||||
dos.writeShort(JPEG.DQT);
|
dos.writeShort(JPEG.DQT);
|
||||||
dos.writeShort(3 + 64);
|
dos.writeShort(3 + 64);
|
||||||
dos.writeByte(tableId);
|
dos.writeByte(tableId);
|
||||||
dos.write(table);
|
dos.write(table);
|
||||||
|
} catch (EOFException e) {
|
||||||
|
// invalid table pointer, ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,30 +640,50 @@ public final class TIFFUtilities {
|
|||||||
if (dcEntry != null && dcEntry.valueCount() > 0) {
|
if (dcEntry != null && dcEntry.valueCount() > 0) {
|
||||||
long[] off = getValueAsLongArray(dcEntry);
|
long[] off = getValueAsLongArray(dcEntry);
|
||||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||||
|
try {
|
||||||
stream.seek(off[tableId]);
|
stream.seek(off[tableId]);
|
||||||
byte[] table = readHUFFTable();
|
byte[] table = readHUFFTable();
|
||||||
|
if (table.length > (16 + 17)) {
|
||||||
|
// to long, table is invalid, just ignoe
|
||||||
|
continue;
|
||||||
|
}
|
||||||
dos.writeShort(JPEG.DHT);
|
dos.writeShort(JPEG.DHT);
|
||||||
dos.writeShort(3 + table.length);
|
dos.writeShort(3 + table.length);
|
||||||
dos.writeByte(tableId);
|
dos.writeByte(tableId);
|
||||||
dos.write(table);
|
dos.write(table);
|
||||||
|
} catch (EOFException e) {
|
||||||
|
// invalid table pointer, ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acEntry != null && acEntry.valueCount() > 0) {
|
if (acEntry != null && acEntry.valueCount() > 0) {
|
||||||
long[] off = getValueAsLongArray(acEntry);
|
long[] off = getValueAsLongArray(acEntry);
|
||||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||||
|
try {
|
||||||
stream.seek(off[tableId]);
|
stream.seek(off[tableId]);
|
||||||
byte[] table = readHUFFTable();
|
byte[] table = readHUFFTable();
|
||||||
|
if (table.length > (16 + 256)) {
|
||||||
|
// to long, table is invalid, just ignoe
|
||||||
|
continue;
|
||||||
|
}
|
||||||
dos.writeShort(JPEG.DHT);
|
dos.writeShort(JPEG.DHT);
|
||||||
dos.writeShort(3 + table.length);
|
dos.writeShort(3 + table.length);
|
||||||
dos.writeByte(16 | tableId);
|
dos.writeByte(16 | tableId);
|
||||||
dos.write(table);
|
dos.write(table);
|
||||||
|
} catch (EOFException e) {
|
||||||
|
// invalid table pointer, ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dos.writeShort(JPEG.EOI);
|
dos.writeShort(JPEG.EOI);
|
||||||
|
|
||||||
bos.close();
|
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());
|
return new TIFFEntry(TIFF.TAG_JPEG_TABLES, TIFF.TYPE_UNDEFINED, bos.toByteArray());
|
||||||
}
|
}
|
||||||
@ -540,15 +693,11 @@ public final class TIFFUtilities {
|
|||||||
stream.readFully(lengths);
|
stream.readFully(lengths);
|
||||||
int numCodes = 0;
|
int numCodes = 0;
|
||||||
for (int i = 0; i < lengths.length; i++) {
|
for (int i = 0; i < lengths.length; i++) {
|
||||||
numCodes += lengths[i];
|
numCodes += ((int) lengths[i]) & 0xff;
|
||||||
}
|
}
|
||||||
byte table[] = new byte[16 + numCodes];
|
byte table[] = new byte[16 + numCodes];
|
||||||
System.arraycopy(lengths, 0, table, 0, 16);
|
System.arraycopy(lengths, 0, table, 0, 16);
|
||||||
int off = 16;
|
stream.readFully(table, 16, numCodes);
|
||||||
for (int i = 0; i < lengths.length; i++) {
|
|
||||||
stream.read(table, off, lengths[i]);
|
|
||||||
off += lengths[i];
|
|
||||||
}
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,7 +708,11 @@ public final class TIFFUtilities {
|
|||||||
stream.seek(offsets[i]);
|
stream.seek(offsets[i]);
|
||||||
|
|
||||||
byte[] buffer = new byte[(int) byteCounts[i]];
|
byte[] buffer = new byte[(int) byteCounts[i]];
|
||||||
|
try {
|
||||||
stream.readFully(buffer);
|
stream.readFully(buffer);
|
||||||
|
} catch (EOFException e) {
|
||||||
|
// invalid strip length
|
||||||
|
}
|
||||||
outputStream.write(buffer);
|
outputStream.write(buffer);
|
||||||
}
|
}
|
||||||
return newOffsets;
|
return newOffsets;
|
||||||
|
@ -202,23 +202,24 @@ public class TIFFUtilitiesTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMergeBogusInterchangeFormatLength() throws IOException {
|
public void testOldStyleJPEGTransform() throws IOException {
|
||||||
String[] testFiles = new String[]{
|
String[] testFiles = new String[]{
|
||||||
"/tiff/old-style-jpeg-bogus-jpeginterchangeformatlength.tif", // InterchangeFormat before StripOffset, length not including StripOffset
|
"/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-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) {
|
for (String testFile : testFiles) {
|
||||||
|
try {
|
||||||
File output = File.createTempFile("imageiotest", ".tif");
|
File output = File.createTempFile("imageiotest", ".tif");
|
||||||
ImageOutputStream outputStream = ImageIO.createImageOutputStream(output);
|
ImageOutputStream outputStream = ImageIO.createImageOutputStream(output);
|
||||||
InputStream inputStream1 = getClassLoaderResource(testFile).openStream();
|
InputStream inputStream = getClassLoaderResource(testFile).openStream();
|
||||||
ImageInputStream imageInput1 = ImageIO.createImageInputStream(inputStream1);
|
ImageInputStream imageInput = ImageIO.createImageInputStream(inputStream);
|
||||||
InputStream inputStream2 = getClassLoaderResource(testFile).openStream();
|
List<TIFFUtilities.TIFFPage> pages = TIFFUtilities.getPages(imageInput);
|
||||||
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);
|
TIFFUtilities.writePages(outputStream, pages);
|
||||||
|
|
||||||
ImageInputStream testOutput = ImageIO.createImageInputStream(output);
|
ImageInputStream testOutput = ImageIO.createImageInputStream(output);
|
||||||
@ -229,9 +230,11 @@ public class TIFFUtilitiesTest {
|
|||||||
reader.read(i);
|
reader.read(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
imageInput1.close();
|
imageInput.close();
|
||||||
imageInput2.close();
|
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
|
} catch (Exception exc) {
|
||||||
|
throw new IOException(testFile, exc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(
|
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,9 +101,17 @@ public final class ColorSpaces {
|
|||||||
private static final Map<Key, ICC_ColorSpace> cache = new LRUHashMap<>(10);
|
private static final Map<Key, ICC_ColorSpace> cache = new LRUHashMap<>(10);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
try {
|
||||||
// Force invocation of ProfileDeferralMgr.activateProfiles() to avoid JDK-6986863
|
// Force invocation of ProfileDeferralMgr.activateProfiles() to avoid JDK-6986863
|
||||||
ICC_Profile.getInstance(ColorSpace.CS_sRGB).getData();
|
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() {}
|
private ColorSpaces() {}
|
||||||
|
|
||||||
|
@ -68,10 +68,7 @@ final class JPEGLosslessDecoder {
|
|||||||
private int xLoc;
|
private int xLoc;
|
||||||
private int yLoc;
|
private int yLoc;
|
||||||
private int mask;
|
private int mask;
|
||||||
private int[] outputData;
|
private int[][] outputData;
|
||||||
private int[] outputRedData;
|
|
||||||
private int[] outputGreenData;
|
|
||||||
private int[] outputBlueData;
|
|
||||||
|
|
||||||
private static final int IDCT_P[] = {
|
private static final int IDCT_P[] = {
|
||||||
0, 5, 40, 16, 45, 2, 7, 42,
|
0, 5, 40, 16, 45, 2, 7, 42,
|
||||||
@ -148,8 +145,6 @@ final class JPEGLosslessDecoder {
|
|||||||
|
|
||||||
int[][] decode() throws IOException {
|
int[][] decode() throws IOException {
|
||||||
int current, scanNum = 0;
|
int current, scanNum = 0;
|
||||||
final int pred[] = new int[10];
|
|
||||||
int[][] outputRef;
|
|
||||||
|
|
||||||
xLoc = 0;
|
xLoc = 0;
|
||||||
yLoc = 0;
|
yLoc = 0;
|
||||||
@ -218,32 +213,27 @@ final class JPEGLosslessDecoder {
|
|||||||
xDim = frame.samplesPerLine;
|
xDim = frame.samplesPerLine;
|
||||||
yDim = frame.lines;
|
yDim = frame.lines;
|
||||||
|
|
||||||
outputRef = new int[numComp][];
|
outputData = new int[numComp][];
|
||||||
|
|
||||||
// TODO: Support 4 components (RGBA/YCCA/CMYK/YCCK), others?
|
for (int componentIndex = 0; componentIndex < numComp; ++componentIndex) {
|
||||||
if (numComp == 1) {
|
// not a good use of memory, but I had trouble packing bytes into int. some values exceeded 255.
|
||||||
outputData = new int[xDim * yDim];
|
outputData[componentIndex] = new int[xDim * yDim];
|
||||||
outputRef[0] = outputData;
|
|
||||||
}
|
}
|
||||||
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;
|
final int firstValue[] = new int[numComp];
|
||||||
outputRef[1] = outputGreenData;
|
for (int i = 0; i < numComp; i++) {
|
||||||
outputRef[2] = outputBlueData;
|
firstValue[i] = (1 << (precision - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int pred[] = new int[numComp];
|
||||||
|
|
||||||
scanNum++;
|
scanNum++;
|
||||||
|
|
||||||
while (true) { // Decode one scan
|
while (true) { // Decode one scan
|
||||||
int temp[] = new int[1]; // to store remainder bits
|
int temp[] = new int[1]; // to store remainder bits
|
||||||
int index[] = new int[1];
|
int index[] = new int[1];
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
System.arraycopy(firstValue, 0, pred, 0, numComp);
|
||||||
pred[i] = (1 << (precision - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restartInterval == 0) {
|
if (restartInterval == 0) {
|
||||||
current = decode(pred, temp, index);
|
current = decode(pred, temp, index);
|
||||||
@ -285,9 +275,10 @@ final class JPEGLosslessDecoder {
|
|||||||
readNumber();
|
readNumber();
|
||||||
current = input.readUnsignedShort();
|
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));
|
} while ((current != JPEG.EOI) && ((xLoc < xDim) && (yLoc < yDim)) && (scanNum == 0));
|
||||||
|
|
||||||
return outputRef;
|
return outputData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processWarningOccured(String warning) {
|
private void processWarningOccured(String warning) {
|
||||||
@ -341,7 +332,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return decodeRGB(prev, temp, index);
|
return decodeRGB(prev, temp, index);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return -1;
|
return decodeAny(prev, temp, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,6 +344,7 @@ final class JPEGLosslessDecoder {
|
|||||||
prev[0] = (1 << (frame.samplePrecision - 1));
|
prev[0] = (1 << (frame.samplePrecision - 1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
final int[] outputData = this.outputData[0];
|
||||||
switch (selection) {
|
switch (selection) {
|
||||||
case 2:
|
case 2:
|
||||||
prev[0] = getPreviousY(outputData);
|
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 {
|
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) {
|
switch (selection) {
|
||||||
case 2:
|
case 2:
|
||||||
prev[0] = getPreviousY(outputRedData);
|
prev[0] = getPreviousY(outputRedData);
|
||||||
@ -437,6 +432,43 @@ final class JPEGLosslessDecoder {
|
|||||||
break;
|
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 value, actab[], dctab[];
|
||||||
int qtab[];
|
int qtab[];
|
||||||
|
|
||||||
@ -694,14 +726,17 @@ final class JPEGLosslessDecoder {
|
|||||||
if (numComp == 1) {
|
if (numComp == 1) {
|
||||||
outputSingle(pred);
|
outputSingle(pred);
|
||||||
}
|
}
|
||||||
else {
|
else if (numComp == 3) {
|
||||||
outputRGB(pred);
|
outputRGB(pred);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
outputAny(pred);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputSingle(final int pred[]) {
|
private void outputSingle(final int pred[]) {
|
||||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||||
outputData[(yLoc * xDim) + xLoc] = mask & pred[0];
|
outputData[0][(yLoc * xDim) + xLoc] = mask & pred[0];
|
||||||
xLoc++;
|
xLoc++;
|
||||||
|
|
||||||
if (xLoc >= xDim) {
|
if (xLoc >= xDim) {
|
||||||
@ -713,9 +748,25 @@ final class JPEGLosslessDecoder {
|
|||||||
|
|
||||||
private void outputRGB(final int pred[]) {
|
private void outputRGB(final int pred[]) {
|
||||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||||
outputRedData[(yLoc * xDim) + xLoc] = pred[0];
|
final int index = (yLoc * xDim) + xLoc;
|
||||||
outputGreenData[(yLoc * xDim) + xLoc] = pred[1];
|
outputData[0][index] = pred[0];
|
||||||
outputBlueData[(yLoc * xDim) + xLoc] = pred[2];
|
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++;
|
xLoc++;
|
||||||
|
|
||||||
if (xLoc >= xDim) {
|
if (xLoc >= xDim) {
|
||||||
|
@ -39,9 +39,12 @@ import javax.imageio.metadata.IIOMetadata;
|
|||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
import static java.lang.String.format;
|
||||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TIFFStreamMetadata.
|
* 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) {
|
switch (value) {
|
||||||
case "BIG_ENDIAN":
|
case "BIG_ENDIAN":
|
||||||
return ByteOrder.BIG_ENDIAN;
|
return ByteOrder.BIG_ENDIAN;
|
||||||
@ -138,6 +141,11 @@ public final class TIFFStreamMetadata extends IIOMetadata {
|
|||||||
}
|
}
|
||||||
else if (streamMetadata != null) {
|
else if (streamMetadata != null) {
|
||||||
TIFFStreamMetadata metadata = new TIFFStreamMetadata();
|
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
|
// Will throw exception if stream format differs from native
|
||||||
metadata.mergeTree(metadata.nativeMetadataFormatName, streamMetadata.getAsTree(metadata.nativeMetadataFormatName));
|
metadata.mergeTree(metadata.nativeMetadataFormatName, streamMetadata.getAsTree(metadata.nativeMetadataFormatName));
|
||||||
imageOutput.setByteOrder(metadata.byteOrder);
|
imageOutput.setByteOrder(metadata.byteOrder);
|
||||||
|
@ -40,6 +40,7 @@ import javax.imageio.metadata.IIOMetadataNode;
|
|||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.nio.ByteOrder;
|
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 com.twelvemonkeys.imageio.plugins.tiff.TIFFStreamMetadata.SUN_NATIVE_STREAM_METADATA_FORMAT_NAME;
|
||||||
import static java.nio.ByteOrder.BIG_ENDIAN;
|
import static java.nio.ByteOrder.BIG_ENDIAN;
|
||||||
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||||
@ -85,9 +86,10 @@ public class TIFFStreamMetadataTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigureStreamForegin() throws IIOInvalidTreeException {
|
public void testConfigureStreamForeign() throws IIOInvalidTreeException {
|
||||||
ImageOutputStream stream = mock(ImageOutputStream.class);
|
ImageOutputStream stream = mock(ImageOutputStream.class);
|
||||||
IIOMetadata metadata = mock(IIOMetadata.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));
|
when(metadata.getAsTree(eq(SUN_NATIVE_STREAM_METADATA_FORMAT_NAME))).thenReturn(createForeignTree(LITTLE_ENDIAN));
|
||||||
|
|
||||||
TIFFStreamMetadata.configureStreamByteOrder(metadata, stream);
|
TIFFStreamMetadata.configureStreamByteOrder(metadata, stream);
|
||||||
@ -95,6 +97,24 @@ public class TIFFStreamMetadataTest {
|
|||||||
verify(stream, only()).setByteOrder(LITTLE_ENDIAN);
|
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) {
|
private IIOMetadataNode createForeignTree(ByteOrder order) {
|
||||||
IIOMetadataNode root = new IIOMetadataNode(SUN_NATIVE_STREAM_METADATA_FORMAT_NAME);
|
IIOMetadataNode root = new IIOMetadataNode(SUN_NATIVE_STREAM_METADATA_FORMAT_NAME);
|
||||||
IIOMetadataNode byteOrder = new IIOMetadataNode("ByteOrder");
|
IIOMetadataNode byteOrder = new IIOMetadataNode("ByteOrder");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user