mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 03:25:28 -04:00
TMI-JPEG: Now does a better effort to gloss over metadata issues in underlying stream.
This commit is contained in:
parent
47425e2ca0
commit
0ff99afe6d
@ -41,13 +41,16 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
|||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import javax.imageio.*;
|
||||||
import javax.imageio.event.IIOReadUpdateListener;
|
import javax.imageio.event.IIOReadUpdateListener;
|
||||||
import javax.imageio.event.IIOReadWarningListener;
|
import javax.imageio.event.IIOReadWarningListener;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_ColorSpace;
|
import java.awt.color.ICC_ColorSpace;
|
||||||
@ -89,6 +92,8 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// TODO: Fix the (stream) metadata inconsistency issues.
|
// TODO: Fix the (stream) metadata inconsistency issues.
|
||||||
// - Sun JPEGMetadata class does not (and can not be made to) support CMYK data.. We need to create all new metadata classes.. :-/
|
// - Sun JPEGMetadata class does not (and can not be made to) support CMYK data.. We need to create all new metadata classes.. :-/
|
||||||
|
|
||||||
|
// TODO: Allow automatic rotation based on EXIF rotation field?
|
||||||
|
|
||||||
private final static boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.jpeg.debug"));
|
private final static boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.jpeg.debug"));
|
||||||
|
|
||||||
/** Segment identifiers for the JPEG segments we care about reading. */
|
/** Segment identifiers for the JPEG segments we care about reading. */
|
||||||
@ -280,7 +285,19 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
assertInput();
|
assertInput();
|
||||||
checkBounds(imageIndex);
|
checkBounds(imageIndex);
|
||||||
|
|
||||||
// TODO: This test is not good enough for JDK7, which seems to have fixed some of the issues.
|
// CompoundDirectory exif = getExif();
|
||||||
|
// if (exif != null) {
|
||||||
|
// System.err.println("exif: " + exif);
|
||||||
|
// System.err.println("Orientation: " + exif.getEntryById(TIFF.TAG_ORIENTATION));
|
||||||
|
// Entry exifIFDEntry = exif.getEntryById(TIFF.TAG_EXIF_IFD);
|
||||||
|
//
|
||||||
|
// if (exifIFDEntry != null) {
|
||||||
|
// Directory exifIFD = (Directory) exifIFDEntry.getValue();
|
||||||
|
// System.err.println("PixelXDimension: " + exifIFD.getEntryById(EXIF.TAG_PIXEL_X_DIMENSION));
|
||||||
|
// System.err.println("PixelYDimension: " + exifIFD.getEntryById(EXIF.TAG_PIXEL_Y_DIMENSION));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// NOTE: We rely on the fact that unsupported images has no valid types. This is kind of hacky.
|
// NOTE: We rely on the fact that unsupported images has no valid types. This is kind of hacky.
|
||||||
// Might want to look into the metadata, to see if there's a better way to identify these.
|
// Might want to look into the metadata, to see if there's a better way to identify these.
|
||||||
boolean unsupported = !delegate.getImageTypes(imageIndex).hasNext();
|
boolean unsupported = !delegate.getImageTypes(imageIndex).hasNext();
|
||||||
@ -288,7 +305,6 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
ICC_Profile profile = getEmbeddedICCProfile(false);
|
ICC_Profile profile = getEmbeddedICCProfile(false);
|
||||||
AdobeDCTSegment adobeDCT = getAdobeDCT();
|
AdobeDCTSegment adobeDCT = getAdobeDCT();
|
||||||
|
|
||||||
// TODO: Probably something bogus here, as ICC profile isn't applied if reading through the delegate any more...
|
|
||||||
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
||||||
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
|
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
|
||||||
if (delegate.canReadRaster() && (
|
if (delegate.canReadRaster() && (
|
||||||
@ -442,6 +458,8 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
// Apply further color conversion for explicit color space, or just copy the pixels into place
|
// Apply further color conversion for explicit color space, or just copy the pixels into place
|
||||||
if (convert != null) {
|
if (convert != null) {
|
||||||
convert.filter(src, dest);
|
convert.filter(src, dest);
|
||||||
|
// WritableRaster filtered = convert.filter(src, null);
|
||||||
|
// new AffineTransformOp(AffineTransform.getRotateInstance(2 * Math.PI, filtered.getWidth() / 2.0, filtered.getHeight() / 2.0), null).filter(filtered, dest);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dest.setRect(0, 0, src);
|
dest.setRect(0, 0, src);
|
||||||
@ -748,6 +766,27 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CompoundDirectory getExif() throws IOException {
|
||||||
|
List<JPEGSegment> exifSegments = getAppSegments(JPEG.APP1, "Exif");
|
||||||
|
|
||||||
|
if (!exifSegments.isEmpty()) {
|
||||||
|
JPEGSegment exif = exifSegments.get(0);
|
||||||
|
InputStream data = exif.data();
|
||||||
|
|
||||||
|
if (data.read() == -1) { // Read pad
|
||||||
|
processWarningOccurred("Exif chunk has no data.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImageInputStream stream = ImageIO.createImageInputStream(data);
|
||||||
|
return (CompoundDirectory) new EXIFReader().read(stream);
|
||||||
|
|
||||||
|
// TODO: Directory offset of thumbnail is wrong/relative to container stream, causing trouble for the EXIFReader...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Util method?
|
// TODO: Util method?
|
||||||
static byte[] readFully(DataInput stream, int len) throws IOException {
|
static byte[] readFully(DataInput stream, int len) throws IOException {
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
@ -911,7 +950,7 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
processWarningOccurred("Exif chunk has no data.");
|
processWarningOccurred("Exif chunk has no data.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImageInputStream stream = ImageIO.createImageInputStream(data);
|
ImageInputStream stream = new MemoryCacheImageInputStream(data);
|
||||||
CompoundDirectory exifMetadata = (CompoundDirectory) new EXIFReader().read(stream);
|
CompoundDirectory exifMetadata = (CompoundDirectory) new EXIFReader().read(stream);
|
||||||
|
|
||||||
if (exifMetadata.directoryCount() == 2) {
|
if (exifMetadata.directoryCount() == 2) {
|
||||||
@ -965,16 +1004,15 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
return thumbnails.get(thumbnailIndex).read();
|
return thumbnails.get(thumbnailIndex).read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
||||||
// TODO: Nice try, but no cigar.. getAsTree does not return a "live" view, so any modifications are thrown away
|
|
||||||
IIOMetadata metadata = delegate.getImageMetadata(imageIndex);
|
IIOMetadata metadata = delegate.getImageMetadata(imageIndex);
|
||||||
|
|
||||||
// IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName());
|
String format = metadata.getNativeMetadataFormatName();
|
||||||
// Node jpegVariety = tree.getElementsByTagName("JPEGvariety").item(0);
|
IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(format);
|
||||||
|
Node jpegVariety = tree.getElementsByTagName("JPEGvariety").item(0);
|
||||||
|
|
||||||
// TODO: Allow EXIF (as app1EXIF) in the JPEGvariety (sic) node.
|
// TODO: Allow EXIF (as app1EXIF) in the JPEGvariety (sic) node.
|
||||||
// As EXIF is (a subset of) TIFF, (and the EXIF data is a valid TIFF stream) probably use something like:
|
// As EXIF is (a subset of) TIFF, (and the EXIF data is a valid TIFF stream) probably use something like:
|
||||||
@ -996,12 +1034,17 @@ public class JPEGImageReader extends ImageReaderBase {
|
|||||||
the version to the method/constructor used to obtain an IIOMetadata object.)
|
the version to the method/constructor used to obtain an IIOMetadata object.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// IIOMetadataNode app2ICC = new IIOMetadataNode("app2ICC");
|
IIOMetadataNode app2ICC = new IIOMetadataNode("app2ICC");
|
||||||
// app2ICC.setUserObject(getEmbeddedICCProfile());
|
app2ICC.setUserObject(getEmbeddedICCProfile(true));
|
||||||
// jpegVariety.getFirstChild().appendChild(app2ICC);
|
Node jpegVarietyFirstChild = jpegVariety.getFirstChild();
|
||||||
|
if (jpegVarietyFirstChild != null) {
|
||||||
|
jpegVarietyFirstChild.appendChild(app2ICC);
|
||||||
|
}
|
||||||
|
|
||||||
// new XMLSerializer(System.err, System.getProperty("file.encoding")).serialize(tree, false);
|
// new XMLSerializer(System.err, System.getProperty("file.encoding")).serialize(tree, false);
|
||||||
|
|
||||||
|
metadata.mergeTree(format, tree);
|
||||||
|
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user