2011-09-08 47 views
2

我正在做一些工作,我正在以编程方式从OpenSearch文档中指定的站点下载图标,如果它是ICO格式,我需要提取第一个图像(现在)。我能够毫无问题地读取ICO文件头,并分出第一个图像文件。但是,在阅读Wikipedia entry explaining the file format后,我发现如果图像是位图格式,那么文件不完整(它缺少标题)。所以我需要重新构造这个头文件,然后才能将数据保存到文件中,但我遇到了一些困难。如何从ICO文件中提取BMP?

根据该Wikipedia entry for BMP file format,报头是14个字节长,并应包含以下内容:

Offset Data 
0x0000 "BM", for our intents and purposes 
0x0002 Size of the bitmap file in bytes 
0x0006 Dependant on the application creating the file 
0x0008 Dependant on the application creating the file 
0x000A Offset of the image data/pixel array 

我想,以字节为单位的位图文件的大小将是所提取的图像+的14的尺寸字节的头,但我不确定在0x0006,0x0008写什么,以及如何获取像素数组的位置在0x000A写入。

我已经读了几篇文章,但我必须承认我的头部有点疼。这是我做这类事情的第一次经历。任何人都可以帮助我弄清楚如何获得像素阵列的位置?

回答

5

0x00060x0008被保留,你应该简单地把零置于那里。至于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作为一个例子,你会采取文件的部分抵消0x00160x013E之间以及与42 4D 36 01 00 00 00 00 00 00 36 00 00 00前面加上它。这给你一个正确的位图文件 - IrfanView甚至会显示它。但是,ICO文件和BMP文件中存储的数据并不完全相同,因为ICO文件需要存储透明度信息。这就是为什么这个favicon根据其DIB头部大小为16x32而不是预期的16x16。

Wikipedia

与颜色深度的小于32位的图像按照特定的格式:该图像被编码为包括彩色掩码(在“XOR掩码”)的单个图像连同不透明蒙板(“和蒙板”)。 XOR掩码必须位于位图数据内的AND掩码之前;如果图像以自下而上的顺序存储(最有可能),则XOR掩码将被绘制在AND掩码下方。

在我们的特殊情况下,这意味着从256个字节的图像数据开始,前64个字节是XOR掩码,最后64个字节是AND掩码,只有中间部分是我们的图像。在我们的特殊情况下,您可以将图像数据的开始(偏移量0x000A)更改为0x76以跳过XOR掩码。然后,您还可以将DIB标头中的图像高度(偏移量0x0016)更改为0x10,以确保忽略AND掩码。这里的这些操作会给你一个有效的位图,非常像你所期望的。在一般情况下,不妨考虑掩码而不是忽略掩码。

+0

这对我不起作用。我正在查看[favicon for serverfault.com](http://sstatic.net/serverfault/img/favicon.ico)。如果我从图标目录中的OFFSET到OFFSET + SIZE中提取图像数据。然后我在0x000A处重新构建位图标题为36,将整个事件保存为bmp文件并尝试在窗口中加载结果。我收到一个错误,说该文件已损坏或太大。维基百科提示像素值在颜色表和可选的1字节间隙后开始。是对的吗? –

+0

@Andy:这是因为ICO文件中的数据不是“常规”位图数据。查看我答案的更新版本。 –

+0

啊,我现在看到了。我不能将位图拉出来,希望Windows能够显示它。我不得不将图像重建为PNG或其他东西。谢谢您的帮助。 –