-
Bug
-
Resolution: Fixed
-
P4
-
7
-
b118
-
generic
-
generic
SYNOPSIS
--------
Unexpected pixel colour when converting images to TYPE_BYTE_INDEXED
OPERATING SYSTEM
----------------
All (tested on Windows and Linux)
FULL JDK VERSION
----------------
All (tested with latest 5.0, 6 and 7)
DESCRIPTION
-----------
The attached testcase creates an image that is totally black, then converts it between two image formats. A number of different combinations are tested, and most of them convert as expected. However, when converting to TYPE_BYTE_INDEXED, some pixels change in colour from 0x000000 (black) to 0x121212 (a dark grey). The affected pixels are not random - they appear to follow a pattern, almost like dithering.
REPRODUCTION INSTRUCTIONS
-------------------------
1. Compile and run attached test program
> javac ImageTest2.java
> java ImageTest2
2. The testcase will indicate which conversions were successful. Failed
conversions are saved to files for viewing afterwards. (successfully
converted (black) pixels are converted to be transparent, so that
the incorrectly converted pixels stand out.)
3. Open the files in an image editor / browser.
Expected result:
All image types should be converted properly, without the change in pixel colour. No files should be written.
Observed result:
All conversions to TYPE_BYTE_INDEXED feature a pattern of pixels which have changed colour from 0x000000 (black) to 0x121212 (a dark grey).
TESTCASE
--------
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
public class ImageTest2 {
static final int[] types = new int[]{
BufferedImage.TYPE_INT_RGB,
BufferedImage.TYPE_INT_ARGB,
BufferedImage.TYPE_INT_ARGB_PRE,
BufferedImage.TYPE_INT_BGR,
BufferedImage.TYPE_3BYTE_BGR,
BufferedImage.TYPE_4BYTE_ABGR,
BufferedImage.TYPE_4BYTE_ABGR_PRE,
BufferedImage.TYPE_USHORT_565_RGB,
BufferedImage.TYPE_USHORT_555_RGB,
BufferedImage.TYPE_BYTE_GRAY,
BufferedImage.TYPE_USHORT_GRAY,
BufferedImage.TYPE_BYTE_BINARY,
BufferedImage.TYPE_BYTE_INDEXED};
static final String[] type_name = new String[]{
"INT_RGB",
"INT_ARGB",
"INT_ARGB_PRE",
"INT_BGR",
"3BYTE_BGR",
"4BYTE_ABGR",
"4BYTE_ABGR_PRE",
"USHORT_565_RGB",
"USHORT_555_RGB",
"BYTE_GRAY",
"USHORT_GRAY",
"BYTE_BINARY",
"BYTE_INDEXED"};
static Hashtable<Integer,String> type_table = new Hashtable<Integer,String>();
static {
for(int i = 0; i < types.length; i++){
type_table.put(new Integer(types[i]), type_name[i]);
}
}
static int w_size = 100;
static int h_size = 100;
ImageTest2(String prefix, int type1, int type2) throws Exception {
BufferedImage img1 = new BufferedImage(w_size, h_size, type1);
Graphics2D img1_g2d = img1.createGraphics();
img1_g2d.setColor(Color.BLACK);
img1_g2d.fillRect(0, 0, img1.getWidth(), img1.getHeight());
BufferedImage img2 = new BufferedImage(img1.getWidth(), img1.getHeight(), type2);
Graphics2D img2_g2d = (Graphics2D) img2.getGraphics();
img2_g2d.drawImage(img1, 0, 0, null);
BufferedImage argb = new BufferedImage(img2.getWidth(), img2.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D argb_g2d = (Graphics2D) argb.getGraphics();
argb_g2d.drawImage(img2, 0, 0, null);
boolean isBlack = true;
for (int i = 0; i < argb.getHeight(); i++) {
for (int j = 0; j < argb.getWidth(); j++) {
if (Color.BLACK.getRGB() == argb.getRGB(j, i)) {
// Make black pixels transparent so that any bad pixels (which are dark grey) stand out
argb.setRGB(j, i, 0);
} else {
// Found a non-black pixel
isBlack = false;
}
}
}
if (isBlack == false) {
System.out.print("FAILED: " + type_table.get(type1) + " -> " + type_table.get(type2));
String outfile = prefix + "_" + type_table.get(type1) + "-" + type_table.get(type2) + ".png";
File f = new File(outfile);
ImageIO.write(argb, "PNG", f);
System.out.println(" (Image written as: " + f.getCanonicalPath() + ")");
} else {
System.out.println("PASSED: " + type_table.get(type1) + " -> " + type_table.get(type2));
}
}
public static void main(String args[]) throws Exception {
String prefix = args.length > 0 ? args[0] : "img";
for(int i = 0; i < types.length; i++) {
for(int j = 0; j < types.length; j++) {
new ImageTest2(prefix, types[i], types[j]);
}
}
}
}
--------
Unexpected pixel colour when converting images to TYPE_BYTE_INDEXED
OPERATING SYSTEM
----------------
All (tested on Windows and Linux)
FULL JDK VERSION
----------------
All (tested with latest 5.0, 6 and 7)
DESCRIPTION
-----------
The attached testcase creates an image that is totally black, then converts it between two image formats. A number of different combinations are tested, and most of them convert as expected. However, when converting to TYPE_BYTE_INDEXED, some pixels change in colour from 0x000000 (black) to 0x121212 (a dark grey). The affected pixels are not random - they appear to follow a pattern, almost like dithering.
REPRODUCTION INSTRUCTIONS
-------------------------
1. Compile and run attached test program
> javac ImageTest2.java
> java ImageTest2
2. The testcase will indicate which conversions were successful. Failed
conversions are saved to files for viewing afterwards. (successfully
converted (black) pixels are converted to be transparent, so that
the incorrectly converted pixels stand out.)
3. Open the files in an image editor / browser.
Expected result:
All image types should be converted properly, without the change in pixel colour. No files should be written.
Observed result:
All conversions to TYPE_BYTE_INDEXED feature a pattern of pixels which have changed colour from 0x000000 (black) to 0x121212 (a dark grey).
TESTCASE
--------
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
public class ImageTest2 {
static final int[] types = new int[]{
BufferedImage.TYPE_INT_RGB,
BufferedImage.TYPE_INT_ARGB,
BufferedImage.TYPE_INT_ARGB_PRE,
BufferedImage.TYPE_INT_BGR,
BufferedImage.TYPE_3BYTE_BGR,
BufferedImage.TYPE_4BYTE_ABGR,
BufferedImage.TYPE_4BYTE_ABGR_PRE,
BufferedImage.TYPE_USHORT_565_RGB,
BufferedImage.TYPE_USHORT_555_RGB,
BufferedImage.TYPE_BYTE_GRAY,
BufferedImage.TYPE_USHORT_GRAY,
BufferedImage.TYPE_BYTE_BINARY,
BufferedImage.TYPE_BYTE_INDEXED};
static final String[] type_name = new String[]{
"INT_RGB",
"INT_ARGB",
"INT_ARGB_PRE",
"INT_BGR",
"3BYTE_BGR",
"4BYTE_ABGR",
"4BYTE_ABGR_PRE",
"USHORT_565_RGB",
"USHORT_555_RGB",
"BYTE_GRAY",
"USHORT_GRAY",
"BYTE_BINARY",
"BYTE_INDEXED"};
static Hashtable<Integer,String> type_table = new Hashtable<Integer,String>();
static {
for(int i = 0; i < types.length; i++){
type_table.put(new Integer(types[i]), type_name[i]);
}
}
static int w_size = 100;
static int h_size = 100;
ImageTest2(String prefix, int type1, int type2) throws Exception {
BufferedImage img1 = new BufferedImage(w_size, h_size, type1);
Graphics2D img1_g2d = img1.createGraphics();
img1_g2d.setColor(Color.BLACK);
img1_g2d.fillRect(0, 0, img1.getWidth(), img1.getHeight());
BufferedImage img2 = new BufferedImage(img1.getWidth(), img1.getHeight(), type2);
Graphics2D img2_g2d = (Graphics2D) img2.getGraphics();
img2_g2d.drawImage(img1, 0, 0, null);
BufferedImage argb = new BufferedImage(img2.getWidth(), img2.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D argb_g2d = (Graphics2D) argb.getGraphics();
argb_g2d.drawImage(img2, 0, 0, null);
boolean isBlack = true;
for (int i = 0; i < argb.getHeight(); i++) {
for (int j = 0; j < argb.getWidth(); j++) {
if (Color.BLACK.getRGB() == argb.getRGB(j, i)) {
// Make black pixels transparent so that any bad pixels (which are dark grey) stand out
argb.setRGB(j, i, 0);
} else {
// Found a non-black pixel
isBlack = false;
}
}
}
if (isBlack == false) {
System.out.print("FAILED: " + type_table.get(type1) + " -> " + type_table.get(type2));
String outfile = prefix + "_" + type_table.get(type1) + "-" + type_table.get(type2) + ".png";
File f = new File(outfile);
ImageIO.write(argb, "PNG", f);
System.out.println(" (Image written as: " + f.getCanonicalPath() + ")");
} else {
System.out.println("PASSED: " + type_table.get(type1) + " -> " + type_table.get(type2));
}
}
public static void main(String args[]) throws Exception {
String prefix = args.length > 0 ? args[0] : "img";
for(int i = 0; i < types.length; i++) {
for(int j = 0; j < types.length; j++) {
new ImageTest2(prefix, types[i], types[j]);
}
}
}
}