;В этой програмке осуществляется вывод содержимого 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.