4

I have a weird JPEG image file that ImageIO.read() fails to load:

ImageIO.read(new URL("http://nocturne.wmw.cc/a.jpg"));

Any ideas?

Exception in thread "main" javax.imageio.IIOException: Unsupported Image Type
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:995)
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:966)
    at javax.imageio.ImageIO.read(ImageIO.java:1448)
    at javax.imageio.ImageIO.read(ImageIO.java:1400)
    at Main.main(Main.java:23)

imageurl

Grim
  • 1,938
  • 10
  • 56
  • 123
  • it throws `"Incompatible color conversion"` for me, maybe image contains error and I don't know why does FireFox could open it(maybe magic!) bu the image size is a little big! 500KB for a very small image is to much huge ! wow! does it contains any embedded data? –  Oct 21 '13 at 16:37
  • Ha! That's what i did like to analyze via Java - embedded data! Maybe some kind of certificate? It is an big official organisation called **Stiftung Warentest**, a consumer-protection institute. – Grim Oct 21 '13 at 16:46
  • Hmm, so you may need manipulate the stream manually, and just separate the image data from the embedded data. but I suggest native code C/C++ for doing such these things...Ta Ta –  Oct 21 '13 at 16:53

1 Answers1

5

Okay... Took me a while to find the problem with this... The problem is with the image itself, it has a CMYK colour profile (namely Coated FOGRA27), confusing the JPEG reading library in java.

Opening the image in photoshop yields an image in CMYK color mode (for me at least) which seems to be unsupported by java. Changing the color mode to RGB and saving with a sRGB color profile allowed the ImageIO library to successfully read the image.

The ImageIO library only implements a subset of readable colour profiles and does not handle images without any profiles.

Further reading into the JPEGImageReader source yielded the following code:

switch (colorSpaceCode) {
    case JPEG.JCS_GRAYSCALE:
        list.add(raw);
        list.add(getImageType(JPEG.JCS_RGB));
        break;
    case JPEG.JCS_RGB:
        list.add(raw);
        list.add(getImageType(JPEG.JCS_GRAYSCALE));
        list.add(getImageType(JPEG.JCS_YCC));
        break;
    case JPEG.JCS_RGBA:
        list.add(raw);
        break;
    case JPEG.JCS_YCC:
        if (raw != null) {  // Might be null if PYCC.pf not installed
            list.add(raw);
            list.add(getImageType(JPEG.JCS_RGB));
        }
        break;
    case JPEG.JCS_YCCA:
        if (raw != null) {  // Might be null if PYCC.pf not installed
            list.add(raw);
        }
        break;
    case JPEG.JCS_YCbCr:
        // As there is no YCbCr ColorSpace, we can't support
        // the raw type.

        // due to 4705399, use RGB as default in order to avoid
        // slowing down of drawing operations with result image.
        list.add(getImageType(JPEG.JCS_RGB));

        if (iccCS != null) {
            list.add(new ImageTypeProducer() {
                protected ImageTypeSpecifier produce() {
                    return ImageTypeSpecifier.createInterleaved
                     (iccCS,
                      JPEG.bOffsRGB,  // Assume it's for RGB
                      DataBuffer.TYPE_BYTE,
                      false,
                      false);
                }
            });

        }

        list.add(getImageType(JPEG.JCS_GRAYSCALE));
        list.add(getImageType(JPEG.JCS_YCC));
        break;
    case JPEG.JCS_YCbCrA:  // Default is to convert to RGBA
        // As there is no YCbCr ColorSpace, we can't support
        // the raw type.
        list.add(getImageType(JPEG.JCS_RGBA));
        break;
}

The source of the exception:

Iterator imageTypes = getImageTypes(imageIndex);
if (imageTypes.hasNext() == false) {
    throw new IIOException("Unsupported Image Type");
}

As you can see, when the color profile of the JPEG image is not listed in the switch statement, nothing is added to the 'list' variable which eventually gets passed to the particular iterator in the second segment of code. With an empty list, the Iterator.hasNext() method returns a false, throwing the exception.

initramfs
  • 8,275
  • 2
  • 36
  • 58
  • Wow dude, I appreciate the work, but I need to say that is kinda trap dude, the image contains embedded data. –  Oct 21 '13 at 16:55
  • @user2511414 Well... Whoever made the image should include a color profile, preferably sRGB... You could write your own JPEG reading library that handles special cases like this or find some image library that can do this for you. – initramfs Oct 21 '13 at 16:57
  • Well, this solves the question 100%, but whats about the embedded data? – Grim Oct 21 '13 at 17:01
  • Good point buddy, what about creating a empty image using `BufferedImage` with a default color schema(sRGB). then try to read the data from url and set the image data pixel by pixel. I don't know does it work or no, but may –  Oct 21 '13 at 17:01
  • @PeterRader I'm sorry... But I don't seem to understand what you mean by embedded data. Do you mean, there is some data encoded in the pixel colours themselves or do you mean, this image contains a payload of additional (possibly) binary data? If this embedded data is in the pixels, find yourself another image reading library that can read images with this colour profile/no colour profile. If the data is in the payload/headers (non-image data), no standard image reading library will pick it up. You're left to creating your own custom library that can extract all the elements of the image file. – initramfs Oct 21 '13 at 17:06
  • Well the Image is official from Professionals. There must be a reason for 0.5MB! – Grim Oct 21 '13 at 18:40
  • @PeterRader It seems that it uses a colour profile named Coated FOGRA27... Any image with that colour profile seems to create images of much higher size. I just tried creating a image of the same size with some basic patterns, and the results were in orders of 100 KBs as well... I highly doubt there is any embedded data... Its just the way the image is stored, quite different from traditional sRGB (Which produces the small image sizes you see). – initramfs Oct 21 '13 at 19:00
  • 2
    @PeterRader See my answer here [for a CMYK capable JPEGImageReader for ImageIO](http://stackoverflow.com/a/16149142/1428606). – Harald K Oct 21 '13 at 19:34