Search code examples
javaawtbufferedimagegraphics2d

Drawing a BufferedImage to another BufferedImage is changing RGBA values


I have an issue trying to make a copy of BufferedImage object.

I'm using drawImage (BufferedImage image, int x, int y, ImageObserver observer) method to draw the original image on the new one, and i'm setting BufferedImage.TYPE_INT_ARGB for each image, however, when i print the values of new image colors, the RGBA values are slightly different.

I need to make a copy of the original image because i have a JPanel holding an image to be drawn as background. In other parts of my application i have to get the image from the panel, but i would like to return a copy to avoid the image to be modified from elsewhere.

How can i solve this issue?

Code:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
public class BufferedImageColorBug
{
    public static void main (String [] a) {
        Color [] colors = {
            new Color (202,230,186,14),
            new Color (254,65,188,214),
            new Color (247,104,197,198),
            new Color (158,93,79,239),
            new Color (235,45,57,194),
            new Color (155,77,126,150),
            new Color (164,237,20,172),
            new Color (184,106,97,191),
            new Color (187,249,135,85),
            new Color (236,112,98,24)
        };
        BufferedImage image = new BufferedImage (colors.length, 1, BufferedImage.TYPE_INT_ARGB);
        for (int x = 0; x < colors.length; x ++) image.setRGB (x, 0, colors [x].getRGB ());
        BufferedImage copy = new BufferedImage (image.getWidth (), image.getHeight (), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = copy.createGraphics ();
        g2d.drawImage (image, 0, 0, null);
        g2d.dispose ();
        for (int x = 0; x < colors.length; x ++) {
            Color color = new Color (copy.getRGB (x, 0), true);
            System.out.println (color.getRed () + "," + color.getGreen () + "," + color.getBlue () + "," + color.getAlpha ());
        }
    }
}

This is the ouput i get:

200,237,182,14
254,66,188,214
247,104,197,198
158,93,79,239
235,45,57,194
155,76,126,150
165,237,19,172
184,105,97,191
186,249,135,85
234,117,96,24

EDIT

I talked about cloning image because this is my aim, but with this question i would like to understand why rgba values are different between images.

I already tried to use BufferedImage.TYPE_INT_ARGB_PRE, but it didn't help.


Solution

  • To create an exact copy of your image (given they are both of the same type), you can change the code just a little bit:

    BufferedImage copy = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
    copy.setData(image.getRaster()); // getRaster() is faster than getData(), as no copy is created
    
    for (int x = 0; x < colors.length; x++) {
        Color color = new Color(copy.getRGB(x, 0), true);
        System.out.println(color.getRed() + "," + color.getGreen() + "," + color.getBlue() + "," + color.getAlpha());
    }
    

    This will print the same colors as in your original colors array.


    PS: I initially thought this was a bug, but realize now it likely isn't.

    After some testing, I found that there's a small difference between your code and the code I normally use to clone images. If you change the alpha compositing rule to Src (meaning only the source will contribute and completely replace the pixels at the destination), you will also get the expected result:

    BufferedImage copy = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
    
    Graphics2D g2d = copy.createGraphics();
    g2d.setComposite(AlphaComposite.Src); // Completely replace, default is SrcOver
    g2d.drawImage(image, 0, 0, null);
    g2d.dispose();
    
    for (int x = 0; x < colors.length; x++) {
        Color color = new Color(copy.getRGB(x, 0), true);
        System.out.println(color.getRed() + "," + color.getGreen() + "," + color.getBlue() + "," + color.getAlpha());
    }
    

    The reason is that in composing semi-transparent pixels over completely transparent pixels, the original transparent pixels at the destination will contribute to the end result, thus altering the RGBA values.