CSC231 Processing BMP Images
--D. Thiebaut (talk) 10:43, 20 October 2014 (EDT)
skelBmp.asm
;;; skelBmp.asm
;;; D. Thiebaut
;;; skeleton file for reading a bmp file and writing it back.
;;; largest amount of pixels read is controlled by MAXPIXEL
;;; To assemble and run, make sure the fileio2.inc file is present
;;; in the current directory:
;;;
;;; nasm -f elf skelBmp.asm
;;; ld -melf_i386 skelBmp.o -o skelBmp
;;;
;;; To process (edit) a bmp file:
;;;
;;; ./skelBmp someFile.bmp
;;;
;;; Note that the program overwrite the image file with new pixels.
;;;
%include "fileio2.inc" ; for basic file operations
%assign SYS_EXIT 1
%assign MAXPIXEL 5000000
%assign RED 2
%assign GREEN 1
%assign BLUE 0
;;; ---------------------------------------------------------
;;; data segments
;;; ---------------------------------------------------------
section .data
errorMsg db "Error accessing file!",0x0A
errorLen equ $-errorMsg
section .bss
filename resb 255 ; reserve 255 chars for filename
handle resd 1 ; file descriptor
noRead resd 1 ; contains number of bytes read
lWidth resd 1 ; the line width rounded to the nearest
; dword boundary lWidth=(((width-1)/4)+1)*4
;;; ----------------------------------------------------------
;;; bmp buffer starts here
;;; ----------------------------------------------------------
bmpBuf equ $
type resw 1 ; header
size resd 1
resvd1 resw 1
resvd2 resw 1
offset resd 1
;;;
size2 resd 1 ; information header
width resd 1
height resd 1
planes resw 1
xbits resw 1
compr resd 1
imgsize resd 1
xres resd 1
yres resd 1
nocol resd 1
impcol resd 1
headLen equ $-bmpBuf ; length of header
pixelBuf resb MAXPIXEL*3 ; times 3 bytes (RGB)
;;; ---------------------------------------------------------
;;; code area
;;; ---------------------------------------------------------
section .text
global _start
_start:
;;; --- check that user entered more than 1 argument on command line ---
pop ebx ; get # of arguments on command line
cmp ebx,1
jg process ; if user forgot file name, exit
dumpStr "Syntax: progName filename"
jmp exit
;;; --- get filename from command line ---
process:
pop ebx ; pointer to argv[0] (name of program)
pop ebx ; pointer to argv[1]
mov edi,filename ; pointer to filename
copy: mov al,[ebx] ; copy name of file from argv[1] to
mov [edi],al ; filename string, until \0 is copied
inc ebx
inc edi
cmp al,0
jne copy
;;; --- open file ---
openFile filename, [handle], errorMsg, errorLen
;;; --- read file in buffer ---
readFile [handle], bmpBuf, MAXPIXEL, noRead
;;; --- compute length of a line of pixel:
;;; line length = (( byte width+3)/4)*4 where
;;; byte width = 3 * width, since we have 3 bytes per pixel
;;;
mov eax,[width]
add eax,[width]
add eax,[width] ; eax <-- 3 x width
dec eax ; eax
shr eax,2 ;
inc eax
shl eax,2
mov [lWidth],eax
;;; --- display status information about the file ----
;;; displayDmem noRead, "noRead = "
;;; displayDmem compr, "compression = "
;;; displayDmem offset, "offset = "
;;; displayDmem width, "width = "
;;; displayDmem lWidth, "lWidth = "
;;; displayDmem height, "height = "
;;; displayWmem xbits, "#bits/pixel = "
;;; --------------------------------------------------------------
;;; MAIN LOOPS
;;; for (h=0; h<height; h++)
;;; for (w=0; w<lWidth; w++) {
;;; ebx = byteIndex(w,h);
;;; // pixel is at byte[pixelBuf+ebx+RED]
;;; // byte[pixelBuf+ebx+BLUE]
;;; // byte[pixelBuf+ebx+GREEN]
;;; }
;;; --------------------------------------------------------------
%define h edi
%define w esi
mov h,0
forh: mov eax,[height]
cmp h,eax
jge skip
mov w,0
forw: cmp w,[lWidth]
jge endforh
push h
push w
call hw2index
;; -----------------------------------
;; add work to be done on pixel here!
;; -----------------------------------
;blue pixel component is accessible as byte[ebx+pixelBuf+BLUE]
;green pixel component is accessible as byte[ebx+pixelBuf+GREEN]
;red pixel component is accessible as byte[ebx+pixelBuf+RED]
;; -----------------------------------
;; end of pixel work area
;; -----------------------------------
inc w
jmp forw
endforh:
inc h
jmp forh
skip:
;;; --- position file pointer back to beginning of file ---
seek0 [handle]
;;; --- write contents back to file ---
writeBuf [handle], bmpBuf, noRead
;;; --- close file ---
close [handle]
;;; --- exit() ---
exit:
mov eax,SYS_EXIT
mov ebx,0
int 0x80 ; final system call
;;; -------------------------------------------------------------
;;; hw2index: converts height and width to pixel index
;;; index returned in ebx. Note that computation is
;;; performed with lWidth which must be computed
;;; separately and is the number of bytes in one line
;;; of pixel, such that number of byte is a multiple of
;;; 4.
;;; registers modified: ebx
;;; -------------------------------------------------------------
hw2index:
push ebp
mov ebp,esp
push eax ; save eax and edx
push edx
mov eax,[lWidth]
xor edx,edx
mul dword[ebp+12] ; eax = lWidth * h
add eax,[ebp+8] ; eax += 3*w
add eax,[ebp+8]
add eax,[ebp+8]
mov ebx,eax ; pass result in ebx
pop edx
pop eax
pop ebp
ret 8
Fileio2.inc
;;; fileio2.inc
;;; D. Thiebaut
;;; a collection of useful macros to deal with files
;;; and read the contents of a file specified as the first
;;; argument on the command line.
%assign SYs_EXIT 1
%assign SYs_WRITE 4
%assign SYs_READ 3
%assign SYs_LSEEK 19
%assign SEEKSET 0
%assign STDOUT 1
%assign SYs_OPEN 5
%assign SYs_CLOSE 6
%assign O_RDWR 2
;;; --- MACRO -----------------------------------------------
;;; writeStr message, messageLength
%macro writeStr2 2
mov eax,SYs_WRITE
mov ebx,STDOUT
mov ecx,%1
mov edx,%2
int 0x80
%endmacro
;;; --- MACRO -----------------------------------------------
;;; dumpStr "literal string"
%macro dumpStr 1
section .data
%%string db %1
db 0x0A
%%strLen equ $-%%string
section .text
writeStr2 %%string, %%strLen
%endmacro
;;; --- MACRO -----------------------------------------------
;;; openFile filename, [handle], errorMsg, errorLen
%macro openFile 4
mov eax,SYs_OPEN
mov ebx,%1
mov ecx,O_RDWR
mov edx,0
int 0x80
test eax,eax
jns %%readFile
writeStr2 %3, %4 ; there was an error. Stop!
mov eax,SYs_EXIT
mov ebx,0
int 0x80 ; final system call
%%readFile:
mov %2,eax
%endmacro
;;; --- MACRO -----------------------------------------------
;;; readFile [handle], buffer, buffer-length, number-bytes-read
%macro readFile 4
mov eax,SYs_READ
mov ebx,%1 ; file descriptor in bx
mov ecx,%2 ; buffer address
mov edx,%3 ; max number of bytes to read
int 0x80
mov [%4],eax ; save number bytes read
%endmacro
;;; --- MACRO -----------------------------------------------
;;; writeBuf [handle], buffer, noBytesToWrite
%macro writeBuf 3
mov eax,SYs_WRITE
mov ebx,%1
mov ecx,%2
mov edx,[%3]
int 0x80
%endmacro
;;; --- MACRO -----------------------------------------------
;;; seek0 [handle]
%macro seek0 1
mov eax,SYs_LSEEK
mov ebx,%1
mov ecx,0
mov edx,SEEKSET
int 0x80
%endmacro
;;; --- MACRO -----------------------------------------------
;;; close [handle]
%macro close 1
mov eax,SYs_CLOSE
mov ebx,%1
int 0x80
%endmacro