如果我正确理解了这个问题,您正在尝试将字节样本数据流转换为BufferedImage。
为了澄清一些事情,4 字节/像素的图像是 32 位/像素的图像(因为 4 * 8 是 32),但是实际的颜色分量可能仅跨越 24 位(3 个字节)作为一个 8 位分量留给 Alpha(透明度)。考虑到这一事实,拥有每个颜色通道 8 位且没有 Alpha 通道的 24 位图像是否完全正常(此时图像将是 3 字节/像素的图像)。
您收到不兼容异常的原因是您使用了错误的方法来创建 WritableRaster。
鉴于您的输入数据是字节数组的形式,并且您正在尝试创建一个图像,其中每个字节存储的不是整个像素,而是 一个像素的样本方法@987654326 @ 立即被视为不合适,因为该方法将每个数据元素(即每个字节)视为其自己的像素,这绝对不是您要在此处完成的操作。
要确定需要使用哪种“创建”方法,需要确定传入数据的格式。
三种主要的样本编码类型如下所示:
图片来源amor.cms.hu-berlin.de
它们是波段顺序格式 (bsq)、按像素格式交错的波段 (bip) 和按行格式交错的波段 (bil)。该图像演示了如何对 3 x 3 样本图像进行编码。为简单起见,我们只考虑后两者(BIP 和 BIL),因为 BSQ 很少使用(据我所知)。
如果传入的图像数据是 BIP 格式,也就是像素交错,则需要使用createInterleavedRaster() 方法读取输入数据。正如文档所述:
基于具有指定数据类型的 PixelInterleavedSampleModel 创建一个 Raster。
另外一个我们需要判断的因素是,如果通过的字节数据包含alpha,本质上图像数据是否是这样的(假设BIP):
R G B R G B ....
或
R G B A R G B A ....
由于有许多采用不同参数的重载方法,我们将使用采用数据类型、宽度、高度、波段和位置的方法。
对于数据类型,我们将使用常量DataBuffer.TYPE_BYTE,因为我们正在输入一个字节数组。
宽度和高度由我们的方法参数提供,这里没什么特别的。
波段对应于有多少不同的数据波段。如果您的输入流不包含 alpha,您将拥有三个不同的波段(红色、绿色和蓝色)。如果您的输入数据包含 alpha,您的图像将有四个波段(红色、绿色、蓝色和 alpha)。
语句如下所示:
//Replace '4' with '3' if your image doesn't have alpha
WritableRaster wr = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 4, null);
接下来要担心的是 ColorModel。由于我们不再使用createPackedRaster() 方法,我们需要将ColorModel 的类型也更改为ComponentColorModel。由于这有点长,我将向您展示我所做的(不过请自己阅读documentation)。
如下:
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
//Change the first 'true' to 'false' if you don't have alpha.
ComponentColorModel ccm = new ComponentColorModel(sRGB, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
现在,将它们组装在一起:
void fun(byte[] imgBuff,int w,int h) throws IOException{
WritableRaster wr = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 4, null);
wr.setDataElements(0, 0, w, h, imgBuff);
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ComponentColorModel ccm = new ComponentColorModel(sRGB, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage img = new BufferedImage(ccm, wr, false, null);
}
你会注意到我添加了一行wr.setDataElements(0, 0, w, h, imgBuff)。这一行直接使用字节数组有效地将实际数据填充到 WritableRaster 中(无需创建 DataBufferByte 对象)。
我之前提到过我会同时讨论 BIP 和 BIL。将上面的方法从 BIP 更改为 BIL 应该就像将 createInterleavedRaster() 方法交换为 createBandedRaster() 一样简单,并且它应该(我可能在这里错了)工作方式相同。