Как я могу извлечь BMP из файла ICO? - PullRequest
2 голосов
/ 08 сентября 2011

Я делаю некоторую работу, где программно загружаю значки с сайтов, указанных в документе OpenSearch, и мне нужно извлечь первое изображение (пока), если оно в формате ICO.Я могу прочитать заголовок файла ICO без проблем и вырезать первый файл изображения.Однако после прочтения записи в Википедии, объясняющей формат файла , я обнаружил, что если изображение в растровом формате, то файл является неполным (в нем отсутствует заголовок).Поэтому мне нужно восстановить этот заголовок, прежде чем я смогу сохранить данные в файл, но у меня возникли некоторые трудности.

Согласно записи Википедии для формата файла BMP ,заголовок имеет длину 14 байтов и должен содержать следующее:

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

Я полагал, что размер файла растрового изображения в байтах будет размером извлеченного изображения + 14 байтов для заголовка, но я 'Я не уверен, что писать в 0x0006, 0x0008 и как получить расположение массива пикселей для записи в 0x000A.

Я читал статью несколько раз, но должен признать, что у меня немного болит голова,Это мой первый опыт такого рода вещей.Кто-нибудь может помочь мне разобраться, как определить местоположение массива пикселей?

1 Ответ

5 голосов
/ 09 сентября 2011

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 на 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.

Из Википедия :

Изображения с глубиной цвета менее 32 бит следуют определенному формату: изображение кодируется как одно изображение, состоящее из цветовой маски («маска XOR») вместе с маской непрозрачности («маска И»). Маска XOR должна предшествовать маске AND внутри данных растрового изображения; если изображение хранится в порядке снизу вверх (что наиболее вероятно), маска XOR будет отображаться под маской AND.

В нашем конкретном случае это означает, что из 256 байтов данных изображения первые 64 байта являются маской XOR, последние 64 байта являются маской AND и только наша средняя часть является нашим изображением. В нашем конкретном случае вы можете изменить начало данных изображения (смещение 0x000A) на 0x76, чтобы пропустить маску XOR. Затем вы также измените высоту изображения в заголовке DIB (смещение 0x0016) на 0x10, чтобы маска И игнорировалась. Здесь эти манипуляции дадут вам правильное растровое изображение, очень похожее на то, что вы ожидали. В общем случае, возможно, лучше рассмотреть маски, а не игнорировать их.

...