如何从字节数组创建图像



我希望能够将图像的数据作为数组,对其进行修改,然后使用该数组创建修改后的图像。以下是我尝试的:

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);
}
}

以下是它的工作原理。

  1. 机器人拍摄屏幕截图,然后将其存储到BufferedImage中
  2. 图像的数据存储在一个整数数组中
  3. int流用于选择与足够蓝的像素相对应的所有像素位置
  4. 这些蓝色像素被放置在一个称为输出的阵列中,与它们被提取的位置相同。但是,数组的其余部分的值为0
  5. 已为我修改的图像创建目标文件
  6. 我创建了一个字节缓冲区,它的长度是输出数组的4倍,来自输出数组的数据就放在其中
  7. 我从缓冲区创建一个字节数组,然后用它创建一个输入流
  8. 最后,我阅读了流,从中创建了一个图像
  9. 我使用System.out.println((从图像中打印一些数据,看看图像是否存在

步骤9是问题出现的地方。我一直得到一个NullPointerException,这意味着图像不存在,它是null。我不明白我做错了什么。我尝试使用ByteArrayInputStream而不是InputStream,但效果不太好。然后,我认为可能前几个字节编码了图像的编码信息,所以我尝试将其复制到输出数组,但这也没有解决问题。我不知道为什么我的字节数组没有变成图像。

Yo在回答中总结注释,问题是您有一个"生的";像素,并尝试将其传递给ImageIO.read()ImageIO.read()读取以定义的文件格式存储的图像,如PNG、JPEG或TIFF(虽然像素阵列只是像素,但它不包含图像尺寸、颜色模型、压缩等信息(。如果没有为输入找到插件,该方法将返回null(因此返回NullPointerException(。

要从像素阵列创建BufferedImage,可以在阵列周围创建光栅,选择合适的颜色模型,并使用采用RasterColorModel参数的构造函数创建新的BufferedImage。你可以在我的另一个答案中看到如何做到这一点。

然而,由于您已经拥有BufferedImage并可以访问其像素,因此重用它要容易得多(而且在CPU/内存方面更便宜(。

您可以用以下内容替换您的代码(有关详细信息和步骤关系,请参阅注释(:

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);
}
}

最新更新