JDK-4413109 : ImageIO.write for BufferedImage.TYPE_USHORT_565_RGB fails
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.imageio
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_8
  • CPU: sparc
  • Submitted: 2001-02-08
  • Updated: 2001-04-12
  • Resolved: 2001-03-13
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.
Other
1.4.0 betaFixed
Related Reports
Relates :  
Description
An attempt to ImageIO.write from a BufferedImage with type TYPE_USHORT_565_RGB
fails with this exception:

  While writing image ./output-u565_rgb.png, caught java.lang.RuntimeException
  java.lang.RuntimeException
        at com.sun.imageio.plugins.png.PNGMetadata.initialize(PNGMetadata.java:252)
        at com.sun.imageio.plugins.png.PNGImageWriter.write(PNGImageWriter.java:788)
        at javax.imageio.ImageWriter.write(ImageWriter.java:591)
        at javax.imageio.ImageIO.write(ImageIO.java:1179)
        at javax.imageio.ImageIO.write(ImageIO.java:1213)
        at headless.bit.imgtest.writeImage(imgtest.java:81)
        at headless.bit.imgtest.runTest(imgtest.java:58)
        at headless.bit.imgtest.main(imgtest.java:117)

Using all other image types the image is produced, however there are 
drawing mistakes in two image types:

   TYPE_BYTE_BINARY  There is a black line down the right side
      of the image.

   TYPE_USHORT_555_RGB  The colors are completely wrong.  Instead
      of white and red, it's two shades of dark grey.

The rendering into the BufferedImage is a simple fill, first
filling the background with white, then filling a square in the
middle with red.

The behavior is the same on Solaris 8 and Windows 2k


Test code follows:



/*
 * imgtest.java
 *
 * Created on February 7, 2001, 4:49 PM
 */

// package headless.bit;

import java.io.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.*;

/**
 *
 * @author  David Herron
 * @version 
 */
public class imgtest extends java.lang.Object {


    protected BufferedImage fb = null;

    protected int    width     = 500;
    protected int    height    = 500;
    
    int[] imageTypes = new int[] {
	BufferedImage.TYPE_3BYTE_BGR,
	BufferedImage.TYPE_4BYTE_ABGR,
	BufferedImage.TYPE_BYTE_BINARY,
	BufferedImage.TYPE_BYTE_GRAY,
	BufferedImage.TYPE_BYTE_INDEXED,
	// XXX BufferedImage.TYPE_CUSTOM
	BufferedImage.TYPE_INT_ARGB,
	BufferedImage.TYPE_INT_ARGB_PRE,
	BufferedImage.TYPE_INT_BGR,
	BufferedImage.TYPE_INT_RGB,
	BufferedImage.TYPE_USHORT_555_RGB,
	BufferedImage.TYPE_USHORT_565_RGB,
	BufferedImage.TYPE_USHORT_GRAY
    };

    /** Creates new imgtest */
    public imgtest(String args[]) {
    }

    public void runTest() {
	try {
	    // Construct the BufferedImage, and run the test
	    for (int itype = 0; itype < imageTypes.length; itype++) {
		int type = imageTypes[itype];
		if (fb != null) {
		    fb.flush();
		    fb = null;
		}
		fb = new BufferedImage(width, height, type);
                render(width, height, (Graphics2D)fb.getGraphics());
                writeImage();
            }
        } catch (Exception e) { }
    }
    
    public void render(int w, int h, Graphics2D g2) {
        g2.setColor(Color.white);
        g2.fillRect(0, 0, w, h);
        g2.setColor(Color.red);
        g2.fillRect((int)((w * .25)/2),
                    (int)((h * .25)/2),
                    (int)(w * .75),
                    (int)(h * .75));
    }

    public void writeImage() {
	// Write the image out to PNG file
	String ifn = null;
	try {
	    String dn = ".";
	    ifn = dn+"/output-"+getImageTypeString()+".png";
            System.out.println("writeImageFromTest " + ifn);
            System.out.println("   " + fb.toString());
	    ImageIO.write((RenderedImage)fb, "png", new File(ifn));
	} catch (Exception e) {
	    System.out.println("While writing image "+ifn+", caught " + e);
	    e.printStackTrace(System.out);
	}
    }
    
    /** Get the image type used to create the current frame buffer. */
    public int getCurrentFrameBufferType() {
	return fb.getType();
    }

    /** Get a string form for the image type. */
    public String getImageTypeString() {
	switch (getCurrentFrameBufferType()) {
	case BufferedImage.TYPE_3BYTE_BGR:         return "3b_bgr";
	case BufferedImage.TYPE_4BYTE_ABGR:        return "4b_abgr";
	case BufferedImage.TYPE_BYTE_BINARY:       return "b_binary";
	case BufferedImage.TYPE_BYTE_GRAY:         return "b_gray";
	case BufferedImage.TYPE_BYTE_INDEXED:      return "b_indexed";
	// XXX BufferedImage.TYPE_CUSTOM
	case BufferedImage.TYPE_INT_ARGB:          return "i_argb";
	case BufferedImage.TYPE_INT_ARGB_PRE:      return "i_argb_pre";
	case BufferedImage.TYPE_INT_BGR:           return "i_bgr";
	case BufferedImage.TYPE_INT_RGB:           return "i_rgb";
	case BufferedImage.TYPE_USHORT_555_RGB:    return "u555_rgb";
	case BufferedImage.TYPE_USHORT_565_RGB:    return "u565_rgb";
	case BufferedImage.TYPE_USHORT_GRAY:       return "u_gray";
	}
	return "unk";
    }

    /**
    * @param args the command line arguments
    */
    public static void main (String args[]) {
        new imgtest(args).runTest();
    }

}

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta FIXED IN: merlin-beta INTEGRATED IN: merlin-beta VERIFIED IN: merlin-beta
14-06-2004

EVALUATION There are three problems exposed by this test case. First, PNGImageWriter refuses to write an image that has more than one bit depth. The USHORT_565 image has 5 bits for red and blue and 6 bits for green, and so is rejected out of hand. This may be fixed by making the test in PNGMetadata.initialize less strict. The fixes for the following problem will ensure that this case can be handled. Second, attempting to encode an image with a bit depth that is not supported by PNG results in a PNG image with the next higher bit depth (unless the bit depth is set explicitly via the metadata). However, the values are not scaled up so a white pixel in a USHORT_565 image has a value of (31, 63, 31). When this is written into an 8-bit PNG image, it has an incorrect color. The fix is to scale the pixels before they are written according to the formula output = round(input*max_output_value/max_input_value) This ensures that the value (31, 63, 31) is mapped to (255, 255, 255) when the file is written. Third, a similar problem exists in the PNG reader which although not a part of this test case involves similar issues. If a USHORT_555 or USHORT_565 or other custom image is used as the destination for reading, the pixel values will not be scaled. The reader should perform scaling in the case where the input and output sample bit depths are different. With these fixes, the PNG writer should be able to write any of the standard BufferedImage types, and the reader should be able to read into any reasonable BufferedImage with the right number of bands. A round-trip in which a 565 image is encoded to 8 bits and read back into a new 565 image should work, perhaps with minor rounding errors. The problem with TYPE_BYTE_BINARY images is a result of faulty logic for completing a scanline of low bit depth. The image samples are accumulated into bytes by shifting them in from the right side. The final byte then needs to be left-justified with an additional shift before it the scanline is sent on to the next stage. This left shift was being performed incorrectly. A regression test will be placed in test/javax/imageio/plugins/png/BitDepth.java.
11-06-2004

WORK AROUND Avoid testing with this image type - but then I can't test with all image types.
11-06-2004

PUBLIC COMMENTS ImageIO.write for BufferedImage.TYPE_USHORT_565_RGB fails
10-06-2004