打印800*600 bmp图片组装

Posted

技术标签:

【中文标题】打印800*600 bmp图片组装【英文标题】:print 800*600 bmp picture assembly 【发布时间】: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

【问题讨论】:

【参考方案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。

以上是关于打印800*600 bmp图片组装的主要内容,如果未能解决你的问题,请参考以下文章

PHP处理bmp格式图片的方法

关于怎么用C++读取bmp图片

base64转化为bmp图片?

C++加密bmp图片程序

简单bmp图片处理工具——python实现

JPG、GIF、PNG和BMP格式的图片各有啥优点和缺点?