如何在Java中将byte []转换为BufferedImage?

时间:2022-03-18 16:33:53

I'm posting this thread because I have some difficulties to deal with pictures in Java. I would like to be able to convert a picture into a byte[] array, and then to be able to do the reverse operation, so I can change the RGB of each pixel, then make a new picture. I want to use this solution because setRGB() and getRGB() of BufferedImage may be too slow for huge pictures (correct me if I'm wrong).

我发布这个帖子是因为我在处理Java中的图片时遇到了一些困难。我希望能够将图片转换为byte []数组,然后能够执行相反的操作,这样我就可以更改每个像素的RGB,然后创建一个新图片。我想使用这个解决方案,因为BufferedImage的setRGB()和getRGB()对于巨大的图片来说可能太慢了(如果我错了,请纠正我)。

I read some posts here to obtain a byte[] array (such as here) so that each pixel is represented by 3 or 4 cells of the array containing the red, the green and the blue values (with the additional alpha value, when there are 4 cells), which is quite useful and easy to use for me. Here's the code I use to obtain this array (stored in a PixelArray class I've created) :

我在这里阅读了一些帖子来获取byte []数组(例如这里),以便每个像素由包含红色,绿色和蓝色值的数组的3或4个单元格表示(带有额外的alpha值,当有是4个细胞),这对我来说非常有用且易于使用。这是我用来获取这个数组的代码(存储在我创建的PixelArray类中):

public PixelArray(BufferedImage image)
{
    width = image.getWidth();
    height = image.getHeight();
    DataBuffer toArray = image.getRaster().getDataBuffer();
    array = ((DataBufferByte) toArray).getData();
    hasAlphaChannel = image.getAlphaRaster() != null;
}

My big trouble is that I haven't found any efficient method to convert this byte[] array to a new image, if I wanted to transform the picture (for example, remove the blue/green values and only keeping the red one). I tried those solutions :

我的大麻烦是我没有找到任何有效的方法将这个byte []数组转换为新图像,如果我想转换图片(例如,删除蓝色/绿色值并仅保留红色值)。我试过这些解决方案:

1) Making a DataBuffer object, then make a SampleModel, to finally create a WritableRaster and then BufferedImage (with additional ColorModel and Hashtable objects). It didn't work because I apparently don't have all the information I need (I have no idea what's the Hashtable for BufferedImage() constructor).

1)创建一个DataBuffer对象,然后创建一个SampleModel,最后创建一个WritableRaster,然后创建BufferedImage(带有额外的ColorModel和Hashtable对象)。它没有用,因为我显然没有我需要的所有信息(我不知道什么是BufferedImage()构造函数的Hashtable)。

2) Using a ByteArrayInputStream. This didn't work because the byte[] array expected with ByteArrayInputStream has nothing to do with mine : it represents each byte of the file, and not each component of each pixel (with 3-4 bytes for each pixel)...

2)使用ByteArrayInputStream。这不起作用,因为ByteArrayInputStream所期望的byte []数组与我的无关:它代表文件的每个字节,而不是每个像素的每个分量(每个像素有3-4个字节)......

Could someone help me?

有人能帮帮我吗?

5 个解决方案

#1


28  

Try this:

尝试这个:

private BufferedImage createImageFromBytes(byte[] imageData) {
    ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
    try {
        return ImageIO.read(bais);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

#2


7  

I have tried the approaches mentioned here but for some reason neither of them worked. Using ByteArrayInputStream and ImageIO.read(...) returns null, whereas byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); returns a copy of the image data, not a direct reference to them (see also here).

我尝试过这里提到的方法,但由于某种原因,它们都没有奏效。使用ByteArrayInputStream和ImageIO.read(...)返回null,而byte [] array =((DataBufferByte)image.getRaster()。getDataBuffer())。getData();返回图像数据的副本,而不是直接引用它们(另请参见此处)。

However, the following worked for me. Let's suppose that the dimensions and the type of the image data are known. Let also byte[] srcbuf be the buffer of the data to be converted into BufferedImage. Then,

但是,以下内容对我有用。让我们假设图像数据的尺寸和类型是已知的。还让byte [] srcbuf成为要转换为BufferedImage的数据的缓冲区。然后,

  1. Create a blank image, for example

    例如,创建一个空白图像

    img=new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    
  2. Convert the data array to Raster and use setData to fill the image, i.e.

    将数据数组转换为Raster并使用setData填充图像,即

    img.setData(Raster.createRaster(img.getSampleModel(), new DataBufferByte(srcbuf, srcbuf.length), new Point() ) );
    

#3


6  

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(pixelArray, 0, array, 0, array.length);

This method does tend to get out of sync when you try to use the Graphics object of the resulting image. If you need to draw on top of your image, construct a second image (which can be persistant, i.e. not constructed every time but re-used) and drawImage the first one onto it.

当您尝试使用生成的图像的Graphics对象时,此方法确实会失去同步。如果需要在图像上绘制,则构造第二个图像(可以是持久的,即每次都不构造但重新使用)并将第一个图像绘制到它上面。

#4


2  

Several people upvoted the comment that the accepted answer is wrong.

有几个人赞同这个评论,认为接受的答案是错误的。

If the accepted answer isn't working, it may be because Image.IO doesn't have support for the type of image you're trying (eg tiff).

如果接受的答案不起作用,可能是因为Image.IO不支持您正在尝试的图像类型(例如tiff)。

Add this to your pom (aka put jai-imageio-core-1.3.1.jar in your classpath):

将它添加到你的pom(也就是你的类路径中的jai-imageio-core-1.3.1.jar):

    <!-- https://mvnrepository.com/artifact/com.github.jai-imageio/jai-imageio-core -->
    <dependency>
        <groupId>com.github.jai-imageio</groupId>
        <artifactId>jai-imageio-core</artifactId>
        <version>1.3.1</version>
    </dependency>

To add support for:

添加支持:

  • wbmp
  • WBMP
  • bmp
  • BMP
  • pcx
  • PCX
  • pnm
  • PNM
  • raw
  • 生的
  • tiff
  • 斗嘴
  • gif (write)
  • gif(写)

You can check the list of supported formats with:

您可以使用以下方法检查支持的格式列表:

     for(String format : ImageIO.getReaderFormatNames())
        System.out.println(format);

Note that you only have to drop eg jai-imageio-core-1.3.1.jar into your classpath to make it work.

请注意,您只需将jai-imageio-core-1.3.1.jar放入类路径中即可使其正常工作。

Other projects that add additional support include:

其他增加额外支持的项目包括:

#5


0  

The approach by using ImageIO.read directly is not right in some cases. In my case, the raw byte[] doesn't contain any information about the width and height and format of the image. By only using ImageIO.read, It is impossible for the program to construct a valid image.

在某些情况下,直接使用ImageIO.read的方法并不正确。在我的例子中,原始byte []不包含有关图像的宽度和高度以及格式的任何信息。仅使用ImageIO.read,程序无法构建有效图像。

It is necessary to pass the basic information of the image to BufferedImage object:

有必要将图像的基本信息传递给BufferedImage对象:

    BufferedImage outBufImg = new BufferedImage(width, height, bufferedImage.TYPE_3BYTE_BGR);

Then set the data for the BufferedImage object by using setRGB or setData. (When using setRGB, it seems we must convert byte[] to int[] first. As a result, it may cause performance issues if the source image data is big. Maybe setData is a better idea for big byte[] typed source data.)

然后使用setRGB或setData设置BufferedImage对象的数据。 (当使用setRGB时,似乎我们必须首先将byte []转换为int []。因此,如果源图像数据很大,它可能会导致性能问题。对于大字节[]类型的源数据,setData可能更好。 。)

#1


28  

Try this:

尝试这个:

private BufferedImage createImageFromBytes(byte[] imageData) {
    ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
    try {
        return ImageIO.read(bais);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

#2


7  

I have tried the approaches mentioned here but for some reason neither of them worked. Using ByteArrayInputStream and ImageIO.read(...) returns null, whereas byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); returns a copy of the image data, not a direct reference to them (see also here).

我尝试过这里提到的方法,但由于某种原因,它们都没有奏效。使用ByteArrayInputStream和ImageIO.read(...)返回null,而byte [] array =((DataBufferByte)image.getRaster()。getDataBuffer())。getData();返回图像数据的副本,而不是直接引用它们(另请参见此处)。

However, the following worked for me. Let's suppose that the dimensions and the type of the image data are known. Let also byte[] srcbuf be the buffer of the data to be converted into BufferedImage. Then,

但是,以下内容对我有用。让我们假设图像数据的尺寸和类型是已知的。还让byte [] srcbuf成为要转换为BufferedImage的数据的缓冲区。然后,

  1. Create a blank image, for example

    例如,创建一个空白图像

    img=new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    
  2. Convert the data array to Raster and use setData to fill the image, i.e.

    将数据数组转换为Raster并使用setData填充图像,即

    img.setData(Raster.createRaster(img.getSampleModel(), new DataBufferByte(srcbuf, srcbuf.length), new Point() ) );
    

#3


6  

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
byte[] array = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(pixelArray, 0, array, 0, array.length);

This method does tend to get out of sync when you try to use the Graphics object of the resulting image. If you need to draw on top of your image, construct a second image (which can be persistant, i.e. not constructed every time but re-used) and drawImage the first one onto it.

当您尝试使用生成的图像的Graphics对象时,此方法确实会失去同步。如果需要在图像上绘制,则构造第二个图像(可以是持久的,即每次都不构造但重新使用)并将第一个图像绘制到它上面。

#4


2  

Several people upvoted the comment that the accepted answer is wrong.

有几个人赞同这个评论,认为接受的答案是错误的。

If the accepted answer isn't working, it may be because Image.IO doesn't have support for the type of image you're trying (eg tiff).

如果接受的答案不起作用,可能是因为Image.IO不支持您正在尝试的图像类型(例如tiff)。

Add this to your pom (aka put jai-imageio-core-1.3.1.jar in your classpath):

将它添加到你的pom(也就是你的类路径中的jai-imageio-core-1.3.1.jar):

    <!-- https://mvnrepository.com/artifact/com.github.jai-imageio/jai-imageio-core -->
    <dependency>
        <groupId>com.github.jai-imageio</groupId>
        <artifactId>jai-imageio-core</artifactId>
        <version>1.3.1</version>
    </dependency>

To add support for:

添加支持:

  • wbmp
  • WBMP
  • bmp
  • BMP
  • pcx
  • PCX
  • pnm
  • PNM
  • raw
  • 生的
  • tiff
  • 斗嘴
  • gif (write)
  • gif(写)

You can check the list of supported formats with:

您可以使用以下方法检查支持的格式列表:

     for(String format : ImageIO.getReaderFormatNames())
        System.out.println(format);

Note that you only have to drop eg jai-imageio-core-1.3.1.jar into your classpath to make it work.

请注意,您只需将jai-imageio-core-1.3.1.jar放入类路径中即可使其正常工作。

Other projects that add additional support include:

其他增加额外支持的项目包括:

#5


0  

The approach by using ImageIO.read directly is not right in some cases. In my case, the raw byte[] doesn't contain any information about the width and height and format of the image. By only using ImageIO.read, It is impossible for the program to construct a valid image.

在某些情况下,直接使用ImageIO.read的方法并不正确。在我的例子中,原始byte []不包含有关图像的宽度和高度以及格式的任何信息。仅使用ImageIO.read,程序无法构建有效图像。

It is necessary to pass the basic information of the image to BufferedImage object:

有必要将图像的基本信息传递给BufferedImage对象:

    BufferedImage outBufImg = new BufferedImage(width, height, bufferedImage.TYPE_3BYTE_BGR);

Then set the data for the BufferedImage object by using setRGB or setData. (When using setRGB, it seems we must convert byte[] to int[] first. As a result, it may cause performance issues if the source image data is big. Maybe setData is a better idea for big byte[] typed source data.)

然后使用setRGB或setData设置BufferedImage对象的数据。 (当使用setRGB时,似乎我们必须首先将byte []转换为int []。因此,如果源图像数据很大,它可能会导致性能问题。对于大字节[]类型的源数据,setData可能更好。 。)