Стиснення даних зображення
Починаючи з версії 3.0 WINDOWS допускає стиснення растрових ображень в файлах .bmp, з використанням простого методу групового кодування (RLE - run-length encoded). Сенс групового кодування в тому, що групи одноколірних пікселів записуються двома байтами: кількість повторень (n) і значення кольору. При відображенні упакованого зображення треба просто n разів повторити піксел з вказаним кольором.
Стиснення дозволяє економити місце на диску і пам'ять, потрібні для зберігання зображення. Чим більше в зображенні ділянок одного кольору, і чим більше розміри цих ділянок, тим ефективніше стискається зображення. Стиснення застосовується для форматів з вісьма або чотирма бітами на пікселя тобто для 256-ти і 16-кольорових зображень. Одноколірні і повно кольорові (true color) зображення не можуть бути стислі.
Елемент bicompression заголовка зображення визначає тип стиснення. Він може мати одне з наступних значень:
Bi_rgb (=0) - зображення не стисле;
Bi_rle8 (=1) - 8-бітове групове кодування;
Bi_rle4 (=2) - 4-бітове групове кодування.
Для стислих 256-кольорових зображень елемент bicompression в заголовку зображення рівний константі Bi_rle8 (=1). Дані зберігаються у вигляді блоків що складаються з двох і більш байт.
Якщо перший байт блоку не рівний нулю, він є числом пікселів в послідовності одного кольору. Це число може приймати значення від 1 до 255. Другий (і останній) байт блоку є індексом в таблиці квітів, по якій визначається колір послідовності пікселів.
Наприклад, блок "0a 14" означає, що треба вивести 10 байт (шістнадцяткове 0a) кольором, певним двадцятим елементом (шістнадцяткове 14) таблиці квітів.
Якщо перший байт блоку рівний нулю, це означає, що за ним слідує деяка команда. Довжина блоку в цьому випадку визначається командою. Значення другого байта конкретизує команду:
0 Кінець рядка;
1 Кінець зображення;
2 Команда переходу (або Delta-команда);
n>=3 Абсолютний режим.
Сенс перших двох команд зрозумілий. Скажу тільки, що довжина блоку для
цих команд складає два байти. Команда переходу означає, що наступний піксел, що виводиться, буде зміщений щодо поточного. Два байти, наступні за командою містять беззнакові байтові значення, вказуючі горизонтальне і вертикальне зсуви. Наприклад, блок "00 02 05 01" означає, що треба переміститися на 5 крапок управо і на 1 рядок вниз. Такі команди застосовуються, коли треба вивести декілька маленьких деталей в різні місця фонового зображення. Як ви вже напевно порахували, довжина блоку команди переходу складає чотири байти.
Абсолютний режим застосовується для запису послідовності одіночних пікселів, кожен з яких має колір, відмінний від квітів сусідів. Другий байт блоку служить не тільки ознакою абсолютного режиму, але і указує, скільки пікселів записано нестислими. Індекси квітів цих пікселів слідують за ознакою команди абсолютного режиму. Якщо їх число непарно, то послідовність для вирівнювання на межу двобаштового слова доповнюється нулем. Довжина блоку цієї команди складає від 6 до 258 байт залежно від значення n.
Відмітимо, що абсолютний режим застосовується тільки для послідовності не менше чим 3 піксели. Якщо різноколірних пікселів 1 або 2, вони кодуються з повторітелем рівним одиниці. Наприклад послідовність пікселів
11 11 11 22 33 44 44
закодується таким чином:
03 11 01 22 01 33 02 44.
В результаті, стисле зображення займає більше місця, чим нестисле. Розглянемо приклад стислого методом групового кодування 8-бітового зображення (шістнадцятиричні значення з двома цифрами в другому стовпці
є індексами кольору одиночного піксела):
Стислі дані Повні дані
10 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c
03 04 04 04 04
00 03 45 56 67 00 45 56 67 (останній 00 - доповнення)
02 78 78 78
00 02 05 01 Переміщення на 5 крапок управо і на 1 рядок вниз
02 78 78 78
00 00 Кінець рядка
09 1e 1e 1e 1e 1e 1e 1e 1e 1e 1e
00 01 Кінець зображення RLE
Відмітимо, що стислі дані досить нестійкі до помилок. Зміни в одному байті нестислих даних приведе до спотворення кольору тільки одного піксела. Подивимося, що відбудеться, якщо в нашому прикладі спотвориться всього один біт і перший байт читатиметься як "00" замість "10". Послідовність "00 0c" означає команду абсолютного режиму, за якою слідують 12 (шістнадцятиричне 0c) нестислих пікселів. Поточна рядок буде сильно спотворений:
03 04 00 03 45 56 67 00 02 78 00 02 01 01 01 01 01 78 78
замість
0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 04 04 04 45 56 67 78 78
Крім того, ми пропустили Delta-команду, і перехід виконаний не буде. У результаті, зображення сильно спотвориться при помилці всього в ОДНОМУ БІТІ. Можливі та інші, більш катастрофічні ситуації. Можете попридумувати
їх самих. Стиснення 16-кольорових зображень (елемент bicompression в заголовку зображення рівний константі Bi_rle4 =2) виконується аналогічно розглянутому. Відмінність полягає в тому, що інформація інтерпретується по тетрадах або півбайтах, тобто по 4 бита. Розглянемо той же приклад (кожна шістнадцятирична цифра в правому стовпці є індексом кольору одиночного піксела):
Стислі дані Повні дані
10 0c 0 C 0 C 0 C 0 C 0 C 0 C 0 C 0 C
03 04 0 4 0
00 06 45 56 67 00 4 5 5 6 6 7
04 78 7 8 7 8
00 02 05 01 Переміщення на 5 управо і на 1 вниз
04 78 7 8 7 8
00 00 Кінець рядка
09 1e 1 E 1 E 1 E 1 E 1
00 01 Кінець зображення RLE
Інтерпретація команд співпадає з раніше розглянутому злучаємо. Істотна відмінність спостерігається в режимі кодування, тобто коли перший байт блоку не рівний нулю і є числом пікселів в послідовності, другий байт містить НЕ ОДИН, А ДВА індекси квітів перший в старшому півбайті (то-есть 4 біта старшого розряду) і другий в молодшому півбайті. У розглянутому прикладі, код "05 06" відповідає послідовності 5 байт з квітами, що чергуються " 0 6 0 6 0". Для зображень з чергуванням квітів таке стиснення буде вельми ефективне але біда, такі зображення зустрічаються дуже рідко.
Такий же метод кодування і подібні формати мають інші графічні файли WINDOWS: файли піктограм (або ікон) *.ico і файли курсорів *.cur.
Файли *.pcxpar
1982 Корпорацией Zsoft для їх програми Paintbrush, але фактично став промисловим стандартом для збереження і пересилки растрових зображень на ПК з MS-DOS. Сучасна версія цього формату може підтримувати дисплеї будь-якої роздільної здатності, що використовують палітри з будь-яким кількістю квітів, і він дуже простий в застосуванні. Крім того, він не обмежується ПК з MS-DOS і Os/2; формат PCX придатний для будь-якого середовища що забезпечує растрову графіку. Сьогодні, практично всі комерційні програми підтримують формат PCX.
У форматі PCX також використаний метод групового кодування (RLE - run-length encoded). Групове кодування, вживане у файлах PCX декілька відрізняється від кодування у файлах BMP, хоча сама ідея групового кодування та ж: замість послідовності однакових байтів зберігати їх кількість і значення.
Файл PCX може мати два або три розділи: 128-байтний заголовок закодовані дані зображення (цей розділ може мати довільну довжину) і необов'язкову палітру. Ця палітра приєднується до файлу тільки у тому випадку, коли зображення містить 256 квітів. Її довжина рівна 769 байт (256*3+1).
Заголовок файлу PCX
Заголовок файлу описує графічне середовище, в якому повинно виводитися зображення. Інформація, що міститься в заголовку, частково залежить від пристрою. Більш того, специфічний тип і відео режим адаптера, необхідні для правильного відображення зображення, не можуть бути однозначно визначені з інформації заголовка файлу. Правильний вибір відеорежиму перед відображенням PCX файлу залишається на совісті користувача.
Структура заголовка файлу така:
typedef struct tagpcxheader
{
BYTE Pcxflag; // Постійний прапорець (0x0a - файл PCX)
BYTE version; // Номер версії PCX
BYTE encod; // Прапор відрядкового кодування (=1)
BYTE bitpx; // Число бітів на піксел на колірну площину
WORD x1; // Положення зображення на екрані
WORD y1;
WORD x2;
WORD y2;
WORD hres; // Горизонтальна роздільна здатність
WORD vres; // Вертикальна роздільна здатність
BYTE clrma[48]; // Палітра
BYTE vmode; // Ігнорується
BYTE nplanes; // Число колірних площин
WORD bplin; // Число байтів на площину рядка розгортки
WORD palinfo; // Інтерпретація палітри
WORD hsize; // Горіз. розмір екрану або дозвіл сканера
WORD vsize; // Вертік.размер екрану або дозвіл сканера
char xtra[54]; // Резерв
} PCXHEADER;
Призначення більшості елементів структури PCXHEADER зрозуміло. Деяких пояснень вимагають лише наступні поля:
Поле палітри (clrma) має розмір всього лише 48 байт. Це вистачає тільки на опис 16 квітів. Таке мале значення відображає історію створення формату PCX. Зараз, для палітри 256-кольорових зображень цього місця не вистачає, і вона винесена в кінець файлу. Палітра представляє собою масив 3-байтних структур RGB, кожен з байтів якої представляє відносну інтенсивність червоного, зеленого і синього компонентів кольору. Порядок проходження компонентів звичний: R-G-B.
Елемент vmode раніше використовувався для вказівки відповідного відеорежиму MS-DOS. Зараз він ігнорується, але повинен бути встановлений
рівним нулю.
Число байтів на площину в рядку розгортки (bplin) для сумісності з деякими існуючими комерційними програмами повинно бути парним (що вирівнюється на границю слова).
У елементі, вказуючому як інтерпретувати кольорову палітру (palinfo), значущими є тільки два самих молодших бита, інші ігноруються. Згідно документації, він може мати одне з двох можливих значень:
0x01 - кольорове або чорно-біле зображення 0x02 - півтонове (сіре) зображення.
Якщо значення palinfo рівне 0x02 (півтонове зображення), у файлі може не бути палітри, а апаратна палітра при виводі повинна бути встановлена відтінками сірого. Проте, і в цьому випадку у файлі може міститися дійсна нелінійна півтонова палітра, і необхідно використовувати саме її. Крім того, деякі програми обнуляють це поле, а деякі, взагалі, пишуть туди сміття. Деякі автори рекомендують ігнорувати цей елемент, як це робить більшість сучасних програм. Проте, коли у файлі палітри немає, треба все ж таки встановлювати відтінки сірого. Як же бути? Поговоримо про це декілька пізніше, після того, як познайомимося із записом у файл PCX палітри.
Запис палітри
Палітра, що міститься у файлі стандарту PCX, є масивом 3-байтних структур. Байти цієї структури визначають інтенсивності червоною, зеленою і синій компонент кольору, номер якого відповідає індексу в масиві палітри.
Формат файлу PCX допускає запис в заголовку файлу палітр, які містять не більше 16 квітів. Великі палітри (для 256-кольорових зображень) у заголовку не поміщаються і дописується в кінці файлу. 24-бітові зображення не вимагають збереження палітри, оскільки в таких зображеннях кожен піксел представляється значеннями інтенсивностей червоною, зеленою і синій компонент в області даних, і додаткова палітра у файлах таких зображень повинна бути відсутньою. Проте деякі програми чогось дописують її в кінці файлу. Нічого страшного в цьому, звичайно ж, немає, але після розпаковування всіх рядків зображення у вас може залишитися необроблений шматок файлу, і не треба в такій ситуації лякатися.
Як же визначити, скільки квітів містить зображення? У заголовку файлу BMP є такий елемент, а в заголовку файлу PCX його немає. Тим не менш, кількість квітів визначити можна використовуючи елементи "число бітів на піксел на колірну площину" і "кількість площин" (див. таблицю):
Битий на | К-ть | К-ть | Розмір | Положення
плоськ. | плоськ. | квітів | палітри | палітри
--------+--------+--------+----------+------------
1 | 4 | до 16 | 48 байт | Заголовок
8 | 1 | до 256 | 769 байт | В кінці
8 | 3 | до 16m | - | Відсутній
Як ви пам'ятаєте, у відеоплатах зазвичай використовуються 6-ти розрядні Цап'и, які дозволяють встановити тільки 6 битий з 8, що містяться в кожному байті інтенсивностей компонент. У 16-кольоровій палітрі, яка записана в заголовку, завжди використовуються старші розряди. Тому при апаратній установці кольору треба значення кожного байта палітри ділити на 4. Так наприклад, якщо деякий колір в палітрі визначений трійкою байт "AA 55 FF", то для апаратної установки цього кольору отримаємо: "2a 15 3f".
256-кольоровій палітрі в кінці файлу завжди передує однобайтний прапор, який може мати значення 0x0c (десяткове 12) або 0x0a (десяткове 10). Він визначає, які розряди в байтах значень інтенсивностей повинні бути використані при установці апаратної палітри. Коли використовуються молодші 6 битий, значення прапора рівне 0x0a; значення ж рівне 0x0c говорить про те, що потрібно використовувати старші 6 битий, тобто при установці палітри ділити значення інтенсивностей компонент на 4.
Тепер поговоримо про файли з сірими зображеннями. Як ви пам'ятаєте, якщо такий файл палітру містить, то треба встановлювати саме її, а якщо немає то формувати рівномірну шкалу відтінків сірого. Як же визначити, є у файлі палітра чи ні?
Для 16-кольорових зображень треба проаналізувати поле палітризаголовку файлу, і, якщо там міститься коректна сіра палітра встановлювати її.
Для 256-кольорових зображень справа трохи складніша: файл може закінчуватися палітрою, а може і не містити її зовсім. Спочатку треба виконати грубу перевірку: подивитися на 769-й від кінця файлу байт. Якщо його значення відмінне від 0a або 0c, це байт зображення, і палітри в файлі немає.
Якщо ж його значення рівне 0a або 0c, то це ще не означає, що за ним слідує палітра. У полі даних зображення цілком можуть бути байти з такими значеннями, і ніхто не забороняє одному з таких байтів бути 769-им від кінця даних. Тому другим кроком треба перевірити на коректність палітри останні 768 байт файлу. Якщо вони не утворюють допустимої сірої палітри, треба встановлювати рівномірну сіру шкалу тобто (0,0,0) (1,1,1) ..., (255,255,255).
Якщо 769-й від кінця файлу байт рівний 0a або 0c, _і_ наступні за ним 768 байт утворюють коректну палітру, це все-рівно може опинитися всього лише збігом. Для того, щоб бути повністю упевненим, що це палітра, треба третім кроком декодувати зображення. І лише якщо після цього залишаться рівно 769 нерозпакованих байт, можна полегшено зітхнути і використовувати їх як палітру, яка, як ми переконалися на другому кроці, коректна.
Я весь час говорю: "коректна" або "допустима" сіра палітра. Що це означає? Відповідь достатньо очевидна. Спробуйте знайти його самі.
Перш за все, у кожного кольору сірої палітри повинні бути рівними значення всіх три компонент, тобто колір повинен бути відтінком сірого. Але
взагалі кажучи, цього мало. Дуже часто всі невживані байти заповнені яким нібудь постійним значенням, наприклад, нулем. В цьому випадку значення всіх три компонент кожного кольору рівні між собою. Але і все кольори також однакові. Ясно, що палітра не повинна бути такій, інакше зображення не міститиме зображення - всі піксели мають один і той же колір.
Таким чином, для коректної сірої палітри виконуються наступні два умови:
1) компоненти R, G, і B кожного кольору рівні, і
2) не всі кольори в палітрі однакові.
Елемент заголовка "номер версії PCX" теж має значення для установки палітри. Зазвичай він рівний 5, проте його значення рівне 3 означає, що в файлі немає інформації про палітру. В цьому випадку при виведенні зображення з файлу на екран треба користуватися стандартною палітрою відеоадаптера. Встановлювати ж палітру з такого файлу небезпечно - замість неї записаний сміття.