我正在尝试从二进制文件创建图像。该文件包含一个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个,而最后一个未使用)。
我设法将图像数据解析为512字节的数组,将调色板解析为32字节的数组。但我不确定如何从这里继续。
我将所有图像数据字节读入BitSet,但我不确定这是否有用。
另外,我不知道如何从两个字节构造颜色。
任何帮助/建议/意见?
谢谢。
所以在你的帮助下我从调色板中创建了一个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)
有任何帮助吗?再一次,非常感谢你。
答案 0 :(得分:2)
javax.imageio.ImageIO
类及其亲属是您所需要的。基本上,javax.imageio
包。
我忘记了细节,但框架甚至允许您在内存结构和输出文件之间进行映射时定义自定义颜色编码(即每种颜色的位数及其顺序)。
<强>更新强>
仍在等待您的回答是文件I / O还是本地图像。同时...
如果查看类java.awt.image.BufferedImage
,您将看到用于编码一些通常的位到像素映射的常量,用于从栅格创建图像的构造函数,用于设置颜色模型的方法,设置栅格等等。
你可能也想看一个体面的教程。我会去寻找一个......
要回答如何将两个字节映射为颜色的问题,请查看java.awt.image.ColorModel
和java.awt.image.ComponentColorModel
。我认为第二个是你想要的那个。
答案 1 :(得分:1)
我前一段时间(使用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;
在每种情况下,您通过ANDing屏蔽了字节中感兴趣的位,并使用仅设置了这些位的数字(以十六进制表示,因为这更容易使用),然后将位移位以便它们将会最终在结果int中右对齐。
其余的很容易:
Color c = new Color(r, g, b);
答案 2 :(得分:0)
你是如何编码颜色的?您可以使用Color
类从其组件生成颜色对象。
然后,您可以在Graphics对象上绘制一堆正确颜色的1x1矩形,以便构建图像。
答案 3 :(得分:0)
如果图像格式众所周知,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并以这种方式定义图像,特别是如果这是您打算广泛使用的文件格式。