【问题标题】:Converting BufferedImage to ByteBuffer将 BufferedImage 转换为 ByteBuffer
【发布时间】:2015-03-27 13:28:49
【问题描述】:

我正在尝试将缓冲图像转换为 ByteBuffer,但我得到了这个异常

java.awt.image.DataBufferInt cannot be cast to java.awt.image.DataBufferByte

谁能帮助我并提出一个好的转换方法。

来源:

public static ByteBuffer convertImageData(BufferedImage bi) 
{
    byte[] pixelData = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
    //        return ByteBuffer.wrap(pixelData);
    ByteBuffer buf = ByteBuffer.allocateDirect(pixelData.length);
    buf.order(ByteOrder.nativeOrder());
    buf.put(pixelData);
    buf.flip();
    return buf;
}

这是我的目标

 ByteBuffer buf = convertImageData(image);

【问题讨论】:

标签: java image-processing bufferedimage bytebuffer


【解决方案1】:

您不能只是将任意数据缓冲区强制转换为 DataBufferByte,您需要确保它实际上是正确的类型:

ByteBuffer byteBuffer;
DataBuffer dataBuffer = bi.getRaster().getDataBuffer();

if (dataBuffer instanceof DataBufferByte) {
    byte[] pixelData = ((DataBufferByte) dataBuffer).getData();
    byteBuffer = ByteBuffer.wrap(pixelData);
}
else if (dataBuffer instanceof DataBufferUShort) {
    short[] pixelData = ((DataBufferUShort) dataBuffer).getData();
    byteBuffer = ByteBuffer.allocate(pixelData.length * 2);
    byteBuffer.asShortBuffer().put(ShortBuffer.wrap(pixelData));
}
else if (dataBuffer instanceof DataBufferShort) {
    short[] pixelData = ((DataBufferShort) dataBuffer).getData();
    byteBuffer = ByteBuffer.allocate(pixelData.length * 2);
    byteBuffer.asShortBuffer().put(ShortBuffer.wrap(pixelData));
}
else if (dataBuffer instanceof DataBufferInt) {
    int[] pixelData = ((DataBufferInt) dataBuffer).getData();
    byteBuffer = ByteBuffer.allocate(pixelData.length * 4);
    byteBuffer.asIntBuffer().put(IntBuffer.wrap(pixelData));
}
else {
    throw new IllegalArgumentException("Not implemented for data buffer type: " + dataBuffer.getClass());
}

如果您的 BufferedImage 是标准类型之一(BufferedImage.TYPE_* 不是 TYPE_CUSTOM),则上述应该可以工作。

请注意,可能存在特殊的DatBuffer 子类,并且可能将像素存储在多个存储区中,具有不同的字节顺序,可能是通道交错(而不是标准像素交错)等。所以上面的代码仍然不完全通用。

如果您要将这些ByteBuffers 传递给本机代码,使用allocateDirect(..) 并复制像素可能会更快,否则我认为使用wrap(..) 将使代码更简单,效率更高。

【讨论】:

  • 是否可以避免大量字节从一个地方复制到另一个地方?
  • 因为我们显然无法避免复制,所以我使用了ImageIO 解决方案,因为它是图像原生的。
  • @Dims 如果它适用于您的用例,当然可以。不过,使用ImageIO 将数据编码为文件格式总是比仅复制字节要慢。
【解决方案2】:

如果您想对图像数据进行编码,您可能需要在此处使用 ImageIO。像这样的:

public static ByteBuffer convertImageData(BufferedImage bi) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        ImageIO.write(bi, "png", out);
        return ByteBuffer.wrap(out.toByteArray());
    } catch (IOException ex) {
        //TODO
    }
    return null;
}

Here is the list 支持的格式。

【讨论】:

  • 虽然您的代码将编译和运行,但它确实做的事情与 OP 在他的代码块中试图实现的完全不同。代码似乎期望一个包含“原始”像素的字节缓冲区,他将在这里得到一个包含 PNG 文件的缓冲区。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-03
相关资源
最近更新 更多