Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8352776

4-bit greyscale images are recognized as RGB instead of grey

XMLWordPrintable

      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, a 4-bit greyscale image (created using: magick test.png -depth 4 -colorspace gray -define png:color-type=0 -define png:bit-depth=4 test.grey.converted-4bit.png)
      is recognized as RGB.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create a 4-bit grey scale image using Image Magick (starting with an arbitrary color test.png):
      magick test.png -depth 4 -colorspace gray -define png:color-type=0 -define png:bit-depth=4 test.grey.converted-4bit.png

      2. Execute the code provided in Test Case Code field below.
      It shows that ImageReader.getRawImageType(...).getColorModel().getColorSpace().getType() returned 5 (=RGB) instead of the expected 6 (=GRAY).


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      17:58:15.942 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - ImageIO.createImageInputStream(/test.grey.converted-4bit.png)
      17:58:16.034 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getColorSpace().getType(): 6 (5=RGB, 6=GRAY, 3=YCbCr)
      ...
      ACTUAL -
      17:58:15.942 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - ImageIO.createImageInputStream(/test.grey.converted-4bit.png)
      17:58:16.034 [main] DEBUG com.mycompany.colorspace.test.ColorSpaceRecognition - rawImageType.getColorModel().getColorSpace().getType(): 5 (5=RGB, 6=GRAY, 3=YCbCr)
      ...

      ---------- BEGIN SOURCE ----------

      ColorSpaceRecognition.java:
      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 {
              // exported from Gimp as grey 8bit, recognized correctly as Grey
              // printColorSpaceInfos("/test.grey.8bit.png");

              // magick test.png -depth 4 -colorspace gray -define png:color-type=0 -define png:bit-depth=4 test.grey.converted-4bit.png
              printColorSpaceInfos("/test.grey.converted-4bit.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);
              }
          }
      }


      pom.xml:
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
          <groupId>com.mycompany</groupId>
          <artifactId>colorspace-test-greyscale</artifactId>
          <version>1.0-SNAPSHOT</version>
          <packaging>jar</packaging>
          <name>colorspace-test-greyscale</name>
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <maven.compiler.source>1.8</maven.compiler.source>
              <maven.compiler.target>1.8</maven.compiler.target>
              <exec.mainClass>com.mycompany.colorspace.test.ColorSpaceRecognition</exec.mainClass>
          </properties>
          <dependencies>
              <dependency>
                  <groupId>ch.qos.logback</groupId>
                  <artifactId>logback-classic</artifactId>
                  <version>1.2.8</version>
              </dependency>
              <dependency>
                  <groupId>com.google.guava</groupId>
                  <artifactId>guava</artifactId>
                  <version>31.0.1-jre</version>
              </dependency>
          </dependencies>
      </project>
      ---------- END SOURCE ----------

            jdv Jayathirth D V
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: