United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6372769 ImageIO.read improperly decodes Nikon Jpegs
JDK-6372769 : ImageIO.read improperly decodes Nikon Jpegs

Details
Type:
Bug
Submit Date:
2006-01-16
Status:
Resolved
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2006-03-22
Component:
client-libs
OS:
windows_xp
Sub-Component:
javax.imageio
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:

Related Reports
Relates:

Sub Tasks

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

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
EVALUATION

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



Hardware and Software, Engineered to Work Together