lundi 29 décembre 2014

Changing a BufferedImage pixel with setRGB changes all BufferedImages


I am having trouble with a weird phenomena with setRGB() in BufferedImage.


I am building a 3D Graphics library that relies only on 2D math, and that there are no vectors. It also is not polygon based. To start out, I thought I would try setting different pixels in an empty image by cutting and pasting them, but to my surprise, Java isn't doing what I want it to.


In Java, you can define integers like so:



int i = 0;


In Java, you can also store that variable in another variable. Java stores the value in this case, but only the reference when it comes to Wrapper type Objects.



int j = i; // j stores the value i, not the reference i


In Java, you can change the value of i and j will not be affected.



i++;


If you compare and use System.out to see the values, you will notice j != i and that j is 0, i is 1.


In Java, I have no idea how return works in a getMethod. While it obviously returns an object, assuming it isn't a primitive type, I would guess just returns a reference if you do return obj (again, assuming it also is not an anonymous type or local value). However, the getRGB() and setRGB methods seem to conflict and write to every BufferedImage no matter which one I choose:



public static void moveRGB(int dx, int dy, Graphics g, BufferedImage img, int x, int y, int distx, int disty) {
// get pixel
final int rgb = img.getRGB(x, y);
System.out.println(rgb);
// paste pixel
img.setRGB(distx, disty, rgb);
// "delete" pixel
img.setRGB(x, y, 0xFFFFFFFF);
g.drawImage(img, dx, dy, null);
}


Apparently the language does not work as expected here because I have rgb as final and yet the value changes and sometimes, the values are inconsistent. For example, sometimes I may put 0xFFFFFF and it will show as -1 or as -16777215 (negative 0xFFFFFF). I tested this on TYPE_INT_ARGB ImageIO-read in image and a TYPE_INT_RGB blank image (which of course was all black).


Logically, you should be able to "move" a pixel by storing the value into memory completely separate from the buffer, then deleting that pixel, and overwriting the stored value into a specified coordinate in the buffer. This is not the case.


What happens is the pixel deletion part causes rgb to lose it's value somehow because the buffer data was overwritten with null (0x00000000). Whether you set it to "null" before or after changing the location of the supposedly stored pixel in rgb, rgb still has it's value changed.


If you comment out the "delete" pixel part of the method, it works fine, until you draw two images. This led me to imply that the data is somehow related to the graphics context, but that seemed far-fetched, as looking at the call hierarchy for both setRGB and getRGB do not conflict with the graphics context (apparently).


What I do vaguely know about, is the JIT does optimizations, especially on these images. Another piece of incriminating evidence is that you can createGraphics() from a BufferedImage. This heavily implies that the Graphics context is changed in such a manner that it is acting as a "static" raster for any image that uses that context.


Above all, the most baffling thing about this is how rgb's value is changing after I supposedly already got the pixel value.


The million dollar question


How can one prevent this from happening with only one Graphics context if at all possible, and how the whole Image drawing process works and what really goes on when setting and getting with setRGB and getRGB.





Aucun commentaire:

Enregistrer un commentaire