mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 03:25:28 -04:00
Clean-up
This commit is contained in:
parent
1292c95040
commit
ee424583c4
@ -26,8 +26,7 @@ class DelegateTileDecoder extends TileDecoder {
|
|||||||
protected final ImageReader delegate;
|
protected final ImageReader delegate;
|
||||||
protected final ImageReadParam param;
|
protected final ImageReadParam param;
|
||||||
|
|
||||||
// TODO: Naming... Is this only due to color space conversion? Is it because we need to read raster?
|
private final Predicate<ImageReader> needsRasterConversion;
|
||||||
private final Predicate<ImageReader> needsConversion;
|
|
||||||
private final RasterConverter converter;
|
private final RasterConverter converter;
|
||||||
private Boolean readRasterAndConvert;
|
private Boolean readRasterAndConvert;
|
||||||
|
|
||||||
@ -35,11 +34,11 @@ class DelegateTileDecoder extends TileDecoder {
|
|||||||
this(warningListener, createDelegate(format), originalParam, imageReader -> false, null);
|
this(warningListener, createDelegate(format), originalParam, imageReader -> false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateTileDecoder(final IIOReadWarningListener warningListener, final String format, final ImageReadParam originalParam, final Predicate<ImageReader> needsConversion, final RasterConverter converter) throws IOException {
|
DelegateTileDecoder(final IIOReadWarningListener warningListener, final String format, final ImageReadParam originalParam, final Predicate<ImageReader> needsRasterConversion, final RasterConverter converter) throws IOException {
|
||||||
this(warningListener, createDelegate(format), originalParam, needsConversion, converter);
|
this(warningListener, createDelegate(format), originalParam, needsRasterConversion, converter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DelegateTileDecoder(final IIOReadWarningListener warningListener, final ImageReader delegate, final ImageReadParam originalParam, final Predicate<ImageReader> needsConversion, final RasterConverter converter) {
|
private DelegateTileDecoder(final IIOReadWarningListener warningListener, final ImageReader delegate, final ImageReadParam originalParam, final Predicate<ImageReader> needsRasterConversion, final RasterConverter converter) {
|
||||||
super(warningListener);
|
super(warningListener);
|
||||||
|
|
||||||
this.delegate = notNull(delegate, "delegate");
|
this.delegate = notNull(delegate, "delegate");
|
||||||
@ -48,7 +47,7 @@ class DelegateTileDecoder extends TileDecoder {
|
|||||||
param = delegate.getDefaultReadParam();
|
param = delegate.getDefaultReadParam();
|
||||||
param.setSourceSubsampling(originalParam.getSourceXSubsampling(), originalParam.getSourceYSubsampling(), 0, 0);
|
param.setSourceSubsampling(originalParam.getSourceXSubsampling(), originalParam.getSourceYSubsampling(), 0, 0);
|
||||||
|
|
||||||
this.needsConversion = needsConversion;
|
this.needsRasterConversion = needsRasterConversion;
|
||||||
this.converter = converter;
|
this.converter = converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ class DelegateTileDecoder extends TileDecoder {
|
|||||||
// If it's the TwelveMonkeys one, we will be able to read JPEG Lossless etc.
|
// If it's the TwelveMonkeys one, we will be able to read JPEG Lossless etc.
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(format);
|
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(format);
|
||||||
if (!readers.hasNext()) {
|
if (!readers.hasNext()) {
|
||||||
throw new IIOException("Could not instantiate " + format + "ImageReader");
|
throw new IIOException("No ImageReader registered for '" + format + "' format");
|
||||||
}
|
}
|
||||||
|
|
||||||
return readers.next();
|
return readers.next();
|
||||||
@ -70,7 +69,7 @@ class DelegateTileDecoder extends TileDecoder {
|
|||||||
|
|
||||||
if (readRasterAndConvert == null) {
|
if (readRasterAndConvert == null) {
|
||||||
// All tiles in an image will use the same format, test once and cache result
|
// All tiles in an image will use the same format, test once and cache result
|
||||||
readRasterAndConvert = needsConversion.test(delegate);
|
readRasterAndConvert = needsRasterConversion.test(delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!readRasterAndConvert) {
|
if (!readRasterAndConvert) {
|
||||||
|
@ -15,8 +15,8 @@ import java.util.function.Predicate;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: JPEGTileDecoder.java,v 1.0 09/11/2023 haraldk Exp$
|
* @version $Id: JPEGTileDecoder.java,v 1.0 09/11/2023 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
class JPEGTileDecoder extends DelegateTileDecoder {
|
final class JPEGTileDecoder extends DelegateTileDecoder {
|
||||||
JPEGTileDecoder(final IIOReadWarningListener warningListener, final byte[] jpegTables, final ImageReadParam originalParam, final Predicate<ImageReader> needsConversion, final RasterConverter converter) throws IOException {
|
JPEGTileDecoder(final IIOReadWarningListener warningListener, final byte[] jpegTables, final int numTiles, final ImageReadParam originalParam, final Predicate<ImageReader> needsConversion, final RasterConverter converter) throws IOException {
|
||||||
super(warningListener, "JPEG", originalParam, needsConversion, converter);
|
super(warningListener, "JPEG", originalParam, needsConversion, converter);
|
||||||
|
|
||||||
if (jpegTables != null) {
|
if (jpegTables != null) {
|
||||||
@ -29,9 +29,9 @@ class JPEGTileDecoder extends DelegateTileDecoder {
|
|||||||
// http://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#abbrev
|
// http://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#abbrev
|
||||||
delegate.getStreamMetadata();
|
delegate.getStreamMetadata();
|
||||||
}
|
}
|
||||||
else {
|
else if (numTiles > 1) {
|
||||||
warningListener.warningOccurred(delegate, "Missing JPEGTables for tiled/striped TIFF with compression: 7 (JPEG)");
|
warningListener.warningOccurred(delegate, "Missing JPEGTables for tiled/striped TIFF with compression: 7 (JPEG)");
|
||||||
// ...and the JPEG reader will probably choke on missing tables...
|
// ...and the JPEG reader might choke on missing tables...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1172,13 +1172,18 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TIFFCustom.COMPRESSION_WEBP:
|
|
||||||
case TIFFExtension.COMPRESSION_JPEG:
|
case TIFFExtension.COMPRESSION_JPEG:
|
||||||
|
case TIFFCustom.COMPRESSION_WEBP:
|
||||||
|
case TIFFCustom.COMPRESSION_JBIG:
|
||||||
|
case TIFFCustom.COMPRESSION_JPEG2000:
|
||||||
readUsingDelegate(imageIndex, compression, interpretation, width, height, tilesAcross, tilesDown, stripTileWidth, stripTileHeight, srcRegion, stripTileOffsets, stripTileByteCounts, param, destination, samplesInTile);
|
readUsingDelegate(imageIndex, compression, interpretation, width, height, tilesAcross, tilesDown, stripTileWidth, stripTileHeight, srcRegion, stripTileOffsets, stripTileByteCounts, param, destination, samplesInTile);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TIFFExtension.COMPRESSION_OLD_JPEG: {
|
case TIFFExtension.COMPRESSION_OLD_JPEG: {
|
||||||
// JPEG ('old-style' JPEG, later overridden in Technote2)
|
// JPEG ('old-style' JPEG, later overridden in Technote2)
|
||||||
// http://www.remotesensing.org/libtiff/TIFFTechNote2.html
|
// http://www.remotesensing.org/libtiff/TIFFTechNote2.html
|
||||||
|
// TODO: Rewrite to use readUsingDelegate with special case handling inside OldJPEGTileDecoder
|
||||||
|
|
||||||
int srcRow = 0;
|
int srcRow = 0;
|
||||||
Boolean needsCSConversion = null;
|
Boolean needsCSConversion = null;
|
||||||
|
|
||||||
@ -1497,10 +1502,8 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
case TIFFCustom.COMPRESSION_PIXARFILM:
|
case TIFFCustom.COMPRESSION_PIXARFILM:
|
||||||
case TIFFCustom.COMPRESSION_PIXARLOG:
|
case TIFFCustom.COMPRESSION_PIXARLOG:
|
||||||
case TIFFCustom.COMPRESSION_DCS:
|
case TIFFCustom.COMPRESSION_DCS:
|
||||||
case TIFFCustom.COMPRESSION_JBIG: // Doable with JBIG plugin?
|
|
||||||
case TIFFCustom.COMPRESSION_SGILOG:
|
case TIFFCustom.COMPRESSION_SGILOG:
|
||||||
case TIFFCustom.COMPRESSION_SGILOG24:
|
case TIFFCustom.COMPRESSION_SGILOG24:
|
||||||
case TIFFCustom.COMPRESSION_JPEG2000: // Doable with JPEG2000 plugin?
|
|
||||||
throw new IIOException("Unsupported TIFF Compression value: " + compression);
|
throw new IIOException("Unsupported TIFF Compression value: " + compression);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1521,7 +1524,7 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
// JPEG ('new-style' JPEG)
|
// JPEG ('new-style' JPEG)
|
||||||
|
|
||||||
// Read data
|
// Read data
|
||||||
try (TileDecoder tileDecoder = createTileDecoder(param, compression, interpretation, samplesInTile)) {
|
try (TileDecoder tileDecoder = createTileDecoder(param, compression, interpretation, tilesAcross * tilesDown, samplesInTile)) {
|
||||||
processImageStarted(imageIndex); // Better yet, would be to delegate read progress here...
|
processImageStarted(imageIndex); // Better yet, would be to delegate read progress here...
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
@ -1569,37 +1572,39 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DelegateTileDecoder createTileDecoder(ImageReadParam param, int compression, final int interpretation, final int samplesInTile) throws IOException {
|
private TileDecoder createTileDecoder(ImageReadParam param, int compression, final int interpretation, final int numTiles, final int samplesInTile) throws IOException {
|
||||||
if (compression == TIFFExtension.COMPRESSION_JPEG) {
|
try {
|
||||||
// JPEG_TABLES should be a full JPEG 'abbreviated table specification', containing:
|
IIOReadWarningListener warningListener = (source, warning) -> processWarningOccurred(warning);
|
||||||
// SOI, DQT, DHT, (optional markers that we ignore)..., EOI
|
|
||||||
Entry tablesEntry = currentIFD.getEntryById(TIFF.TAG_JPEG_TABLES);
|
|
||||||
byte[] tablesValue = tablesEntry != null ? (byte[]) tablesEntry.getValue() : null;
|
|
||||||
|
|
||||||
Predicate<ImageReader> needsConversion = (reader) -> needsCSConversion(compression, interpretation, readJPEGMetadataSafe(reader));
|
if (compression == TIFFExtension.COMPRESSION_JPEG) {
|
||||||
RasterConverter csConverter = (raster) -> {
|
// JPEG_TABLES should be a full JPEG 'abbreviated table specification', containing:
|
||||||
switch (raster.getTransferType()) {
|
// SOI, DQT, DHT, (optional markers that we ignore)..., EOI
|
||||||
case DataBuffer.TYPE_BYTE:
|
Entry tablesEntry = currentIFD.getEntryById(TIFF.TAG_JPEG_TABLES);
|
||||||
normalizeColor(interpretation, samplesInTile, ((DataBufferByte) raster.getDataBuffer()).getData());
|
byte[] jpegTables = tablesEntry != null ? (byte[]) tablesEntry.getValue() : null;
|
||||||
break;
|
|
||||||
case DataBuffer.TYPE_USHORT:
|
|
||||||
normalizeColor(interpretation, samplesInTile, ((DataBufferUShort) raster.getDataBuffer()).getData());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unsupported transfer type: " + raster.getTransferType());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new JPEGTileDecoder((source, warning) -> processWarningOccurred(warning), tablesValue, param, needsConversion, csConverter);
|
Predicate<ImageReader> needsConversion = (reader) -> needsCSConversion(compression, interpretation, readJPEGMetadataSafe(reader));
|
||||||
|
RasterConverter normalize = (raster) -> normalizeColor(interpretation, samplesInTile, raster);
|
||||||
|
|
||||||
|
return new JPEGTileDecoder(warningListener, jpegTables, numTiles, param, needsConversion, normalize);
|
||||||
|
}
|
||||||
|
else if (compression == TIFFCustom.COMPRESSION_JBIG) {
|
||||||
|
// TODO: Create interop test suite using third party plugin.
|
||||||
|
// LEAD Tools have one sample file: https://leadtools.com/support/forum/resource.ashx?a=545&b=1
|
||||||
|
// Haven't found any plugins. There is however a JBIG2 plugin...
|
||||||
|
return new DelegateTileDecoder(warningListener, "JBIG", param);
|
||||||
|
}
|
||||||
|
else if (compression == TIFFCustom.COMPRESSION_JPEG2000) {
|
||||||
|
// TODO: Create interop test suite using third party plugin
|
||||||
|
// LEAD Tools have one sample file: https://leadtools.com/support/forum/resource.ashx?a=545&b=1
|
||||||
|
// The open source JAI JP2K reader decodes this as a fully black image...
|
||||||
|
return new DelegateTileDecoder(warningListener, "JPEG2000", param);
|
||||||
|
}
|
||||||
|
else if (compression == TIFFCustom.COMPRESSION_WEBP) {
|
||||||
|
return new DelegateTileDecoder(warningListener, "WebP", param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (compression == TIFFCustom.COMPRESSION_JBIG) {
|
catch (IIOException e) {
|
||||||
return new DelegateTileDecoder((source, warning) -> processWarningOccurred(warning), "JBIG", param);
|
throw new IIOException("Unsupported TIFF Compression value: " + compression, e);
|
||||||
}
|
|
||||||
else if (compression == TIFFCustom.COMPRESSION_JPEG2000) {
|
|
||||||
return new DelegateTileDecoder((source, warning) -> processWarningOccurred(warning), "JP2K", param);
|
|
||||||
}
|
|
||||||
else if (compression == TIFFCustom.COMPRESSION_WEBP) {
|
|
||||||
return new DelegateTileDecoder((source, warning) -> processWarningOccurred(warning), "WebP", param);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IIOException("Unsupported TIFF Compression value: " + compression);
|
throw new IIOException("Unsupported TIFF Compression value: " + compression);
|
||||||
@ -2165,6 +2170,19 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void normalizeColor(int interpretation, int numBands, Raster raster) throws IOException {
|
||||||
|
switch (raster.getTransferType()) {
|
||||||
|
case DataBuffer.TYPE_BYTE:
|
||||||
|
normalizeColor(interpretation, numBands, ((DataBufferByte) raster.getDataBuffer()).getData());
|
||||||
|
break;
|
||||||
|
case DataBuffer.TYPE_USHORT:
|
||||||
|
normalizeColor(interpretation, numBands, ((DataBufferUShort) raster.getDataBuffer()).getData());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unsupported transfer type: " + raster.getTransferType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void normalizeColor(int photometricInterpretation, int numBands, byte[] data) throws IOException {
|
private void normalizeColor(int photometricInterpretation, int numBands, byte[] data) throws IOException {
|
||||||
switch (photometricInterpretation) {
|
switch (photometricInterpretation) {
|
||||||
case TIFFBaseline.PHOTOMETRIC_WHITE_IS_ZERO:
|
case TIFFBaseline.PHOTOMETRIC_WHITE_IS_ZERO:
|
||||||
|
@ -6,6 +6,8 @@ import java.awt.*;
|
|||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TileDecoder.
|
* TileDecoder.
|
||||||
*
|
*
|
||||||
@ -18,7 +20,7 @@ abstract class TileDecoder implements AutoCloseable {
|
|||||||
protected final IIOReadWarningListener warningListener;
|
protected final IIOReadWarningListener warningListener;
|
||||||
|
|
||||||
public TileDecoder(IIOReadWarningListener warningListener) {
|
public TileDecoder(IIOReadWarningListener warningListener) {
|
||||||
this.warningListener = warningListener;
|
this.warningListener = notNull(warningListener, "warningListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract void decodeTile(ImageInputStream input, Rectangle sourceRegion, Point destinationOffset, BufferedImage destination) throws IOException;
|
abstract void decodeTile(ImageInputStream input, Rectangle sourceRegion, Point destinationOffset, BufferedImage destination) throws IOException;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user