将 BufferedImage 转换为 ByteBuffer
Posted
技术标签:
【中文标题】将 BufferedImage 转换为 ByteBuffer【英文标题】:Converting BufferedImage to 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);
【问题讨论】:
当你创建一个缓冲图像时,你可以给它一个常数来指示图像的色彩空间。看起来您正在混合 int 和 byte 类型的图像。例如,docs.oracle.com/javase/7/docs/api/java/awt/image/…。您也可以使用docs.oracle.com/javase/7/docs/api/java/awt/image/… 来查找现有图像的类型 【参考方案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
子类,并且可能将像素存储在多个存储区中,具有不同的字节顺序,可能是通道交错(而不是标准像素交错)等。所以上面的代码仍然不完全通用。
如果您要将这些ByteBuffer
s 传递给本机代码,使用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 文件的缓冲区。以上是关于将 BufferedImage 转换为 ByteBuffer的主要内容,如果未能解决你的问题,请参考以下文章
将每个动画 GIF 帧转换为单独的 BufferedImage