天天看点

【汇编】图形打印(.asm源码)

项目环境

  • 编译环境:搭建一个nasm2.8的编译环境。
  • 镜像文件:采用winhex_18.2刷入编码。
  • 虚拟机:采用Bochs-2.4.5。

项目软件

  • 傻瓜式环境配置。
  • 解压文件到D盘能直接使用。
  • ​​项目软件及项目运行环境下载地址​​

运行结果

  • 简单得说就是你能得到一个二维矩阵点,你就能打印图形,图片等等形状。

程序源码(.asm)

org 0x8400

;CS,DS,ES,SS默认的段基址为0000
;利用jmp指令跳过段数据的定义部分
jmp start

;其中0号默认为背景色,1号默认为画笔的颜色
pallete:
  db 0,255,255,255  ;白色背景色
  db 1,0,0,0      ;黑色
  db 2,255,0,0    ;红色

;画笔色号
pen:
  db 1

;直线起始(x,y),长度len
linex:
  dw 0
liney:
  dw 0
linelength:
  dw 1


;字符起始位置(x,y)
charStartX:        ;起始x位置
  dw 0
charStartY:        ;起始y位置
  dw 0
tempX:          ;临时存储变量x
  dw 0
tempY:          ;临时存储变量y
  dw 0
charLength:        ;汉字16宽
  dw 16
charHeight:        ;汉字48高
  dw 64
charSum:        ;在字符点阵中的偏移总量
  dw 0
charX:          ;汉字矩阵二维数组的x
  dw 0
charY:          ;汉字矩阵二维数组的y
  dw 0
charVertical:
  dw 0
charHorizontal:
  dw 0
character:        ;汉字矩阵
  db 0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,
  db 0,0,0,0,1,1,1,0,1,0,1,0,0,0,0,0,
  db 0,1,1,1,1,0,0,0,1,0,0,1,0,0,0,0,
  db 0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,
  db 0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,
  db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
  db 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,
  db 0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,
  db 0,0,0,0,1,0,1,0,1,0,0,1,0,0,0,0,
  db 0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,
  db 0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,
  db 0,1,1,0,1,0,0,0,1,0,1,0,0,0,0,0,
  db 0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,
  db 0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,
  db 0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0,
  db 0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,

  db 0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,
  db 0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
  db 0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,
  db 0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,
  db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
  db 0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,
  db 1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,
  db 0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
  db 0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,
  db 0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,
  db 0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,
  db 0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,
  db 0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,0,
  db 0,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,
  db 0,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,

  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  db 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,

  db 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
  db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
  db 0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,
  db 0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,
  db 0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,1,0,0,1,0,0,
  db 0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,
  db 0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,0,
  db 0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
  db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
  db 0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,

  
;主函数入口地址
start:
  ;进入13号320*200 256色的图形模式  
  mov ah,00h
  mov al,13h
  int 10h

  mov si,pallete
  call editcolor                ;第一个颜色,背景色,白色
  call editcolor                ;第二个颜色,黑色
  call editcolor                ;第三个颜色,红色

  mov ax,0xa000                ;0xb800为显存的段基址
  mov es,ax
  
  ;初始化画笔和字符起始位置
  mov byte[ds:pen],1
  mov word[ds:charStartX],0
  mov word[ds:charStartY],0
  call paint_char
  x:  
    jmp $


;编制自定义颜色
editcolor:
  push dx                    ;压栈
  push ax                    ;压栈
  push si                    ;压栈

  mov dx,0x3c8                ;设置颜色号接口0x3c8
  mov al,[si]
  out dx,al
  mov dx,0x3c9                ;RGB分量接口0x3c9
  mov al,[si+1]
  out dx,al
  mov al,[si+2]
  out dx,al
  mov al,[si+3]
  out dx,al
  add si,4

  pop si                    ;出栈
  pop ax                    ;出栈
  pop dx                    ;出栈

  ret

;绘制一条竖线
paint_vertical_line:
  push cx                    ;压栈
  push ax                    ;压栈
  push bx                    ;压栈
  push si                    ;压栈

  mov cx,[ds:linex]              ;cx,起始横坐标
  mov ax,[ds:liney]              ;ax,起始纵坐标
  mov bx,[ds:linelength]            ;bx,直线长度

  ;用乘法计算横纵坐标
  mov si,320
  mul si
  add ax,cx
  
  mov dx,bx                  ;直线总长度
  mov si,ax                  ;绘图起始位置
  mov bx,0                  ;变化偏移量
  mov ax,0                  ;变化次数
  
  mov cl,[ds:pen]                ;cl,画笔色号

  loop_paint_vertical_line:
    cmp ax,dx
    jae exitpaintvl
    mov byte [es:bx+si], cl
    add bx,320
    inc ax
    jmp loop_paint_vertical_line

  exitpaintvl:
    pop si                  ;出栈
    pop bx                  ;出栈
    pop ax                  ;出栈
    pop cx                  ;出栈
    ret



;字符打印
paint_char:                    ;循环初始化
  push ax                    ;压栈
  push dx                    ;压栈
  push bx                    ;压栈
  push cx                    ;压栈

  mov word[ds:charSum],0            ;防止另外程序写入,重新置偏移总量为0
  mov word[ds:charVertical],0          ;防止另外程序写入,重新置竖直偏移量为0
  mov word[ds:charHorizontal],0        ;防止另外程序写入,重新置水平偏移量为0

  ;起始x
  mov ax,[ds:charStartX]            
  mov word[ds:charX],ax
  ;起始y
  mov ax,[ds:charStartY]
  mov word[ds:charY],ax
  
  paint_char_column_loop:            ;列循环
    mov dx,[ds:charHeight]          ;字高度
    cmp word[ds:charVertical],dx      ;与字竖直偏移量比较
    jae exit_char_paint            ;若竖直偏移量大于等于字高度,退出

    ;行循环  
    mov word[ds:charHorizontal],0      ;行循环初始化
      
    paint_char_row_loop:          ;行循环
      ;比较判断是否跳出行循环,进入列循环
      mov bx,word[ds:charHorizontal]    ;字水平偏移量
      cmp bx,[ds:charLength]        ;与字长度比较
      jae next_column_loop        ;若字水平偏移量大于等于字长度,退出

      mov bx,[ds:charSum]
      cmp byte[character+bx],1
      jne next_row_loop
      
      mov cx,[ds:charX]
      mov word[ds:linex],cx

      mov cx,[ds:charY]
      mov word[ds:liney],cx
      
      mov word[ds:linelength],1

      call paint_vertical_line
    ;行循环处理下一次
    next_row_loop:
      inc word[ds:charX]
      inc word[ds:charHorizontal]
      inc word[ds:charSum]

      jmp paint_char_row_loop

  next_column_loop:
    ;列层循环的下一次
    inc word[ds:charVertical]        ;竖直偏移量++
    mov word[ds:charHorizontal],0      ;水平偏移量置0
    ;重置字符(x,y)
    mov ax,[ds:charStartX]
    mov word[ds:charX],ax
    mov ax,[ds:charVertical]
    add ax,[ds:charStartY]
    mov word[ds:charY],ax

    jmp paint_char_column_loop
    
  exit_char_paint:
    push ax                  ;出栈
    push dx                  ;出栈
    push bx                  ;出栈
    push cx                  ;出栈
    ret      

继续阅读