Ця стаття про те, як виглядає графічний формат bmp. Хоча це і один із простих форматів, але через те, що існує багато варіацій цього формату, то не всі моменти очевидні. Отже, годі лити воду, почнемо.
Структури формату
Формат bmp (від слів BitMaP - бітова карта, або, говорячи російською, бітовий масив) являє собою несжате (в основному) зображення, яке досить легко читається і виводиться в ОС Windows, в якій є спеціальні функції API, які в цьому допомагають.
Для початку наведемо графічне представлення даних у bmp (картинка взята з MSDN).
На початку стоїть заголовок файлу (BITMAPFILEHEADER). Він описаний так:
bfTypeвизначає тип файлу. Тут він має бути BM. Якщо Ви відкриєте будь-який файл BMP у текстовому (а краще у 16-річному редакторі), то побачите, що перші два символи - це BM (від слова BitMap, як ви вже, мабуть, здогадалися).
bfSize- це розмір файлу в байтах. Строго кажучи, ви повинні його вираховувати (що рекомендується), але я ставив розмір файлу неправильно (правда, не навмисне:)) і ніяких проблем не було (ACDSee читало без проблем, моя програма працювала), але я вам не рекомендую писати його свідомо неправильно раптом з'явиться сумлінна програма, яка звірить цей розмір зі справжнім і вирішить, що це не bmp, а щось інше. В ідеалі всі програми для того, щоб переконатися, що перед ними дійсно bmp, а не підробка, повинні, по-перше, перевірити, що bfType містить "BM" (без лапок), а по-друге, що bfSize дорівнює розміру файлу .
bfReserved1 та bfReserved2зарезервовані та мають бути нулями.
bfOffBits. Це один із найважливіших полів у цій структурі. Він показує, де починається сам бітовий масив щодо початку файлу (або, як написано в MSDN, "від початку структури BITMAPFILEHEADER"), який описує картинку. Тобто щоб гарантовано потрапляти на початок масиву ви повинні писати:
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, яка описана так: |
Зберігання даних у форматі bmp
Ну ось і підійшли до найцікавішого. Після структур BITMAPFILEHEADER та BITMAPINFOHEADER йде палітра. Причому, якщо формат безпалітровий, то його може й не бути, проте на це не треба розраховувати. Справа в тому, що коли я тільки починав розбиратися з форматом bmp, в одній книжці я вичитав, що, нібито, якщо формат безпалітровий, то взагалі немає палітри. Там навіть були дві картинки – схеми формату: одна з палітрою, інша без. А я тим часом писав програму, яка старанно оперує з bmp-шками. І мені треба було перетворювати вхідні картинки з 256 кольорів на 24-бітові (якщо такі були) у тимчасові файли. І я в 24-бітних палітру просто не створював (bfOffBits зі структури BITMAPFILEHEADER у мене дорівнював сумі sizeof(BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER), а вхідні 24-розрядні залишав без змін. З 256-кольоровими растрами мені не попалася 24-розрядна картинка, у якої внизу замість потрібної частини відображалося сміття. Я не відразу зрозумів у чому справа. 1024 байта).Там була палітра. Використовуючи bfOffBits, Палітра являє собою масив структур RGBQUAD, що йдуть один за одним Навіть якщо в палітрі використовуються не всі кольори (а тільки, наприклад, 16), то часто все одно під палітру відводять 256 полів. 4 - розмір структури RGBQUAD, тобто і виходить той самий кілобайт.
Відразу за палітрою йде сам растр. Тут уже заплутаніше. По-перше, пікселі тут описуються так, як написано в таблиці вище залежно від формату. І можуть самі містити значення компонентів кольору (для безпалітрових), а можуть бути індексами масиву-палітри. Сама картинка записується рядково. По-друге, картинка йде як би перевернута догори ногами. Тобто спочатку записано нижній рядок, потім передостанній і так далі до самого верху. І, по-третє, як написано в , якщо розмір рядка растру не кратен 4, то вона доповнюється від 1 до 3 порожніми (нульовими) байтами, щоб довжина рядка виявилася кратною параграфу. Ось це і є найнеприємніше. Справа в тому, що для кожного формату доводиться підлаштовувати це число порожніх байтів (правда, я люблю туди записувати частину палітри, просто мені не хочеться заводити зайві "нульові" змінні, якщо все одно ці байти пропускають і нікому вони не потрібні). Я наводжу таблицю з формулами, які показують для якого формату скільки байт треба дописувати до кінця рядка. Там під змінною Width, як можна здогадатися, мається на увазі ширина картинки. Усі ці формули були встановлені експериментально. Я наведу приклад тільки для форматів, що найбільш використовуються. Для решти ви можете написати самі.
Приклади програм
Усі вихідники ви можете скачати .Я особливо не буду тут багато писати. Просто наведу функції із коментарями.
Привіт 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;
}
У функцію треба передавати імена вихідного та кінцевого файлу відповідно.
Найчастішою причиною проблем із розкриттям файлу BMP є просто відсутність відповідних програм, встановлених на Вашому комп'ютері. У такому випадку достатньо знайти, завантажити та встановити програму, яка обслуговує файли у форматі BMP – такі програми доступні нижче.
Пошукова система
Введіть розширення файлу
Допомога
Підказка
Необхідно врахувати, що деякі закодовані дані з файлів, які наш комп'ютер не читає, іноді можна переглянути у Блокноті. Таким чином, ми прочитаємо фрагменти тексту або числа - Варто перевірити, чи діє цей метод також у разі файлів BMP.
Що робити, якщо програму зі списку вже встановлено?
Часто встановлена програма повинна автоматично зв'язатися з файлом BMP. Якщо це не сталося, файл BMP успішно можна зв'язати вручну з новою встановленою програмою. Достатньо натиснути правою кнопкою мишки на файл BMP, а потім серед доступних вибрати опцію "Вибрати програму за замовчуванням". Потім потрібно вибрати опцію "Переглянути" і знайти обраний додаток. Введені зміни необхідно затвердити за допомогою опції "OK".
Програми, які відкривають файл BMP
Windows
Mac OS
Чому я не можу відкрити файл BMP?
Проблеми з файлами BMP можуть мати також інший ґрунт. Іноді навіть встановлення на комп'ютері програмного забезпечення, що обслуговує файли BMP, не вирішить проблему. Причиною неможливості відкриття, а також роботи з файлом BMP може бути:
Невідповідні зв'язки файлу BMP у записах реєстру
- Пошкодження файлу BMP, який ми відкриваємо
- інфікування файлу BMP (віруси)
- надто маленький ресурс комп'ютера
- неактуальні драйвери
- усунення розширення BMP із реєстру системи Windows
- незавершене встановлення програми, що обслуговує розширення BMP
Вирішення цих проблем повинно призвести до вільного відкриття та роботи з файлами BMP. У випадку, якщо комп'ютер, як і раніше, має проблеми з файлами, необхідно скористатися за допомогою експерта, який встановить точну причину.
Мій комп'ютер не показує розширення файлів, що робити?
У стандартних установках Windows користувач комп'ютера не бачить розширення файлів BMP. Це успішно можна змінити у налаштуваннях. Достатньо увійти в "Панель управління" та вибрати "Вигляд та персоналізація". Потім необхідно увійти в "Опції папок" та відкрити "Вид". В закладці "Вид" знаходиться опція "Прикрити розширення відомих типів файлів" - необхідно вибрати цю опцію та підтвердити операцію натисканням кнопки "OK". У цей момент розширення всіх файлів, у тому числі BMP, повинні з'явитися сортовані за назвою файлу.
Оголошення
Формат файлів BMP Raster image
BMP (файл растрового зображення, растровий формат файлу, незалежний від пристрою, растрове зображення) – файли растрового зображення, які використовуються для зберігання цифрових растрових зображень окремо від пристрою відображення. Цей тип файлів раніше використовувався у Microsoft Windows та OS/2. Термін "растровий" походить від ідеї програмістів про карту бітів. Зображення BMP зазвичай не стискаються або стискаються без втрат (наприклад, за допомогою ZIP або RAR – завдяки наявності у файлі надлишкових даних). Сьогодні JPG є кращим форматом зображень - в основному через великий розмір файлу BMP, що може викликати проблеми або затримки при завантаженні, відправці або вивантаженні файлів.
Технічні відомості про файли BMP
Файли BMP зберігаються у вигляді 2D-зображень різних розмірів, кольорів та значень глибини кольору без стиснення даних, колірних профілів або альфа-каналів. Зображення BMP зберігаються у форматах апаратно-незалежних растрових зображень (DIB), тобто для зображення вказані кольори, а не технічні характеристики системи. Це пояснює, чому деякі зображення BMP на різних комп'ютерах виглядають по-різному. Зображення BMP можна переглядати на будь-якому пристрої, у тому числі на комп'ютерних та телевізійних екранах. Відсутність патентів перетворила цей тип зображення на популярний формат для широкого спектру пристроїв.
Додаткова інформація про формат BMP
Розширення файлу | .bmp |
Категорія файлів | |
Файл-приклад | (2,7 MiB) (487,85 KiB) |
Пов'язані програми | Adobe Photoshop MS Paint Microsoft Photo Editor Paintbrush |