логотип нашего сайта о программировании для начинающих

Программирование на ассемблере для начинающих. Ассемблер gas под linux, fasm под windows, tasm под dos, и многое другое.


Сайт для программистов, начинающих кодеров, и людей, желающих заняться программированием.



Меню невыпадающее
Программистам : Другое :

Вывод bmp картинки на экран силами Tasm




;В этой програмке осуществляется вывод содержимого BMP файла на экран с использованием средств ассемблера. Не знаю нужно ли это кому нибудь:) но для знакомства с ассемблером это очень наглядный пример. Для простоты используется формат BMP файла - 24-разрядный рисунок. Я особо не заморачивался на счет размеров, так что можно вывести только файлы размер которых до 64 кБайт(стока помещается в 16-разрядный регистр) ну это чуть больше чем 100х100 точек. Для вывода на экран используется режим EGA 640x480 16 цветов. Собственно весь алгоритм состоит из двух процедур - convert и bit_i. Первая для перевода из 24-разрядного формата к 16 цветовой палитре (точнее сначала к 8 цветовой). Вторая для установки яркости (в 16 цветовой палитре первые 8 цветов темные следующие светлые).

.286         ; разрешить привилегированные инструкции i286

model     small             ; выбор модели памяти
.stack                         ;сегмент стека
.data                         ;сегмент данных
name_file db '1.bmp',0                 ;это думаю можно не комментировать:)
;тут всякие переменные для хранения размеров и прочие вспомогательные
x     dw     ?
x2   dw     ?        
;x/2
y     dw     ?
y2   dw     ?        
;y/2
cur_x     dw     320         ;текущие координаты. Пока что центр экрана
cur_y     dw     240
handle   dw     ?         ;для файлового номера
_size     dw     ?         ;на всякий случай:) тут будет размер файла
buffer db 28 dup (?)             ;первый буффер. Сюда записываются размеры и прочая ерунда
buffer1 db 0ffffh-1100 dup (0)             ;а сюда считывается собственно изображение

.code             ;сегмент кода

; процедура вычисления размера файла, размера по вертикали и по горизонтали
read_size proc
mov ax,3d00h            
;открываем
lea dx,name_file
int 21h
mov bx,ax
lea dx,buffer
mov ah,3Fh            
;читаем
mov cx,26             ;прочитаем 26 байт. Пока нам больше и не надо
int 21h
mov ax,word ptr [buffer+2]
mov _size,ax
mov ax,word ptr [buffer+18]
mov x,ax            
;сохраняем размер изображения по горизонтали
mov ax,word ptr [buffer+22]
mov y,ax            
;по вертикали
ret
read_size endp

; процедура открытия файла
;думаю тут комментировать нечего
open_file proc
mov ax,3d00h
lea dx,name_file
int 21h
mov handle,ax
ret
open_file endp

; процедура чтения файла в буфер
read_x proc
pusha        
;сохраним на всякий случай все регистры
mov bx,handle
lea dx,buffer1
mov ah,3Fh
mov cx, 0ffffh        
;вот скока байт мы читаем из файла(не совсем корректно ну все равно работает:)
;правильнее конечно было бы вычислить точно сколько читать
;(для этого собственно и предназначалась переменная _size)
;но я немного упростил)
int 21h
popa        
;восстановим регистры
ret
read_x endp

;яркость. Проверяется если цвет от 0 до 128 то он темный, если от 128 до 255 то яркий.
bit_i proc
push si        
;сохраним наш счетчик
sub si,3         ;так как процедура используется после конвертирования вернемся назад на три байта
mov ah,byte ptr [buffer1+si]
cmp ah,80h        
;сравниваем первый байт
ja off_i
inc si
mov ah,byte ptr [buffer1+si]
cmp ah,80h        
;второй
ja off_i
inc si
mov ah,byte ptr [buffer1+si]
cmp ah,80h        
;третий
ja off_i
inc si
and al,0111b        
;вот он четвертый бит в цвете отвечает за яркость
off_i:
pop si
ret
bit_i endp

;собственно главная процедура - конвертирует 24-разрядный формат в палитру. Результат сохраняется в регистре al. Ниче сложного тут нет. В 24-разрядном изображении для каждого цвета (RGB) используется байт, в 16 цветном бит. Алгоритм основан на сдвигах.

convert proc near
xor al,al
mov ah,byte ptr [buffer1+si]
        ;B
; читаем сколько у нас синего
shr ah,7
; сдвигаем вправо на 7 разрядов
and ah,00000001b         ;первый бит цвета отвечает за синий остальные нам не нужны
or al,ah         ;выставляем синий
inc si         ;прибавляем счетчик (в BMP рисунке цвета располагаяся в порядке BGR
;поэтому сначала читаем синий потом зеленый и наконец красный)
;все тоже самое для зеленого, только со сдвигом на 1 разряд левее
mov ah,byte ptr [buffer1+si]         ;G
shr ah,6
and ah,00000010b        
;второй бит - зеленый
or al,ah         ;выставляем зеленый
inc si
; и наконец красный. Все тоже самое что и выше только на разряд левее
mov ah,byte ptr [buffer1+si]         ;R
shr ah,5
and ah,00000100b        
;третий бит - красный
or al,ah         ;выставляем красный
inc si
or al,00001000b        
;четвертый бит яркости.
;Вообще он будет выставляться процедурой bit_i но пока на вский случай включим его. Да будет свет!
ret
convert endp


; все. Процедуры кончились начинается сам код.
.startup

mov ax,18
int 10h        
; устанавливаем EGA 640x480x16

;вычисляем размеры
call read_size

call open_file
call read_x

;вычисляем половины размеров по вертикали и горизонтали. Изображение выводится начиная с левого нижнего угла(именно так оно записано в BMP)

mov ax,x
shr ax,1
mov x2,ax        
;x2=x/2

mov ax,y
shr ax,1
mov y2,ax        
;y2=y/2

mov si,54         ;устанавливаем указатель на 54-й байт(само изображение начинается с 54-го байта.
; До этого всякая служебная информация)
; текущие координаты установлены на центр. установим их на левый нижний угол изображения
mov cx,cur_x
sub cx,x2
mov dx,cur_y
add dx,y2

;==============         =================
;цикл вывода изображения на экран
@l:
call convert
call bit_i
mov ah,0ch        
;функция вывода на экран точки.
; Очень медленная, но можно вместо нее использовать процедуру pixel которая приведена ниже.
;Записывает прямо в видеобуфер. Получается намного быстрее
int 10h
;call pixel
inc cx
push bx
mov bx,320
add bx,x2
cmp cx,bx        
;дошли до конца линии?
pop bx
jb @l        
;если нет переходим к следующей точке
;===============         ==================
;все строчка кончилась двигаемся на точку вверх и все по новой
dec dx
sub cx,x
push bx
mov bx,240
sub bx,y2
cmp dx,bx        
;240-y2 смотрим не дошли еще до верха?
pop bx
ja @l        
; если не дошли продолжаем цикл

mov ah,0
int 16h        
;ждем пока кто нибудь нажмет на клавишу
mov ax,3         ;возвращаем текстовый режим
int 10h
mov ax,4c00h        
;ФСЕ. Валим отсюдова.
int 21h
end

;Если не нравится что изображение медленно "выплывает" снизу, можно использовать следующую процедуру для вывода точки на экран:

;pixel proc near
;pusha
;push es
;push 0a000h
;pop es
;mov si,cx
;mov di,dx
;push ax
;and cx,0007h
;mov ah,80h
;shr ah,cl
;mov dx,3CEh
;mov al,8
;out dx,ax
;mov bx,si
;shr bx,3
;mov ax,di
;xor dx,dx
;mov cx,80
;mul cx
;add bx,ax
;mov al,es:[bx]
;mov dx,3C4h
;mov ax,0F02h
;out dx,ax
;mov byte ptr es:[bx],0
;inc dx
;pop ax
;out dx,al
;mov byte ptr es:[bx],0FFh
;mov cx,si
;mov dx,di
;pop es
;popa
;ret
;pixel endp
;процедура получилась громоздкая но все равно работает намного быстрее чем прерыванием



Вот в принципе и все, осталось добавить , что на жк - мониторах работает из-под DOS, а на обычных и из-под Windows. И в каталоге с программой должен находиться 24-разрядный bmp-рисунок весом до 64 кБ, в архиве он уже есть.

С уважением Витал.




Непосредственно вводимый код выделен фиолетовым цветом , все остальное(зеленым) - комментарии.
Примечание Pauk_pv.

Скачать исходный код и исполняемый файл в архиве zip


Здесь со времнем появятся ссылки дружественных и понравившихся сайтов

Информер ТИЦ


агентство недвижимости Екатеринбург

Сайт создан Pauk_pv // Pauk@paukpv.pp.ru

Rambler's Top100 Каталог@MAIL.RU - каталог ресурсов интернет

При использовании информации с сайта обязательна ссылка на сайт
Pauk_pv ©