sgoeschl / java-image-processing-survival-guide

Draft for an article about image processing in Java land
Apache License 2.0
107 stars 16 forks source link

PNG processing of fails with "Unsupported JPEG process: SOF type" using Twelve monkey's library #5

Open thekalinga opened 9 years ago

thekalinga commented 9 years ago

Hi,

Since you mentioned in one of your presentation that the library is tested with all the images in the same project, I'm opening this ticket.

When I tried processing test-image-48-bit-reduced-to-24-bit.png with twelve monkey's library, I get the following error

javax.imageio.IIOException: Unsupported JPEG process: SOF type 0xce
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method)
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1236)
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1039)
    at com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader.read(Unknown Source)
    at javax.imageio.ImageReader.read(ImageReader.java:939)
    at com.test.TmTest.getRawImageMetadata(ToJpgImageReprocessorTest.java:67)
    at com.test.TmTest.access$000(ToJpgImageReprocessorTest.java:37)
    at com.test.TmTest$TestImageProvider.imageFileMetadataAndRawImageStream(ToJpgImageReprocessorTest.java:260)
    at com.test.TmTest$TestImageProvider.lambda$null$1(ToJpgImageReprocessorTest.java:240)
    at java.util.Iterator.forEachRemaining(Iterator.java:116)
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at com.test.TmTest$TestImageProvider.lambda$provideInputStreams$2(ToJpgImageReprocessorTest.java:237)
    at java.util.Iterator.forEachRemaining(Iterator.java:116)
    at com.test.TmTest$TestImageProvider.provideInputStreams(ToJpgImageReprocessorTest.java:234)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at junitparams.internal.parameters.ParamsFromMethodCommon.getDataFromMethod(ParamsFromMethodCommon.java:37)
    at junitparams.internal.parameters.ParametersFromExternalClassProvideMethod.gatherParamsFromAllMethodsFrom(ParametersFromExternalClassProvideMethod.java:71)
    at junitparams.internal.parameters.ParametersFromExternalClassProvideMethod.getParamsFromSourceHierarchy(ParametersFromExternalClassProvideMethod.java:52)
    at junitparams.internal.parameters.ParametersFromExternalClassProvideMethod.fillResultWithAllParamProviderMethods(ParametersFromExternalClassProvideMethod.java:40)
    at junitparams.internal.parameters.ParametersFromExternalClassProvideMethod.getParameters(ParametersFromExternalClassProvideMethod.java:25)
    at junitparams.internal.parameters.ParametersReader.read(ParametersReader.java:36)
    at junitparams.internal.TestMethod.parametersSets(TestMethod.java:121)
    at junitparams.internal.TestMethod.isIgnored(TestMethod.java:78)
    at junitparams.internal.TestMethod.isNotIgnored(TestMethod.java:85)
    at junitparams.internal.ParameterisedTestClassRunner.addTestMethodForEachParamSet(ParameterisedTestClassRunner.java:87)
    at junitparams.internal.ParameterisedTestClassRunner.computeFrameworkMethods(ParameterisedTestClassRunner.java:61)
    at junitparams.internal.ParameterisedTestClassRunner.<init>(ParameterisedTestClassRunner.java:37)
    at junitparams.JUnitParamsRunner.<init>(JUnitParamsRunner.java:393)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
    at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
    at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:36)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:41)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
[2015-08-28 07:30:57.743] log4j2 - ???? TRACE [main] --- ToJpgImageReprocessor: Image format name : JPEG

Process finished with exit code 255

Can you please let me know what the issue is?

haraldk commented 9 years ago

Hi Ashok,

There seems to be two different issues here:

1: The image you are mentioning is a PNG file. It reads fine, using the standard JRE PNGImageReader.

If you try to force reading it using the JPEGImageReader, you should get an error saying "Not a JPEG stream (starts with: 0x8950, expected SOI: 0xffd8)".

2: The stack trace you have posted is from the JPEGImageReader. So most likely, it is from a different file.

Anyway, the JPEG standard specifies a lot (16, in fact) different algorithms (or "processes") for compressing image data. Most JPEGs uses only baseline or progressive options, with standard Huffman coding, so most decoders will not implement all of these options. Ours don't. The error message "Unsupported JPEG process: SOF type 0xce" is just a technical way of saying, "Sorry, we can't decode this JPEG because it is using progressive DCT process, with differential arithmetic coding, and we* haven't implemented that".

*) We, in this case, is the Independent JPEG Group (IJG). The TwelveMonkeys JPEG plugin delegates all encoding/decoding to the native code provided by the JRE, which for all Oracle derived and standard OpenJDK JREs will be the IJG's LibJPEG.

Best regards,

Harald K

thekalinga commented 9 years ago

Hi,

The failure is due to test-image-differential-progressive-arithmetic.jpg, which you rightly said. Is it because this image contains a "process" that is not currently part of twelve monkeys?

I'm sorry. I din't pay enough attention to that error and made a wrong assumption.

Also, I tried transforming test-image-48-bit-reduced-to-24-bit.png -> JPG and it generated 0 bytes JPG, without throwing any exception.

Any idea what could be causing this issue (As you might have noticed, I'm quite novice in image processing basics).

Here is the snippet I borrowed for this transformation

    ImageInputStream imageInputStream = ImageIO.createImageInputStream(rawImageStream);
    Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageInputStream);
    ImageReader imageReader = imageReaders.next();
    imageReader.setInput(imageInputStream);

    BufferedImage bufferedImage = imageReader.read(0, reader.getDefaultReadParam());

    boolean hasAlpha = bufferedImage.getColorModel().hasAlpha()
        || bufferedImage.getType() == BufferedImage.TYPE_4BYTE_ABGR
        || bufferedImage.getType() == BufferedImage.TYPE_BYTE_INDEXED;

    if (hasAlpha) {
    BufferedImage rgbBufferedImage =
        new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(),
            BufferedImage.TYPE_INT_RGB);
    Graphics2D graphics = rgbBufferedImage.createGraphics();
    graphics.drawImage(bufferedImage, 0, 0, null);
    graphics.dispose();
    bufferedImage = rgbBufferedImage;
    }

Thanks again


Edit: Corrected the description to be more accurate