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$
|
||||
*/
|
||||
public final class TIFFImageWriteParam extends ImageWriteParam {
|
||||
// TODO: Support no compression (None/1)
|
||||
// TODO: Support ZLIB (/Deflate) compression (8)
|
||||
// TODO: Support PackBits compression (32773)
|
||||
// TODO: Support JPEG compression (7)
|
||||
// TODO: Support CCITT Modified Huffman compression (2)
|
||||
// TODO: Support LZW compression (5)?
|
||||
// TODO: Support CCITT Modified Huffman compression (2) BASELINE!!
|
||||
// TODO: Support CCITT T.4 (3)
|
||||
// TODO: Support CCITT T.6 (4)
|
||||
// TODO: Support JBIG compression via ImageIO plugin/delegate?
|
||||
// TODO: Support JPEG2000 compression via ImageIO plugin/delegate?
|
||||
// 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() {
|
||||
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
|
||||
// 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];
|
||||
canWriteCompressed = true;
|
||||
}
|
||||
@ -102,6 +111,9 @@ public final class TIFFImageWriteParam extends ImageWriteParam {
|
||||
else if (param.getCompressionType().equals("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()));
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import com.twelvemonkeys.imageio.metadata.Entry;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.EXIFWriter;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.Rational;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// Write compression field from param or metadata
|
||||
int compression = TIFFImageWriteParam.getCompressionType(param);
|
||||
entries.add(new TIFFEntry(TIFF.TAG_COMPRESSION, compression));
|
||||
// TODO: Let param control
|
||||
// TODO: Let param control predictor
|
||||
switch (compression) {
|
||||
case TIFFExtension.COMPRESSION_ZLIB:
|
||||
case TIFFExtension.COMPRESSION_DEFLATE:
|
||||
@ -169,7 +171,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
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));
|
||||
|
||||
if (photometric == TIFFBaseline.PHOTOMETRIC_PALETTE && colorModel instanceof IndexColorModel) {
|
||||
@ -179,9 +183,9 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
else {
|
||||
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();
|
||||
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()));
|
||||
}
|
||||
}
|
||||
@ -228,8 +232,26 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
}
|
||||
|
||||
// TODO: Create compressor stream per Tile/Strip
|
||||
// Write image data
|
||||
writeImageData(createCompressorStream(renderedImage, param), renderedImage, numComponents, bandOffsets, bitOffsets);
|
||||
if (compression == TIFFExtension.COMPRESSION_JPEG) {
|
||||
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
|
||||
if (compression != TIFFBaseline.COMPRESSION_NONE) {
|
||||
@ -304,7 +326,8 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
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);
|
||||
OutputStream stream;
|
||||
|
||||
@ -321,7 +344,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
|
||||
case TIFFExtension.COMPRESSION_ZLIB:
|
||||
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) {
|
||||
// TODO: Determine how to interpret compression quality...
|
||||
// Docs says:
|
||||
@ -740,4 +763,5 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
|
||||
TIFFImageReader.showIt(read, output.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user