将处理后的位图图像写入文件

时间:2012-12-02 06:22:27

标签: assembly bitmap x86 masm masm32

我正在开发一个项目,该项目读取BMP文件的内容并对图像执行平滑的数字滤镜。我的代码几乎完成了这项工作。我只是不知道应该在哪里存储已处理的像素以及如何将处理后的图像写入文件。我的下面的代码已经注释掉了,所以任何帮助都会受到高度赞赏。

        .586
        .model      flat, stdcall
        option      casemap :none
        include     ..\masm32\include\windows.inc
        include     ..\masm32\include\user32.inc
        include     ..\masm32\include\kernel32.inc
        include     ..\masm32\macros\macros.asm
        include     ..\masm32\include\masm32.inc

        includelib  ..\masm32\lib\user32.lib
        includelib  ..\masm32\lib\kernel32.lib
        includelib  ..\masm32\lib\masm32.lib

        .data
FileName    db  "bitmap2.bmp", 0
filename    db  "bitmap_fil.bmp",0
errMsg      BYTE    "Cannot create file",0dh,0ah,0

hFile       HANDLE  ?
hwFile      HANDLE  ?

hMemory     HANDLE  ?       ;incoming data
pMemory     DWORD   ?

hMemory_o   HANDLE  ?       ;outgoing data
pMemory_o   DWORD   ?

ReadSize    DWORD   ?

bytesWritten    DWORD   ?
firstLine   DWORD   ?
FileSize    DWORD   ?
BDoff       DWORD   ?
BHSize      DWORD   ?
szTemp      byte    16 dup (0)  ;buffer for messages
szPrime     byte    "%08i", 0   ;message format string
szPrimeH    byte    "%08lx",0   ;message hexa format string
signature   DD  0
MEMORYSIZE      equ 65535   ;This is how much memory allocated
                        ; to store the file.
im_offset   dd  ?
im_width    dd  ?
im_height   dd  ?
bits_pix    dd  ?





    .code
;................................
show    MACRO   caption, value      
    print   SADD(caption)
    mov eax, value
    invoke  wsprintf, offset szTemp, offset szPrime, eax    ;converts eax into string
    print   offset szTemp                   ;print string
    print   SADD(13,10) 
    ENDM
;..................................

start:  

    invoke      CreateFile, addr FileName,GENERIC_READ,FILE_SHARE_READ,NULL, OPEN_EXISTING,     FILE_ATTRIBUTE_NORMAL, NULL
    mov      hFile, eax

;Allocate and lock the memory for incoming file.
    invoke      GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMORYSIZE
    mov         hMemory, eax
    invoke      GlobalLock, hMemory
    mov         pMemory, eax

;Allocate and lock the memory for outgoing file.
    invoke      GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMORYSIZE
    mov         hMemory_o, eax
    invoke      GlobalLock, hMemory_o
    mov         pMemory_o, eax


;Read file and save image parameters
    invoke      ReadFile, hFile, pMemory, MEMORYSIZE-1, addr ReadSize, NULL
    mov     esi, pMemory

    add     esi, 02     ;get filesize
    mov     edi, [esi]
    mov     FileSize,edi
    invoke      wsprintf, offset szTemp, offset szPrime, edi
    print       offset szTemp
    print       SADD(10,13)

    add         esi, 8      ; jump 8 bytes to get image offset
    mov     edi, [esi]  ; get image offset
    mov         im_offset,edi
    invoke      wsprintf, offset szTemp, offset szPrimeH, edi
    print       offset szTemp
    print       SADD(10,13)

    add     esi,8       ;jump 8 bytes to get image width
    mov     edi, [esi]  ; get image width       
    mov     im_width, edi   
    invoke      wsprintf, offset szTemp, offset szPrime, edi
    print       offset szTemp
    print       SADD(10,13)

    add     esi,4       ;jump 4 bytes to get image height
    mov     edi, [esi]  ; get image height
    mov     im_height, edi  
    invoke      wsprintf, offset szTemp, offset szPrime, edi
    print       offset szTemp
    print       SADD(10,13)

    add     esi,4       ;jump 4 bytes to get color plane
    mov     ebx, [esi]  
    shr     ebx,16      ; get color plane and bit-pix
    mov     bits_pix,ebx ;
    print       SADD("bit-per-pix ")
    invoke      wsprintf, offset szTemp, offset szPrime, ebx
    print       offset szTemp
    print       SADD(10,13)

    mov     ebp, pMemory    ; get ready to start processing the image
    add     ebp, im_offset  ; esi now points to the first pix

;filtering process
;leave first row and first column and last row and last column untouched.

    mov     esi,1       ; esi is the row counter
    mov     edi,1       ; edi is the column counter


proc_pix:
    ;show       "current column is: ",edi
    ;show       "current row is: ",esi
    xor     ebx,ebx     ; ebx = 0 ebx will accumulate intermediate values for averaging
    mov     eax, im_width   ; eax is the pointer to the pixel
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I,J) 

    mov     eax, im_width
    add     esi,1       ;next row (I+1)
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I+1,J) 


    mov     eax, im_width
    sub     esi,2       ; prev row (I-1)
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I-1,J) 

    add     esi,1       ;back to the current row

    add     edi,1       ;get next column (J+1)
    mov     eax, im_width
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I,J+1) 


    sub     edi,2       ; get prev column (J-1)
    mov     eax, im_width
    mul     esi
    add     eax,edi     
    add     ebx, [ebp+eax]  ;get the pixel(I,J-1) 

    add     edi,1       ;back current column
    xor     edx, edx    ;clear upper part dividend
    mov     eax, ebx    ; move data to eax to divide
    mov     ecx, 5  
    div     ecx     ;do the average (div 5)>>> result in eax

; where should I store the processed pixels?

    inc     edi     ; do the next column
    cmp     edi, im_width   
    jl      proc_pix

    inc             esi     ; do the next row
    mov     edi,1       ; skip the first column 
    cmp     esi, im_height  
    jl      proc_pix

;....................................................................................


new_file: 
    invoke      CreateFile,ADDR filename, GENERIC_WRITE, NULL, NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
    mov         hwFile,eax      ; save file handle

; handling of error if invalid file handle
    cmp         eax,INVALID_HANDLE_VALUE
    jne     writef
    invoke      StdOut, addr errMsg ; Display error message
    jmp         QuitNow

writef: invoke      WriteFile, hwFile, pMemory_o, FileSize, ADDR bytesWritten, 0        


QuitNow:
    invoke      GlobalUnlock, pMemory
    invoke      GlobalUnlock, pMemory_o
    invoke      GlobalFree, hMemory
    invoke      CloseHandle, hFile
    invoke      CloseHandle, hwFile
    invoke      ExitProcess, NULL
    end         start

;finish

1 个答案:

答案 0 :(得分:2)

您已有输出缓冲区;看来,你只需要找出存储它的缓冲区。如果您过滤的像素是(I,J),您从pMemory + im_offset + J * im_width + I读取,则需要将其写入pMemory_o + im_offset + J * im_width + I。 (顺便说一句,你的代码似乎假定每像素8位;你可能想要明确地检查它,如果不是这样就退出并且错误,以避免非8bpp图像文件出现意外行为。)

要正确写入目标像素,您可以执行与读取相同的行/列乘法,以获得eax中的偏移量,添加im_offset,并将其添加到pMemory_o(最后两个而不是像阅读案例中那样使用ebp

除了将像素写入新图像之外,您还希望从源文件中复制标题(以便查看器等将其视为位图);从memcpyrep movsb {长度pMemory执行pMemory_o(或适当的im_offset)来做到这一点。您还需要复制第一行和第一行(并且,我希望,最后一行和列也会出现问题,这与第一行和第一行的问题相同:您无法获得某些边的周围像素)。一个“愚蠢”但有效的方法就是将旧图像的全部内容复制到新的,标题,像素和所有内容,然后只需用过滤器更改内部像素。

创建和编写输出缓冲区的代码似乎是正确的;据推测,它现在会写出一个正确长度的零/随机填充文件。

顺便说一句,一旦你弄清楚它,你可以节省大量的工作(可能效率是首先在汇编中写入的原因之一?),使用加法和减法而不是相乘:添加{ {1}}跳转到下一行,将其减去前一行,等等(您可能需要计算一个步幅而不是直接使用im_width,向上舍入到最近的32位;如果您的样本图像不是4像素宽的倍数,由于没有使用正确的步幅,您可能会看到奇怪的结果。)

跟随其他人的有用参考:BITMAPFILEHEADER(从文件偏移0开始),其中包含签名,文件大小(您的im_width)和图像偏移(FileSize),其后是BITMAPINFOHEADER,其中包含宽度,高度和位深度等信息。