Записать обработанное растровое изображение в файл

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

У вас уже есть буфер для вывода; вам просто нужно вычислить смещение в этом буфере, чтобы сохранить его. Если отфильтрованный вами пиксель (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 как в случае чтения).

Однако, как и запись пикселей в новое изображение, вы хотите скопировать заголовок из исходного файла (чтобы зрители и т. Д. Видели его как растровое изображение); сделать memcpy (или уместно rep movsb) от pMemory в pMemory_oдлина im_offset, чтобы сделать это. Вам также нужно скопировать в него первую строку и столбец (и, как я ожидаю, последнюю строку и столбец, что будет иметь ту же проблему, что и первый: вы не можете получить окружающие пиксели для некоторых сторон). "Тупой", но эффективный метод состоит в том, чтобы просто скопировать все содержимое старого изображения в новое, заголовок, пиксели и все, а затем просто изменить внутренние пиксели с помощью фильтра.

Ваш код для создания и записи выходного буфера кажется правильным; по-видимому, теперь он записывает заполненный нулем / случайным образом файл правильной длины.

Кроме того, как только вы это сделаете правильно, вы можете сэкономить много работы (предположительно, эффективность является одной из причин писать в сборку в первую очередь?), Используя сложение и вычитание вместо умножения: добавление im_width переходит на следующую строку, вычитая ее на предыдущую и т. д. (возможно, вам придется вычислять шаг вместо использования im_width непосредственно, округляя до ближайших 32 бит; и если ваше примерное изображение не кратно 4 пикселям в ширину, вы можете увидеть странные результаты из-за неправильного шага).

Ниже приведены полезные ссылки для других: BITMAPFILEHEADER (начиная со смещения файла 0), который содержит подпись, размер файла (ваш FileSize) и смещение изображения (im_offset), за которым следует BITMAPINFOHEADER, который имеет такую ​​информацию, как ширина, высота и битовая глубина.

Другие вопросы по тегам