【问题标题】:Java: Create an image from binary data (both image data and color palette)Java:从二进制数据(图像数据和调色板)创建图像
【发布时间】:2011-01-04 21:46:44
【问题描述】:

我正在尝试从二进制文件创建图像。该文件包含一个 32x32 图标及其对应的 16 色调色板。

规格


图标长度为 512 字节。图标以 4x4 的图块分隔。每个图块为 4x8 字节。

这是单个图块的 4x8 字节排列:

B B B B
B B B B
B B B B
B B B B
B B B B
B B B B
B B B B
B B B B

这是从上述字节扩展而来的位:

11110000 11110000 11110000 11110000
00001111 00001111 00001111 00001111
11110000 11110000 11110000 11110000
00001111 00001111 00001111 00001111
11110000 11110000 11110000 11110000
00001111 00001111 00001111 00001111
11110000 11110000 11110000 11110000
00001111 00001111 00001111 00001111

将每个字节分成四个像素,每个像素给出以下图块:

1111 0000 1111 0000 1111 0000 1111 0000
0000 1111 0000 1111 0000 1111 0000 1111
1111 0000 1111 0000 1111 0000 1111 0000
0000 1111 0000 1111 0000 1111 0000 1111
1111 0000 1111 0000 1111 0000 1111 0000
0000 1111 0000 1111 0000 1111 0000 1111
1111 0000 1111 0000 1111 0000 1111 0000
0000 1111 0000 1111 0000 1111 0000 1111

每4位是调色板中颜色的索引。

调色板长 32 个字节,包含 16 种颜色。每种颜色为 16 位(每个组件 5 个,而最后一个未使用)。

问题 - 第 1 步


我已经设法将图像数据解析为一个 512 字节的数组,并将调色板解析为一个 32 字节的数组。但我不确定如何从这里继续。

我将所有图像数据字节读入 BitSet,但我不确定这是否有用。

另外,我不知道如何从两个字节构造颜色。

任何帮助/建议/cmets?

谢谢。

问题 - 第 2 步


在您的帮助下,我从调色板中创建了一个 IndexColorModel,如下所示:

int[] colors = new int[16*3];
for (int i = 0; i < 16; i++) {
  byte b1 = this.palette[i]; // byte 1: 5 bits of R and 3 bits of G
  byte b2 = this.palette[i+1]; // byte 2: 2 bits of G and 5 bits of B and 0.

  // colors are encoded in inverse order
  colors[i+2] = (b2 & 0x3E) >>> // red
  colors[i+1] = ((b1 & 0x07) << 2) | ((b2 & 0xC0) >> 6); // green
  colors[i] = (b1 & 0xF8) >>> 3; // blue
}

IndexColorModel cm = new IndexColorModel(5, 16*3, colors, 0, false, 0, DataBuffer.TYPE_BYTE);

现在我需要使用上面的 IndexColorModel 从二进制文件中读取的字节数组创建一个 BufferedImage。

到目前为止,我有这个:

  DataBuffer buffer = new DataBufferByte(this.titleData, 32*32);

  int pixelStride = 4; //assuming r, g, b, skip, r, g, b, skip...
  int scanlineStride = 4*32; //no extra padding   
  int[] bandOffsets = {0, 1, 2}; //r, g, b
  WritableRaster raster = Raster.createInterleavedRaster(buffer, 32, 32, scanlineStride, pixelStride, bandOffsets, null);

  boolean isAlphaPremultiplied = false;

  BufferedImage bim = new BufferedImage(cm, raster, isAlphaPremultiplied, null);

取自here

this.titleData 是一个 512 字节的数组,从二进制文件中读取。

以上代码抛出如下异常:

原因:java.awt.image.RasterFormatException: 数据数组太小(应该是4094)

有什么帮助吗?再次感谢您。

【问题讨论】:

  • 下一步计划是什么?您想在画布上绘制此图标,还是将其输出到图形文件?
  • 在画布上绘制,特别是 JLabel。
  • 这个有趣的问题值得 +1。

标签: java image binary


【解决方案1】:

javax.imageio.ImageIO 类及其亲属是您所需要的。本质上,javax.imageio 包。

我忘记了细节,但该框架甚至允许您在内存结构和输出文件之间映射时定义自定义颜色编码(即每种颜色的位数及其顺序)。

更新

无论是文件 I/O 还是只是本地图像,仍在等待您的答复。同时……

如果您查看java.awt.image.BufferedImage 类,您会看到用于编码一些常见的位到像素映射的常量、用于从光栅创建图像的构造函数、用于设置颜色模型的方法、用于设置栅格等。

您可能还想看一个不错的教程。我去找找……

要回答如何将两个字节映射为颜色的问题,请查看java.awt.image.ColorModeljava.awt.image.ComponentColorModel。我认为第二个是您想要的。

【讨论】:

  • 抱歉,没有看到您的问题。确实,我已经尝试弄清楚这个颜色模型,但找不到一个好的教程。我目前正在看这个:java.sun.com/developer/technicalArticles/GUI/java2d/…
  • 还不错,看起来和我做这个的时候用的差不多,但只有一次,大约 2 年前。
  • 组件颜色模型?一直以来我都在试图弄清楚 IndexColorModel 因为描述听起来很像我需要的......:S
  • 找到这个教程,大概4页,不错很详细:javaboutique.internet.com/tutorials/rasters
  • 糟糕,我错过了你提到你有调色板的地方。 IndexColorModel 是,你是对的。
【解决方案2】:

我前一阵子(使用java.awt.image 的东西)努力解决了这个问题,但现在我震惊地发现我忘记了太多东西,无法提供太多帮助。

以防万一您对 Java API 方法有太多麻烦,我想向 Michael Brewer-Davis 回答您的问题:

鉴于颜色是 16 位,每个组件有 5 位(最后一个未使用),你能告诉我如何构造颜色吗?请记住,我从二进制逐字节读取数据。这意味着我将整个调色板解析为一个 32 字节的数组。换句话说,我首先需要为每种颜色粘贴两个字节。谢谢。

byte b1 = 0x??; // byte 1: 5 bits of R and 3 bits of G
byte b2 = 0x??; // byte 2: 2 bits of G and 5 bits of B and 0.

int r = (b1 & 0xF8) >>> 3;
int g = ((b1 & 0x07) << 2) | ((b2 & 0xC0) >>> 6);
int b = (b2 & 0x3E) >>> 1;

在每种情况下,您都通过与仅设置了这些位的数字进行与运算来屏蔽字节中感兴趣的位(以十六进制表示,因为这样更容易使用),然后移动这些位以便它们将最终在结果 int 中右对齐。

剩下的很简单:

Color c = new Color(r, g, b);

【讨论】:

    【解决方案3】:

    你是如何编码颜色的?您可以使用Color 类从其组件中生成颜色对象。

    然后,您可以在 Graphics 对象上绘制一堆颜色正确的 1x1 矩形,以构建您的图像。

    【讨论】:

    • 好吧,不幸的是,我的规范并没有准确解释颜色是如何编码的,但经过一些研究,我认为每种颜色有 5 位(最后一个没有使用)。所以可能是 RRRRRGGGGGBBBBBU。我怎样才能从中构造颜色......? :S
    • 使用按位运算将每种颜色的位转换为单独的整数,然后使用new Color(r, g, b)
    • 对不起,如果我要求太多,但我有两个字节用于一种颜色。我如何结合这个提取整数?我对按位运算不是很熟悉,如果您能提供一些代码,我将不胜感激。
    • 虽然我对自己答案的细节仍然有些模糊,但我认为如果您尝试逐个像素地执行此操作,性能将会很糟糕。 Java API 中有一个功能可以一次对数据数组执行此操作,并明确指定位计数和颜色顺序。
    • 我真的希望是这样。 ;P
    【解决方案4】:

    如果图像格式是众所周知的,那么 ImageIO 类可能会起作用,或者您可以找到一个服务提供者来从 ImageIO 中解析它。如果是自定义格式,您需要自己滚动。

    首先您需要解析您的color model,即确定 16 位颜色如何映射到真实世界的颜色。这很可能是 15 位 RGB (555) 或 16 位 RGB (565),但一切皆有可能(例如,4444 ARGB,其中一些字节用于 alpha/透明度)。

    完成后,最简单的做法是根据您提供的平铺结构创建并填写BufferedImage

    类似:

    BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
    byte[] imageData;
    
    for (int i = 0; i < imageData.length; ++i) {
        int x = // figure out x based on tiling
        int y = // figure out y based on tiling
    
        byte highBits = (imageData[i] >> 4) & 0xF;
        Color c = getColor(highBits); // translate bits into RGB color model
        image.setRGB(x, y, c.getRGB());
    
        x = // figure out for second bits, probably x+1?
        y = // figure out for second bits, probably unchanged?
    
        byte lowBits = imageData[i] & 0xF;
        c = getColor(lowBits);
        image.setRGB(x, y, c.getRGB());
    }
    

    您还可以定义自己的 ColorModel 并以这种方式定义您的图像,特别是如果这是您打算广泛使用的文件格式。

    【讨论】:

    • 鉴于颜色是 16 位,每个组件有 5 位(最后一个未使用),你能告诉我如何构造颜色吗?请记住,我从二进制逐字节读取数据。这意味着我将整个调色板解析为一个 32 字节的数组。换句话说,我首先需要为每种颜色粘贴两个字节。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2014-06-12
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    相关资源
    最近更新 更多