【问题标题】:print 800*600 bmp picture assembly打印800*600 bmp图片组装
【发布时间】:2019-03-08 19:06:13
【问题描述】:

我一直在做一个组装项目,我需要在屏幕上打印一张 bmp 图片。我将屏幕的分辨率更改为 800*600,并且我有一个代码(我没有写)打印 320*200 bmp 图片。不知道怎么改成打印800*600的图片。

有人可以帮忙吗?谢谢。

那是代码中需要改动的部分:

proc CopyBitmap
; BMP graphics are saved upside-down.
; Read the graphic line by line (200 lines in VGA format),
; displaying the lines from bottom to top.
mov ax, 0A000h
mov es, ax
mov cx,200
PrintBMPLoop:
push cx
; di = cx*320, point to the correct screen line
mov di,cx
shl cx,6
shl di,8
add di,cx
; Read one line
mov ah,3fh
mov cx,320
mov dx,offset ScrLine
int 21h
; Copy one line into video memory
cld ; Clear direction flag, for movsb
mov cx,320
mov si,offset ScrLine 

rep movsb ; Copy line to the screen
 ;rep movsb is same as the following code:
 ;mov es:di, ds:si
 ;inc si
 ;inc di
 ;dec cx
 ;... loop until cx=0
pop cx
loop PrintBMPLoop
ret
endp CopyBitmap

【问题讨论】:

    标签: assembly x86-16 bmp vga


    【解决方案1】:

    你说的不是你自己写的代码是错误的!要使用相同大小的位图填充整个 320x200 256 色屏幕,Y 坐标必须从 199 变为 0。此代码当前从 200 循环到 1,因此从不显示位图的底线。这很容易解决。

    当您告诉我们您已将屏幕分辨率更改为 800x600 时,您也应该告诉我们颜色分辨率。在下面的代码中,我假设它是 256 色,就像在示例代码中一样。此外,我将介绍一个使用 LinearFrameBuffer 方法的解决方案。存在窗口化方法,但更困难(当然,如果您不想走太多弯路)。对于不再适合 64KB 图形窗口(800 * 600 = 480000 字节)的视频模式,它将涉及使用 VESA 进行库切换。

    但是 320x200 的例子也可以使用 LFB 方法。

    视频窗口位于分段地址 0A000h:0000h。这实际上是线性地址 000A0000h。

    ; On entry BX is handle for the file with filepointer at bitmap data!!!
    proc CopyBitmap
        ; BMP graphics are saved upside-down.
        ; Read the graphic line by line (200 lines in VGA format),
        ; displaying the lines from bottom to top.
        push    es
        xor     ax, ax
        mov     es, ax
        mov     cx, 200
    PrintBMPLoop:
        push    cx
    
        ; Point to the correct screen line
        dec     cx             ; Y ranging from 199 to 0
        movzx   edi, cx
        imul    edi, 320
        add     edi, 000A0000h
    
        ; Read one line
        mov     dx, offset ScrLine
        mov     cx, 320
        mov     ah, 3Fh        ; DOS.ReadFile
        int     21h
        jc      WhatIfError?
        cmp     ax, cx
        jne     WhatIfError?
    
        ; Copy one line into video memory
        mov     si, dx
        add     dx, cx         ; DX now points to the end of the buffer
    CopyLoop:
        lodsd                  ; Load 4 pixels together
        stosd   [edi]          ; This generates an AddressSizePrefix
        cmp     si, dx
        jb      CopyLoop
    
        pop     cx
        loop    PrintBMPLoop
    
        pop     es
        ret
    endp CopyBitmap
    

    和800x600的代码很相似。

    您可以通过检查 VESA 4F01h ReturnVBEModeInformation 函数的结果获得 BytesPerScanLine 值和 LinearFrameBuffer 地址。

    • ModeInfoBlock PhysBasePtr (dword) 的偏移量 +40
    • ModeInfoBlock LinBytesPerScanLine 的偏移量 +50(字)

    BytesPerScanLine 值不必是 800。图形环境可能很容易选择 1024 作为更合理的值。你需要检查而不是假设。

    ; On entry BX is handle for the file with filepointer at bitmap data!!!
    proc CopyBitmap
        ; BMP graphics are saved upside-down.
        ; Read the graphic line by line (600 lines in SVGA format),
        ; displaying the lines from bottom to top.
        push    es
        xor     ax, ax
        mov     es, ax
        mov     cx, 600
    PrintBMPLoop:
        push    cx
    
        ; Point to the correct screen line
        dec     cx             ; Y ranging from 599 to 0
        movzx   edi, cx
        imul    edi, BytesPerScanLine
        add     edi, LinearFrameBuffer
    
        ; Read one line
        mov     dx, offset ScrLine
        mov     cx, 800
        mov     ah, 3Fh        ; DOS.ReadFile
        int     21h
        jc      WhatIfError?
        cmp     ax, cx
        jne     WhatIfError?
    
        ; Copy one line into video memory
        mov     si, dx
        add     dx, cx         ; DX now points to the end of the buffer
    CopyLoop:
        lodsd                  ; Load 4 pixels together
        stosd   [edi]          ; This generates an AddressSizePrefix
        cmp     si, dx
        jb      CopyLoop
    
        pop     cx
        loop    PrintBMPLoop
    
        pop     es
        ret
    endp CopyBitmap
    

    【讨论】:

    • 如果您将 SI 零扩展为 ESI,您应该能够使用rep movsd 比 lodsd / stosd 循环更快地有效地复制 ECX dwords。 The manual 表示地址大小属性决定了 CX/ECX/RCX 中的哪一个是计数器。
    • 顺便说一句,当您使用 EDI 写入 ES 的 64k 段限制之外时,不会出现此错误吗? OP 没有提到已更改为保护模式并返回以将内部 ES 限制设置为 4GB(我认为这会在实模式下坚持对 ES 基础的更改。wiki.osdev.org/Unreal_Mode)。
    • 帖子有 x86-16 标签。如果从字面上看,这意味着没有 stosd [edi]。虚幻模式不错。在某些时候,我可以自动运行它,可能是通过加载 himem.sys 而没有 emm386.exe。
    猜你喜欢
    • 1970-01-01
    • 2022-06-19
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    • 2011-10-28
    • 2013-12-24
    • 2013-12-07
    • 2014-07-22
    相关资源
    最近更新 更多