Оскільки метафайли містять растрові та векторні дані, при їх перетворенні виникають такі ж проблеми які виникають при перетворенні растрового у растровий та векторного у векторний. (див. два попередніх пункти).
Таке перетворення називають раструванням. Суть полягає у тому, що вихідне зображення розбивається на рядки та стовпчики (з заданою щільністю у dpi), що утворюють пікселі, які залишається записати в результуючому (растровому) форматі. При цьому, може виникнути ефект сходинок на похилих лініях та дугах, який можна приховати за допомогою невеличкого розмиття (anti-aliasing).
Перетворення растрового та метафайлового у векторний є дуже складною операцією. Не завжди можна досягти гарних результатів, тому що при такому перетворенні використовуються складні алгоритми обробки зображень, еврістичні методи пошуку та виділення в однорідних растрових даних ліній, прямокутників, градієнтів, тощо.Ще однією проблемою проблемою є точна передача кольорів. Растрові дані, як правило, повнокольорові (24 bit), а векторні підтримують лише декілька кольорів, що може призвести до втрати кольорів у результуючому забраженні.
Найпоширенішими програмами, що можуть робити подібне перетворення, є Adobe Streamline та Corel Trace.
Таке перетворення не мусить викликати багато проблем, тому що метафайли добре підтримують растрові та векторні дані. Але формат зберігання растрових чи векторних даних може бути різним, тому виникають такі ж проблеми як і при перетворенні растрового у растровий та векторного у векторний.
Розглянемо перетворення двох растрових форматів на конкретному прикладі створення програми для перетворення графічного зображення з формату PCX на Microsoft BMP третьої версії. Уся обробка графічних файлів була написана на мові Паскаль з нуля, без використання бібліотек, які в великій кількості можна знайти в Інтернет. На вході програми – файл у форматі PCX, на виході – BMP. Основний принцип роботи програми такий: зчитується заголовок файлу PCX, на його основі створюється заголовок файлу BMP, зчитуються дані кожного пікселя і записуються у формат BMP. Через те, що у форматі BMP рядки даних йдуть знизу догори (у PCX та інших форматах – навпаки), то спочатку записується тимчасовий файл з перевернутим зображенням, а потім цей тимчасовий файл перевертається, щоб отримати нормальний файл BMP, який можна відкривати й використовувати в інших програмах. Оскільки при написанні програми єдиною метою було зрозуміти головний принцип перетворення, то створена програма не є універсальною. Тому вона працює тільки з попередньо заданими іменами файлів і перетворює файли лише з 24 бітами на піксель. Інтерфейс програми вибрано найпростішим для того, щоб концентрувати увагу на самому перетворенні, а не реалізації інтерфейсу. Також, не було приділено уваги анлізу помилок. Розглянемо формати файлів PCX та BMP докладніше, перш ніж перейти до аналізу самої програми.
PCX – один з форматів, що часто використовується, через свою простоту. Спочатку він був розроблений фірмою Zsoft для використання у програмі PC Paintbrush для MS-DOS. Дані зображення кодуються за допомогою одного з варіантів алгоритму RLE, який незважаючи на простоту та швидкісь, не є ефективним. Цей формат може містити зображення з 4, 8 та 24 бітами на піксель. Далі ми будемо розглядати особливості 24 бітового формату.
Перші 128 байтів файлу містять заголовок:
Typedef struct _PcxHeader { | |
BYTE Id; | Ідентикатор PCX (0Ah) |
BYTE Version; | Версія |
BYTE Format; | Кодування (1 - RLE) |
BYTE BitsPixelPlane; | Кількість бітів на піксель |
WORD Xmin; | Ліва мінімальна координата |
WORD Ymin; | Верхня мінімальна координата |
WORD Xmax; | Права максимальна координата |
WORD Ymax; | Нижня максимальна координата |
WORD Hdpi; | Горизонтальна роздільна здатність |
WORD Vdpi; | Вертикальна роздільна здатність |
BYTE EgaPalette[48]; | Палітра |
BYTE Reserved; | Зарезервовано |
BYTE NumberOfPlanes; | Кількість площин |
WORD BytesLinePlane; | Кількість байтів на рядок |
WORD PaletteInfo; | Тип палітри |
WORD HScreenSize; | Розмір екрану по горизонталі |
WORD VScreenSize; | Розмір екрану по вертикалі |
BYTE Filler[54]; | Зарезервовано |
} PCXHEADER; |
Поле Id містить 0Ah, це означає, що даний файл направді є файлом формату PCX. Натепер підтримується лише один тип кодування – RLE, якому відповідає значення 1. Назви інших полів говорять самі за себе.
Дані у форматі PCX стискаються за допомогою простого алгоритму групового кодування, у якому група байтів, що повторюються, замінюється двома байтами: кількістю значень та самим значенням. Перший байт цієї двобайтової групи містить у двох старших бітах по одиниці, а у шести менших – кількість значень, які повторюються, що визначає максимальну довжину – 63 пікселя. Другий байт містить восьмибітове значення, що на виході повторюється стільки разів, скільки було задано у молодших шести бітах першого байту. Далі йде наступна пара кількість/значення. Якщо старші два біти першого байту нулі, то цей байт містить саме значення, а кількість повторень вважається 1. Отримані дані кодують колір послідовних пікселів, по три на піксель у форматі RGB. Але дані записуються не триплетами, а спочатку усі червоні компоненти для одного рядка растру, потім так само зелені, а потім сині. При цьому палітра не використовується.
Формат BMP був створений компанією Microsoft спеціально для зберігання растрових даних у системі Windows. Дані заголовку та й його розмір змінювалися й доповнювалися з випуском нових версій цієї операційної системи. Ми будемо розглядати формат BMP версії три. Перший 14-байтовий заголовок однаковий для усіх версій:
Typedef struct BITMAPFILEHEADER { | |
UINT16 type; | Тип файлу – 4D42h ("BM") |
UINT32 size; | Розмір файлу в байтах |
INT16 xHotspot; | Резерв |
INT16 yHotspot; | Резерв |
UINT32 offsetToBits; | Початок даних зображення |
} BITMAPFILEHEADER; |
У версії три далі йде 40-байтовий додатковий заголовок:
Typedef struct BITMAPHEADER { | |
UINT32 size; | Розмір цього заголовку у байтах |
INT32 width; | Ширина зображення в пікселях |
INT32 height; | Висота зображення в пікселях |
UINT16 numBitPlanes; | Кількість площин |
UINT16 numBitsPerPlane; | Кількість бітів на піксель |
UINT32 compressionScheme; | Тип стиснення |
UINT32 sizeOfImageData; | Розмір растру у байтах |
UINT32 xResolution; | Горизонтальна роздільна здатність у пікселях на метр |
UINT32 yResolution; | Вертикальна роздільна здатність у пікселях на метр |
UINT32 numColorsUsed; | Кількість кольорів у зображенні |
UINT32 numImportantColors; | Кількість важливих кольорів |
} |
Після заголовків йдуть дані 24-бітового зображення у форматі RGB, але на відміну від PCX, площини не використовуються і триплети кольорів йдуть один за одним.
Розглянемо програму перетворення растрового зображення з формату PCX у BMP рядок за рядком. Повний лістінг програми див. у додатку 1.
uses
crt;
Додатковий стандартний модуль crt використовується для позиціонування текстового курсора та очищення рядку.
Далі визначаються змінні:
var
PCXF, BMPF: file;
Нетипізовані файли для зчитування та запису інформації.
PCXheader: array [0..127] of byte;
Масив для зберігання заголовку PCX файлу.
BMPheader: array [0..53] of byte;
Масив для зберігання заголовку BMP файлу.
i, result, curx, HGT: integer;
Змінна циклу, результат зчитування та запису файлів і умова виходу з циклу, вказівник на поточний елемент у масиві buf, висота зображення у рядках (або пікселах).
buf: array [0..1959] of byte;
Масив для зберігання даних одного рядка. Максимальне значення індексу масиву вибрано довільно, але так, щоб можна було перетворити тестовий файл.
b, val: byte;
Дуплети даних формату PCX запакованого за алгоритмом RLE.
size, pos1, BPL: longint;
Рахівник кількості перетворених пікселів, кількості рядків, що були перевернуті з тимчасового файлу перевернутого BMP та кількість пікселів на рядок. BPL*3 – реальний об‘єм потрібного буфера для зберігання одного рядку.
Begin
assign(PCXF, 'dollar.pcx');
reset(PCXF, 1);
assign(BMPF, 'dollar.tmp');
rewrite(BMPF, 1);
Відкриваються два файли – для зчитування з PCX та запису у TMP.
blockread(PCXF, PCXheader, 128);
Зчитується заголовок PCX в масив PCXheader розміром 128 байт:
for i:=0 to 53 do begin
BMPheader[i]:=0;
end;
Майже всі дані новоствореного заголовку BMP міститимуть нулі.
writeln('Width: ', PCXheader[9]*256+PCXheader[8]+1);
HGT := PCXheader[11]*256+PCXheader[10]+1;
writeln('Height: ', HGT);
На екран виводяться ширина та висота зображення, взяті з заголовку PCX файлу, при чому висота нам ще знадобиться. Формула використовується для перетворення двох байтових значень у одне слово.
BPL := PCXheader[67]*256+PCXheader[66];
Визначається кількість байтів на рядок. Далі створюється заголовок формату BMP, поки що в пам‘яті.
BMPheader[0] := $42; {header word}
BMPheader[1] := $4D;
Заголовок всього формату BMP – "BM".