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

AlphaComposite.SRC_OVER operation has unexpected result on 8 bit display

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 6
    • 1.4.1
    • client-libs
    • None
    • 2d
    • beta
    • sparc
    • solaris_7

      When doing alpha composite in a buffered image with AlphaComposite.SRC_OVER
      rule on a 8 bit display, the output of the pixel values are sometimes
      unexpected.

      Here is a test program:

      import java.awt.*;
      import java.awt.image.*;

      public class SrcOverTest {
          public static final BufferedImage bi;
          public static final Graphics2D g2;
          protected static int colorDepth, maxError;

          public static final Color colors[] = { new Color(255, 0, 255),
              Color.black, Color.red, Color.pink, Color.orange, Color.yellow,
              Color.green, Color.magenta, Color.cyan, Color.blue};

          static {
              GraphicsEnvironment lge =
                  GraphicsEnvironment.getLocalGraphicsEnvironment();
              GraphicsConfiguration gc =
                  lge.getDefaultScreenDevice().getDefaultConfiguration();
              bi = gc.createCompatibleImage(200, 200);
              g2 = bi.createGraphics();
              g2.setColor(new Color(0, 255, 0));
              g2.fill3DRect(1, 0, 100, 50, true);
              
          }
              
          public static Color accountForColorConversion(Color c) {
               BufferedImage bi2 = GraphicsEnvironment.
                  getLocalGraphicsEnvironment().getDefaultScreenDevice().
                  getDefaultConfiguration().createCompatibleImage(1,1);
              int x = 0;
              int y = 0;

              // Set a pixel with the input color
              int rgb = c.getRGB();
              bi2.setRGB(x, y, rgb);

              // Read the pixel we just set, BufferedImage should take care
              // of the color conversion
              rgb = bi2.getRGB(x,y);

              // Return the converted color
              return new Color(rgb);
          }

          public static Color calcSrcOver(Color cb, Color c, float alpha, ColorModel colorModel) {
              boolean hasAlpha = colorModel.hasAlpha();
              float[] rgbaSrc = c.getRGBComponents(null);
              float[] rgbaDst = cb.getRGBComponents(null);

              float alphasource = rgbaSrc[3] * alpha;
              float alphadest = rgbaDst[3];

              float r = rgbaSrc[0]*alphasource + rgbaDst[0]*alphadest*(1-alphasource);
              float g = rgbaSrc[1]*alphasource + rgbaDst[1]*alphadest*(1-alphasource);
              float b = rgbaSrc[2]*alphasource + rgbaDst[2]*alphadest*(1-alphasource);
              float a = alphasource + alphadest*(1-alphasource);

              if (hasAlpha) {
                  return new Color(r, g, b, a);
              } else if (a != 0.0f) {
                  return new Color(r / a, g / a, b / a, 1.0f);
              } else {
                  return new Color(0.0f, 0.0f, 0.0f, 1.0f);
              }
          }
          
          public static void main(String[] args) {
              float alphas[] = {0.0f, 0.5f, 1.0f};
              for (int j = 0; j < alphas.length; j++) {
                  for (int i = 0; i < colors.length; i++) {
                      Color c_before = new Color(bi.getRGB(50, 25), true);
                      AlphaComposite composite =
                          AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alphas[j]);
                      g2.setComposite(composite);
                      Color c = accountForColorConversion(colors[i]);
                      g2.setColor(c);
                      g2.fill3DRect(1, 0, 100, 50, true);
                      Color c_after = new Color(bi.getRGB(50, 25), true);
          
                      Color c_expected = calcSrcOver(c_before, c, alphas[j],
                                                     bi.getColorModel());
                      System.out.println("ColorModel has alpha: " + bi.getColorModel().hasAlpha());
                      System.out.println("alpha of the composite: " + composite.getAlpha());
                      System.out.println("Source Color: " + c + ", alpha: " + c.getAlpha());
                      System.out.println("Dest Color: " + c_before + ", alpha: " + c_before.getAlpha());
                      System.out.println("Returned color: "+ c_after +
                                             ", alpha: " + c_after.getAlpha());
                      System.out.println("Expected color: " + c_expected +
                                          ", alpha: " + c_expected.getAlpha());
                      System.out.println();
                  }
              }
          }
      }

      Attached is the output on 24 bit display and output on 8 bit display. It shows
      that the all resulting colors on 24 bit display are consistent with expected
      values. However, some resulting colors on 8 bit display are not within
      expectation, especially when alpha of blending is not 1.0, for example:

      ColorModel has alpha: false
      alpha of the composite: 0.0
      Source Color: java.awt.Color[r=255,g=0,b=255], alpha: 255
      Dest Color: java.awt.Color[r=0,g=255,b=0], alpha: 255
      Returned color: java.awt.Color[r=59,g=250,b=52], alpha: 255
      Expected color: java.awt.Color[r=0,g=255,b=0], alpha: 255
      ...

      ColorModel has alpha: false
      alpha of the composite: 0.5
      Source Color: java.awt.Color[r=0,g=0,b=0], alpha: 255
      Dest Color: java.awt.Color[r=197,g=98,b=139], alpha: 255
      Returned color: java.awt.Color[r=127,g=0,b=0], alpha: 255
      Expected color: java.awt.Color[r=99,g=49,b=70], alpha: 255

      It is acceptable that there might be some errors in
      floating point calculation, but some returned values are way off.
      For instance, in the first 8 bit output example, the alpha is 0, which means
      the resulting color should be the same as the original destination color.
      But the actual resulting color is totally unexpected.

            campbell Christopher Campbell (Inactive)
            xwangsunw Xiaozhong Wang (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: