【问题标题】:Trying to Draw a 24bit image in Java尝试在 Java 中绘制 24 位图像
【发布时间】:2014-01-03 17:07:06
【问题描述】:

我有一个图像,其中每个像素是 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

如何从 bytebuffer 通过PackedRaster 到 24bit 以上四个字节的缓冲图像

【问题讨论】:

  • 4 字节是 32 位图像。

标签: java bufferedimage illegalargumentexception


【解决方案1】:

如果我正确理解了这个问题,您正在尝试将字节样本数据流转换为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() 一样简单,并且它应该(我可能在这里错了)工作方式相同。

【讨论】:

  • 好的,我几乎可以完成这项工作,但无法对事物的颜色方面进行排序。我有 BandedRaster,字节的顺序是一个字节的 Alpha,然后是一个字节的红色,然后是一个字节的绿色,然后是一个字节的蓝色。但是颜色不正确,例如,如果我的数据有 0x00FFFFFF 那么它应该是白色的,因为它的出来是绿松石
  • 代码如下 WritableRaster wr = Raster.createBandedRaster(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); img = new BufferedImage(ccm,wr,false,null);
  • @user2873619 只是指出,如果您的数据以A R G B 的形式出现,那么它的像素交错而不是 BIL(这将显示为 A A R R G G B B...(对于 2 像素宽的图像)。绝对有必要使用WritableRasters吗?我个人坚持使用简单的for循环进行图像处理。另外需要指出的是,输入数据0x00、0xFF、0xFF、0xFF不会是白色的,因为alpha为0(完全透明)。原因你看到一些奇怪的颜色是sRGB 颜色空间将数据定义为RGBA 格式。所以你的 alpha 被映射到你的红色,红色到绿色等等。
  • 谢谢 - 不尝试 tp 操作图像,只是将其绘制在屏幕上。即以字节格式读取图像,因为我当时不知道它是否为 1、4、8、12、16、24 位,然后尝试输出它。还没有让24位工作。数据字节的顺序是 A R G B A R G B 等。我想我可以在输入端将其更改为 R G B A。
  • @user2873619 对于A R G B 输入,我通常只输入this
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-03
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多