Бібліотека ASM-86 для перегляду графіки в стандартах BMP та PCX

Зміст



	Вступ

	Постановка задачі

	Обґрунтування вибору методів розв’язку задачі

	Алгоритм програми

	Реалізація програми

	Системні вимоги

	Інструкція для користувача

	Висновки

	Використана література

	Додаток. Лістинг програми


Вступ



Тепер комп’ютери відіграють у житті людини все більшу та більш роль. Раніше, коли ще не було комп’ютерів, чи вони були мало розповсюдженні, все робилося вручну. Коли комп’ютери одержали широке розповсюдження, комп’ютер став допомагати людині, бо він може багато операцій робити набагато швидше, ніж людина.

В наш час дуже популярні графічні редактори, які дозволяють зберігати зображення в популярних графічних форматах. Але інколи потрібна невелика програма, яка дозволяє переглядати графічні формати. Якщо ви хочете написати програму для зображень строго визначеного формату, щоб вона, наприклад, працювала удвічі швидше, ніж "Load from..." у PC Paintbrush, то ви повинні вивчити структуру заголовку та алгоритм стиснення даних для даного формату.


1. Постановка задачі

Розробити на мові програмування ASM-86 бібліотеку, сумісну з мовою програмування Pascal для перегляду графіки в стандартах: BMP, PCX.



2. Обгрунтування вибору методів розв’язку задачі



Необхідно написати, бібліотеку бібліотеку, сумісну з мовою програмування Pascal для перегляду графіки в стандартах: BMP, PCX.

Структура заголовків графіки в стандартах BMP та PCX, а також алгоритми розшифрування даних в цих стандартах приводиться в багатьох книжках, тож з вибором алгоритму у мене не виникло ніяких труднощів.

Формат файлу зображень (.PCX) Файли зображень з розширеннями .PCX починаються з заголовка довжиною 128 байт. Звичайно ви можете ігнорувати цей заголовок, якщо усі ваші зображення будуть мати однаковий дозвіл. Якщо ж ви хочете обробляти зображення з різним дозволом і різною кількістю квітів, вам належить коректно інтерпретувати інформацію, що знаходиться в даному заголовку. Частина файлу, що залишилася, із зображенням складається з закодованих графічних даних. При кодуванні використовується простий алгоритм, заснований на методі довгих серій. Ми залишаємо за собою право змінювати цей алгоритм із метою підвищення ефективності упакування даних. Якщо у файлі запам'ятовується кілька колірних шарів, кожен рядок зображення запам'ятовується по колірних шарах (у загальному випадку червоному-R, зеленому-G, синьому-B і шарую інтенсивності-I) за схемою, приведеної нижче: 



Рядок зображення 0:

RRR...

GGG...

BBB...

III...

Рядок зображення 1:

RRR...

GGG...

BBB...

III...



Метод кодування полягає в наступному:

ДЛЯ кожного байта X, прочитаного з файлу ЯКЩО обоє старших біта X рівні 1, то <повторювач> = 6 молодшим биткам X <дані> = наступному байту за X ІНАКШЕ <повторювач> = 1 <дані> = X

Формат заголовка PCX

Зміщений. Позначення Довжина Опис/коментар

0 Manufacturer 1 Постійний прапор 10 = ZSoft .PCX

1 Version 1 Інформація про версію:

0 = Версія 2.5

2 = Версія 2.8 з інформацією про палітру

3 = Версія 2.8 без інформації про палітру

5 = Версія 3.0

2 Encoding 1 1 = .PCX кодування довгими серіями

3 Bits per pixel 1 Число біт на піксел у шарі

4 Window 8 Розміри зображення (Xmin, Ymin) - (Xmax, Ymax) у пікселах включно

12 HRes 2 Горизонтальний дозвіл пристрою, що створює

14 VRes 2 Вертикальний дозвіл пристрою, що створює

16 Colormap 48 Набір колірної палітри (див. далі текст)

64 Reserved 1

65 NPlanes 1 Число колірних шарів

66 Bytes per Line 2 Число байт на рядок у колірному шарі (для PCX-файлів завжди повинне бути парним)

68 Palette Info 2 Як інтерпретувати палітру:

1 = кольорова/чорно-біла,

2 = градації сірого

70 Filler 58 Заповнюється нулями до кінця заголовка

Декодування файлів у форматі PCX

Спочатку визначите розмір зображення, обчисливши



[XSIZE = Xmax - Xmin + 1] і [YSIZE = Ymax - Ymin + 1].



Потім обчислите, скільки байтів потрібно для збереження одного незжатого рядка розгорнення зображення:



TotalBytes = NPlanes * BytesPerLine



Відзначимо, що оскільки завжди використовується ціле число байтів, можливе існування невикористовуваних даних наприкінці кожного рядка розгорнення. TotalBytes показує скількох пам'ятей повинне бути доступно для декодування кожного рядка розгорнення, включаючи невикористовувану інформацію на правому кінці кожного рядка.

Тепер ви можете почати декодування першого рядка розгорнення - прочитайте перший байт даних з файлу. Якщо два старших біти цього байта рівні 1, то залишилися шість бітів, які показують скільки разів варто повторити НАСТУПНИЙ байт із файлу. Якщо це не так, то цей байт сам є даними з повторювачем рівним 1. Продовжуйте декодування до кінця рядка, ведучи підрахунок кількості байтів, переданих у буфер висновку. Наприкінці кожного рядка розгорнення має місце зупинка алгоритму кодування, але її не існує при переході від одного шару до іншого. Коли рядок сформований цілком, наприкінці кожного шару усередині рядка можливий наявність зайвих даних. Для перебування цього залишку використовуйте значення XSIZE і YSIZE. Якщо дані є багатошаровими, то BytesPerLine показує, де закінчується кожен шар усередині рядка розгорнення. 

Продовжуйте декодування рядків, що залишилися. У файлі можлива наявність зайвих рядків з округленням на 8 чи 16 рядків.

Опис інформації про палітру

Інформація про 16-кольорову палітру (EGA/VGA)

Інформація про палітру запам'ятовується в одному з двох різних форматів. У стандартному форматі RGB (IBM EGA, IBM VGA) дані запам'ятовуються в 16 трійках. Кожна трійка складається з байтів зі значеннями червоного (Red), зеленого (Green) і синього (Blue) квітів. Значення можуть знаходитися в діапазоні 0-255, і тому необхідна їхня інтерпретація у формат використовуваного устаткування. Наприклад, на IBM EGA існують 4 можливих рівні RGB для кожного кольору. Оскільки 256/4 = 64, те нижче приведений список відповідності колірних значень і рівнів:

Значення Рівень



0-63 0

64-127 1

128-192 2

193-254 3



Інформація про 256-кольорову палітру VGA

В даний час ZSoft додав можливість збереження у файлі зображення PCX палітри, що перевищує 16 квітів. 256-кольорова палітра форматується й інтерпретується точно так, як 16-кольорова, природно, за винятком того, що вона довша. Палітра (число кольорів x 3 байти довжини) додається в кінець PCX файлу і їй передує байт із десятковим значенням 12. Для визначення палітри VGA BIOS вам досить розділити прочитані значення квітів на 4. 

Для доступу до 256-кольорової палітри потрібно:

1. Прочитати в заголовку поле Version. Якщо воно дорівнює 5, палітра повинна бути.

2. Прочитати кінець файлу і відрахувати назад 769 байт. Знайдене вами значення повинне дорівнювати 12, що вказує на присутність 256-кольорової палітри.



3. Алгоритм програми



Алгоритм головної програми:

		Перехід в графічний режим

		Виклик процедури виводу графіки в стандарті .PCX. 

	Чекання натиснення клавіші ENTER.

	Виклик процедури виводу графіки в стандарті .BMP. 

	Чекання натиснення клавіші ENTER.

			6.	Закінчити програму.

Алгоритм функції виводу графіки в стандарті .BMP.

1.Читання заголовку.

2.Аналіз заголовку

3.Читання палітри

4.Заповнення палітри

5.Читання даних

6.Аналіз даних та вивід на екран

7.Кінець функції.

Алгоритм функції виводу графіки в стандарті .PCX.

Читання заголовку.

Аналіз заголовку

3. Читання палітри

4. Заповнення палітри

5. Читання даних

6. Аналіз даних та вивід на екран

7. Кінець функції. 


4. Реалізація програми



Програма написана на мові ASM-86 з використанням команд процесора 86/286. Вона складається з головної програми, яка написана на мові програмування Pascal, і з бібліотеки, написаної на мові програмування ASM-86, функції якої викликаються в головній програмі. 

Функції бібліотеки: 



LoadPcx(x,y:integer;s:string);



Де x, y – координати початку виводу картини, s – імя файлу з розширенням PCX.



LoadBmp(x,y:integer;s:string);



Де x, y – координати початку виводу картини, s – імя файлу з розширенням BMP. Бібліотека компілюється за допомогою Turbo Assembler, зв’язується з головною програмою за допомогою TURBO.EXE.



5. Системні вимоги



IBM сумісний комп’ютер із мікропроцесором Intel 80386 або старшим.

Операційна система – ДОС

- Пам’ять – 640 К і вище



6. Інструкція для користувача



Для демонстрації бібліотеки написана програма, яка виводить на екран графіки в форматі .BMP, .PCX. Для запуску цієї програми потрібно в командному рядку набрати load_my.exe та натиснути Enter. 	Програма спочатку виведе на екран картину в форматі .PCX, потім, після натиснення Enter виведе другу картину в форматі .PCX, потім після натиснення Enter програма завершить свою роботу.


Висновки



Отже, на мові ASM-86 створено бібліотеку перегляду графіки в форматі .BMP, .PCX, та були розглянуті структури заголовків та алгоритми перегляду графіків.




Використана література



1. Р.Джордейн “Справочник программиста персональных компьютеров типа IBM PC” М: Мир, 1991р. 2. П.Абель “Мова асемблера для IBM PC та програмування.” М.:Вища школа,1992. 3. “Основи мови” Асемблер” В.I. Криволап. Москва 1997р. ст.309

4. “Ассемблер для початкiвцiв”М.П.Шукiн.Київ 1980р. ст.155

5. “Турбо Асемблер”Л.В.Захаров. Харків 1995 р ст.178

6. “Макро Асемблер”К.С. Кропiйко О.Д. Богатирова.Київ – “Наука” 1991р.

7. Електроний довідник BOOK

8. Електронна документація про формати .PCX та .BMP.


Додаток. Лістинг програми



uses crt;

var graphresult1,graphresult,i:integer; {результат чтения графики}

procedure setvideo(mode:byte);assembler;{устанавливает видеорежимы}

asm

mov ah,0 {функция установки видеорежема}

mov al,mode {номер режима}

int 10h {прерывание для работы с видеорежимами}

end;

{$L pcx.obj} {подключаем нашу библиотеку}

function LoadPcx(x,y:integer;s:string):integer;

 external;{обьявляем функции, которые находятся в библиотеке}

function LoadBmp(x,y:integer;s:string):integer;{для чтения файлов .PCX, .BMP}

external;

begin {MAIN}

if paramcount=0 then 

begin

 setvideo($5f); {устанавливает видеорежим 640x480 256 цветов}

 graphresult:=LoadPcx(1,1,'a1.pcx');{вызывает функцию для чтения .PCX

				 и возвращает результат чтения}

 readln; {ждет нажатия Enter}

 setvideo($5f);

 graphresult1:=LoadBmp(1,1,'a3.bmp');

 readln;

 setvideo(3); {установка текстового видеорежима}

 if graphresult<>0 then writeln('Ошибка чтения a1.pcx');

 if graphresult1<>0 then writeln('Ошибка чтения a3.bmp');

end

else {paramcount - количество параметров}

 for i:=1 to paramcount do begin {перебор всех параметров команд. стр.}

 setvideo($5f); {устанавливает видеорежим 640x480 256 цветов}

 if pos('.pcx',paramstr(i))>0 then

 graphresult:=LoadPcx(1,1,paramstr(i)){вызывает функцию для чтения .PCX

с указанным в командной строке именем файла

			 и возвращает результат чтения}

 else 

 graphresult:=LoadBMP(1,1,paramstr(i));{вызывает функцию для чтения .BMP

				 и возвращает результат чтения}

if graphresult<>0 then begin

	setvideo(3); {установка текстового видеорежима}

	writeln('Ошибка чтения '+paramstr(i));

	readln;

	end else readln; {ждет нажатия Enter}

end;

readln;

setvideo(3); {установка текстового видеорежима}

end.



Текст бібліотеки:

.386		;разрешение инструкций 386 процессора

IDEAL ;переход в идеальный режим

model SMALL,PASCAL ;модель памяти SMALL для распределения кода и данных 

		;и совместимая с паскалем

PUBLIC PASCAL LoadPcx ;Обьявляем общие процедуры

PUBLIC PASCAL LoadBmp

CODESEG

zagpcx db 130 dup(0) ;буфер для заголовков BMP и PCX

nfile db 'a.pcx',100 dup(0) ;буфер для имени файла

flc dw 0 ;индекс файла

x1 dw 0 ;координаты текущей точки 	

y1 dw 0

x2 dw 0

y2 dw 0

col db 770 dup(0) ;буфер для палитры 

c1 dw 0 ;цвет текущей точки

yres dw 0 ;размер картинки

xres dw 0

povt db 0 ;повторитель(сколько пикселей нарисовать)

buf db 1024 dup(0) ;буфер для данных 

bufsz dw 1024 ;размер буфера данных

bufpos dw 0 ;текущее положение буфера

maxx dw 640 

PROC PutPixel ;процедура вывода точки на экран

pusha		 ;сохранение регистров в стеке

mov ax,[maxx] ;проверка на выход за экран

cmp [x1],ax

jnb @@ex

mov ax,[C1] ;задаем цвет

mov ah,0ch

mov cx,[x1] ;задаем координаты

mov dx,[y1]

mov bh,0

int 10h ;вывод точки

@@ex:

popa ;восстановление регистров

ret

ENDP

PROC LoadBmp ;процедура вывода картинки в стандарте BMP

ARG nx:WORD,ny:WORD,file:WORD:2 ;параметры ;адрес строки имени картинки

pusha; ;сохранение регистров

push ds

mov dx,cs ;установка DS на сегмент кода

mov ds,dx

MASM ;переход в режим MASM

mov ax,[file] ;копирование имени файла

mov bx,ax

mov ax,[file]+2

mov es,ax

mov si,offset nfile

IDEAL ;переход в идеальный режим

mov al,[es:bx];

inc bx;

@lpabmp:mov cl,[es:bx];

mov [si],cl;

inc si;

inc bx;

sub al,1;

jnz @lpabmp; ;копирование имени файла в буфер

mov al,0

mov [si],al;

mov ax,3d00h; ;открытие файла

mov dx,offset nfile;адрес имени файла

int 21h;

jnc @lpbbmp;

jmp @lppoorbmp;

@lpbbmp:

mov [flc],ax;сохраняем номер файла

mov dx,offset zagpcx;адрес буфера

mov cx,54; количество байт для чтения данных из файла

mov bx,[flc]; заносим номер файла

mov ax,3f00h; чтение файла

int 21h;

mov bx,offset zagpcx;адрес буфера заголовка

mov ax,[bx];первое слово заголовка 

cmp ax,4D42h;проверка на PCX

jz @lpcbmp;

jmp @lppoor1bmp;

@lpcbmp:

@lpdbmp:add bx,18; чтение координат окна картинки

mov ax,[bx];

mov [x1],ax;

add bx,4;

mov ax,[bx];

mov [y1],ax;

add bx,4;

mov ax,[nx];

add ax,[x1];

mov [xres],ax;

add bx,2;

mov ax,[ny];

add ax,[y1];

mov [yres],ax;

mov ax,[nx]; устанавливаем текущую точку в начальную точку

mov [x1],ax;

mov ax,[ny];

mov [y1],ax;

mov [x2],0;

mov [y2],0;

@lpgbmp:

mov dx,offset col;

mov cx,768;

mov bx,[flc];

mov ax,3f00h;

int 21h;

mov bx,offset col;

mov cx,768;

MASM

@lpfbmp:ror byte ptr [bx],2;деление на 4 всех элементов палитры

IDEAL

inc bx;

sub cx,1;

jnz @lpfbmp;

mov dx,offset col;

mov ax,ds;

mov es,ax;

mov ax,1012h;

mov bx,0h;

mov cx,256;

int 10h; установка палитры

mov bx,offset zagpcx;

add bx,10

mov dx,[bx];

mov ax,4200h;

mov bx,[flc];

mov cx,0;

int 21h;

mov [povt],0;

@lpibmp:mov bx,[flc];

mov cx,[bufsz]; ;чтение данных в буфер по блокам (1 Kb).

mov ax,3f00h;

mov dx,offset buf

int 21h;

mov [bufpos],0;

@lpxbmp:

push ds

pop es

mov bx,offset buf

add bx,[bufpos];

mov ax,[bufpos];

cmp ax,[bufsz];

jz @lpibmp;

mov al,[es:bx];

inc [bufpos];

cmp [povt],0;

jz @lpkbmp;

mov cl,[povt];

mov ah,0h;

mov [c1],ax;

@lmdbmp:

call putpixel ;вывод точки

inc [x1];

inc [x2];

mov ax,[x2];

cmp ax,[xres];

jnz @lmcbmp;

mov ax,[nx];

mov [x1],ax;

mov [x2],0;

inc [y1];

inc [y2];

mov ax,[y2];

dec ax;

cmp ax,[yres];

jnz @lmcbmp;

jmp @lpokbmp;

@lmcbmp:dec cl;

cmp cl,0;

jnz @lmdbmp;

mov [povt],0;

jmp @lpxbmp;

@lpkbmp:

mov ah,al;

@lpybmp:

mov ah,0h;

mov [c1],ax;

call putpixel; вывод точки

inc [x1];

inc [x2];

mov ax,[x2];

dec ax;

cmp ax,[xres];

jnz @lpxbmp;

mov ax,[nx];

mov [x1],ax;

mov [x2],0;

inc [y1];

inc [y2];

mov ax,[y2];

dec ax;

cmp ax,[yres];

jnz @lpxbmp;

jmp @lpokbmp;

@lpokbmp:

pop ds

popa; ;восстановление регистров

mov ax,0

jmp @lpubmp;

@lppoor1bmp:

mov ah,3eh; ;закрытие файла

mov bx,[flc];

int 21h;

@lppoorbmp:

pop ds

popa; ;восстановление регистров

mov ax,3

@lpubmp:

ret

endp

PROC LoadPcx ;процедура чтения и вывода на экран PCX

ARG nx:WORD,ny:WORD,file:WORD:2 ;адрес строки имени картинки

pusha; ;сохранение регистров

push ds

mov dx,cs ;установка сегмента данных равным сегменту кода

mov ds,dx

MASM

mov ax,[file] ;копирование имени файла в буфер

mov bx,ax

mov ax,[file]+2

mov es,ax

mov si,offset nfile

IDEAL

mov al,[es:bx];

inc bx;

@lpa:mov cl,[es:bx];

mov [si],cl;

inc si;

inc bx;

sub al,1;

jnz @lpa; ;конец копирование имени файла в буфер

mov al,0

mov [si],al;

mov ax,3d00h; ;открытие файла

mov dx,offset nfile;адрес имени файла

int 21h;

jnc @lpb;

jmp @lppoor;

@lpb:

mov [flc],ax;сохраняем номер файла

mov dx,offset zagpcx;адрес буфера

mov cx,128; количество байт для чтения данных из файла

mov bx,[flc]; заносим номер файла

mov ax,3f00h; чтение файла

int 21h;

mov bx,offset zagpcx;адрес буфера заголовка

mov ax,[bx];первое слово заголовка 

cmp ax,050ah;проверка на PCX

jz @lpc;

jmp @lppoor1;

@lpc:add bx,2;

mov ax,[bx];

cmp ax,0801h; проверка на 256 цветов

jz @lpd;

jmp @lppoor1;

@lpd:add bx,2; чтение координат окна картинки

mov ax,[bx];

mov [x1],ax;

add bx,2;

mov ax,[bx];

mov [y1],ax;

add bx,2;

mov ax,[bx];

sub ax,[x1];

mov [xres],ax

add bx,2;

mov ax,[bx];

sub ax,[y1];

mov [yres],ax ; вычисление размеров картинки

mov ax,[nx];

mov [x1],ax; устанавливаем текущую точку в начальную точку

mov ax,[ny];

mov [y1],ax;

mov [x2],0;

mov [y2],0;

add bx,55;

mov al,[bx]; проверка

cmp al,01h;

jz @lpg;

jmp @lppoor1;

@lpg:mov ax,4202h; установка указателя файла на конец файла

mov bx,[flc];

mov cx,0;

mov dx,0;

int 21h;

sub ax,769; вычисление начало палитры

sbb dx,0h;

mov cx,dx;

mov dx,ax;

mov bx,[flc];

mov ax,4200h; установка указателя файла на начало палитры

int 21h;

mov dx,offset col;чтение палитры

mov cx,769; количество байт для чтения

mov bx,[flc];

mov ax,3f00h;

int 21h; чтение

mov bx,offset col;

MASM

cmp byte ptr [bx],0ch; проверка на 256 цветов

jz @lpe;

jmp @lppoor1;

@lpe:inc bx;

mov cx,768;

@lpf:ror byte ptr [bx],2;деление на 4 всех элементов палитры

IDEAL

inc bx ;

sub cx,1;

jnz @lpf;

mov dx,offset col+1;

mov ax,ds;

mov es,ax;

mov ax,1012h; установка палитры

mov bx,0h;

mov cx,256;

int 10h;

mov ax,4200h; установка положения указателя файла на 128 от начала

mov bx,[flc]; для чтения данных

mov cx,0;

mov dx,80h;

int 21h;

mov [povt],0;

@lpi:mov bx,[flc];

mov cx,[bufsz];

mov ax,3f00h;

mov dx,offset buf ;чтение данных в буфер по блокам (1 Kb).

int 21h;

mov [bufpos],0;устaнoвка положения буфера в 0

@lpx:

push ds

pop es

mov bx,offset buf

add bx,[bufpos];

mov ax,[bufpos];

cmp ax,[bufsz]; проверка на конец блока

jz @lpi;

mov al,[es:bx];

inc [bufpos]; увеличение положения буфера

cmp [povt],0; установка повторителя в 0

jz @lpk;

mov cl,[povt]; чтение повторителя

mov ah,0h;

mov [c1],ax; установка цвета точки

@lmd:

call putpixel ;вывод точки на экран

inc [x1]; увеличение Х

inc [x2];

mov ax,[x2];

dec ax;

cmp ax,[xres]; сравнение с размерами картинки

jnz @lmc;

mov ax,[nx]; установка X в начальное положение 

mov [x1],ax;

mov [x2],0;

inc [y1]; увеличение Y

inc [y2];

mov ax,[y2];

dec ax;

cmp ax,[yres]; сравнение с размерами картинки

jnz @lmc;

jmp @lpok;

@lmc:dec cl;

cmp cl,0; проверка количества точек на 0

jnz @lmd;

mov [povt],0; установка повторителя в 0

jmp @lpx;

@lpk:mov ah,al;

and ah,0c0h; проверка на несколько точек

cmp ah,0c0h;

jnz @lpy;

and al,3fh;

mov [povt],al; установка повторителя в кол. точек

jmp @lpx;

@lpy:mov ah,0h;

mov [c1],ax; установка цвета

call putpixel; вывод точки

inc [x1]; увеличение Х

inc [x2];

mov ax,[x2];

dec ax;

cmp ax,[xres];сравнение с размерами картинки

jnz @lpx;

mov ax,[nx]; установка X в начальное положение 

mov [x1],ax;

mov [x2],0;

inc [y1]; увеличение Y

inc [y2];

mov ax,[y2];

dec ax;

cmp ax,[yres]; сравнение с размерами картинки

jnz @lpx;

jmp @lpok;

@lpok:

pop ds

popa; ;восстановление регистров

mov ax,0

jmp @lpu;

@lppoor1:

mov ah,3eh; ;закрытие файла

mov bx,[flc];

int 21h;

@lppoor:

pop ds

popa; ;восстановление регистров

mov ax,3

@lpu:

ret

endp

END