JDK-8022632 : Reading a PNG file fails because of WBMPImageReaderSpi.canDecodeInput()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.imageio
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • Submitted: 2013-08-08
  • Updated: 2013-10-17
  • Resolved: 2013-10-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b112Fixed
Description
FULL PRODUCT VERSION :
java version  " 1.7.0_25 " 
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Darwin Kernel Version 11.4.2: Thu Aug 23 16:25:48 PDT 2012; root:xnu-1699.32.7~1/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
While inspecting PNG header, com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi.canDecodeInput() throws IOException because the first byte of a PNG header is 137 (unsigned byte), which was read as a negative value (signed byte). Hence it doesn't call  " stream.reset() "  and when the image is passed to PNGImageReader, the first byte is skipped and the reader falsely throws  " javax.imageio.IIOException: Bad PNG signature! " .

REGRESSION.  Last worked in version 6u43

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
just call javax.imageio.ImageIO.read() with any PNG file.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Should read a PNG file successfully.
ACTUAL -
It throws  " javax.imageio.IIOException: Bad PNG signature! "  exception.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
javax.imageio.IIOException: I/O error reading PNG header!
at com.sun.imageio.plugins.png.PNGImageReader.readHeader(PNGImageReader.java:315)
at com.sun.imageio.plugins.png.PNGImageReader.readMetadata(PNGImageReader.java:654)
at com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1229)
at com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1577)
at javax.imageio.ImageIO.read(ImageIO.java:1448)
at com.syslore.image.reader.BufferedImageBlobImageReader.read(BufferedImageBlobImageReader.java:34)
at com.syslore.image.reader.BlobImageFactory.create(BlobImageFactory.java:61)
at com.syslore.flowmanager.autocrop.SimpleAutoCropper.crop(SimpleAutoCropper.java:56)
at com.syslore.flowmanager.preprocess.AutoCropperBlobImageBuilder.build(AutoCropperBlobImageBuilder.java:55)
at com.syslore.flowmanager.preprocess.AutoCropperBlobImageBuilderTest.testCropSimpleImage(AutoCropperBlobImageBuilderTest.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:55)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:42)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:75)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:49)
at sun.reflect.GeneratedMethodAccessor10.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:99)
at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.TypeCastDispatch.dispatch(TypeCastDispatch.java:30)
at org.gradle.messaging.remote.internal.WorkerProtocol.handleIncoming(WorkerProtocol.java:53)
at org.gradle.messaging.remote.internal.WorkerProtocol.handleIncoming(WorkerProtocol.java:31)
at org.gradle.messaging.remote.internal.ProtocolStack$ProtocolStage.handleIncoming(ProtocolStack.java:167)
at org.gradle.messaging.remote.internal.ProtocolStack$BottomStage.handleIncoming(ProtocolStack.java:277)
at org.gradle.messaging.remote.internal.ProtocolStack$BottomConnection$1.run(ProtocolStack.java:299)
at org.gradle.messaging.remote.internal.ProtocolStack$ExecuteRunnable.dispatch(ProtocolStack.java:120)
at org.gradle.messaging.remote.internal.ProtocolStack$ExecuteRunnable.dispatch(ProtocolStack.java:116)
at org.gradle.messaging.dispatch.AsyncDispatch.dispatchMessages(AsyncDispatch.java:132)
at org.gradle.messaging.dispatch.AsyncDispatch.access$000(AsyncDispatch.java:33)
at org.gradle.messaging.dispatch.AsyncDispatch$1.run(AsyncDispatch.java:72)
at org.gradle.messaging.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: javax.imageio.IIOException: Bad PNG signature!
at com.sun.imageio.plugins.png.PNGImageReader.readHeader(PNGImageReader.java:242)
... 60 more

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
ImageInputStream imageInputStream = new FileImageInputStream(new File( " simple_10x10.png " ));

BufferedImage bufferedImage = javax.imageio.ImageIO.read(imageInputStream);
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround found.
Comments
isn't a regression from jdk8 pov
02-10-2013

The reason of the problem is incorrect implementation of the read() method in the image input stream supplied in the test. The spec says that the method read() should return integer value in range [0 ... 255] http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#read%28%29 Instead, the test stream returns negative integers for bytes greater than 127, that leads to an IOException during plugin detection. However, this peculiarity in the test discovers a mistake in canDecodeInput() of WBMP spi: it does not reset the stream in case of I/O problems. It results in a failure of other plugins (in particular PNG), who start reading the stream for a wrong position. Suggested fix: http://cr.openjdk.java.net/~bae/8022632/webrev.00/
30-08-2013

Original test from submitter.
09-08-2013

Failed to reproduce the problem, need more info how to reproduce.
09-08-2013

I failed to reproduce the problem. I will request more info from submitter. However, last time when the code in question (WBMPImageReaderSpi.canDecodeInput()) has been touched is 2009 (jdk7 b63), so this problem (if it really exists) affects all releases of jdk7.
09-08-2013

With the test provided by the submitter, the problem can be reproduced on early releases of jdk7 (in particular, I have reproduced it with 7u7 on windows).
09-08-2013

needs to know Introduced In release / affected version first time
08-08-2013