寻找了各种办法终于实现了显示256色的位图,但是防止数据段超过64k最终还是没有使用。还是写下来留作纪念吧。
首先我们需要了解清楚bmp文件的结构,下面是关于bmp(位图)结构体的介绍:
1. BMP文件组成
BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
2. BMP文件头(14字节)
BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。
其结构定义如下:
- typedef struct tagBITMAPFILEHEADER
- {
- WORD bfType; // 位图文件的类型,必须为BM(1-2字节)
- DWORD bfSize; // 位图文件的大小,以字节为单位(3-6字节)
- WORD bfReserved1; // 位图文件保留字,必须为0(7-8字节)
- WORD bfReserved2; // 位图文件保留字,必须为0(9-10字节)
- DWORD bfOffBits; // 位图数据的起始位置,以相对于位图(11-14字节)
- // 文件头的偏移量表示,以字节为单位
- } BITMAPFILEHEADER;
3. 位图信息头(40字节)
BMP位图信息头数据用于说明位图的尺寸等信息。
- typedef struct tagBITMAPINFOHEADER{
- DWORD biSize; // 本结构所占用字节数(15-18字节)
- LONG biWidth; // 位图的宽度,以像素为单位(19-22字节)
- LONG biHeight; // 位图的高度,以像素为单位(23-26字节)
- WORD biPlanes; // 目标设备的级别,必须为1(27-28字节)
- WORD biBitCount;// 每个像素所需的位数,必须是1(双色),(29-30字节)
- // 4(16色),8(256色)16(高彩色)或24(真彩色)之一
- DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),(31-34字节)
- // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
- DWORD biSizeImage; // 位图的大小,以字节为单位(35-38字节)
- LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数(39-42字节)
- LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数(43-46字节)
- DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数(47-50字节)
- DWORD biClrImportant;// 位图显示过程中重要的颜色数(51-54字节)
- } BITMAPINFOHEADER;
4. 颜色表
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:
- typedef struct tagRGBQUAD {
- BYTE rgbBlue;// 蓝色的亮度(值范围为0-255)
- BYTE rgbGreen; // 绿色的亮度(值范围为0-255)
- BYTE rgbRed; // 红色的亮度(值范围为0-255)
- BYTE rgbReserved;// 保留,必须为0
- } RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
- typedef struct tagBITMAPINFO {
- BITMAPINFOHEADER bmiHeader; // 位图信息头
- RGBQUAD bmiColors[1]; // 颜色表
- } BITMAPINFO;
5. 位图数据
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是
4的倍数(即以long为单位),不足的以0填充,
- biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;
- ;------------------------------------------------------------------------------------------
- ; 数据段定义
- data segment
- pathname db '1.bmp', 00 ; 图片路径
- x0 dw 0
- y0 dw 0
- handle dw ? ; 文件指针
- bmpdata1 db 256*4 dup(?) ; 存放位图文件调色板
- bmpdata2 db 64000 dup(0) ; 存放位图信息
- bmpwidth dw ? ; 位图宽度
- bmplength dw ? ; 位图长度
- pelsnum dw ? ; temp num
- num dw ?
- flag dw ? ; scren set
- screnwidth dw 320
- screnlength dw 200
- data ends
- ;stack
- stack1 segment stack
- dw 100h dup(?)
- stack1 ends
- ; code
- prognam segment
- assume cs:prognam, ds:data, ss:stack1
- main proc far
- ; main part of the program
- mov ax, data
- mov ds, ax
- call openf
- call getinfo
- call readf
- call dispy1
- call dispy2
- main endp
- ;---------------------------------------------------
- ; 打开文件并存令handle指向文件
- openf proc near
- lea dx, pathname
- ; ah = 3dh,al = 0 打开文件并读取,成功存入AX
- mov ah, 3dh
- mov al, 0
- int 21h
- mov handle, ax
- ret
- openf endp
- ;--------------------------------------------------
- ; 获取位图信息函数
- getinfo proc near
- ; 移动文件指针,bx = 文件代号, cx:dx = 位移量, al = 0即从文件头绝对位移
- mov ah, 42h
- mov al, 0
- mov bx, handle
- mov cx, 0
- mov dx, 12h ; 跳过18个字节直接指向位图的宽度信息
- int 21h
- ; 读取文件,ds:dx = 数据缓冲区地址, bx = 文件代号, cx = 读取的字节数, ax = 0表示已到文件尾
- mov ah, 3fh
- lea dx, bmpwidth ; 存放位图宽度
- mov cx, 2
- int 21h
- mov ah, 42h
- mov al, 0
- mov bx, handle
- mov cx, 0
- mov dx, 16h ; 跳过22个字节直接指向位图的长度信息
- int 21h
- mov ah, 3fh
- lea dx, bmplength ; 存放位图长度
- mov cx, 2
- int 21h
- mov ax, bmpwidth
- mul bmplength
- mov pelsnum, ax ; 计算出位图大小放入pelsnum中
- ret
- getinfo endp
- ;---------------------------------------------------
- ; 读取位图颜色信息
- readf proc near
- ; 跳过前54个字节进入颜色信息
- mov ah, 42h
- mov al, 0
- mov bx, handle
- mov cx, 0
- mov dx, 36h
- int 21h
- mov ah, 3fh
- lea dx, bmpdata1 ; 将颜色信息放入bmpdata1
- mov cx, 256*4 ; 蓝+绿+红+色彩保留(0)一共占256*4个字节
- int 21h
- ret
- readf endp
- ;-------------------------------------------------------
- ;display 函数
- dispy1 proc near
- ; 设置256色,320*200像素
- mov ax, 0013h
- int 10h
- ; 设置调色板输出色彩索引号及rgb数据共写256次
- mov cx, 256
- lea si, bmpdata1 ; 颜色信息
- p:
- mov dx, 3c8h ; 设定i/o端口
- mov ax, cx
- dec ax
- neg ax ; 求补
- add ax, 255 ; ax = ffffh(al = ffh, ah = ffh)
- out dx, al ; 将al中的数据传入dx指向的i/o端口中
- inc dx
- ; bmp调色板存放格式:bgr~bgr~...(~为空00h)
- ; rgb/4后写入,显卡要求,rgb范围(0~63),位图中(0~255)
- mov al, [si+2]
- shr al, 1
- shr al, 1
- out dx, al
- mov al, [si+1]
- shr al, 1
- shr al, 1
- out dx, al
- mov al, [si]
- shr al, 1
- shr al, 1
- out dx, al
- add si, 4
- loop p
- ret
- dispy1 endp
- ;--------------------------------------------------
- dispy2 proc near
- mov bx, 0a000h ; 40k
- mov es, bx
- dp30:
- mov di, 0
- cld ; df清零
- mov cx, y0 ; cx = 0
- dp00:
- mov ax, bmpwidth ; ax = 位图宽度
- mov dx, ax
- and dx, 11b
- jz dp000
- mov ax, 4
- sub ax, dx
- add ax, bmpwidth
- dp000:
- inc cx
- mul cx
- dec cx
- mov bx, 0
- sub bx, ax
- mov ax, bx
- mov bx, 0
- sbb bx, dx
- mov dx, bx
- push cx
- mov cx, dx
- mov dx, ax
- mov bx, handle
- mov ax, 4202h
- int 21h
- mov dx, offset bmpdata2
- mov cx, bmpwidth
- mov ah, 3fh
- int 21h
- pop cx
- cmp ax, bmpwidth
- jb dp3
- mov si, offset bmpdata2
- add si, x0
- dp0:
- push di
- mov dx, 0
- dp1:
- lodsb
- stosb
- inc dx
- cmp dx, 320
- jae dp2
- push dx
- add dx, x0
- cmp dx, bmpwidth
- pop dx
- jb dp1
- dp2:
- pop di
- add di, 320
- inc cx
- push cx
- sub cx, y0
- cmp cx, 200
- pop cx
- jae dp3
- push cx
- cmp cx, bmplength
- pop cx
- jb dp00
- dp3:
- mov ah,0
- int 16h
- cmp ax, 4800h
- je up
- cmp ax, 4b00h
- je left
- cmp ax, 4d00h
- je right
- cmp ax, 5000h
- je down
- cmp ax, 011bh
- je exit
- jmp dp3
- up:
- mov ax, y0
- sub ax, 1
- jl dp3
- mov y0, ax
- jmp dp30
- down:
- mov ax, y0
- add ax, 1
- push ax
- add ax, 200
- cmp ax, bmplength
- pop ax
- jae dp3
- mov y0,ax
- jmp dp30
- left:
- mov ax, x0
- sub ax, 1
- jl dp3
- mov x0, ax
- jmp dp30
- right:
- mov ax, x0
- add ax, 1
- push ax
- add ax, 320
- cmp ax, bmpwidth
- pop ax
- jae dp3
- mov x0, ax
- jmp dp30
- exit:
- mov ax, 3
- int 10h
- mov ax, 4c00h
- int 21h
- xp1:
- mov ax, bmplength
- mul screnwidth
- mov num, ax
- lea si, bmpdata2
- mov cx, bmpwidth
- push cx
- mov ax, bmplength
- mov flag, ax
- dec flag
- sub num, 320
- mov di, num
- add di, 320
- add di, bmpwidth
- l2:
- sub di, 320
- sub di, bmpwidth
- cmp flag, 0
- jz l3
- dec flag
- pop cx
- push cx
- dis:
- mov al, [si]
- mov ah, 0
- stosb
- add si, 1
- cmp cx, 1
- jz l2
- loop dis
- l3:
- mov ah, 0
- int 16h
- mov ax, 3
- int 10h
- mov ax, 4c00h
- int 21h
- dispy2 endp
- prognam ends
- end main