尝试用Java绘制24位图像

尝试用Java绘制24位图像,java,bufferedimage,illegalargumentexception,Java,Bufferedimage,Illegalargumentexception,我有一个图像,其中每个像素是4字节,即红色掩码是0xFF0000,绿色是0xFF00,蓝色是0xFF。我读入图像并将其作为函数传递给函数(字节imgBuff,intw,inth) 那么我有 void fun(byte imgBuff,int w,int h) { Graphics g; BufferedImage img; DataBuffer dBuffer = new DataBufferByte(imgBuff, w * h); Wr

我有一个图像,其中每个像素是4字节,即红色掩码是0xFF0000,绿色是0xFF00,蓝色是0xFF。我读入图像并将其作为函数传递给函数(字节imgBuff,intw,inth) 那么我有

  void fun(byte imgBuff,int w,int h)
  {
      Graphics g;
      BufferedImage img;
      DataBuffer dBuffer = new DataBufferByte(imgBuff, w * h);
      WritableRaster wr = Raster.createPackedRaster(dBuffer,w,h,24,null);
      DirectColorModel dcm = new DirectColorModel(24,0xFF0000,0xFF00,0xFF);
      img = new BufferedImage(dcm,wr,false,null);
      g = getGraphics();
      g.drawImage(img,x,y,w,h,null);
  }
但是当我跑的时候

线程“thread-23”java.lang.IllegalArgumentException中的异常: 光栅sun.awt.image。SunWritableRaster@1d82ed7不符合 ColorModel DirectColorModel:rmask=ff0000 gmask=ff00 bmask=ff amask=0


如何通过
PackedRaster
从bytebuffer转换为四字节24位的缓冲图像

如果我正确理解了这个问题,您正在尝试将字节样本数据流转换为
缓冲图像

为了澄清一些事情,4字节/像素图像是32位/像素图像(因为4*8是32),但是实际的颜色分量可能只跨越24位(3字节),因为一个8位分量留给Alpha(透明度)。考虑到这一事实,具有每个颜色通道8位且没有alpha通道的24位图像(其中图像将是3字节/像素图像)是完全正常的

出现不兼容异常的原因是您使用了错误的方法来创建可写光栅

考虑到您的输入数据是字节数组的形式,并且您试图创建一个图像,其中每个字节存储的不是整个像素,而是一个像素样本
,因此方法
createPackedRaster()
立即被视为不合适,因为该方法处理每个数据元素(即每个字节)作为它自己的像素,这绝对不是你想要实现的

要确定需要使用哪些“创建”方法,需要确定传入数据的格式

下面显示了三种主要的样本编码类型:

图像源

它们是波段顺序格式(bsq)、按像素格式交织的波段(bip)和按行格式交织的波段(bil)。该图像演示了如何对3×3样本图像进行编码。为了简单起见,我们只考虑后两个(BIP和BIL),因为BSQ很少使用(据我所知)。 如果通过的图像数据是BIP格式,也称为像素交错,则需要使用
createInterleavedRaster()
方法读取输入数据。如文件所述:

基于具有指定数据类型的像素InterleavedSampleModel创建光栅

我们需要确定的另一个因素是,如果通过的字节数据包含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
。由于这是一个有点长,我会告诉你我做了什么(请一定要阅读自己的文章)

详情如下:

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()
方法替换为
CreateBandedMaster()
,它应该(这里可能是错误的)工作原理相同。

如果我正确理解了这个问题,您正在尝试将字节样本数据流转换为
缓冲区图像

为了澄清一些事情,4字节/像素图像是32位/像素图像(因为4*8是32),但是实际的颜色分量可能只跨越24位(3字节),因为一个8位分量留给Alpha(透明度)。考虑到这一事实,具有每个颜色通道8位且没有alpha通道的24位图像(其中图像将是3字节/像素图像)是完全正常的

出现不兼容异常的原因是您使用了错误的方法来创建可写光栅

考虑到您的输入数据是字节数组的形式,并且您试图创建一个图像,其中每个字节存储的不是整个像素,而是一个像素样本
,因此方法
createPackedRaster()
立即被视为不合适,因为该方法处理每个数据元素(即每个字节)作为它自己的像素,这绝对不是你想要实现的

要确定需要使用哪些“创建”方法,需要确定传入数据的格式

下面显示了三种主要的样本编码类型:

图像源

它们是波段顺序格式(bsq)、按像素格式交织的波段(bip)和按行格式交织的波段(bil)。该图像演示了如何对3×3样本图像进行编码。为了简单起见,我们只考虑后两个(BIP和BIL),因为BSQ很少使用(据我所知)。 如果图像是dat