Preparing JPEGImageReader for extension.

This commit is contained in:
Harald Kuhr 2015-04-30 10:20:35 +02:00
parent 2db58dc73d
commit 051a1dcb5b
3 changed files with 138 additions and 59 deletions

View File

@ -28,7 +28,6 @@
package com.twelvemonkeys.imageio.plugins.jpeg; package com.twelvemonkeys.imageio.plugins.jpeg;
import com.twelvemonkeys.image.ImageUtil;
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.metadata.CompoundDirectory; import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
@ -152,10 +151,10 @@ public class JPEGImageReader extends ImageReaderBase {
/** Cached list of JPEG segments we filter from the underlying stream */ /** Cached list of JPEG segments we filter from the underlying stream */
private List<JPEGSegment> segments; private List<JPEGSegment> segments;
JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) { protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
super(provider); super(provider);
this.delegate = Validate.notNull(delegate);
this.delegate = Validate.notNull(delegate);
progressDelegator = new ProgressDelegator(); progressDelegator = new ProgressDelegator();
} }
@ -298,7 +297,9 @@ public class JPEGImageReader extends ImageReaderBase {
super.setInput(input, seekForwardOnly, ignoreMetadata); super.setInput(input, seekForwardOnly, ignoreMetadata);
// JPEGSegmentImageInputStream that filters out/skips bad/unnecessary segments // JPEGSegmentImageInputStream that filters out/skips bad/unnecessary segments
delegate.setInput(imageInput != null ? new JPEGSegmentImageInputStream(imageInput) : null, seekForwardOnly, ignoreMetadata); delegate.setInput(imageInput != null
? new JPEGSegmentImageInputStream(imageInput)
: null, seekForwardOnly, ignoreMetadata);
} }
@Override @Override
@ -629,7 +630,7 @@ public class JPEGImageReader extends ImageReaderBase {
} }
} }
private ICC_Profile ensureDisplayProfile(final ICC_Profile profile) { protected ICC_Profile ensureDisplayProfile(final ICC_Profile profile) {
// NOTE: This is probably not the right way to do it... :-P // NOTE: This is probably not the right way to do it... :-P
// TODO: Consider moving method to ColorSpaces class or new class in imageio.color package // TODO: Consider moving method to ColorSpaces class or new class in imageio.color package
@ -835,7 +836,7 @@ public class JPEGImageReader extends ImageReaderBase {
return data; return data;
} }
ICC_Profile getEmbeddedICCProfile(final boolean allowBadIndexes) throws IOException { protected ICC_Profile getEmbeddedICCProfile(final boolean allowBadIndexes) throws IOException {
// ICC v 1.42 (2006) annex B: // ICC v 1.42 (2006) annex B:
// APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination) // APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination)
// + 1 byte chunk number + 1 byte chunk count (allows ICC profiles chunked in multiple APP2 segments) // + 1 byte chunk number + 1 byte chunk count (allows ICC profiles chunked in multiple APP2 segments)
@ -1301,7 +1302,58 @@ public class JPEGImageReader extends ImageReaderBase {
} }
public static void main(final String[] args) throws IOException { public static void main(final String[] args) throws IOException {
for (final String arg : args) { ImageIO.setUseCache(false);
int subX = 1;
int subY = 1;
Rectangle roi = null;
boolean metadata = false;
boolean thumbnails = false;
for (int argIdx = 0; argIdx < args.length; argIdx++) {
final String arg = args[argIdx];
if (arg.charAt(0) == '-') {
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx) {
String[] sub = args[++argIdx].split(",");
try {
subX = Integer.parseInt(sub[0]);
subY = sub.length > 1 ? Integer.parseInt(sub[1]) : subX;
}
catch (NumberFormatException e) {
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
}
}
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx) {
String[] region = args[++argIdx].split(",");
try {
if (region.length >= 4) {
roi = new Rectangle(Integer.parseInt(region[0]), Integer.parseInt(region[2]), Integer.parseInt(region[2]), Integer.parseInt(region[3]));
}
else {
roi = new Rectangle(Integer.parseInt(region[0]), Integer.parseInt(region[2]));
}
}
catch (IndexOutOfBoundsException | NumberFormatException e) {
System.err.println("Bad source region ([x,y,]w, h): '" + args[argIdx] + "'");
}
}
else if (arg.equals("-m") || arg.equals("--metadata")) {
metadata = true;
}
else if (arg.equals("-t") || arg.equals("--thumbnails")) {
thumbnails = true;
}
else {
System.err.println("Unknown argument: '" + arg + "'");
System.exit(-1);
}
continue;
}
File file = new File(arg); File file = new File(arg);
ImageInputStream input = ImageIO.createImageInputStream(file); ImageInputStream input = ImageIO.createImageInputStream(file);
@ -1317,15 +1369,15 @@ public class JPEGImageReader extends ImageReaderBase {
continue; continue;
} }
ImageReader reader = readers.next(); final ImageReader reader = readers.next();
// System.err.println("Reading using: " + reader); System.err.println("Reading using: " + reader);
reader.addIIOReadWarningListener(new IIOReadWarningListener() { reader.addIIOReadWarningListener(new IIOReadWarningListener() {
public void warningOccurred(ImageReader source, String warning) { public void warningOccurred(ImageReader source, String warning) {
System.err.println("Warning: " + arg + ": " + warning); System.err.println("Warning: " + arg + ": " + warning);
} }
}); });
reader.addIIOReadProgressListener(new ProgressListenerBase() { final ProgressListenerBase listener = new ProgressListenerBase() {
private static final int MAX_W = 78; private static final int MAX_W = 78;
int lastProgress = 0; int lastProgress = 0;
@ -1354,10 +1406,12 @@ public class JPEGImageReader extends ImageReaderBase {
System.out.println("]"); System.out.println("]");
} }
}); };
reader.addIIOReadProgressListener(listener);
reader.setInput(input); reader.setInput(input);
try {
// For a tables-only image, we can't read image, but we should get metadata. // For a tables-only image, we can't read image, but we should get metadata.
if (reader.getNumImages(true) == 0) { if (reader.getNumImages(true) == 0) {
IIOMetadata streamMetadata = reader.getStreamMetadata(); IIOMetadata streamMetadata = reader.getStreamMetadata();
@ -1366,17 +1420,21 @@ public class JPEGImageReader extends ImageReaderBase {
continue; continue;
} }
try { BufferedImage image;
ImageReadParam param = reader.getDefaultReadParam(); ImageReadParam param = reader.getDefaultReadParam();
// if (args.length > 1) { if (subX > 1 || subY > 1 || roi != null) {
// int sub = Integer.parseInt(args[1]); param.setSourceSubsampling(subX, subY, 0, 0);
// int sub = 4; param.setSourceRegion(roi);
// param.setSourceSubsampling(sub, sub, 0, 0);
// } image = reader.getImageTypes(0).next().createBufferedImage((reader.getWidth(0) + subX - 1)/ subX, (reader.getHeight(0) + subY - 1) / subY);
BufferedImage image = reader.getImageTypes(0).next().createBufferedImage(reader.getWidth(0), reader.getHeight(0)); }
else {
image = reader.getImageTypes(0).next().createBufferedImage(reader.getWidth(0), reader.getHeight(0));
}
param.setDestination(image); param.setDestination(image);
// long start = System.currentTimeMillis(); long start = DEBUG ? System.currentTimeMillis() : 0;
try { try {
image = reader.read(0, param); image = reader.read(0, param);
} }
@ -1387,12 +1445,13 @@ public class JPEGImageReader extends ImageReaderBase {
continue; continue;
} }
} }
// System.err.println("Read time: " + (System.currentTimeMillis() - start) + " ms");
// System.err.println("image: " + image);
if (DEBUG) {
System.err.println("Read time: " + (System.currentTimeMillis() - start) + " ms");
System.err.println("image: " + image);
}
// image = new ResampleOp(reader.getWidth(0) / 4, reader.getHeight(0) / 4, ResampleOp.FILTER_LANCZOS).filter(image, null); /*
int maxW = 1280; int maxW = 1280;
int maxH = 800; int maxH = 800;
if (image.getWidth() > maxW || image.getHeight() > maxH) { if (image.getWidth() > maxW || image.getHeight() > maxH) {
@ -1406,9 +1465,11 @@ public class JPEGImageReader extends ImageReaderBase {
} }
// System.err.println("Scale time: " + (System.currentTimeMillis() - start) + " ms"); // System.err.println("Scale time: " + (System.currentTimeMillis() - start) + " ms");
} }
*/
showIt(image, String.format("Image: %s [%d x %d]", file.getName(), reader.getWidth(0), reader.getHeight(0))); showIt(image, String.format("Image: %s [%d x %d]", file.getName(), reader.getWidth(0), reader.getHeight(0)));
if (metadata) {
try { try {
IIOMetadata imageMetadata = reader.getImageMetadata(0); IIOMetadata imageMetadata = reader.getImageMetadata(0);
System.out.println("Metadata for File: " + file.getName()); System.out.println("Metadata for File: " + file.getName());
@ -1423,11 +1484,19 @@ public class JPEGImageReader extends ImageReaderBase {
} }
System.out.println(); System.out.println();
}
catch (IIOException e) {
System.err.println("Could not read thumbnails: " + arg + ": " + e.getMessage());
e.printStackTrace();
}
}
if (thumbnails) {
try {
int numThumbnails = reader.getNumThumbnails(0); int numThumbnails = reader.getNumThumbnails(0);
for (int i = 0; i < numThumbnails; i++) { for (int i = 0; i < numThumbnails; i++) {
BufferedImage thumbnail = reader.readThumbnail(0, i); BufferedImage thumbnail = reader.readThumbnail(0, i);
// System.err.println("thumbnail: " + thumbnail); // System.err.println("thumbnail: " + thumbnail);
showIt(thumbnail, String.format("Thumbnail: %s [%d x %d]", file.getName(), thumbnail.getWidth(), thumbnail.getHeight())); showIt(thumbnail, String.format("Thumbnail: %s [%d x %d]", file.getName(), thumbnail.getWidth(), thumbnail.getHeight()));
} }
} }
@ -1436,6 +1505,7 @@ public class JPEGImageReader extends ImageReaderBase {
e.printStackTrace(); e.printStackTrace();
} }
} }
}
catch (Throwable t) { catch (Throwable t) {
System.err.println(file); System.err.println(file);
t.printStackTrace(); t.printStackTrace();

View File

@ -29,6 +29,7 @@
package com.twelvemonkeys.imageio.plugins.jpeg; package com.twelvemonkeys.imageio.plugins.jpeg;
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase; import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
import com.twelvemonkeys.imageio.util.IIOUtil; import com.twelvemonkeys.imageio.util.IIOUtil;
import com.twelvemonkeys.lang.Validate; import com.twelvemonkeys.lang.Validate;
@ -48,14 +49,14 @@ import java.util.Locale;
* @version $Id: JPEGImageReaderSpi.java,v 1.0 24.01.11 22.12 haraldk Exp$ * @version $Id: JPEGImageReaderSpi.java,v 1.0 24.01.11 22.12 haraldk Exp$
*/ */
public class JPEGImageReaderSpi extends ImageReaderSpiBase { public class JPEGImageReaderSpi extends ImageReaderSpiBase {
private ImageReaderSpi delegateProvider; protected ImageReaderSpi delegateProvider;
/** /**
* Constructor for use by {@link javax.imageio.spi.IIORegistry} only. * Constructor for use by {@link javax.imageio.spi.IIORegistry} only.
* The instance created will not work without being properly registered. * The instance created will not work without being properly registered.
*/ */
public JPEGImageReaderSpi() { public JPEGImageReaderSpi() {
super(new JPEGProviderInfo()); this(new JPEGProviderInfo());
} }
/** /**
@ -69,6 +70,15 @@ public class JPEGImageReaderSpi extends ImageReaderSpiBase {
this.delegateProvider = Validate.notNull(delegateProvider); this.delegateProvider = Validate.notNull(delegateProvider);
} }
/**
* Constructor for subclasses.
*
* @param info
*/
protected JPEGImageReaderSpi(final ReaderWriterProviderInfo info) {
super(info);
}
static ImageReaderSpi lookupDelegateProvider(final ServiceRegistry registry) { static ImageReaderSpi lookupDelegateProvider(final ServiceRegistry registry) {
Iterator<ImageReaderSpi> providers = registry.getServiceProviders(ImageReaderSpi.class, true); Iterator<ImageReaderSpi> providers = registry.getServiceProviders(ImageReaderSpi.class, true);
@ -83,7 +93,7 @@ public class JPEGImageReaderSpi extends ImageReaderSpiBase {
return null; return null;
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked", "deprecation"})
@Override @Override
public void onRegistration(final ServiceRegistry registry, final Class<?> category) { public void onRegistration(final ServiceRegistry registry, final Class<?> category) {
if (delegateProvider == null) { if (delegateProvider == null) {

View File

@ -63,8 +63,7 @@ import static org.junit.Assume.assumeNoException;
import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeNotNull;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.*;
import static org.mockito.Mockito.verify;
/** /**
* JPEGImageReaderTest * JPEGImageReaderTest
@ -75,9 +74,9 @@ import static org.mockito.Mockito.verify;
*/ */
public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader> { public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader> {
private static final JPEGImageReaderSpi SPI = new JPEGImageReaderSpi(lookupDelegateProvider()); protected static final JPEGImageReaderSpi SPI = new JPEGImageReaderSpi(lookupDelegateProvider());
private static ImageReaderSpi lookupDelegateProvider() { protected static ImageReaderSpi lookupDelegateProvider() {
return JPEGImageReaderSpi.lookupDelegateProvider(IIORegistry.getDefaultInstance()); return JPEGImageReaderSpi.lookupDelegateProvider(IIORegistry.getDefaultInstance());
} }
@ -370,7 +369,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
assertEquals(1772, image.getWidth()); assertEquals(1772, image.getWidth());
assertEquals(8, image.getHeight()); assertEquals(8, image.getHeight());
verify(warningListener).warningOccurred(eq(reader), anyString()); verify(warningListener, atLeast(1)).warningOccurred(eq(reader), anyString());
} }
@Test @Test