mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 03:55:28 -04:00
TMI-26: TIFF writer support with JPEG encoder
This commit is contained in:
parent
b0e667e683
commit
47a18c63d7
@ -0,0 +1,55 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
import javax.imageio.stream.ImageOutputStreamImpl;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SubImageOutputStream.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: harald.kuhr$
|
||||||
|
* @version $Id: SubImageOutputStream.java,v 1.0 30/03/15 harald.kuhr Exp$
|
||||||
|
*/
|
||||||
|
public class SubImageOutputStream extends ImageOutputStreamImpl {
|
||||||
|
private final ImageOutputStream stream;
|
||||||
|
|
||||||
|
public SubImageOutputStream(final ImageOutputStream stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
stream.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
|
stream.write(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return stream.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
return stream.read(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCached() {
|
||||||
|
return stream.isCached();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCachedMemory() {
|
||||||
|
return stream.isCachedMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCachedFile() {
|
||||||
|
return stream.isCachedFile();
|
||||||
|
}
|
||||||
|
}
|
@ -39,16 +39,20 @@ import java.util.Locale;
|
|||||||
* @version $Id: TIFFImageWriteParam.java,v 1.0 18.09.13 12:47 haraldk Exp$
|
* @version $Id: TIFFImageWriteParam.java,v 1.0 18.09.13 12:47 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public final class TIFFImageWriteParam extends ImageWriteParam {
|
public final class TIFFImageWriteParam extends ImageWriteParam {
|
||||||
// TODO: Support no compression (None/1)
|
// TODO: Support CCITT Modified Huffman compression (2) BASELINE!!
|
||||||
// TODO: Support ZLIB (/Deflate) compression (8)
|
// TODO: Support CCITT T.4 (3)
|
||||||
// TODO: Support PackBits compression (32773)
|
// TODO: Support CCITT T.6 (4)
|
||||||
// TODO: Support JPEG compression (7)
|
|
||||||
// TODO: Support CCITT Modified Huffman compression (2)
|
|
||||||
// TODO: Support LZW compression (5)?
|
|
||||||
// TODO: Support JBIG compression via ImageIO plugin/delegate?
|
// TODO: Support JBIG compression via ImageIO plugin/delegate?
|
||||||
// TODO: Support JPEG2000 compression via ImageIO plugin/delegate?
|
// TODO: Support JPEG2000 compression via ImageIO plugin/delegate?
|
||||||
// TODO: Support tiling
|
// TODO: Support tiling
|
||||||
// TODO: Support predictor. See TIFF 6.0 Specification, Section 14: "Differencing Predictor", page 64.
|
// TODO: Support OPTIONAL predictor. See TIFF 6.0 Specification, Section 14: "Differencing Predictor", page 64.
|
||||||
|
|
||||||
|
// DONE:
|
||||||
|
// Support no compression (None/1)
|
||||||
|
// Support ZLIB (/Deflate) compression (8)
|
||||||
|
// Support PackBits compression (32773)
|
||||||
|
// Support LZW compression (5)?
|
||||||
|
// Support JPEG compression (7)
|
||||||
|
|
||||||
TIFFImageWriteParam() {
|
TIFFImageWriteParam() {
|
||||||
this(Locale.getDefault());
|
this(Locale.getDefault());
|
||||||
@ -59,7 +63,12 @@ public final class TIFFImageWriteParam extends ImageWriteParam {
|
|||||||
|
|
||||||
// NOTE: We use the same spelling/casing as the JAI equivalent to be as compatible as possible
|
// NOTE: We use the same spelling/casing as the JAI equivalent to be as compatible as possible
|
||||||
// See: http://download.java.net/media/jai-imageio/javadoc/1.1/com/sun/media/imageio/plugins/tiff/TIFFImageWriteParam.html
|
// See: http://download.java.net/media/jai-imageio/javadoc/1.1/com/sun/media/imageio/plugins/tiff/TIFFImageWriteParam.html
|
||||||
compressionTypes = new String[] {"None", /* "CCITT RLE", "CCITT T.4", "CCITT T.6", */ "LZW", "JPEG", "ZLib", "PackBits", "Deflate", /* "EXIF JPEG" */ };
|
compressionTypes = new String[] {
|
||||||
|
"None",
|
||||||
|
null, null, null,/* "CCITT RLE", "CCITT T.4", "CCITT T.6", */
|
||||||
|
"LZW", "JPEG", "ZLib", "PackBits", "Deflate",
|
||||||
|
null/* "EXIF JPEG" */ // A well-defined form of "Old-style JPEG", no tables/process, only 513 (offset) and 514 (length)
|
||||||
|
};
|
||||||
compressionType = compressionTypes[0];
|
compressionType = compressionTypes[0];
|
||||||
canWriteCompressed = true;
|
canWriteCompressed = true;
|
||||||
}
|
}
|
||||||
@ -102,6 +111,9 @@ public final class TIFFImageWriteParam extends ImageWriteParam {
|
|||||||
else if (param.getCompressionType().equals("JPEG")) {
|
else if (param.getCompressionType().equals("JPEG")) {
|
||||||
return TIFFExtension.COMPRESSION_JPEG;
|
return TIFFExtension.COMPRESSION_JPEG;
|
||||||
}
|
}
|
||||||
|
// else if (param.getCompressionType().equals("EXIF JPEG")) {
|
||||||
|
// return TIFFExtension.COMPRESSION_OLD_JPEG;
|
||||||
|
// }
|
||||||
|
|
||||||
throw new IllegalArgumentException(String.format("Unsupported compression type: %s", param.getCompressionType()));
|
throw new IllegalArgumentException(String.format("Unsupported compression type: %s", param.getCompressionType()));
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ import com.twelvemonkeys.imageio.metadata.Entry;
|
|||||||
import com.twelvemonkeys.imageio.metadata.exif.EXIFWriter;
|
import com.twelvemonkeys.imageio.metadata.exif.EXIFWriter;
|
||||||
import com.twelvemonkeys.imageio.metadata.exif.Rational;
|
import com.twelvemonkeys.imageio.metadata.exif.Rational;
|
||||||
import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
||||||
|
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||||
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||||
@ -157,10 +158,11 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
entries.add(new TIFFEntry(TIFF.TAG_EXTRA_SAMPLES, TIFFBaseline.EXTRASAMPLE_UNSPECIFIED));
|
entries.add(new TIFFEntry(TIFF.TAG_EXTRA_SAMPLES, TIFFBaseline.EXTRASAMPLE_UNSPECIFIED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write compression field from param or metadata
|
// Write compression field from param or metadata
|
||||||
int compression = TIFFImageWriteParam.getCompressionType(param);
|
int compression = TIFFImageWriteParam.getCompressionType(param);
|
||||||
entries.add(new TIFFEntry(TIFF.TAG_COMPRESSION, compression));
|
entries.add(new TIFFEntry(TIFF.TAG_COMPRESSION, compression));
|
||||||
// TODO: Let param control
|
// TODO: Let param control predictor
|
||||||
switch (compression) {
|
switch (compression) {
|
||||||
case TIFFExtension.COMPRESSION_ZLIB:
|
case TIFFExtension.COMPRESSION_ZLIB:
|
||||||
case TIFFExtension.COMPRESSION_DEFLATE:
|
case TIFFExtension.COMPRESSION_DEFLATE:
|
||||||
@ -169,7 +171,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
int photometric = getPhotometricInterpretation(colorModel);
|
int photometric = compression == TIFFExtension.COMPRESSION_JPEG ?
|
||||||
|
TIFFExtension.PHOTOMETRIC_YCBCR :
|
||||||
|
getPhotometricInterpretation(colorModel);
|
||||||
entries.add(new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, photometric));
|
entries.add(new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, photometric));
|
||||||
|
|
||||||
if (photometric == TIFFBaseline.PHOTOMETRIC_PALETTE && colorModel instanceof IndexColorModel) {
|
if (photometric == TIFFBaseline.PHOTOMETRIC_PALETTE && colorModel instanceof IndexColorModel) {
|
||||||
@ -179,9 +183,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
else {
|
else {
|
||||||
entries.add(new TIFFEntry(TIFF.TAG_SAMPLES_PER_PIXEL, numComponents));
|
entries.add(new TIFFEntry(TIFF.TAG_SAMPLES_PER_PIXEL, numComponents));
|
||||||
|
|
||||||
// TODO: What is the default TIFF color space?
|
// Note: Assuming sRGB to be the default RGB interpretation
|
||||||
ColorSpace colorSpace = colorModel.getColorSpace();
|
ColorSpace colorSpace = colorModel.getColorSpace();
|
||||||
if (colorSpace instanceof ICC_ColorSpace) {
|
if (colorSpace instanceof ICC_ColorSpace && !colorSpace.isCS_sRGB()) {
|
||||||
entries.add(new TIFFEntry(TIFF.TAG_ICC_PROFILE, ((ICC_ColorSpace) colorSpace).getProfile().getData()));
|
entries.add(new TIFFEntry(TIFF.TAG_ICC_PROFILE, ((ICC_ColorSpace) colorSpace).getProfile().getData()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,8 +232,26 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Create compressor stream per Tile/Strip
|
// TODO: Create compressor stream per Tile/Strip
|
||||||
// Write image data
|
if (compression == TIFFExtension.COMPRESSION_JPEG) {
|
||||||
writeImageData(createCompressorStream(renderedImage, param), renderedImage, numComponents, bandOffsets, bitOffsets);
|
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("JPEG");
|
||||||
|
if (!writers.hasNext()) {
|
||||||
|
// This can only happen if someone deliberately uninstalled it
|
||||||
|
throw new IIOException("No JPEG ImageWriter found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageWriter jpegWriter = writers.next();
|
||||||
|
try {
|
||||||
|
jpegWriter.setOutput(new SubImageOutputStream(imageOutput));
|
||||||
|
jpegWriter.write(renderedImage);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
jpegWriter.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Write image data
|
||||||
|
writeImageData(createCompressorStream(renderedImage, param), renderedImage, numComponents, bandOffsets, bitOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Update IFD0-pointer, and write IFD
|
// TODO: Update IFD0-pointer, and write IFD
|
||||||
if (compression != TIFFBaseline.COMPRESSION_NONE) {
|
if (compression != TIFFBaseline.COMPRESSION_NONE) {
|
||||||
@ -304,7 +326,8 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
output.length: 12600399
|
output.length: 12600399
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: Use predictor only by default for -PackBits,- LZW and ZLib/Deflate, unless explicitly disabled (ImageWriteParam)
|
// Use predictor by default for LZW and ZLib/Deflate
|
||||||
|
// TODO: Unless explicitly disabled in TIFFImageWriteParam
|
||||||
int compression = TIFFImageWriteParam.getCompressionType(param);
|
int compression = TIFFImageWriteParam.getCompressionType(param);
|
||||||
OutputStream stream;
|
OutputStream stream;
|
||||||
|
|
||||||
@ -321,7 +344,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
case TIFFExtension.COMPRESSION_ZLIB:
|
case TIFFExtension.COMPRESSION_ZLIB:
|
||||||
case TIFFExtension.COMPRESSION_DEFLATE:
|
case TIFFExtension.COMPRESSION_DEFLATE:
|
||||||
int deflateSetting = Deflater.BEST_SPEED; // This is consistent with default compression quality being 1.0 and 0 meaning max compression....
|
int deflateSetting = Deflater.BEST_SPEED; // This is consistent with default compression quality being 1.0 and 0 meaning max compression...
|
||||||
if (param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT) {
|
if (param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT) {
|
||||||
// TODO: Determine how to interpret compression quality...
|
// TODO: Determine how to interpret compression quality...
|
||||||
// Docs says:
|
// Docs says:
|
||||||
@ -740,4 +763,5 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
TIFFImageReader.showIt(read, output.getName());
|
TIFFImageReader.showIt(read, output.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user