Описание формата BMP | jenyay.net

Описание формата BMP

Эта статья про то, как выглядит графический формат bmp. Хоть это и один из простых форматов, но из-за того, что существует много вариаций этого формата, то не все моменты очевидны. Итак, хватит лить воду, начнем.

Структуры формата

Формат bmp (от слов BitMaP - битовая карта, или, говоря по-русски, битовый массив) представляет из себя несжатое (в основном) изображение, которое довольно легко читается и выводится в ОС Windows, в которой есть специальные функции API, которые в этом помогают.

Для начала приведем графическое представление данных в bmp (картинка взята из MSDN).


В начале стоит заголовок файла (BITMAPFILEHEADER). Он описан следующим образом:

 typedef struct tagBITMAPFILEHEADER
 {
   WORD    bfType;
   DWORD   bfSize;
   WORD    bfReserved1;
   WORD    bfReserved2;
   DWORD   bfOffBits;
 } BITMAPFILEHEADER, *PBITMAPFILEHEADER;

bfType определяет тип файла. Здесь он должен быть BM. Если Вы откроете любой файл BMP в текстовом (а лучше в 16-ричном редакторе), то увидите, что первые два символа - это BM (от слова BitMap, как вы уже, наверное, догадались).
bfSize - это размер самого файла в байтах. Строго говоря вы должны его высчитывать (что рекомендуется), но я ставил размер файла неправильно (правда, не нарочно :)) и никаких проблем не было (ACDSee читало без проблем, моя программа работала), но я вам не рекомендую писать его заведомо неправильно, вдруг появится добросовестная программа, которая сверит этот размер с настоящим и решит, что это не bmp, а что-нибудь другое. В идеале все программы для того, чтобы убедиться, что перед ними действительно bmp, а не подделка, должны, во-первых, проверить, что bfType содержит "BM" (без кавычек), а, во-вторых, что bfSize равен размеру файла.
bfReserved1 и bfReserved2 зарезервированы и должны быть нулями.
bfOffBits. Это один из самых важных полей в этой структуре. Он показывает, где начинается сам битовый массив относительно начала файла (или, как написано в MSDN, "от начала структуры BITMAPFILEHEADER"), который и описывает картинку. То есть, чтобы гарантированно попадать на начало массива вы должны писать:

SetFilePointer (hFile, bfh.bfOffBits, NULL, FILE_BEGIN);

Здесь и далее будем считать, что переменная bfh объявлена как BITMAPFILEHEADER bfh;

А дальше идет структура BITMAPINFOHEADER, которая объявлена так:

 typedef struct tagBITMAPINFOHEADER
 {
   DWORD  biSize;
   LONG   biWidth;
   LONG   biHeight;
   WORD   biPlanes;
   WORD   biBitCount;
   DWORD  biCompression;
   DWORD  biSizeImage;
   LONG   biXPelsPerMeter;
   LONG   biYPelsPerMeter;
   DWORD  biClrUsed;
   DWORD  biClrImportant;
 } BITMAPINFOHEADER, *PBITMAPINFOHEADER;

biSize - это размер самой структуры. Ее нужно инициализировать следующим образом: bih.biSize = sizeof (BITMAPINFOHEADER);
Снова здесь и дальше будем считать, что bih объявлена следующим образом: BITMAPINFOHEADER bih;
biWidth и biHeight задают соответственно ширину и высоту картинки в пикселях.
biPlanes задает количество плоскостей. Пока оно всегда устанавливается в 1.
biBitCount - Количество бит на один пиксель. Подробнее про это поговорим ниже.
biCompression обозначает тип сжатия. Не удивляйтесь и не пугайтесь, что в bmp и вдруг сжатие. Я лично не видел не одной сжатой bmp (но я не говорю, что таких не существует). Если сжатия нет, то этот флаг надо устанавливать в BI_RGB. В этой статье мы говорим про несжатый формат, поэтому другие флаги я даже не буду перечислять. Похоже, что эта же структура используется и в файлах JPEG и PNG, потому что, начиная с Windows 98 тут появились варианты BI_JPEG, которая показывает, что эта картинка - JPEG и BI_PNG, что это PNG (про формат Jpeg я ничего не знаю, я только сделал эти выводы исходя из того, что написано в MSDN).
biSizeImage обозначает размер картинки в байтах. Если изображение несжато (то есть предыдущее поле установлено в BI_RGB), то здесь должен быть записан ноль. biXPelsPerMeter и biYPelsPerMeter обозначают соответственно горизонтальное и вертикальное разрешение (в пикселях на метр) конечного устройства, на которое будет выводиться битовый массив (растр). Приложение может использовать это значение для того, чтобы выбирать из группы ресурсов наиболее подходящий битовый массив для нужного устройства. Дело в том, что формат bmp - это по сути аппаратно-независимый растр, то есть когда внешний вид того, что получается не зависит от того, на что этот растр проецируется (если можно так выразится). Например, картинка будет выглядеть одинаково вне зависимости от того, рисуется она на экране монитора или печатается на принтере. Но вот разрешение у устройств разное, и именно для того, чтобы выбрать наиболее подходящую картинку из имеющихся и используют эти параметры.
biClrUsed определяет количество используемых цветов из таблицы. Если это значение равно нулю, то в растре используется максимально возможное количество цветов, которые разрешены значением biBitCount. Это актуально только для сжатых картинок. Если biClrUsed не нуль и biBitCount меньше 16, то biClrUsed определяет текущее число цветов графического движка или доступного драйвера устройства. Если biBitCount больше или равно 16, то biClrUsed определяет размер таблицы цветов, используемой для оптимизации текущей системной палитры.
biClrImportant - это количество важных цветов. Определяет число цветов, которые необходимы для того, чтобы изобразить рисунок. Если это значение равно 0 (как это обычно и бывает), то все цвета считаются важными.

Виды формата BMP

Все разновидности формата bmp условно можно разделить на два типа: палитровые и беспалитровые. То есть используется в данном с формате палитра или нет. Заметьте, что палитра может быть даже в беспалитровых форматах, только там она не используется. В беспалитровых bmp цвет высчитывается прямо из тех битов, которые идут в файле, начиная с некоторого места. А в палитровых каждый байт описывает один или несколько пикселей, причем значения байта (или битов) - это индекс цвета в палитре. Для начала приведу таблицу, которая сравнивает возможные варианты. Вид картинки (палитровая или беспалитровая) зависит от того, сколько бит отдается на один пиксель, то есть от значения biBitCount структуры BITMAPINFOHEADER.

biBitCountПалитровый или беспалитровый форматМаксимально возможное количество цветовПримечания
1Палитровый2Двуцветная, заметьте, не обязательно черно-белая, палитровая картинка. Если бит растра (что это такое чуть ниже) сброшен (равен 0), то это значит, что на этом месте должен быть первый цвет из палитры, а если установлен (равен 1), то второй.
4Палитровый16Каждый байт описывает 2 пикселя. Вот пример из MSDN.Если первый байт в картинке 0x1F, то он соответствует двум пикселям, цвет первого - второй цвет из палитры (потому что отсчет идет от нуля), а второй пиксель - 16-й цвет палитры.
8Палитровый256Один из самых распространенных вариантов. Но в то же время и самых простых. Палитра занимает один килобайт (но на это лучше не рассчитывать). Один байт - это один цвет. Причем его значение - это номер цвета в палитре.
16Беспалитровый2^16 или 2^15Это самый запутанный вариант. Начнем с того, что он беспалитровый, то есть каждые два байта (одно слово WORD) в растре однозначно определяют один пиксель. Но вот что получается: битов-то 16, а компонентов цветов - 3 (Красный, Зеленый, Синий). А 16 никак на 3 делиться не хочет. Поэтому здесь есть два варианта. Первый - использовать не 16, а 15 битов, тогда на каждую компоненту цвета выходит по 5 бит. Таким образом мы можем использовать максимум 2^15 = 32768 цветов и получается тройка R-G-B = 5-5-5. Но тогда за зря теряется целый бит из 16. Но так уж случилось, что наши глаза среди всех цветов лучше воспринимают зеленый цвет, поэтому и решили этот один бит отдавать на зеленую компоненту, то есть тогда получается тройка R-G-B = 5-6-5, и теперь мы может использовать 2^16 = 65536 цветов. Но что самое неприятное, что используют оба варианта. В MSDN предлагают для того, чтобы различать сколько же цветов используется, заполнять этим значением поле biClrUsed из структуры BITMAPINFOHEADER. Чтобы выделить каждую компоненту надо использовать следующие маски. Для формата 5-5-5: 0x001F для синей компоненты, 0x03E0 для зеленой и 0x7C00 для красной. Для формата 5-6-5: 0x001F - синяя, 0x07E0 - зеленая и 0xF800 красная компоненты соответственно.
24Беспалитровый2^24А это самый простой формат. Здесь 3 байта определяют 3 компоненты цвета. То есть по компоненте на байт. Просто читаем по структуре RGBTRIPLE и используем его поля rgbtBlue, rgbtGreen, rgbtRed. Они идут именно в таком порядке.
32Беспалитровый2^32Здесь 4 байта определяют 3 компоненты. Но, правда, один байт не используется. Его можно отдать, например, для альфа-канала (прозрачности). Читать растр в данном случае удобно структурами RGBQUAD, которая описана так:
typedef struct tagRGBQUAD
 {
   BYTE    rgbBlue;
   BYTE    rgbGreen;
   BYTE    rgbRed;
   BYTE    rgbReserved;
 } RGBQUAD;

Хранение данных в формате bmp

Ну вот и подошли к самому интересному. После структур BITMAPFILEHEADER и BITMAPINFOHEADER идет палитра. Причем, если формат беспалитровый, то ее может и не быть, однако, на это рассчитывать не надо. Дело в том, что, когда я только начинал разбираться с форматом bmp, в одной книжке я вычитал, что, якобы, если формат беспалитровый, то у нее вообще нет палитры. Там даже были две картинки - схемы формата: одна с палитрой, другая без. А я в это время писал программу, которая усердно оперирует с bmp-шками. И мне надо было преобразовывать входящие картинки из 256 цветов в 24-битные (если таковые имелись) во временные файлы. И я в 24-битных палитру просто не создавал (bfOffBits из структуры BITMAPFILEHEADER у меня был равен сумме sizeof(BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), а входящие 24-разрядные оставлял без изменений. С 256-цветными растрами все работало как надо, пока мне не попалась 24-разрядная картинка, у которой внизу вместо нужной части отображался мусор. Я не сразу понял в чем дело. Пока не сравнил размер исходного файла с теоретическим, который должен был быть, не будь палитры. Разница оказалась ровно 1 Kб (ровно 1024 байта). Там была палитра. Поэтому никогда не рассчитывайте на то, есть ли палитра и не надейтесь на ее размер (хотя все картинки, которые мне попадались имели размер палитры 256 цветов, или 1Кб), всегда перемещайтесь по файлу на начало растра, используя bfOffBits. Палитра представляет из себя массив структур RGBQUAD идущих друг за другом. Даже если в палитре используются не все цвета (а только, например, 16), то часто все равно под палитру отводят 256 полей. А 256 * 4 = 1024, где 4 - размер структуры RGBQUAD, то есть и получается тот самый один килобайт.

Сразу за палитрой идет сам растр. Тут уже более запутано. Во-первых, пиксели тут описываются так, как написано в таблице выше в зависимости от формата. И могут сами содержать значение компонентов цвета (для беспалитровых), а могут быть индексами массива-палитры. Сама картинка записывается построчно. Во-вторых, картинка идет как бы перевернутая вверх ногами. То есть сначала записана нижняя строка, потом предпоследняя и так далее до самого верха. И, в-третьих, как написано в [1], если размер строки растра не кратен 4, то она дополняется от 1 до 3 пустыми (нулевыми) байтами, чтобы длина строки оказалась кратна параграфу. Вот это и есть самое неприятное. Дело в том, что для каждого формата приходится подстраивать это число пустых байтов (правда, я люблю туда записывать часть палитры, просто мне не хочется заводить лишние "нулевые" переменные, если все-равно эти байты пропускают и никому они не нужны). Я привожу таблицу с формулами, которые показывают для какого формата сколько байт надо дописывать в конец строки. Там под переменной Width, как можно догадаться, подразумевается ширина картинки. Все эти формулы были установлены экспериментально. Я приведу пример только для наиболее используемых форматов. Для остальных вы можете написать сами.

biBitCountФормула на С
8(3 * Width) % 4
16(2 * Width) % 4
24Width % 4

Примеры программ

Все исходники вы можете скачать отсюда.Я особо не буду тут много писать. Просто приведу функции с комментариями.

Привет 1. Создание картинки в формате bmp.
Здесь создается однотонная картинка. В примерах таких функций три: создание bmp 8, 16 и 24 бит. Я приведу только для 16-битных.

 // Создадим картинку в формате bmp 16 бит типа 5-5-5, которая будет просто однотонной
 void CreateBmp555 (char *fname, WORD color)
 {
     HANDLE hFile;
     DWORD RW;
     int i, j;

     // Объявим нужные структуры
     BITMAPFILEHEADER bfh;
     BITMAPINFOHEADER bih;
     BYTE Palette [1024];    // Палитра

     // Пусть у нас будет картинка размером 35 x 50 пикселей
     int Width = 35;
     int Height = 50;

     memset (Palette, 0, 1024);                     // В палитре у нас нули заполним их
     memset (&bfh, 0, sizeof(bfh));

     bfh.bfType = 0x4D42;                           // Обозначим, что это bmp 'BM'
     bfh.bfOffBits = sizeof(bfh) + sizeof(bih) + 1024;    // Палитра занимает 1Kb, но мы его использовать не будем
     bfh.bfSize = bfh.bfOffBits +
         sizeof(color) * Width * Height +
         Height * ((sizeof(color) * Width) % 4);    // Посчитаем размер конечного файла
     memset (&bih, 0, sizeof(bih));
     bih.biSize = sizeof(bih);                      // Так положено
     bih.biBitCount = 16;                           // 16 бит на пиксель
     bih.biClrUsed = 32768;                         // Мы используем 5-5-5
     bih.biCompression = BI_RGB;                    // Без сжатия
     bih.biHeight = Height;
     bih.biWidth = Width;
     bih.biPlanes = 1;                              // Должно быть 1
                                                    // А остальные поля остаются 0

     hFile = CreateFile (fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
     if (hFile == INVALID_HANDLE_VALUE)
         return;

     // Запишем заголовки
     WriteFile (hFile, &bfh, sizeof (bfh), &RW, NULL);
     WriteFile (hFile, &bih, sizeof (bih), &RW, NULL);

     // Запишем палитру
     WriteFile (hFile, Palette, 1024, &RW, NULL);
     for (i = 0; i < Height; i++)
     {
         for (j = 0; j < Width; j++)
         {
             WriteFile (hFile, &color, sizeof(color), &RW, NULL);
         }

         // Выровняем по границе
         WriteFile (hFile, Palette, (sizeof (color) * Width) % 4, &RW, NULL);
     }
     CloseHandle(hFile);
 }

color - цвет картинки. Значение этой переменной должно быть заполнено в соответствии с первой таблицей. Получившуюся картинку вы можете посмотреть в ACDSee, например. Просто я пробовал ее открыть в Photoshop'е, оказалось, что в этом формате он их читать не умеет. А вы можете :).

Пример 2. Преобразование картинки из формата 8 бит (256 цветов) в 24 бит.

 BOOL Convert256To24 (char *fin, char *fout)
 {
     BITMAPFILEHEADER bfh;
     BITMAPINFOHEADER bih;
     int Width, Height;
     RGBQUAD Palette[256];
     BYTE *inBuf;
     RGBTRIPLE *outBuf;
     HANDLE hIn, hOut;
     DWORD RW;
     DWORD OffBits;
     int i, j;

     hIn = CreateFile (fin, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
     if (hIn == INVALID_HANDLE_VALUE)
         return FALSE;

     hOut = CreateFile (fout, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
     if (hOut == INVALID_HANDLE_VALUE)
     {
         CloseHandle (hIn);
         return FALSE;
     }

     // Прочтем данные
     ReadFile (hIn, &bfh, sizeof(bfh), &RW, NULL);
     ReadFile (hIn, &bih, sizeof(bih), &RW, NULL);
     ReadFile (hIn, Palette, 256 * sizeof(RGBQUAD), &RW, NULL);

     // Установим указатель на начало растра
     SetFilePointer (hIn, bfh.bfOffBits, NULL, FILE_BEGIN);
     Width = bih.biWidth;
     Height = bih.biHeight;
     OffBits = bfh.bfOffBits;

     // Выделим память
     inBuf = new BYTE [Width];
     outBuf = new RGBTRIPLE [Width];

     // Заполним заголовки
     bfh.bfOffBits = sizeof (bfh) + sizeof (bih);                               // Не будем писать палитру
     bih.biBitCount = 24;
     bfh.bfSize = bfh.bfOffBits + 4 * Width * Height + Height * (Width % 4);    // Размер файла

     // А остальное не меняется
     // Запишем заголовки
     WriteFile (hOut, &bfh, sizeof(bfh), &RW, NULL);
     WriteFile (hOut, &bih, sizeof(bih), &RW, NULL);

     // Начнем преобразовывать
     for (i = 0; i < Height; i++)
     {
         ReadFile (hIn, inBuf, Width, &RW, NULL);
         for (j = 0; j < Width; j++)
         {
             outBuf[j].rgbtRed = Palette[inBuf[j]].rgbRed;
             outBuf[j].rgbtGreen = Palette[inBuf[j]].rgbGreen;
             outBuf[j].rgbtBlue = Palette[inBuf[j]].rgbBlue;
         }
         WriteFile (hOut, outBuf, sizeof(RGBTRIPLE) * Width, &RW, NULL);

         // Пишем мусор для выравнивания
         WriteFile (hOut, Palette, Width % 4, &RW, NULL);
         SetFilePointer (hIn, (3 * Width) % 4, NULL, FILE_CURRENT);
     }

     delete inBuf;
     delete outBuf;
     CloseHandle (hIn);
     CloseHandle (hOut);
     return TRUE;
 }

В функцию надо передавать имена исходного и конечного файла соответственно.

Источники

  1. Д. Гончаров, Т. Салихов. "DirectX 7.0 для программистов"
  2. MSDN

Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.
4.5 stars

Рейтинг 4.3/5. Всего 401 голос(а, ов)



 06.12.2007 - 18:17

confused smiley

 24.02.2008 - 20:25

как это вы додумались до этого?

Jenyay 25.02.2008 - 19:23

До чего именно?

Хорош_гусь)) 26.02.2008 - 22:18

Big Endian - Small Endian

Надо ещё учесть то, что все числа лежат в формате Big Endian, т.е. байты местами переставлены! Я до этого долго доходил!

Сергей 11.07.2008 - 17:00

программы для открытия структуры файла BMP

Здравствуйте подскажите какие программы позволяют открывать структуру любого файла BMP (с просмотром кода каждого пикселя)?

Фосса 05.11.2008 - 12:15

Little Endian!

Таки данные представлены в формате Little Endian, то есть младшим байтом-вперёд }=

Den 08.01.2009 - 13:04

Так если это взято из MSDN, тогда почему другие графические
редакторы не могут открыть файл в этом формате????????

Jenyay 08.01.2009 - 17:32

Какой файл?

amarant555 13.02.2009 - 15:04

пробовал на делфи работать с файлом созданым фотожоп >16 бит
не воспринимает видимо там 5-5-5 вместо 5-6-5 (с которым умеет работать делфи)
кому не трудно можете проверить прав я или нет.

amarant555 13.02.2009 - 15:07

поправка вернее делфи работает с файлом 16 бит но воспринимает формат как кастом, при этом не возможно использовать ряд функций.

PanzerDogg 22.02.2009 - 22:55

GOOD!!!

 26.02.2009 - 09:43

confused smileyangry smiley

 10.05.2009 - 17:50

Мне очень понравилось содержание, но все же стоит сделать текст доступным не только для программистов, или студентов-программистов. Почему не сделать эту статью более выразительной и доступной

Jenyay 10.05.2009 - 17:57

Просто интересно, а кому может понадобиться описание формата файла кроме программистов?

DiezAver 16.05.2009 - 11:18

мне вот очень интересно, а в этом месте:

 // Пишем мусор для выравнивания
         WriteFile (hOut, Palette, Width % 4, &RW, NULL);
         SetFilePointer (hIn, (3 * Width) % 4, NULL, FILE_CURRENT);

пишется мусор размером Width % 4. При размере картинки, скажем 255, Width % 4 будет = 3, но разве записать надо не на 1 байт?

Jenyay 16.05.2009 - 11:23

Нет, нужно писать не один байт, потому что один пиксель занимает три байта. Если бы картинка была 8-битовая, а не 24-битовой, то достаточно было бы одного байта.

DiezAver 19.05.2009 - 09:01

О, действительно, просто я как раз с 8-битовыми сейчас работаю

Влад 01.06.2009 - 19:08

Проблема с чтением палитры

Я создал 256-цветный рисунок в стандартном Paint'е. В програме загрузил рисунок и палитру, но цвета отображаются неправильно(нету оттенков красного).
Так загружаю палитру:

for(int i=0; i<256; i++){
    fin.get(color.blue);
    fin.get(color.green);
    fin.get(color.red);
    fin.get(reserved);
    setPaletteRegistr(i, &color);
  }

daim 31.07.2009 - 08:10

такой вот глупый вопросец:
с 24 бит на пиксель понятно
допустим белый - FF FF FF
читаем каждый канал и записываем
В свои байтные переменные
а с 16 бит на пиксель как?
тотже белый FF 7F FF?
как то через маску....?
и размер параграфа то же будьте добры,
просто первый раз здесь услышал

Джей 13.11.2009 - 17:04

"...есть надписи на русском языке"

> "BitMaP - битовая карта, или, говоря по-русски, битовый массив"
Вообще-то слово "массив" - французского происхождения (massif от massiz).
Но это мелочи. Я тут чеек посторонний, просветите: што за язык чудной вы используете для программ своих написания? Уж не Си ли это?

Jenyay 13.11.2009 - 17:11

Джей

Да, Си, но тут не столько сам язык, сколько вызовы функций WinAPI, от самого языка не так много осталось :)

Джей 17.11.2009 - 10:51

Si, si...

Я щас пишу на C# (уж больно заказчик формы любит...). Какую среду разработки посоветуете?

Jenyay 17.11.2009 - 10:55

Visual C# Express, если не хочется денег на среду тратить.

Джей 17.11.2009 - 11:28

Ah, bien merci, merci bien...

Mille mercis...
З.ы. source: "Распространенье наше по планете / Особенно заметно вдалеке. / В общественном парижском туалете / Есть надписи на русском языке" (В.С. Высоцкий)

Джей 17.11.2009 - 17:32

mille pardons

Je m'excuse de vous demander pardon... Вы в ЦОИз шарите? Если да, в чём именно?

Jenyay 30.11.2009 - 22:26

В ЦОИ скорее теоретически представляю что к чему. А вообще по работе я иногда занимаюсь обработкой несколько специфических изображений (радиоизображений).

Людмила 17.01.2010 - 18:44

Очень важная для меня, интересная информация. Большое спасибо. Удачи, здоровья.

murder 07.04.2010 - 13:52

16-битные изображения

По моим наблюдениям Photoshop не использует поле biClrUsed.

Алгоритм такой:
Если поле biCompression равно BI_RGB то формат 5:5:5. Если же это поле содержит BI_BITFIELDS, то цвета нужно считывать согласно маскам bV5RedMask, bV5GreenMask, bV5BlueMask.

Кроме того BI_BITFIELDS в сочетании с масками позволяет менять расположение цветов (например RGB вместо стандартного BGR). Я проверял это на функции SetDIBitsToDevice - работает.

Domen0 25.05.2010 - 12:08

Огромное спасибо! Наконец-то нашел.grinning smiley

Винт 01.09.2010 - 18:27

маленькая поправочка для концовки
...

     delete[] inBuf;
     delete[] outBuf;

 25.09.2010 - 20:07

shrieking smileyconfused smileyfrowning smileyangry smiley

 01.10.2010 - 18:14

shrieking smileyshrieking smileyshrieking smileyshrieking smileyshrieking smileyshrieking smileyshrieking smileyshrieking smiley

)))) 21.12.2010 - 05:54

confused smileyangry smileyshrieking smiley

 14.01.2011 - 20:55

здесь никто ни чего не знает

Ротва 18.01.2011 - 02:09

Амет

Написал собственную прогу по этой статье. Спасибо.
Проверил все варианты, за исключением 5-5-5, 5-6-5.
Если у кого-то есть изображения с таким форматом и БЕЗ сжатия, очень прошу выложить на http://pixs.ru/
и скинуть линк сюда! thx!

апт 12.03.2011 - 11:01

врт

куgrinning smiley

Duk Nukem 27.10.2011 - 20:43

Ошибка в программе

Ваша программа при компиляции выдаёт ошибку в строке:

hFile = CreateFile (fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);

fname неправильного типа.Как исправить это?

Jenyay 29.10.2011 - 09:47

Попробовал сейчас скомпилировать исходник в Visual C++ 2008 Express, все скомпилировалось. А у Вас каком компилятор?

eugrita 27.12.2011 - 05:41

создание BMP

у меня ваша программа создала BMP-файл, но просмотр его оказался недоступен. Почему??? (Win XP)

eugrita 27.12.2011 - 05:43

cоздание BMP

При попытке открытия Paint говорит что недостаточно ресурсов для выполнения операции

Slavon G. 11.01.2012 - 02:26

re: создание BMP

eugrita, тяжело что-то сказать, не видя кода программы
Jenyay, а вот тут ошибочкаhappy smiley
//Convert256To24()
bfh.bfSize = bfh.bfOffBits + 3 * Width * Height + Height * (Width % 4);

Slavon G 11.01.2012 - 02:29

re: создание BMP

Поэтому в последний рисунок, размер файла записывается в заголовок неправильно.

PS: каптча любит шестеркиshrieking smiley

mao 12.08.2012 - 14:55

А сколько здесь байт в LONG? что-то я смотрю в редакторе одну бмп-картинку и похоже на то, что 4, но в чём тогда отличие от dword?

mao 12.08.2012 - 15:24

А, википедия популярно объясняет, что
« Тип WORD должен иметь размер 16 бит, типы DWORD и LONG — 32 бита, тип LONG — знаковый, порядок байтов подразумевается little endian. »

Касательно этого два вопроса:
1) зачем знаковость в biWidth и biHeight?
2) little endian везде или только в long?

mitas 24.11.2012 - 15:01

вопросик.

Всем доброе время суток.
Хочу сказать автору спасибо, все изложено очень наглядно и понятно.
Есть только один вопрос. Он касается примера 1-го, а именно подсчет размера конечного файла.
bfh.bfSize = bfh.bfOffBits + sizeof(color) * Width * Height +  Вопрос к этой формуле.

         Height * ((sizeof(color) * Width) % 4  это так называемая проверка на кратность.

bfh.bfOffBits - размер в байт
sizeof(color) - размер в байт
Width * Height - а тут размер в битах
Нету ли здесь ошибки в подсчете ???
Предположим есть bmp картинка 256x256пик. С глубиной цвета 24бит. По факту ее размер 196662 байта или 1572864 бит.
Проверяем:
bfh.bfOffBits = 14 + 40 = 54 байт +
sizeof(color) = 3 бита(24 байт) *
Width * Height = 256 * 256 = 65636 бит
Сложим по формуле:
1. (54 байт + (24бита + 65636 бит))
2. (54 байт + 1572864 бит)  пот и сам вопрос как ?
3. (= 1572918 бит \ 8 = 196614,75 байт) а должны получить (196662 байта)
4. Я так понимаю 54 байта нужно + к (1572864 бит / 8 = 196608 бита) = 196662 байта

h21 16.10.2013 - 11:20

Компилировал на GCC, язык C++ .
Во-первых, нужно заменить названия типов данных:
WORD - unsigned short
DWORD - unsigned int
LONG - int или long

Во-вторых, размер структуры в памяти зависит от настроек компилятора и от директив. Поля структуры выравниваются кратно своему размеру: 1-байтовые поля не выравниваются, 2-байтовые — выравниваются на чётные позиции, 4-байтовые — на позиции кратные четырём и т.д.. Таким образом, в памяти остаются пустые места между полями структуры, при этом, соответственно, она запишется в файл вместе с ними. Чтобы поля размещались без пропусков, следует указывать следующие директивы:

  1. pragma pack(push, 1)

// Объявление структур
...

  1. pragma pack(pop)

Структуры должны иметь следующие размеры:
BITMAPFILEHEADER - 14 байтов
BITMAPINFOHEADER - 40 байтов

h21 16.10.2013 - 11:38

В предыдущем сообщении, не пойму, откуда взялись единицы перед директивами, вместо # (октоторп).

  1. pragma pack(push, 1)

// Объявление структур
...

  1. pragma pack(pop)

Борис 31.12.2013 - 15:03

Пиксели

Подскажите frowning smiley, вот я записал сами байты изображения в массив , как перевести их в целые числа(для цвета) , 0 до 15 . Плиз?

Борис 31.12.2013 - 15:04

mas=(unsigned char *)malloc(sizeof(unsigned char)*(inf.biSizeImage));

fseek(fp, bmp.bfOffBits, SEEK_SET);
fread(mas, inf.biSizeImage, 1, fp)
Вот конкретно , а что дальше можно сделать?confused smiley НА чистом СИ

I.D. 09.01.2014 - 15:52

Хорошая статья happy smiley

Прохожий 27.01.2014 - 13:32

Представление чисел в памяти и регистрах

Хорошая статья. Числа в памяти записаны справа налево (т.е. о
рег AX 2233h Число в памяти 3322h (после записи)
рег EAX 22334455h Число в памяти 55443322h

Серж 25.05.2014 - 01:36

Мегаспасибо

Никак не мог понять, почему у меня не получается сохранить 8-битный массив с камеры размером 1625x1234 в бмп-файл. Хотя 1624x1234 сохраняется без проблем.
Все заработало как только я добавил в файл дополнительно нули в количестве - как вы указали - "(3 * Width) % 4" (для 8 бит)
Огромное Вам спасибо!

девочка, совершившая ошибку в своей жизни 27.10.2014 - 21:54

Помощь, мне нужна помощь, ребятки!

Я сохранила рисунок, который я очень долго и старательно рисовала в графическом редакторе-Paint. Так вот, этот рисунок имеет очень хорошую чёткость в Painte, но когда я его сохраняла, получается, что картинка не имеет такой же четкости, когда была рисунком. А совершила я ошибку в том, что сохранила рисунок в "256-цветный рисунок (*.bmp*;.did)" и сейчас он поменял цвета, а изначально он был у меня в формате *.png. Это очень плохо для меня. Прошу, помогите пожалуйста мне вернуть обратно цвет рисунку, который был раньше, и сделать так, чтобы при сохранении рисунка, картинка получалась такой же четкой, как и рисунок, если это возможно.

Jenyay 27.10.2014 - 22:37

Из испорченного рисунка получить качественный уже не получится, а в принципе Paint должен уметь сохранять png.

 11.02.2015 - 15:33

поправьте комменты плиз

>bih.biBitCount =8;// 16 бит на пиксель

 11.02.2015 - 15:37

можете пожалуйста подсказать с конвертированием 24-битного в 8-битный, а именно как посоветуете распределять цвета. вот у вас есть пример 8 битной с использования палитры, так, а вот есть у нас 3 байта, для кодирования R, G и B, вот как правильно преобразовать в индекс цвета в таблице...

Vlad K 02.03.2015 - 10:25

Обратная задача

У меня обратная задача. Нужно оцифровать график с картинки от BMP 8-бит от Paint(к примеру). Подскажите, с чего начать?
Спасибо

ДмитрийК 12.02.2016 - 20:59

Автор, вы большой молодец, большое спасибо вам.

Georgy Sviridov 28.06.2019 - 17:20

Спасибо, быстро разобрался.

oss 14.09.2019 - 14:49

Спасибо большое за статью!

Иван Иванов 11.12.2019 - 10:53

Много полезна статия. Благодаря!

Виктор 01.03.2021 - 12:24

Тема

Параграф это 4 байта ?
Если так, то формула расчета для добавление недостающих байтов в строку будет такой, для 24 битового формата:
4 - (Width*3 mod 4)

Виктор 01.03.2021 - 12:24

Тема

Параграф это 4 байта ?
Если так, то формула расчета для добавление недостающих байтов в строку будет такой, для 24 битового формата:
4 - (Width*3 mod 4)

Виктор 01.03.2021 - 12:25

Тема

Параграф это 4 байта ?
Если так, то формула расчета для добавление недостающих байтов в строку будет такой, для 24 битового формата:
4 - (Width*3 mod 4)

ElpanovEvgeniy 04.12.2024 - 10:15

Огромное спасибо за пояснения в структуре bmp картинок. Мне пришлось с нуля написать конвертер из 24 бита в 1 бит. На официальном сайте куча информации, но мелочи там не описаны. Хотя и вы не описывали двухцветные картинки, но ваша статья помогла за день преодолеть все сложности.

В целом была задача - на входе два изображение чертежей до и после редактирования, на выходе три изображения в один цвет, первое по совпадающим пикселам, второе по удаленным, а третье по добавленным. Чтоб эти результирующие изображения можно было наложить и быстро оценить работу в целом.

Еще раз, огромное СПАСИБО!


Подписаться на комментарии
Автор:
Тема:
 Ваш комментарий
 
 
Введите код 750