печать 800*600 bmp изображение в сборе

Я работаю над сборочным проектом, и мне нужно распечатать изображение в формате 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

person maya    schedule 08.03.2019    source источник


Ответы (1)


Код, который, как вы говорите, вы не написали сами, неверен! Чтобы заполнить весь 256-цветный экран 320x200 растровым изображением того же размера, координата Y должна изменяться от 199 до 0. В настоящее время этот код зацикливается от 200 до 1, поэтому нижняя строка растрового изображения никогда не отображается. Это легко исправить.

Когда вы сказали нам, что изменили разрешение экрана на 800x600, вы также должны были сообщить нам цветовое разрешение. В приведенном ниже коде я предполагаю, что это 256 цветов, как и в примере кода. Кроме того, я представлю решение, использующее метод LinearFrameBuffer. Оконный подход существует, но он сложнее (конечно, если вы не хотите срезать слишком много углов). Для видеорежима, который больше не подходит для графического окна размером 64 КБ (800 * 600 = 480 000 байт), потребуется переключение банка с помощью 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

И код 800х600 очень похож.

Вы получаете значение BytesPerScanLine и адрес LinearFrameBuffer в результате проверки результатов функции VESA 4F01h ReturnVBEModeInformation.

  • смещение +40 для ModeInfoBlock PhysBasePtr (dword)
  • смещение +50 для ModeInfoBlock LinBytesPerScanLine (слово)

Значение 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
person Sep Roland    schedule 10.03.2019
comment
Если вы нулевое расширение SI в ESI, вы сможете использовать rep movsd для эффективного копирования dwords ECX (намного) быстрее, чем цикл lodsd / stosd. В руководстве сказано, что атрибут address-size определяет, какой из CX/ECX/RCX является счетчиком. - person Peter Cordes; 11.03.2019
comment
Кстати, не будет ли это ошибкой, когда вы используете EDI для записи вне предела сегмента 64 КБ для ES? В ОП не упоминается о переходе в защищенный режим и обратно, чтобы установить внутреннее ограничение ES на 4 ГБ (что, я думаю, сохранит изменения в базе ES в реальном режиме. wiki.osdev.org/Unreal_Mode). - person Peter Cordes; 11.03.2019
comment
Сообщение имеет тег x86-16. Если понимать это буквально, это означает отсутствие стосд [эди]. Нереальный режим хорош. В какой-то момент у меня это сработало автоматически, вероятно, загрузив himem.sys, а не emm386.exe. - person idspispopd; 11.03.2019