-
Bug
-
Resolution: Unresolved
-
P4
-
8, 11, 17, 23, 24, 25
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
It occurs both on Java 8 and Java 23
A DESCRIPTION OF THE PROBLEM :
While an 8-bit greyscale image is recognized correctly as ColorSpace.TYPE_GRAY, an 1-bit monochrome image is recognized as ColorSpace.TYPE_RGB.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a binary image (i.e. an image that only contains black and white and no other greyscale values) from a color image as following:
magick test.24bit.png test.converted.pbm
magick test.converted.pbm test.converted.monochrome.png
2. Execute code further below
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
While the BufferedImage.getType() returns 12 which corresponds to BufferedImage.TYPE_BYTE_BINARY, both ImageReader.getRawImageType(...).getColorModel().getColorSpace().getType() returned the same result as ImageIO.read(...).getColorModel().getColorSpace().getType() which is TYPE_RGB.
More appropriate would be to return ColorSpace.TYPE_GRAY (because like grey images, binary images have only a single color channel).
(An alternative could be to introduce another enum value which would represent a monochrome binary (i.e. representing only black and white) images).
ACTUAL -
ImageReader.getRawImageType(...).getColorModel().getColorSpace().getType() returned the same result as ImageIO.read(...).getColorModel().getColorSpace().getType() which is TYPE_RGB.
You will seee the following output from the test program in the attached zip:
16:38:10.751 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - ImageIO.createImageInputStream(/test.converted.monochrome.png)
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getColorSpace().getType(): 5 (5=RGB, 6=GRAY, 3=YCbCr)
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getPixelSize(): 1
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getNumColorComponents(): 3
...
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getColorSpace().isCS_sRGB(): true
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - ImageIO.read(/test.converted.monochrome.png)
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getColorModel().getColorSpace().getType(): 5 (5=RGB, 6=GRAY, 3=YCbCr)
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getType(): 12
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getColorModel().getPixelSize(): 1
...
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getColorModel().getColorSpace().isCS_sRGB(): true
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getSampleModel().getNumBands(): 1
---------- BEGIN SOURCE ----------
package com.mycompany.colorspace.test;
import com.google.common.io.ByteStreams;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.stream.ImageInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ColorSpaceRecognition {
private static final Logger logger = LoggerFactory.getLogger(ColorSpaceRecognition.class);
public static void main(String[] args) throws IOException {
// Created using:
// magick test.24bit.png test.converted.pbm
// magick test.converted.pbm test.converted.monochrome.png
printColorSpaceInfos("/test.converted.monochrome.png");
}
private static void printColorSpaceInfos(String resourceName) throws IOException {
printRawColorSpace(resourceName);
printNonRawColorSpace(resourceName);
}
private static void printNonRawColorSpace(String resourceName) throws IOException {
logger.debug("ImageIO.read({})", resourceName);
BufferedImage image = ImageIO.read(new ByteArrayInputStream(getResourceAsBytes(resourceName)));
if (image == null) {
throw new RuntimeException("image format not supported");
}
logger.debug(" image.getColorModel().getColorSpace().getType(): {} ({}=RGB, {}=GRAY, {}=YCbCr)",
image.getColorModel().getColorSpace().getType(), ColorSpace.TYPE_RGB, ColorSpace.TYPE_GRAY, ColorSpace.TYPE_YCbCr);
logger.debug(" image.getType(): {}", image.getType());
logger.debug(" image.getColorModel().getPixelSize(): {}",
image.getColorModel().getPixelSize());
logger.debug(" image.getColorModel().getNumColorComponents(): {}",
image.getColorModel().getNumColorComponents());
logger.debug(" image.getColorModel().getComponentSize().length: {}",
image.getColorModel().getComponentSize().length);
for (int i = 0; i < image.getColorModel().getComponentSize().length; i++) {
logger.debug(" image.getColorModel().getComponentSize()[{}]: {}", i,
image.getColorModel().getComponentSize()[i]);
}
logger.debug(" image.getColorModel().getColorSpace().isCS_sRGB(): {}",
image.getColorModel().getColorSpace().isCS_sRGB());
logger.debug(" image.getSampleModel().getNumBands(): {}",
image.getSampleModel().getNumBands());
}
private static void printRawColorSpace(String resourceName) throws IOException {
logger.debug("ImageIO.createImageInputStream({})", resourceName);
try (ImageInputStream input
= ImageIO.createImageInputStream(new ByteArrayInputStream(getResourceAsBytes(resourceName)))) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
if (!readers.hasNext()) {
throw new RuntimeException("image format not supported");
} else {
ImageReader reader = readers.next();
try {
reader.setInput(input);
ImageTypeSpecifier rawImageType = reader.getRawImageType(0);
if (rawImageType == null) {
logger.debug(" rawImageType: null");
} else {
logger.debug(" rawImageType.getColorModel().getColorSpace().getType(): {} ({}=RGB, {}=GRAY, {}=YCbCr)",
rawImageType.getColorModel().getColorSpace().getType(), ColorSpace.TYPE_RGB, ColorSpace.TYPE_GRAY, ColorSpace.TYPE_YCbCr);
logger.debug(" rawImageType.getColorModel().getPixelSize(): {}",
rawImageType.getColorModel().getPixelSize());
logger.debug(" rawImageType.getColorModel().getNumColorComponents(): {}",
rawImageType.getColorModel().getNumColorComponents());
logger.debug(" rawImageType.getColorModel().getComponentSize().length: {}",
rawImageType.getColorModel().getComponentSize().length);
for (int i = 0; i < rawImageType.getColorModel().getComponentSize().length; i++) {
logger.debug(" rawImageType.getColorModel().getComponentSize()[{}]: {}", i,
rawImageType.getColorModel().getComponentSize()[i]);
}
logger.debug(" rawImageType.getColorModel().getColorSpace().isCS_sRGB(): {}",
rawImageType.getColorModel().getColorSpace().isCS_sRGB());
}
} finally {
reader.dispose();
}
}
}
}
private static byte[] getResourceAsBytes(String resourceName) {
return getResourceAsBytes(resourceName, ColorSpaceRecognition.class);
}
private static byte[] getResourceAsBytes(String resourceName, Class<?> clazz) {
try (InputStream in = clazz.getResourceAsStream(resourceName)) {
if (in == null) {
throw new RuntimeException("Resource '" + resourceName
+ "' could not be loaded with ClassLoader for " + clazz.getCanonicalName());
}
return ByteStreams.toByteArray(in);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
---------- END SOURCE ----------
It occurs both on Java 8 and Java 23
A DESCRIPTION OF THE PROBLEM :
While an 8-bit greyscale image is recognized correctly as ColorSpace.TYPE_GRAY, an 1-bit monochrome image is recognized as ColorSpace.TYPE_RGB.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a binary image (i.e. an image that only contains black and white and no other greyscale values) from a color image as following:
magick test.24bit.png test.converted.pbm
magick test.converted.pbm test.converted.monochrome.png
2. Execute code further below
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
While the BufferedImage.getType() returns 12 which corresponds to BufferedImage.TYPE_BYTE_BINARY, both ImageReader.getRawImageType(...).getColorModel().getColorSpace().getType() returned the same result as ImageIO.read(...).getColorModel().getColorSpace().getType() which is TYPE_RGB.
More appropriate would be to return ColorSpace.TYPE_GRAY (because like grey images, binary images have only a single color channel).
(An alternative could be to introduce another enum value which would represent a monochrome binary (i.e. representing only black and white) images).
ACTUAL -
ImageReader.getRawImageType(...).getColorModel().getColorSpace().getType() returned the same result as ImageIO.read(...).getColorModel().getColorSpace().getType() which is TYPE_RGB.
You will seee the following output from the test program in the attached zip:
16:38:10.751 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - ImageIO.createImageInputStream(/test.converted.monochrome.png)
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getColorSpace().getType(): 5 (5=RGB, 6=GRAY, 3=YCbCr)
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getPixelSize(): 1
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getNumColorComponents(): 3
...
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getColorSpace().isCS_sRGB(): true
16:38:10.927 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - ImageIO.read(/test.converted.monochrome.png)
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getColorModel().getColorSpace().getType(): 5 (5=RGB, 6=GRAY, 3=YCbCr)
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getType(): 12
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getColorModel().getPixelSize(): 1
...
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getColorModel().getColorSpace().isCS_sRGB(): true
16:38:10.937 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - image.getSampleModel().getNumBands(): 1
---------- BEGIN SOURCE ----------
package com.mycompany.colorspace.test;
import com.google.common.io.ByteStreams;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.stream.ImageInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ColorSpaceRecognition {
private static final Logger logger = LoggerFactory.getLogger(ColorSpaceRecognition.class);
public static void main(String[] args) throws IOException {
// Created using:
// magick test.24bit.png test.converted.pbm
// magick test.converted.pbm test.converted.monochrome.png
printColorSpaceInfos("/test.converted.monochrome.png");
}
private static void printColorSpaceInfos(String resourceName) throws IOException {
printRawColorSpace(resourceName);
printNonRawColorSpace(resourceName);
}
private static void printNonRawColorSpace(String resourceName) throws IOException {
logger.debug("ImageIO.read({})", resourceName);
BufferedImage image = ImageIO.read(new ByteArrayInputStream(getResourceAsBytes(resourceName)));
if (image == null) {
throw new RuntimeException("image format not supported");
}
logger.debug(" image.getColorModel().getColorSpace().getType(): {} ({}=RGB, {}=GRAY, {}=YCbCr)",
image.getColorModel().getColorSpace().getType(), ColorSpace.TYPE_RGB, ColorSpace.TYPE_GRAY, ColorSpace.TYPE_YCbCr);
logger.debug(" image.getType(): {}", image.getType());
logger.debug(" image.getColorModel().getPixelSize(): {}",
image.getColorModel().getPixelSize());
logger.debug(" image.getColorModel().getNumColorComponents(): {}",
image.getColorModel().getNumColorComponents());
logger.debug(" image.getColorModel().getComponentSize().length: {}",
image.getColorModel().getComponentSize().length);
for (int i = 0; i < image.getColorModel().getComponentSize().length; i++) {
logger.debug(" image.getColorModel().getComponentSize()[{}]: {}", i,
image.getColorModel().getComponentSize()[i]);
}
logger.debug(" image.getColorModel().getColorSpace().isCS_sRGB(): {}",
image.getColorModel().getColorSpace().isCS_sRGB());
logger.debug(" image.getSampleModel().getNumBands(): {}",
image.getSampleModel().getNumBands());
}
private static void printRawColorSpace(String resourceName) throws IOException {
logger.debug("ImageIO.createImageInputStream({})", resourceName);
try (ImageInputStream input
= ImageIO.createImageInputStream(new ByteArrayInputStream(getResourceAsBytes(resourceName)))) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
if (!readers.hasNext()) {
throw new RuntimeException("image format not supported");
} else {
ImageReader reader = readers.next();
try {
reader.setInput(input);
ImageTypeSpecifier rawImageType = reader.getRawImageType(0);
if (rawImageType == null) {
logger.debug(" rawImageType: null");
} else {
logger.debug(" rawImageType.getColorModel().getColorSpace().getType(): {} ({}=RGB, {}=GRAY, {}=YCbCr)",
rawImageType.getColorModel().getColorSpace().getType(), ColorSpace.TYPE_RGB, ColorSpace.TYPE_GRAY, ColorSpace.TYPE_YCbCr);
logger.debug(" rawImageType.getColorModel().getPixelSize(): {}",
rawImageType.getColorModel().getPixelSize());
logger.debug(" rawImageType.getColorModel().getNumColorComponents(): {}",
rawImageType.getColorModel().getNumColorComponents());
logger.debug(" rawImageType.getColorModel().getComponentSize().length: {}",
rawImageType.getColorModel().getComponentSize().length);
for (int i = 0; i < rawImageType.getColorModel().getComponentSize().length; i++) {
logger.debug(" rawImageType.getColorModel().getComponentSize()[{}]: {}", i,
rawImageType.getColorModel().getComponentSize()[i]);
}
logger.debug(" rawImageType.getColorModel().getColorSpace().isCS_sRGB(): {}",
rawImageType.getColorModel().getColorSpace().isCS_sRGB());
}
} finally {
reader.dispose();
}
}
}
}
private static byte[] getResourceAsBytes(String resourceName) {
return getResourceAsBytes(resourceName, ColorSpaceRecognition.class);
}
private static byte[] getResourceAsBytes(String resourceName, Class<?> clazz) {
try (InputStream in = clazz.getResourceAsStream(resourceName)) {
if (in == null) {
throw new RuntimeException("Resource '" + resourceName
+ "' could not be loaded with ClassLoader for " + clazz.getCanonicalName());
}
return ByteStreams.toByteArray(in);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
---------- END SOURCE ----------