34

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

我在这里阅读了一些帖子以获得一个 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;
}

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

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

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

有人可以帮助我吗?

4

5 回答 5

42

试试这个:

private BufferedImage createImageFromBytes(byte[] imageData) {
    ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
    try {
        return ImageIO.read(bais);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
于 2012-11-20T01:51:11.550 回答
16

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

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

  1. 例如创建一个空白图像

    img=new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    
  2. 将数据数组转换为Raster并用于setData填充图像,即

    img.setData(Raster.createRaster(img.getSampleModel(), new DataBufferByte(srcbuf, srcbuf.length), new Point() ) );
    
于 2015-04-03T08:10:22.360 回答
8
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);

当您尝试使用生成图像的 Graphics 对象时,此方法确实会不同步。如果您需要在图像上绘制,请构建第二个图像(可以是持久的,不是每次都构建,而是重复使用)并将drawImage第一个图像放在上面。

于 2014-06-24T07:50:50.883 回答
6

有几个人赞成接受的答案是错误的评论。

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

要使其工作,您需要添加一个额外的 jar 来处理图像类型。

您可以添加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>

添加对以下内容的支持:

  • wbmp
  • bmp
  • 个人电脑
  • 纳米级
  • 生的
  • tiff
  • gif(写)

您可以通过以下方式检查支持的格式列表:

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

请注意,您只需将 jar(例如 jai-imageio-core-1.3.1.jar)拖放到类路径中即可使其工作。

其他为图像类型添加额外支持的项目包括:

于 2017-04-13T11:36:51.400 回答
0

在某些情况下,直接使用 ImageIO.read 的方法是不正确的。就我而言,原始字节 [] 不包含有关图像宽度和高度以及格式的任何信息。仅使用 ImageIO.read,程序不可能构造出有效的图像。

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

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

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

于 2018-06-16T02:57:51.287 回答