Difference btw. Graphics fillRect and clearRect

Viewed 58

I noticed some interesting difference between fillRect and clearRect when I want to initialize a BufferedImage with a half-transparent background color:

using fillRect:

Color someHalfTransparentColor = new Color(Integer.parseInt("77affe07", 16), true);
BufferedImage bi = new BufferedImage(10, 10, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = bi.createGraphics();
g.setColor(someHalfTransparentColor);
g.fillRect(0, 0, 10, 10);
g.dispose();
        
System.out.println(Integer.toString(bi.getRGB(0, 0), 16));
// WORKS NOT AS EXPECTED: 77b0ff06 != 77affe07

using clearRect:

Color someHalfTransparentColor = new Color(Integer.parseInt("77affe07", 16), true);
BufferedImage bi = new BufferedImage(10, 10, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = bi.createGraphics();
g.setBackground(someHalfTransparentColor);
g.clearRect(0, 0, 10, 10);
g.dispose();
        
System.out.println(Integer.toString(bi.getRGB(0, 0), 16));
// WORKS AS EXPECTED: 77affe07 == 77affe07

It seems when using fillRect the color values are slightly changed. Can someone explain this behavior?

1 Answers

The difference is that fillRect uses the current composite (getComposite) of the Graphics2D, and clearRect ignores it. By default, the composite is AlphaComposite.SrcOver. When drawing a new rect, this composite will decide the final color by combining the color at the destination and the color about to be drawn with some maths.

On the other hand, (at least on my version of the JDK) clearRect sets the composite temporarily to AlphaComposite.Src (hence ignoring the current composite), which totally ignores the destination, and simply copies the color you want to draw to the place you want.

You can see that if you do g.setComposite(AlphaComposite.Src); before fillRect, you get the same output as clearRect.

The parts of the docs that sort of mention this are:

clearRect:

This operation does not use the current paint mode.

setComposite:

Sets the Composite for the Graphics2D context. The Composite is used in all drawing methods such as drawImage, drawString, draw, and fill. It specifies how new pixels are to be combined with the existing pixels on the graphics device during the rendering process.

It could be argued that:

  • clearRect isn't a "drawing method". It erases things, so setComposite doesn't apply to it.
  • the composite is part of the "paint mode" (the docs doesn't define this term for some reason), and so clearRect doesn't use it.
Related