如何从字节数组创建图像?
How do I create an Image from a byte array?
我希望能够将图像的数据作为数组,对其进行修改,然后使用该数组创建修改后的图像。这是我的尝试:
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);
}
}
这是它的工作原理。
- 机器人对屏幕进行屏幕截图,然后将其存储到 BufferedImage 中。
- 图像的数据存储在整数数组中
- int 流用于select 对应于足够蓝色像素的所有像素位置
- 这些蓝色像素被放置在一个名为输出的数组中,位置与它们的来源相同。但是,数组的其余部分的值为 0。
- 为我的修改图像创建了一个目标文件
- 我创建了一个长度为输出数组长度 4 倍的字节缓冲区,并将输出数组中的数据放入其中。
- 我从缓冲区创建一个字节数组,然后用它创建一个输入流
- 最后,我读取流以从中创建图像
- 我使用 System.out.println() 从图像中打印一些数据以查看图像是否存在。
第 9 步出现问题。
我不断收到 NullPointerException,这意味着该图像不存在,它为空。
我不明白我做错了什么。
我尝试使用 ByteArrayInputStream 而不是 InputStream,但效果不佳。然后,我想也许前几个字节编码了图像的编码信息,所以我尝试将其复制到输出数组,但这也没有解决问题。我不确定为什么我的字节数组没有变成图像。
你在答案中总结了评论,问题是你有一个“原始”像素数组,并尝试将其传递给 ImageIO.read()
。 ImageIO.read()
读取以定义的文件格式存储的图像,如 PNG、JPEG 或 TIFF(虽然像素数组只是像素,但它不包含有关图像尺寸、颜色模型、压缩等的信息)。如果没有为输入找到插件,该方法将 return null
(因此 NullPointerException
)。
要从像素阵列创建 BufferedImage
,您可以围绕阵列创建光栅,选择合适的颜色模型并使用采用 [=17= 的构造函数创建新的 BufferedImage
] 和 ColorModel
参数。你可以在我的其他答案之一中看到如何做到这一点。
但是,由于您已经 拥有 一个 BufferedImage
并可以访问它的像素,因此重用它会更容易(并且更便宜 CPU/memory 明智) .
您可以用以下代码替换您的代码(有关详细信息和与您的步骤相关的信息,请参阅评论):
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);
}
}
我希望能够将图像的数据作为数组,对其进行修改,然后使用该数组创建修改后的图像。这是我的尝试:
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);
}
}
这是它的工作原理。
- 机器人对屏幕进行屏幕截图,然后将其存储到 BufferedImage 中。
- 图像的数据存储在整数数组中
- int 流用于select 对应于足够蓝色像素的所有像素位置
- 这些蓝色像素被放置在一个名为输出的数组中,位置与它们的来源相同。但是,数组的其余部分的值为 0。
- 为我的修改图像创建了一个目标文件
- 我创建了一个长度为输出数组长度 4 倍的字节缓冲区,并将输出数组中的数据放入其中。
- 我从缓冲区创建一个字节数组,然后用它创建一个输入流
- 最后,我读取流以从中创建图像
- 我使用 System.out.println() 从图像中打印一些数据以查看图像是否存在。
第 9 步出现问题。 我不断收到 NullPointerException,这意味着该图像不存在,它为空。 我不明白我做错了什么。 我尝试使用 ByteArrayInputStream 而不是 InputStream,但效果不佳。然后,我想也许前几个字节编码了图像的编码信息,所以我尝试将其复制到输出数组,但这也没有解决问题。我不确定为什么我的字节数组没有变成图像。
你在答案中总结了评论,问题是你有一个“原始”像素数组,并尝试将其传递给 ImageIO.read()
。 ImageIO.read()
读取以定义的文件格式存储的图像,如 PNG、JPEG 或 TIFF(虽然像素数组只是像素,但它不包含有关图像尺寸、颜色模型、压缩等的信息)。如果没有为输入找到插件,该方法将 return null
(因此 NullPointerException
)。
要从像素阵列创建 BufferedImage
,您可以围绕阵列创建光栅,选择合适的颜色模型并使用采用 [=17= 的构造函数创建新的 BufferedImage
] 和 ColorModel
参数。你可以在我的其他答案之一中看到如何做到这一点。
但是,由于您已经 拥有 一个 BufferedImage
并可以访问它的像素,因此重用它会更容易(并且更便宜 CPU/memory 明智) .
您可以用以下代码替换您的代码(有关详细信息和与您的步骤相关的信息,请参阅评论):
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);
}
}