Categories
Java

Reading JPEGs with CMYK profile

Today I tried to read a JPEG with the ImageIO-Library, provided by the JRE. But instead of a wonderful image I only received the following exception:

1
2
3
4
5
6
7
8
java.lang.IllegalArgumentException: bandOffsets.length is wrong!
	at javax.imageio.ImageTypeSpecifier$Interleaved.< init >(ImageTypeSpecifier.java:382)
	at javax.imageio.ImageTypeSpecifier.createInterleaved(ImageTypeSpecifier.java:495)
	at com.sun.imageio.plugins.jpeg.JPEGImageReader.getImageTypes(JPEGImageReader.java:743)
	at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:935)
	at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:912)
	at javax.imageio.ImageIO.read(ImageIO.java:1400)
	at javax.imageio.ImageIO.read(ImageIO.java:1322)

With an EXIF-Reader (by the way a nice website) I tried to analyze the picture and saw the picture includes an embedded color profile “(unrecognized embedded color profile ‘SWOP (Coated), 20%’)”. A little bit more research showed the currently unresolved bugs in the JRE (especially ImageIO-Library; #4799903 and #5100094). So I’m not the only person, who had the problem. There are some code snippets and bug workarounds on the net trying to convert CMYK or YCCK to RGB. For my picture the CMYK-Solution doesn’t work, because the JRE means the embedded ICC profile doesn’t match the given raster (raster contains 3 bytes per pixel, but CMYK 4 bytes). But Werner Randelshofer wrote that it is important to use the given ICC, because of unexpectable color problems. So just to use a fix conversion method is not the wanted solution.

Then I tried first not to use the ImageIO library, but to give AWT-Toolkit a try. I was very surprised, that this function can correctly read the given image. So I didn’t need to handle the embedded ICC profiles directly. I modified my code to use this method, if ImageIO fails. The resulting code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    private BufferedImage readImage(InputStream picture) throws IOException {
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        byte[] b = new byte[10240];
        int l = 0;
        while ((l = picture.read(b)) >= 0) {
            buf.write(b, 0, l);
        }
        buf.close();
        byte[] picturedata = buf.toByteArray();
        buf = null;
        try {
            return ImageIO.read(new ByteArrayInputStream(picturedata));
        } catch (IllegalArgumentException e) {
                ImageInputStream input = ImageIO
                        .createImageInputStream(new ByteArrayInputStream(
                                picturedata));
                Iterator< ImageReader > readers = ImageIO.getImageReaders(input);
                ImageReader reader = null;
                while (readers.hasNext()) {
                    reader = (ImageReader) readers.next();
                    if (reader.canReadRaster())
                        break;
                }
 
                if (reader == null)
                    throw new IOException("no reader found");
                // Set the input.
                reader.setInput(input);
                int w = reader.getWidth(0);
                int h = reader.getHeight(0);
                BufferedImage image;
                image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                Image intImage = Toolkit.getDefaultToolkit().createImage(
                        picturedata);
                new ImageIcon(intImage);
                Graphics2D g = image.createGraphics();
                g.drawImage(intImage, 0, 0, null);
                g.dispose();
                return image;
        }
    }

The Toolkit-Method also has no problems on servers without an X11 server.