将 8 位灰度图像字节数组转换为 BufferedImage
Convert 8bit Grayscale image byte array to a BufferedImage
我有一个包含原始灰度 8 位图像数据的字节数组,我需要将其转换为 BufferedImage。我试过:
BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
但是,生成的 image
对象为空,这意味着我在这里做错了。
进行这种转换的正确方法是什么?
我已经成功地通过以下方式完成了 640x480 分辨率的转换:
BufferedImage image = new BufferedImage(640,480,BufferedImage.TYPE_BYTE_INDEXED);
int i = 0;
for(int y = 0; y < 480; y++)
{
for(int x = 0; x < 640; x++)
{
int g = imageBytes[i++] & 0xFF;
image.setRGB(x,y,new Color(g,g,g).getRGB());
}
}
编辑:删除了无用的代码(感谢 Marco13)
根据您的用例,有两种很好的方法可以做到这一点。
要么创建一个新的灰色图像,然后将数据复制到其中。这将保留图像 "managed",这可能会带来更好的渲染性能(即在屏幕上)。但它需要两倍的内存,并将数据从输入复制到图像。
另一种,是直接创建灰度图像"around"您现有的像素数据。这会更快,并且几乎不使用额外的堆,因为它避免了复制像素数据。但是图像不会被管理(因为支持数组是公开的和可变的)。
两种选择如下所示:
int w = 640;
int h = 480;
byte[] imageBytes = new byte[w * h];
// 1 Keeps the image "managed" at the expense of twice the memory + a large array copy
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, imageBytes);
System.out.println("image: " + image);
// 2 Faster, and uses less memory, but will make the image "unmanaged"
ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(new DataBufferByte(imageBytes, imageBytes.length), w, h, w, 1, new int[]{0}, null);
BufferedImage image2 = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
System.out.println("image2: " + image2);
如果图像数据不是线性灰色 space,可以使用 IndexColorModel
将输入映射到您想要的任何范围:
// Alternate, using IndexColorModel, if your input isn't in linear gray color space
int[] cmap = new int[256]; // TODO: Add ARGB packed colors here...
IndexColorModel icm = new IndexColorModel(8, 256, cmap, 0, false, -1, DataBuffer.TYPE_BYTE);
// As 1
BufferedImage image3 = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED, icm);
image3.getRaster().setDataElements(0, 0, w, h, imageBytes);
System.out.println("image3: " + image3);
// As 2
BufferedImage image4 = new BufferedImage(icm, raster, cm.isAlphaPremultiplied(), null);
System.out.println("image4: " + image4);
Java
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, width, height, array));
科特林
val image = BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY)
image.raster.setDataElements(0, 0, width, height, byteArray )
我有一个包含原始灰度 8 位图像数据的字节数组,我需要将其转换为 BufferedImage。我试过:
BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
但是,生成的 image
对象为空,这意味着我在这里做错了。
进行这种转换的正确方法是什么?
我已经成功地通过以下方式完成了 640x480 分辨率的转换:
BufferedImage image = new BufferedImage(640,480,BufferedImage.TYPE_BYTE_INDEXED);
int i = 0;
for(int y = 0; y < 480; y++)
{
for(int x = 0; x < 640; x++)
{
int g = imageBytes[i++] & 0xFF;
image.setRGB(x,y,new Color(g,g,g).getRGB());
}
}
编辑:删除了无用的代码(感谢 Marco13)
根据您的用例,有两种很好的方法可以做到这一点。
要么创建一个新的灰色图像,然后将数据复制到其中。这将保留图像 "managed",这可能会带来更好的渲染性能(即在屏幕上)。但它需要两倍的内存,并将数据从输入复制到图像。
另一种,是直接创建灰度图像"around"您现有的像素数据。这会更快,并且几乎不使用额外的堆,因为它避免了复制像素数据。但是图像不会被管理(因为支持数组是公开的和可变的)。
两种选择如下所示:
int w = 640;
int h = 480;
byte[] imageBytes = new byte[w * h];
// 1 Keeps the image "managed" at the expense of twice the memory + a large array copy
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, imageBytes);
System.out.println("image: " + image);
// 2 Faster, and uses less memory, but will make the image "unmanaged"
ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(new DataBufferByte(imageBytes, imageBytes.length), w, h, w, 1, new int[]{0}, null);
BufferedImage image2 = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
System.out.println("image2: " + image2);
如果图像数据不是线性灰色 space,可以使用 IndexColorModel
将输入映射到您想要的任何范围:
// Alternate, using IndexColorModel, if your input isn't in linear gray color space
int[] cmap = new int[256]; // TODO: Add ARGB packed colors here...
IndexColorModel icm = new IndexColorModel(8, 256, cmap, 0, false, -1, DataBuffer.TYPE_BYTE);
// As 1
BufferedImage image3 = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED, icm);
image3.getRaster().setDataElements(0, 0, w, h, imageBytes);
System.out.println("image3: " + image3);
// As 2
BufferedImage image4 = new BufferedImage(icm, raster, cm.isAlphaPremultiplied(), null);
System.out.println("image4: " + image4);
Java
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, width, height, array));
科特林
val image = BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY)
image.raster.setDataElements(0, 0, width, height, byteArray )