How do I create a BufferedImage from array containing pixels? - java

I get the pixels from BufferedImage using the method getRGB(). The pixels are stored in array called data[]. After some manipulation on data array, I need to create a BufferedImage again so that I can pass it to a module which will display the modified image, from this data array, but I am stuck with it.

I get the pixels from the BufferedImage using the method getRGB(). The
pixels are stored in array called data[].
Note that this can possibly be terribly slow. If your BufferedImage supports it, you may want to instead access the underlying int[] and directly copy/read the pixels from there.
For example, to fastly copy your data[] into the underlying int[] of a new BufferedImage:
BufferedImage bi = new BufferedImage( w, h, BufferedImage.TYPE_INT_ARGB );
final int[] a = ( (DataBufferInt) res.getRaster().getDataBuffer() ).getData();
System.arraycopy(data, 0, a, 0, data.length);
Of course you want to make sure that your data[] contains pixels in the same representation as your BufferedImage (ARGB in this example).

BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Then set the pixels again.
bufferedImage.setRGB(x, y, your_value);
PS: as stated in the comments, please use the answer from #TacticalCoder

You can set the RGB (int) values for the pixels in the new image using the setRGB methods.

Related

Removing a number of pixels of an image

Pre: Receives a buffered image and a number of pixels to remove
Post: creates and returns a copy of the received image with the given number of the images remaining pixels removed
I am having trouble with this method because I need to remove random pixels...I have only made a new copy of the image to print, but I need to change it so that the number of pixels given are removed...can anyone help?
public static BufferedImage removePixels(BufferedImage img,int numToRemove)
{
//so far what I have gotten
BufferedImage copy = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
copy.getGraphics().drawImage(img, 0,0,null);
return copy;
}
bufferedImage.setRGB(int x , int y , int rgb) and bufferedImage.getRGB(int x , int y) might be what you're looking for.

Performing setRGB on BufferedImage changes pixel to black instead of color

** Important update, see below! **
I am creating a program that changes the pixels of a BufferedImage to a certain color when that pixel fulfills a set of conditions in Java. However, when I write the image to disk, the pixels that should be colored are instead black.
First I define the color, using RGB codes:
Color purple = new Color(82, 0, 99);
int PURPLE = purple.getRGB();
Then I read the image I want to alter from a File into a BufferedImage called "blank":
BufferedImage blank = ImageIO.read(new File("some path"));
Now, loop through the pixels, and when a pixel at location (x, y) matches a criteria, change its color to purple:
blank.setRGB(x, y, PURPLE);
Now, write "blank" to the disk.
File output = new File("some other path");
ImageIO.write(blankIn, "png", output); // try-catch blocks intentionally left out
The resulting file should be "blank" with some purple pixels, but the pixels in question are instead black. I know for a fact that the issue is with setRGB and NOT any import or export functions, because "blank" itself is a color image, and gets written to file as such. I read around and saw a lot of posts recommending that I use Graphics2D and to avoid setRGB, but with no discussion of pixel-by-pixel color changing.
I also tried direct bit manipulation, like this:
blank.setRGB(x, y, ((82 << 16) + (0 << 8) + 99));
I'm probably doing that wrong, but if I put it in correctly it wouldn't matter, because the pixels are getting set to transparent when I do this (regardless of what the numbers say, which is very strange, to say the least).
** When I try this:
blank.setRGB(x, y, Color.RED.getRGB());
My output file is grayscale, so that means setRGB is, in fact, modifying my picture in grayscale. I think this is actually a rather simple issue, but the solution eludes me.
Based on the insights in https://stackoverflow.com/a/21981173 that you found yourself ... (a few minutes after posting the question) ... it seems that it should be sufficient to simply convert the image into ARGB directly after it was loaded:
public static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
The original image that was imported into Java was actually grayscale, so when Java read it into the BufferedImage, it simply imported it as a grayscale BufferedImage. By adding a very small but imperceptible colored dot in the corner of my image, I was able to get Java to output a correctly colored image.
Unfortunately, this is only a half solution, because I do not know how to fix this programmatically.
SOLUTION:
Convert the BufferedImage from grayscale to ARGB with this snippet:
BufferedImage blank2 = blank;
// Create temporary copy of blank
blank = new BufferedImage(blank.getWidth(), blank.getHeight(), BufferedImage.TYPE_INT_ARGB);
// Recreate blank as an ARGB BufferedImage
ColorConvertOp convert = new ColorConvertOp(null);
// Now create a ColorConvertOp object
convert.filter(blank2, blank);
// Convert blank2 to the blank color scheme and hold it in blank
You want to add this right after blank = ImageIO.read(new File("some path")).

Manipulating the pixels within a BufferedImage through an Array

I'm currently following a series on Java game development from scratch. I understand most java and oop concepts but have very little experience when dealing with graphics and hardware acceleration.
The lines of code that I am questioning are:
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
The BufferedImage "image" variable is always the variable being drawn to the screen through a render method. Usually something like:
public void render() {
BufferStrategy bs = this.getBufferStrategy;
if(bs == null) { this.createBufferStrategy(3); return; }
Graphics g = bs.getDrawGraphics();
g.drawImage(image, 0, 0, WIDTH, HEIGHT, null);
g.dispose();
bs.show();
}
I understand the array of pixels contains every pixel within the BufferedImage, however, it seems as though everytime that array is filled with values it directly effects the contents of the "image" variable. There is never a method used to copy the pixels array values into the image.
Are these varibales actually linked in such a way? Does the use of:
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
create an automated link between the image and the array being created in the code above? Maybe I am going cray and just missed something but I have reviewed the code several times and not once is the "image" varibale manipulated after it's initial creation. (besides being rendered to the screen of course.) It's always the array "pixels" just being filled with different values that causes the change in the rendered image.
Some insight on this would be wonderful. Thank you in advance!
Why don't you call
image.getData()
instead of
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
image.getData() returns a copy of the Raster. getRaster() returns a WriteableRaster with the ability to modify pixels. I'm guessing but getRaster() probably returns a child of the image Raster and therefore is writeable if you modify the array. Try image.getData() to see if it works. If not, post back here and I'll take a closer look.
I looked into this further. The source code that comes with the JDK shows that image.getRaster().getDataBuffer().getData() returns the source data array. image.getData() indeed returns a copy. If the image is modified, the data in getData() will not be modified.
You can call getPixels on the returned Raster:
public int[] getPixels(int x,
int y,
int w,
int h,
int[] iArray)
Returns an int array containing all samples for a rectangle of pixels,
one sample per array element. An ArrayIndexOutOfBoundsException may be
thrown if the coordinates are not in bounds. However, explicit bounds
checking is not guaranteed.
Use int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); instead of image.getData(). image.getData() just returns a copy of the image data where image.getRaster() returns the original pixel array allowing to actually write pixels to it.

Layer multiple BufferedImages on top of one another?

I have multiple transparent BufferedImage instances which I'd like to layer on top of each other (aka Photoshop layers) and bake into one BufferedImage output. How do I do this?
I would say the best bet would be to take the buffered images, and create an additional one in order to have an object to append to. Then simply use the Graphics.drawImage() to place them on top of each other.
So something along these lines:
BufferedImage a = ImageIO.read(new File(filePath, "a.png"));
BufferedImage b = ImageIO.read(new File(filePath, "b.png"));
BufferedImage c = new BufferedImage(a.getWidth(), a.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = c.getGraphics();
g.drawImage(a, 0, 0, null);
g.drawImage(b, 0, 0, null);
Let's pretend that the first BufferedImage is named bi1 and the second bi2, while the image you want to layer them onto is target.
BufferedImage target=new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
Graphics2D targetGraphics=target.createImage();
targetGraphics.drawImage(bi1,0,0,null);//draws the first image onto it
int[] pixels2=((DataBufferInt) bi2.getRaster().getDataBuffer()).getData();
int[] pixelsTgt=((DataBufferInt) target.getRaster().getDataBuffer()).getData();
for(int a=0;a<pixels2.length;a++)
{
pixelsTgt[a]+=pixels2[a];//this adds the pixels together
}
Make sure that all three BufferedImage objects are of TYPE_INT_ARGB so that alpha is turned on. This may not give you the exact results that you had wanted if the two added together are more than the max integer, so you might want to add in something to help fix that. Pixels use bit shifts to add to colors with the integer ordered as AARRGGBB.
Also consider the AlphaComposite modes available to the graphics context, discussed here.

How to clone Image?

I have an Image. I need to make a exactly copy of it and save it to BufferedImage, but there is no Image.clone(). The thing should be inside a calculating loop and so it should be really fast, no pixel-by-pixel copying. What's the best in perfomance method to do this?
You can draw to a buffered image, so make a blank bufferedImage, create a graphics context from it, and draw your original image to it.
BufferedImage copyOfImage =
new BufferedImage(widthOfImage, heightOfImage, BufferedImage.TYPE_INT_RGB);
Graphics g = copyOfImage.createGraphics();
g.drawImage(originalImage, 0, 0, null);
There is another way:
BufferedImage copyOfImage = image.getSubimage(0, 0, image.getWidth, image.getHeight);
Image clone = original.getScaledInstance(original.getWidth(), -1, Image.SCALE_DEFAULT);
This might not be very pretty, but getScaledInstance returns, as the name suggests, an instance of your original Image object. Usually only used for resizing. -1 tells the method to keep the aspect ratio as it is
You can create a method that returns the subimage of the image you want to clone.
Such as:
public static BufferedImage clone(BufferedImage img)
{
return img.getSubimage(img.getMinX(), img.getMinY(), img.getWidth(), img.getHeight());
}

Categories