我正在做一些工作,我以编程方式从OpenSearch文档中指定的网站下载图标,如果它是ICO格式,我需要提取第一个图像(现在)。我能够毫无问题地读取ICO文件头并切出第一个图像文件。但是,在阅读Wikipedia entry explaining the file format后我发现,如果图像是位图格式,则文件不完整(它缺少标题)。所以我需要在将数据保存到文件之前重新构建此标题,但是我遇到了一些困难。
根据Wikipedia entry for BMP file format,标题长度为14个字节,应包含以下内容:
Offset Data0x0000
"BM", for our intents and purposes0x0002
Size of the bitmap file in bytes0x0006
Dependant on the application creating the file0x0008
Dependant on the application creating the file0x000A
Offset of the image data/pixel array
我认为位图文件的大小(以字节为单位)将是提取图像的大小+标头的14个字节,但我不确定要写入0x0006,0x0008以及如何获取位置像素数组写入0x000A。
我已经读了几遍这篇文章,但我必须承认我的脑袋有点伤害。这是我第一次做这种事情的经历。任何人都可以帮我解决如何获取像素阵列的位置吗?
答案 0 :(得分:5)
0x0006
和0x0008
,你应该在那里放零。对于0x000A
,这是实际图像数据在文件中开始的位置。通常,此处的标头后跟DIB标头(从偏移0x000E
开始),DIB标头的前四个字节是其大小。因此,您获取DIB标头的大小,添加其起始偏移量(0x000E
),您获得的是实际数据开始的位置 - 将其放在0x000A
位置。
以下是来自随机位图文件的示例数据:
42 4D "BM"
2E 78 08 00 Size of the entire bitmap file (0x8782E meaning 555054 bytes)
00 00 creator1, reserved
00 00 creator2, reserved
36 00 00 00 Image data starts at offset 0x36 because the next 0x28 bytes are DIB header
28 00 00 00 DIB header started and its size is 0x28 (40 bytes)
another 36 bytes
FF FF FF First pixel of the image (white as it happens)
如果以favicon on serverfault.com为例,您可以将文件的一部分放在偏移0x0016
和0x013E
之间,并将其与42 4D 36 01 00 00 00 00 00 00 36 00 00 00
一起添加。这为您提供了一种正确的位图文件 - 而IrfanView甚至可以显示它。但是,存储在ICO文件和BMP文件中的数据并不完全相同,因为ICO文件需要存储透明度信息。这就是为什么这个favicon的大小为16x32,根据它的DIB头而不是预期的16x16。
来自Wikipedia:
色深小于32位的图像遵循特定格式:图像被编码为由彩色遮罩(“XOR遮罩”)和不透明遮罩(“AND遮罩”)组成的单个图像。 XOR掩码必须位于位图数据内的AND掩码之前;如果图像以自下而上的顺序存储(很可能是这样),则XOR掩码将被绘制在AND掩码下面。
在我们的特殊情况下,这意味着从256字节的图像数据开始,前64个字节是XOR掩码,最后64个字节是AND掩码,只有中间部分是我们的图像。在我们的特定情况下,您可以将图像数据的开始(偏移0x000A
)更改为0x76以跳过XOR掩码。然后,您还可以将DIB标头中的图像高度(偏移0x0016
)更改为0x10,以确保忽略AND掩码。在这里,这些操作将为您提供有效的位图,非常类似于您的预期。一般情况下,考虑掩码可能更好,而不是忽略它们。