不明白我的 PCX 代码有什么问题

Don't understand what's wrong with my PCX code

我有一个代码可以使用程序集显示 PCX
按其宽度

示例图片 320x200 x=0, y=0

但是如果X(StartPictX)和Y(StartPictY)不等于0,就会毁图

我需要解决这个问题...

原代码:

;--------------------------------------
; Load and show file *.PCX 320x200x256
;
;--------------------------------------
        IDEAL

        MODEL large
P386

MACRO SHOWPCX StartX, StartY, fName 
        mov ax, [StartX]
        mov [Point_X], ax
        mov ax, [StartY]
        mov [Point_Y], ax

        mov dx, offset fName

        call ShowPCXFile
ENDM SHOWPCX

    STACK 256

    DATASEG

    ErrorReadingFile DB 'Can not open file$'

        FileName1       DB 'mouse.pcx',0
        FileName        DW ?    ; offset file name for current file

        FileHandle      DW ?

        FileSize        DW ?

        ImageSizeInFile DW ?

        ImageWidth      DW ?
        ImageHeigth     DW ?

        PaletteOffset   DW ?

        Point_X         DW ?
        Point_Y         DW ?
        Color           DB ?

        StartPictX      DW ?
        StartPictY      DW ?

SEGMENT FILEBUF para public  'DATA'  
        DB 65200 DUP(?)
ENDS

        CODESEG   

Start:
        mov ax, @data
        mov ds, ax

        mov ax, 0013h
        int 10h
; -----------------= Show Pic1 =----------------
        mov [StartPictX], 0
        mov [StartPictY], 0

        SHOWPCX StartPictX, StartPictY, FileName1 

        mov ah,00h
        int 16h

        mov ah,00h
        mov al,03h
        int 10h
Exit:
        mov ax,04c00h
        int 21h

;-------------------------------------------
; ReadPCXFile - read PCX file into FILEBUF 
;-------------------------------------------
; Input:
;   File name
; Output:
;   File into FILEBUF
; Registers
;       AX, BX, CX, DX, DS
;-------------------------------------------
PROC ReadPCXFile Near
        pusha

;-----  Initialize variables
        mov     [FileHandle],0
        mov     [FileSize],0

;-----  Open file for reading
        mov     ah, 3Dh
        mov     al, 0
        ; mov DX,offset FileName  
        int     21h
        jc      @@Err
        mov     [FileHandle],AX   ; save Handle

;-----  Get the length of a file by setting a pointer to its end
        mov     ah, 42h
        mov     al ,2
        mov     bx, [FileHandle]
        xor     cx, cx
        xor     dx, dx
        int     21h
        jc      @@Err
        cmp     dx,0
        jne     @@Err  ;file size exceeds 64K

;-----  Save size of file
        mov     [FileSize], ax

;----- Return a pointer to the beginning of the file
        mov     ah, 42h
        mov     al, 0
        mov     bx, [FileHandle]
        xor     cx, cx
        xor dx, dx
        int 21h
        jc  @@Err

;-----  Read file into FILEBUF
        mov     bx, [FileHandle]
        pusha     
        push    ds
        mov     ax,FILEBUF
        mov     ds, ax
        xor     dx, dx
        mov     cx, 65200
        mov     ah, 3Fh
        int     21H
        pop     ds
        popa
        jc      @@Err

;-----  Close the file
        mov     ah, 3Eh
        mov     bx,[FileHandle]
        int     21H
        jc      @@Err
        popa
        ret

;-----  Exit - error reading file
@@Err:  ; Set text mode
        mov     ax, 3
        int     10h

        mov     dx, offset ErrorReadingFile
        mov     ah, 09h
        int     21h
        jmp     Exit
ENDP ReadPCXFile

;-------------------------------------------
; ShowPCXFile - show PCX file 
;-------------------------------------------
; Input:
;   File name
; Output:
;   The file
; Registers
;    AX, BX, CX, DX, DS
;-------------------------------------------
PROC ShowPCXFile Near   
        pusha

        call    ReadPCXFile

        mov     ax, FILEBUF
        mov     es, ax

;-----  Set ES:SI on the image
        mov     si, 128

;-----  Calculate the width and height of the image
        mov     ax, [es:42h]
        mov     [ImageWidth], ax
        dec     [ImageWidth]

        mov     ax, [es:0Ah]
        sub     ax, [es:6]
        inc     ax
        mov     [ImageHeigth], ax

;-----  Calculate the offset from the beginning of the palette file
        mov     ax, [FileSize]
        sub     ax, 768
        mov     [PaletteOffset], ax
        call    SetPalette
        mov     ax, [FileSize]
        sub     ax, 128+768
        mov     [ImageSizeInFile], ax

        xor  ch, ch            ; Clear high part of CX for string copies
        push [StartPictX]      ; Set start position
        pop  [Point_x]
        push [StartPictY]
        pop  [Point_y]
NextByte:
        mov     cl, [es:si]     ; Get next byte
        cmp     cl, 0C0h        ; Is it a length byte?
        jb      normal          ;  No, just copy it
        and     cl, 3Fh         ; Strip upper two bits from length byte
        inc     si              ; Advance to next byte - color byte

    mov     al, [es:si]
    mov     [Color], al
NextPixel:
        call    PutPixel
        cmp     cx, 1
        je  CheckEndOfLine

        inc     [Point_X]

        loop    NextPixel       
        jmp     CheckEndOfLine
Normal:
        mov     [Color], cl
        call    PutPixel

CheckEndOfLine:
        mov     ax, [Point_X]
        sub     ax, [StartPictX]
        cmp     ax, [ImageWidth]
;-----  [Point_X] - [StartPictX] >= [WidthPict] 
        jae     LineFeed
        inc     [Point_x]
        jmp     cont
LineFeed:
        push    [StartPictX]
        pop     [Point_x]
        inc     [Point_y]
cont:
        inc     si
        cmp     si, [ImageSizeInFile]     ; End of file? (written 320x200 bytes)
        jb      nextbyte
        popa
        ret
ENDP ShowPCXFile

;-------------------------------------------
; PutPixel - draw pixel 
;-------------------------------------------
; Input:
;   x - Point_x, y - Point_y, Color - color
; Output:
;   The pixel
; Registers
;    AX, BH, CX, DX
;-------------------------------------------
PROC PutPixel near
        pusha
        mov     bh, 0h
        mov     cx, [Point_x]
        mov     dx, [Point_Y]
        mov     al, [color]
        mov     ah, 0ch
        int     10h
        popa
        ret
ENDP PutPixel       

;-------------------------------------------
; SetPalette - change palette from 0-255 to from 0-63 
;-------------------------------------------
; Input:
;   PaletteOffset
; Output:
;   New palette
; Registers
;    AX, BX, CX, DX, SI, ES
;-------------------------------------------
SetPalette:
        pusha
        mov cx, 256*3
        mov si, [PaletteOffset]     
NextColor:
        shr [byte es:si], 2
        inc si
        loop NextColor

        mov dx, [PaletteOffset]
        mov ax, 1012h
        mov bx, 00h
        mov cx, 256d  
        int 10h
        popa
ret
        End Start

我意识到问题出在图像的宽度上。它继续排列像素,直到我们达到图像的宽度,然后添加到 Y。
我尝试更改它但没有成功:

CheckEndOfLine:
    mov     ax, [Point_X]
    ;sub     ax, [StartPictX]
    cmp     ax, 320
    jae     LineFeed
    inc     [Point_x]
    inc     si
    jmp     cont
LineFeed:
        push    [StartPictX]
        pop     [Point_x]
        inc     [Point_y]

        mov     bx,320
        sub     bx,[StartPictX]

@@lop:
        mov     cl, [es:si]     ; Get next byte
        cmp     cl, 0C0h        ; Is it a length byte?
        jb      nor
        and     cl, 3Fh         ; Strip upper two bits from length byte
        add     si,cx
        sub     bx,cx
        jmp next
nor:
        inc si
        dec bx
next:   
        cmp bx,1
        jg @@lop
cont:
        cmp     si, [ImageSizeInFile]     ; End of file? (written 320x200 bytes)
        jb      nextbyte
        popa
        ret

我真的需要帮助:)
Tnx 帮助者

ImageSizeInFile 的计算是正确的但是您的代码使用此信息就好像它代表地址一样!。我建议您重命名变量并使用下一个计算:

    mov     ax, [FileSize]
    sub     ax, 768
    mov     [ImageEndAddressInFile], ax

您需要正确计算 ImageWidth,就像计算 ImageHeight 一样。 1 条扫描线中的字节数不一定对应于以像素为单位的图像宽度,尤其是在压缩的情况下!

    mov     ax, [es:0008h]     ; X2
    sub     ax, [es:0004h]     ; X1
    inc     ax
    mov     [ImageWidth], ax

    mov     ax, [es:000Ah]     ; Y2
    sub     ax, [es:0006h]     ; Y1
    inc     ax
    mov     [ImageHeight], ax

您当前的程序仅有条件地递增 X 位置 Point_x。这不好。对于您处理过的每个像素,您必须始终具有 inc [Point_x].

NextByte:
    mov     cl, [es:si]     ; Get next byte
    inc     si
    cmp     cl, 0C0h        ; Is it a length byte?
    jb      Normal          ;  No, just copy it

    and     cx, 003Fh       ; Strip upper two bits from length byte
    mov     al, [es:si]     ; The color
    inc     si
    mov     [Color], al
    jcxz    CheckEndOfLine  ; Could exist this one!
NextPixel:
    call    PutPixel
    inc     [Point_X]
    loop    NextPixel       
    jmp     CheckEndOfLine

Normal:
    mov     [Color], cl
    call    PutPixel
    inc     [Point_x]

CheckEndOfLine:
    mov     ax, [Point_X]
    sub     ax, [StartPictX]   ; Number of processed pixels
    cmp     ax, [ImageWidth]   ; Image width measured in pixels
    jb      Cont
LineFeed:
    push    [StartPictX]
    pop     [Point_x]
    inc     [Point_y]
Cont:
    cmp     si, [ImageEndAddressInFile]
    jb      NextByte

现在可以解决自由选择StartPictXStartPictY.

的问题了

一个简单的解决方案是完全处理图像数据(就好像图像会紧贴屏幕一样)并让 PutPixel 过程剪掉落在屏幕之外的点屏幕。

PROC PutPixel near
    cmp     [Point_y], 200
    jnb     IsOutside
    cmp     [Point_x], 320
    jnb     IsOutside
    pusha
    mov     dx, [Point_y]
    mov     cx, [Point_x]
    mov     bh, 0
    mov     al, [Color]
    mov     ah, 0Ch
    int     10h
    popa
  IsOutside:
    ret
ENDP PutPixel       

混合解决方案会好一些。始终显示 PutPixel 有效的 Y 坐标:

LineFeed:
    push    [StartPictX]
    pop     [Point_x]
    inc     [Point_y]
    cmp     [Point_y], 200          <<<<<
    jnb     Done                    <<<<<
Cont:
    cmp     si, [ImageEndAddressInFile]
    jb      NextByte
Done:

PROC PutPixel near
    cmp     [Point_x], 320
    jnb     IsOutside
    pusha
    mov     dx, [Point_y]
    mov     cx, [Point_x]
    mov     bh, 0
    mov     al, [Color]
    mov     ah, 0Ch
    int     10h
    popa
  IsOutside:
    ret
ENDP PutPixel