mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 20:15:28 -04:00
JPEG Exif/thumbnail fixes.
(cherry picked from commit fbc738f2d4836e82315831774c0e722a4984e967)
This commit is contained in:
parent
efe5f3c34a
commit
d5e664cdcc
@ -30,37 +30,6 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.color.ColorSpace;
|
|
||||||
import java.awt.color.ICC_ColorSpace;
|
|
||||||
import java.awt.color.ICC_Profile;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.io.DataInput;
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.SequenceInputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageReadParam;
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.event.IIOReadUpdateListener;
|
|
||||||
import javax.imageio.event.IIOReadWarningListener;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
||||||
@ -72,7 +41,6 @@ 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.metadata.tiff.TIFF;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||||
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
@ -80,6 +48,24 @@ import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
|||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
import com.twelvemonkeys.xml.XMLSerializer;
|
import com.twelvemonkeys.xml.XMLSerializer;
|
||||||
|
|
||||||
|
import javax.imageio.*;
|
||||||
|
import javax.imageio.event.IIOReadUpdateListener;
|
||||||
|
import javax.imageio.event.IIOReadWarningListener;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.color.ICC_ColorSpace;
|
||||||
|
import java.awt.color.ICC_Profile;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JPEG {@code ImageReader} implementation based on the JRE {@code JPEGImageReader},
|
* A JPEG {@code ImageReader} implementation based on the JRE {@code JPEGImageReader},
|
||||||
* that adds support and properly handles cases where the JRE version throws exceptions.
|
* that adds support and properly handles cases where the JRE version throws exceptions.
|
||||||
@ -140,7 +126,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
private List<Segment> segments;
|
private List<Segment> segments;
|
||||||
|
|
||||||
private int currentStreamIndex = 0;
|
private int currentStreamIndex = 0;
|
||||||
private List<Long> streamOffsets = new ArrayList<>();
|
private final List<Long> streamOffsets = new ArrayList<>();
|
||||||
|
|
||||||
protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
||||||
super(provider);
|
super(provider);
|
||||||
@ -197,10 +183,10 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IIOException ignore) {
|
catch (IIOException e) {
|
||||||
// May happen if no SOF is found, in case we'll just fall through
|
// May happen if no SOF is found, in case we'll just fall through
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ignore.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,26 +733,26 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
long lastKnownSOIOffset = streamOffsets.get(streamOffsets.size() - 1);
|
long lastKnownSOIOffset = streamOffsets.get(streamOffsets.size() - 1);
|
||||||
imageInput.seek(lastKnownSOIOffset);
|
imageInput.seek(lastKnownSOIOffset);
|
||||||
|
|
||||||
try (ImageInputStream stream = new BufferedImageInputStream(imageInput)) { // Extreme (10s -> 50ms) speedup if imageInput is FileIIS
|
try {
|
||||||
for (int i = streamOffsets.size() - 1; i < imageIndex; i++) {
|
for (int i = streamOffsets.size() - 1; i < imageIndex; i++) {
|
||||||
long start = 0;
|
long start = 0;
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
System.out.println(String.format("Start seeking for image index %d", i + 1));
|
System.out.printf("Start seeking for image index %d%n", i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to skip over segments, as they may contain JPEG markers (eg. JFXX or EXIF thumbnail)
|
// Need to skip over segments, as they may contain JPEG markers (eg. JFXX or EXIF thumbnail)
|
||||||
JPEGSegmentUtil.readSegments(stream, Collections.<Integer, List<String>>emptyMap());
|
JPEGSegmentUtil.readSegments(imageInput, Collections.<Integer, List<String>>emptyMap());
|
||||||
|
|
||||||
// Now, search for EOI and following SOI...
|
// Now, search for EOI and following SOI...
|
||||||
int marker;
|
int marker;
|
||||||
while ((marker = stream.read()) != -1) {
|
while ((marker = imageInput.read()) != -1) {
|
||||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.EOI) {
|
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.EOI) {
|
||||||
// Found EOI, now the SOI should be nearby...
|
// Found EOI, now the SOI should be nearby...
|
||||||
while ((marker = stream.read()) != -1) {
|
while ((marker = imageInput.read()) != -1) {
|
||||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.SOI) {
|
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.SOI) {
|
||||||
long nextSOIOffset = stream.getStreamPosition() - 2;
|
long nextSOIOffset = imageInput.getStreamPosition() - 2;
|
||||||
imageInput.seek(nextSOIOffset);
|
imageInput.seek(nextSOIOffset);
|
||||||
streamOffsets.add(nextSOIOffset);
|
streamOffsets.add(nextSOIOffset);
|
||||||
|
|
||||||
@ -780,10 +766,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println(String.format("Seek in %d ms", System.currentTimeMillis() - start));
|
System.out.printf("Seek in %d ms%n", System.currentTimeMillis() - start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (EOFException eof) {
|
catch (EOFException eof) {
|
||||||
IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("Image index " + imageIndex + " not found in stream");
|
IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("Image index " + imageIndex + " not found in stream");
|
||||||
@ -843,9 +828,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
return JPEGSegmentUtil.readSegments(imageInput, JPEGSegmentUtil.ALL_SEGMENTS);
|
return JPEGSegmentUtil.readSegments(imageInput, JPEGSegmentUtil.ALL_SEGMENTS);
|
||||||
}
|
}
|
||||||
catch (IIOException | IllegalArgumentException ignore) {
|
catch (IIOException | IllegalArgumentException e) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ignore.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@ -1162,6 +1147,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
if (jpegLength > 0 && jpegOffset + jpegLength <= stream.length()) {
|
if (jpegLength > 0 && jpegOffset + jpegLength <= stream.length()) {
|
||||||
// Verify first bytes are FFD8
|
// Verify first bytes are FFD8
|
||||||
stream.seek(jpegOffset);
|
stream.seek(jpegOffset);
|
||||||
|
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
if (stream.readUnsignedShort() == JPEG.SOI) {
|
if (stream.readUnsignedShort() == JPEG.SOI) {
|
||||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||||
}
|
}
|
||||||
@ -1189,7 +1175,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
// EXIFThumbnailReader?
|
// EXIFThumbnailReader?
|
||||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with empty or incomplete uncompressed thumbnail");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
||||||
@ -1246,7 +1234,15 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
||||||
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
||||||
|
|
||||||
return thumbnails.get(thumbnailIndex).read();
|
// processThumbnailStarted(imageIndex, thumbnailIndex);
|
||||||
|
// processThumbnailProgress(0f);
|
||||||
|
|
||||||
|
BufferedImage thumbnail = thumbnails.get(thumbnailIndex).read();;
|
||||||
|
|
||||||
|
// processThumbnailProgress(100f);
|
||||||
|
// processThumbnailComplete();
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
@ -1423,7 +1419,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
final String arg = args[argIdx];
|
final String arg = args[argIdx];
|
||||||
|
|
||||||
if (arg.charAt(0) == '-') {
|
if (arg.charAt(0) == '-') {
|
||||||
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx) {
|
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx + 1) {
|
||||||
String[] sub = args[++argIdx].split(",");
|
String[] sub = args[++argIdx].split(",");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1442,7 +1438,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
|
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx) {
|
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx + 1) {
|
||||||
String[] region = args[++argIdx].split(",");
|
String[] region = args[++argIdx].split(",");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user