; Bitmap Display Program (bitmap.asm) ; The ShowBMP procedure loads a Windows type BMP file ; and display it on the screen. Input parameters: ; DS:DX points to an ASCIIZ string containing the ; BMP file path. The maximum resolution is 320x200, with ; 256 colors. (by Diego Escala, Miami, Florida) .model small .186 .code extrn Open_infile:proc, Close_file:proc PUBLIC ShowBMP ShowBMP proc pusha ; Save registers call Open_infile ; Open file pointed to by DS:DX jc FileErr ; Error? Display error message and quit mov bx,ax ; Put the file handle in BX call ReadHeader ; Reads the 54-byte header containing file info jc InvalidBMP ; Not a valid BMP file? Show error and quit call ReadPal ; Read the BMP's palette and put it in a buffer push es call InitVid ; Set up the display for 320x200 VGA graphics call SendPal ; Send the palette to the video registers call LoadBMP ; Load the graphic and display it call close_file ; Close the file pop es jmp ProcDone FileErr: mov ah,9 mov dx,offset msgFileErr int 21h jmp ProcDone InvalidBMP: mov ah,9 mov dx,offset msgInvBMP int 21h ProcDone: popa ; Restore registers ret ShowBMP endp ; Check the first two bytes of the file. If they do not ; match the standard beginning of a BMP header ("BM"), ; the carry flag is set. CheckValid proc clc mov si,offset Header mov di,offset BMPStart mov cx,2 ; BMP ID is 2 bytes long. CVloop: mov al,[si] ; Get a byte from the header. mov dl,[di] cmp al,dl ; Is it what it should be? jne NotValid ; If not, set the carry flag. inc si inc di loop CVloop jmp CVdone NotValid: stc CVdone: ret CheckValid endp GetBMPInfo proc ; This procedure pulls some important BMP info from the header ; and puts it in the appropriate variables. mov ax,header[0Ah] ; AX = Offset of the beginning of the graphic. sub ax,54 ; Subtract the length of the header shr ax,2 ; and divide by 4 mov PalSize,ax ; to get the number of colors in the BMP ; (Each palette entry is 4 bytes long). mov ax,header[12h] ; AX = Horizontal resolution (width) of BMP. mov BMPWidth,ax ; Store it. mov ax,header[16h] ; AX = Vertical resolution (height) of BMP. mov BMPHeight,ax ; Store it. ret GetBMPInfo endp InitVid proc ; This procedure initializes the video mode and makes ES point to ; video memory. mov ax,13h int 10h ; Set video mode to 320x200x256. push 0A000h pop es ; ES = A000h (video segment). ret InitVid endp LoadBMP proc ; BMP graphics are saved upside-down. This procedure reads the graphic ; line by line, displaying the lines from bottom to top. The line at ; which it starts depends on the vertical resolution, so the top-left ; corner of the graphic will always be at the top-left corner of the screen. ; The video memory is a two-dimensional array of memory bytes which ; can be addressed and modified individually. Each byte represents ; a pixel on the screen, and each byte contains the color of the ; pixel at that location. mov cx,BMPHeight ; We're going to display that many lines ShowLoop: push cx mov di,cx ; Make a copy of CX shl cx,6 ; Multiply CX by 64 shl di,8 ; Multiply DI by 256 add di,cx ; DI = CX * 320, and points to the first ; pixel on the desired screen line. mov ah,3fh mov cx,BMPWidth mov dx,offset ScrLine int 21h ; Read one line into the buffer. cld ; Clear direction flag, for movsb. mov cx,BMPWidth mov si,offset ScrLine rep movsb ; Copy line in buffer to screen. pop cx loop ShowLoop ret LoadBMP endp ; This procedure checks to make sure the file is a valid BMP, ; and gets some information about the graphic. ReadHeader proc mov ah,3fh mov cx,54 mov dx,offset Header int 21h ; Read file header into buffer. call CheckValid ; Is it a valid BMP file? jc RHdone ; No? Quit. call GetBMPInfo ; Otherwise, process the header. RHdone: ret ReadHeader endp ; Read the video palette. ReadPal proc mov ah,3fh mov cx,PalSize ; CX = Number of colors in palette. shl cx,2 ; CX = Multiply by 4 to get size (in bytes) ; of palette. mov dx,offset palBuff int 21h ; Put the palette into the buffer. ret ReadPal endp SendPal proc ; This procedure goes through the palette buffer, sending information about ; the palette to the video registers. One byte is sent out ; port 3C8h, containing the number of the first color in the palette that ; will be sent (0=the first color). Then, RGB information about the colors ; (any number of colors) is sent out port 3C9h. mov si,offset palBuff ; Point to buffer containing palette. mov cx,PalSize ; CX = Number of colors to send. mov dx,3c8h mov al,0 ; We will start at 0. out dx,al inc dx ; DX = 3C9h. sndLoop: ; Note: Colors in a BMP file are saved as BGR values rather than RGB. mov al,[si+2] ; Get red value. shr al,2 ; Max. is 255, but video only allows ; values of up to 63. Dividing by 4 ; gives a good value. out dx,al ; Send it. mov al,[si+1] ; Get green value. shr al,2 out dx,al ; Send it. mov al,[si] ; Get blue value. shr al,2 out dx,al ; Send it. add si,4 ; Point to next color. ; (There is a null chr. after every color.) loop sndLoop ret SendPal endp .data Header label word HeadBuff db 54 dup('H') palBuff db 1024 dup('P') ScrLine db 320 dup(0) BMPStart db 'BM' PalSize dw ? BMPHeight dw ? BMPWidth dw ? msgInvBMP db "Not a valid BMP file.",7,0Dh,0Ah,24h msgFileErr db "Error opening file.",7,0Dh,0Ah,24h end