Reputation: 143
I want to be able to take the data of an image as an array, modify it, and then use that array to create a modified image. Here is what I attempted:
public class Blue {
public static void main (String [] args) throws AWTException, IOException {
Robot robot = new Robot ();
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
BufferedImage img = robot.createScreenCapture(new Rectangle(0,0,d.width,d.height));
int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
int[] newPixels = IntStream.range(0,pixels.length).parallel().filter(i ->{
int p = pixels[i];
// get red
int r = (p >> 16) & 0xff;
// get green
int g = (p >> 8) & 0xff;
// get blue
int b = p & 0xff;
return b >= 200;
}).toArray();
int[] output = new int[pixels.length];
for(int i = 0; i<newPixels.length; i++) {
output[newPixels[i]] = 0x0000FF;
}
File f = new File("Result.jpg");
ByteBuffer byteBuffer = ByteBuffer.allocate(output.length * 4);
for (int i = 0; i< output.length; i++) {
byteBuffer.putInt(output[i]);
}
byte[] array = byteBuffer.array();
InputStream stream = new ByteArrayInputStream(array);
BufferedImage image1 = ImageIO.read(stream);
System.out.println(image1.getWidth());
ImageIO.write(image1, "png", f);
}
}
Here is how it works.
Step 9 is where the problem shows up. I keep getting a NullPointerException, meaning that the image doesn't exist, it is null. I don't understand what I did wrong. I tried using ByteArrayInputStream instead of InputStream, but that doesn't work as well. Then, I thought that maybe the first couple of bytes encode the coding information for the image, so I tried copying that over to the output array, but that didn't solve the problem either. I am not sure why my byte array isn't turning into an image.
Upvotes: 0
Views: 1615
Reputation: 27094
Yo summarize the comments in an answer, the problem is that you have an array of "raw" pixels, and try to pass that to ImageIO.read()
. ImageIO.read()
reads images stored in a defined file format, like PNG, JPEG or TIFF (while the pixel array is just pixels, it does not contain information on image dimension, color model, compression etc.). If no plugin is found for the input, the method will return null
(thus the NullPointerException
).
To create a BufferedImage
from the pixel array, you could create a raster around the array, pick a suitable color model and create a new BufferedImage
using the constructor taking a Raster
and ColorModel
parameter. You can see how to do that in one of my other answers.
However, as you already have a BufferedImage
and access to its pixels, it's much easier (and cheaper CPU/memory wise) to just reuse that.
You can replace your code with the following (see comments for details and relation to your steps):
public class Blue {
public static void main (String [] args) throws AWTException, IOException {
// 1. Create screen capture
Robot robot = new Robot ();
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
BufferedImage img = robot.createScreenCapture(new Rectangle(0, 0, d.width, d.height));
// 2: Get backing array
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
// 3: Find all "sufficiently blue" pixels
int[] bluePixels = IntStream.range(0, pixels.length).parallel()
.filter(i -> pixels[i] & 0xff >= 200).toArray();
// 4a: Clear all pixels to opaque black
for (int i = 0; i < pixels.length; i++) {
pixels[i] = 0xFF000000;
}
// 4b: Set all blue pixels to opaque blue
for (int i = 0; i < bluePixels.length; i++) {
pixels[bluePixels[i]] = 0xFF0000FF;
}
// 5: Make sure the file extension matches the file format for less confusion... 😀
File f = new File("result.png");
// 9: Print & write image (steps 6-8 is not needed)
System.out.println(img);
ImageIO.write(img, "png", f);
}
}
Upvotes: 1