试图用Java绘制24位图像

时间:2014-01-03 17:07:07

标签: java bufferedimage illegalargumentexception

我有一个图像,其中每个像素是4个字节,即红色掩码是0xFF0000绿色是0xFF00和蓝色0xFF。我在图像中读取并将其作为函数传递给函数(byte imgBuff,int w,int h) 然后我

  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到4位字节的24位缓冲图像

1 个答案:

答案 0 :(得分:4)

如果我正确理解了这个问题,那么您正尝试将字节样本数据流转换为BufferedImage

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

您获得不兼容性异常的原因是您使用了错误的方法来创建WritableRaster。

鉴于您的输入数据是字节数组的形式,并且您正在尝试创建一个图像,其中每个字节不存储整个像素,而是像素的样本方法{{ 1}}被立即认为是不合适的,因为该方法将每个数据元素(即每个字节)视为自己的像素,这绝对不是你想要在这里完成的。

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

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

Image Sample Encoding Demonstration

图片来源amor.cms.hu-berlin.de

它们是波段顺序格式(bsq),通过像素格式(bip)交错的波段和通过线格式(bil)交织的波段。该图像演示了如何编码3乘3的样本图像。为简单起见,我们只考虑后两者(BIP和BIL),因为很少使用BSQ(据我所知, )。

如果通过的图像数据采用BIP格式,也简单地称为像素交错,则需要使用createPackedRaster()方法读取输入数据。正如文档所述:

  

基于具有指定数据类型的PixelInterleavedSampleModel创建Raster。

我们需要确定的另一个因素是,如果通过的字节数据包含alpha,实质上是否图像数据是这样的(假设是BIP):

  

R G B R G B ....

  

R G B A R G B A ....

由于有许多重载方法采用不同的参数,我们将使用带有dataType,宽度,高度,波段和位置的方法。

对于dataType,我们将使用常量createInterleavedRaster(),因为我们正在输入一个字节数组。

宽度和高度由我们的方法参数提供,这里没什么好用的。

这些频段对应于有多少不同的数据带。如果输入流不包含alpha,则会有三个不同的波段(红色,绿色和蓝色)。如果输入数据包含alpha,则图像将具有四个波段(红色,绿色,蓝色和alpha)。

该陈述如下所示:

DataBuffer.TYPE_BYTE

担心的下一部分是ColorModel。由于我们不再使用//Replace '4' with '3' if your image doesn't have alpha WritableRaster wr = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 4, null); 方法,因此我们需要将ColorModel的类型更改为createPackedRaster()。由于这有点长,我只会告诉你我做了什么(请尽快阅读documentation)。

如下:

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); } 。该行有效地使用字节数组直接将实际数据填充到WritableRaster中(无需创建DataBufferByte对象)。

我之前提到过,我会谈论BIP和BIL。将上述方法从BIP更改为BIL应该就像将wr.setDataElements(0, 0, w, h, imgBuff)方法交换到createInterleavedRaster()一样简单,而应该(我可能在这里错了)也可以正常工作。