JDK-6372769 : ImageIO.read improperly decodes Nikon Jpegs
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.imageio
  • Affected Version: 5.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-01-16
  • Updated: 2011-02-16
  • Resolved: 2006-03-22
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 6
6 b77Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
Jpeg files saved with the ICC profile "Nikon sRGB 4.0.0.3001" do not load properly using Java ImageIO.read(). This appears to be similar to the problems reported in bugid 6246622, which was fixed in 1.5_04 and is now closed.  The image in this case is far too dark, but the colors are not swapped.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use Nikon Picture Project to save a JPEG, this will add the ICC profile "Nikon sRGB 4.0.0.3001" to the Jpeg.  Use ImageIO.read to create a BufferedImage from the Jpeg file.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
An image that displays as it does when loaded with Adobe PhotoShop.
ACTUAL -
The image was far too dark, close to totally black.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.swing.*;
import java.awt.*;
import java.awt.color.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;

public class Gui {
	private JFrame frame = new JFrame();
    private Container contentPane;
    private BufferedImage bug;
    private BufferedImage fix;
    private JLabel bugLabel = new JLabel("bug not loaded");
    private JLabel fixLabel = new JLabel("fix not loaded");
    
    Gui() {
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        File file = new File("nikon.jpg");
        try {
            bug = ImageIO.read(file);
            bugLabel = new JLabel("buggy", new ImageIcon(bug), SwingConstants.LEFT);
            fix = read(file);
            fixLabel = new JLabel("fixed", new ImageIcon(fix), SwingConstants.LEFT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        frame.getContentPane().add(bugLabel, BorderLayout.NORTH);
        frame.getContentPane().add(fixLabel, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String [] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Gui();
            }
        });
    }
    
   public static BufferedImage read(File file) throws IOException {
        BufferedImage image = null;
        ImageInputStream iis = ImageIO.createImageInputStream(file);
        if (iis == null) {
            throw new IOException("File not found");
        }
        Iterator<ImageReader> iir = ImageIO.getImageReaders(iis);
        boolean looking = true;
        ImageReader reader = null;
        ImageReadParam param = null;
        while(looking && iir.hasNext()) {
            reader = iir.next();
            reader.setInput(iis);
            param = reader.getDefaultReadParam();
            Iterator it = reader.getImageTypes(0);
            
            while (looking && it.hasNext()) {
                ImageTypeSpecifier type = (ImageTypeSpecifier) it.next();
                ColorSpace cs = type.getColorModel().getColorSpace();
                if ( cs.isCS_sRGB() ) {
                    param.setDestinationType(type);
                    looking = false;
                }   
                if ( cs.getType() != ColorSpace.TYPE_RGB ) {
                    looking = false;
                }
            }
        }
        if (reader != null) {
            image = reader.read(0, param);
        }
        return image;
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Replace the ImageIO.read(file) with

[code]
    ImageInputStream iis = ImageIO.createImageInputStream(file);
    Iterator<ImageReader> iir = ImageIO.getImageReaders(iis);
    boolean looking = true;
    ImageReader reader = null;
    ImageReadParam param = null;
    while(looking && iir.hasNext()) {
        reader = iir.next();
        reader.setInput(iis);
        param = reader.getDefaultReadParam();
        Iterator it = reader.getImageTypes(0);
        while (looking && it.hasNext()) {
            ImageTypeSpecifier type = (ImageTypeSpecifier) it.next();
            ColorSpace cs = type.getColorModel().getColorSpace();
            if (cs.isCS_sRGB()) {
                param.setDestinationType(type);
                looking = false;
            }
            if (cs.getType() != ColorSpace.TYPE_RGB) {
                looking = false;
            }
        }
    }
    if (reader != null) {
        img = reader.read(0, param);
    }
[/code]

Comments
EVALUATION Was fixed as part of 4705399. Extra color conversion was removed.
2006-03-03

EVALUATION It looks like that ImageIO jpeg reader do extra color conversion if image contains embedded color profile. Please note that color model for such images uses embedded color profile (i.e. color conversion will be performed each time when image will be drawn). In addition, image reader converts image data to same color space after decoding raster data (JPEGImageReader.java, line 786). This problem can be fixed by removing extra color conversion operation. However, we need to take into account the fact that images with embedded color profile cause performance degradation (please see 4705399).
2006-02-08