如何在Java SE中将字节数组转换为图像

6

如何在Java SE中将原始字节数组转换为图像。

该数组由字节组成,其中每三个字节表示一个像素,每个字节对应RGB组件。

有人能提供一个代码示例吗?

谢谢, Mike


最终我没有找到比这更好的方法: for(int y=0; y<height; y++) { for(int x=0; x<width; x++) { int i0 = (y*width+x)*3; frameImg.setRGB(x, y, ((data[i0]&0xFF) | ((data[i0+1]&0xFF)<<8) | ((data[i0+2]&0xFF)<<16))); } } - Ma99uS
字节数组的维度是什么?它是一维数组,二维数组还是三维数组? - Anderson Green
5个回答

10

你可以使用Raster类来完成。这样做更好,因为它不需要迭代和复制字节数组。

 byte[] raw = new byte[width*height*3]; // raw bytes of our image
 DataBuffer buffer = new DataBufferByte(raw, raw.length);

 //The most difficult part of awt api for me to learn
 SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 3, width*3, new int[]{2,1,0});

 Raster raster = Raster.createRaster(sampleModel, buffer, null);

 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
 image.setData(raster);

谢谢您发布这个。它真的很有用! - Brent Writes Code

6
假设您知道图片的高度和宽度。
BufferedImage img=new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for(int r=0; r<height; r++)
for(int c=0; c<width; c++)
{
  int index=r*width+c;
  int red=colors[index] & 0xFF;
  int green=colors[index+1] & 0xFF;
  int blue=colors[index+2] & 0xFF;
  int rgb = (red << 16) | (green << 8) | blue;
  img.setRGB(c, r, rgb);
}

大致上来说,这个假设像素数据被编码为一组行;并且颜色的长度是3 * 宽度 * 高度(这应该是有效的)。

那么遍历数组是我在这里最好的选择吗?感觉一定有一种接受数组作为参数并可以一次性填充/重新创建图像的方法。也许与 Raster 类有关? - Ma99uS
据我所知没有,不过Raster对我来说很陌生。如果这是遵循标准图像格式的话,你可以使用ImageIO类,但这就是我的知识极限了。 - CoderTao
1
你也可以这样做:int rgb = ((int)colors[in] << 24) + ((int)colors[in+1] << 8) + (int)colors[in] - notnoop
1
这样你就可以解决有符号/无符号问题: frameImg.setRGB(x, y, ((data[i0]&0xFF) | ((data[i0+1]&0xFF)<<8) | (data[i0+2]&0xFF)<<16))); - Ma99uS
1
尽管被接受,但这个答案似乎不正确。如果“colors”是一个RGB数组(其中R、G和B是单独的字节),那么“index”在每次循环中是否应该增加超过1? - Brent Writes Code
显示剩余5条评论

2

如果你的RGB值是B,G,R顺序,folkyatina的方法是可行的,但如果它们是R,G,B顺序,我发现以下代码可以工作:

    DataBuffer rgbData = new DataBufferByte(rgbs, rgbs.length);

    WritableRaster raster = Raster.createInterleavedRaster(
        rgbData, width, height,
        width * 3, // scanlineStride
        3, // pixelStride
        new int[]{0, 1, 2}, // bandOffsets
        null);

    ColorModel colorModel = new ComponentColorModel(
        ColorSpace.getInstance(ColorSpace.CS_sRGB),
        new int[]{8, 8, 8}, // bits
        false, // hasAlpha
        false, // isPreMultiplied
        ComponentColorModel.OPAQUE,
        DataBuffer.TYPE_BYTE);

    return new BufferedImage(colorModel, raster, false, null);

1

有一个setRGB变量,它接受一个RGBA值的int数组:

BufferedImage img=new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] raw = new int[data.length * 4 / 3];
for (int i = 0; i < data.length / 3; i++) {
    raw[i] = 0xFF000000 | 
        ((data[3 * i + 0] & 0xFF) << 16) |
        ((data[3 * i + 1] & 0xFF) << 8) |
        ((data[3 * i + 2] & 0xFF));
}
img.setRGB(0, 0, width, height, raw, 0, width);

性能特征与 CoderTao 的解决方案类似。


1
假设您的原始数据是一个类似于1维数组的形式:
byte[] imageBytes = new byte[1024];
// transform to bufferImage
BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
// if you want to do some operations to the image, like resize, 
// use the lib (net.coobird.thumbnailator)
BufferedImage image = Thumbnails.of(bufferedImage).forceSize(WIDTH, HEIGHT)
                                .outputFormat("bmp").asBufferedImage();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接