如何将256色位图转换为含DB指令的ASM文件?
位图转ASM文件的实现方案
需求说明
- 将320×200分辨率的256色BMP位图转换为ASM文件,文件需包含多条
DB指令,字节格式支持emu8086的十进制、二进制或十六进制 - 转换后的ASM文件通过
include指令加载到内存,读取每个字节绘制屏幕像素
现有代码问题分析
你附上的读取TXT文件的程序存在多处逻辑错误,导致无法正常工作:
org 100h JMP START INPUT DB "TEST.TXT", 0 OUTPUT DB "TEST.DB", 0 ERROR DB "FILE NOT FOUND$" HANDLE DW ? BUFFER DB 4 DUP(' ') ; 这个缓冲区是DOS中断读取文件时的临时存储区域,用来存放读取到的内容 START: MOV AH,00H ; 设置视频模式 MOV AL,03H ; 这里选了80x25文本模式,处理位图应该用320x200 256色的图形模式(AL=13H) INT 10H ; 调用视频中断 ; -------------------- ; 读取文件(你实际读的是TXT而非BMP) ; -------------------- MOV AH,3DH ; DOS中断:打开文件 MOV AL,0 ; 只读模式 MOV DX,OFFSET INPUT ; 指向文件名 INT 21H ; 执行中断 JC STOP ; 若CF标志置位(打开失败),跳转到错误处理 MOV HANDLE,AX ; 保存文件句柄——DOS打开文件后返回的句柄是后续读写/关闭的唯一标识,不能随便设为0 MOV BX,HANDLE MOV DX,OFFSET BUFFER MOV CX,0042H ; 读取42字节 MOV AH,3FH INT 21H ; 错误:这里把有效文件句柄重置为0,导致后续关闭文件操作失效 ; MOV HANDLE,0000H READ: ; 错误:硬编码访问0124H内存,应该读取缓冲区里的内容,比如MOV DL,BUFFER[0] ; MOV DL,[0124H] MOV DL,BUFFER[0] ; 读取缓冲区第一个字节 MOV AH,02H ; DOS中断:打印单个字符 INT 21H ; 执行中断 ; 错误:关闭文件应该放在所有读取操作完成后,而不是打印一次就关闭 MOV AH,3EH MOV BX,HANDLE INT 21H JMP EXIT STOP: MOV DX,OFFSET ERROR MOV AH,9 INT 21H EXIT: ret
核心错误点:
- 视频模式选择错误:处理320x200 256色位图必须切换到图形模式
AL=13H - 文件句柄被错误重置,导致后续关闭文件失败
- 未正确使用读取缓冲区,反而硬编码访问未知内存地址
- 读取逻辑不完整,没有循环处理所有字节,也未处理实际读取的字节数
位图转ASM文件的实现方法
方法1:用脚本自动转换(推荐)
写一个简单的Python脚本,自动解析BMP像素数据并生成符合要求的ASM文件:
# 320x200 256色BMP转ASM工具 import struct def bmp_to_asm(bmp_path, asm_path): with open(bmp_path, 'rb') as f: # 读取BMP文件头(固定54字节) header = f.read(54) # 验证文件格式 if header[:2] != b'BM': print("无效的BMP文件") return # 获取像素数据的起始偏移量 data_offset = struct.unpack('<I', header[10:14])[0] # 获取位图的宽高和颜色位数 width = struct.unpack('<I', header[18:22])[0] height = struct.unpack('<I', header[22:26])[0] bits_per_pixel = struct.unpack('<H', header[28:30])[0] # 验证是否为目标格式 if width != 320 or height != 200 or bits_per_pixel != 8: print("仅支持320x200分辨率的256色BMP") return # 跳转到像素数据区域 f.seek(data_offset) # 读取所有像素行(BMP行是倒序存储的,需要反转) pixel_rows = [] for _ in range(height): # 320是4的倍数,无需处理行对齐填充 row = f.read(320) pixel_rows.append(row) # 反转行顺序,恢复从上到下的像素排列 pixel_rows = pixel_rows[::-1] # 合并为一维字节数组 flat_pixels = b''.join(pixel_rows) # 生成ASM文件 with open(asm_path, 'w') as asm_file: asm_file.write("; 320x200 256色位图像素数据\n") asm_file.write("BITMAP_DATA DB ") # 每16个字节写一行,提升可读性 for idx, byte in enumerate(flat_pixels): if idx % 16 == 0 and idx != 0: asm_file.write("\nDB ") # 用十六进制格式,兼容emu8086 asm_file.write(f"0x{byte:02X}, ") # 去掉最后多余的逗号 asm_file.seek(asm_file.tell() - 2) asm_file.write("\n") # 使用示例:把input.bmp转换成bitmap_data.asm bmp_to_asm("input.bmp", "bitmap_data.asm")
运行脚本后,生成的bitmap_data.asm可直接通过include "bitmap_data.asm"引入到你的emu8086程序中,通过BITMAP_DATA标签访问像素字节。
方法2:手动解析生成ASM(适合理解原理)
如果不想用脚本,可按以下步骤手动处理:
- 提取像素数据:用十六进制编辑器打开BMP文件,跳过前54字节的文件头,从第55字节开始的64000字节(320×200)就是像素数据(注意BMP的行是倒序存储的,需把最后一行移到最前面)
- 编写DB指令:把像素数据按每16个字节一组,写成
DB 0xXX, 0xXX, ...的格式,示例:
BITMAP_DATA DB 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F DB 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F ; ... 剩余所有像素字节
绘制位图的示例程序
引入生成的ASM文件后,可用以下代码绘制整个位图:
org 100h include "bitmap_data.asm" START: ; 设置显存段地址(模式13H的显存位于A000:0000) MOV AX, 0A000H MOV ES, AX ; 切换到320x200 256色图形模式 MOV AH,00H MOV AL,13H INT 10H ; 绘制位图 MOV SI, 0 ; 像素数据索引 MOV CX, 200 ; 总行数 ROW_LOOP: MOV DX, 200-CX ; 当前行号(从0到199) MOV BX, 320 ; 每行像素数 MUL BX ; AX = 行号×320,计算显存偏移 MOV DI, AX ; DI指向当前行的显存起始位置 PUSH CX MOV CX, 320 ; 每行320个像素 PIXEL_LOOP: MOV AL, BITMAP_DATA[SI] ; 读取当前像素颜色 MOV ES:[DI], AL ; 写入显存 INC SI INC DI LOOP PIXEL_LOOP POP CX LOOP ROW_LOOP ; 等待按键后退出 MOV AH,00H INT 16H ; 恢复文本模式 MOV AH,00H MOV AL,03H INT 10H ret
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

