News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Operations on bitmap file

Started by ktosik2, July 13, 2015, 07:25:32 PM

Previous topic - Next topic

ktosik2

Hello

I have to write an application in MASM32 that load an bmp image, modify it (for example make a blur on it) show it and save as a new bmp file. I am good in C++, but unfortunately in assembler I am not good. I read Iczelion's Win32 Assembly tutorial, and I made a window with menu and Multi Document Interface. I know how to load an image with LoadBitmap function and how to show it with BitBlt function. But I can't find examples showing how to modify an image and save it. And I don't know if I should use other method of loading an image if next I want to modify it. The modification of image should be done with SSE instructions. Can anyone help me with this problem? I would be very grateful for any samples of code.

PS. Sorry for my English.

dedndave

you want to create a DIB section of the appropriate bit-depth (16-color, 256-color, or 24-bit, etc)

CreateDIBSection
https://msdn.microsoft.com/en-us/library/dd183494%28v=vs.85%29.aspx

load the bitmap image
select it into a memory DC
create a DIB section
select it into a second memory DC
BitBlt the image from the first DC into the second
modify the image
write the file header to the file (including palette, if required)
write the data from the DIB section to the file

when you create the DC's, use the desktop DC as a reference

notice, that you can create a DIB section when you use LoadImage, by using the LR_CREATEDIBSECTION flag
but - i have found that copying that data to a file doesn't seem to work properly
so, a DIB section created by LoadImage is somehow not the same as one created by CreateDIBSection   :redface:

ktosik2

Thanks for your reply.

Could you write function names of each step which I should use in my application? I have a problem with loading an image, I do it with LoadBitmap function, and I am able to load an image that path is defined in *.rc file by two lines:
#define IDB_MAIN 100
IDB_MAIN BITMAP "C:\file path\file.bmp"

and I want to do it with image that path is loaded with function GetOpenFileName,
                INVOKE GetOpenFileName, ADDR ofn
                .IF eax==TRUE
                    INVOKE RtlZeroMemory, ADDR FilePath, MAXSIZE  ;(MAXSIZE is defined as 260)
                    INVOKE lstrcat, ADDR FilePath, ofn.lpstrFile
                    INVOKE MessageBox, hWnd, ADDR FilePath, ADDR AppName, MB_OK ;to see if it works properly
                    INVOKE LoadBitmap, hInstance, ADDR FilePath
    mov    hBitmap, eax
                .ENDIF

but the window doesn't show this image. The code showing this image is:
.ELSEIF uMsg==WM_PAINT
            INVOKE BeginPaint, hChild, ADDR ps
            mov    hdc, eax
            INVOKE CreateCompatibleDC, hdc
            mov    hMemDC, eax
            INVOKE SelectObject, hMemDC, hBitmap
            INVOKE GetClientRect, hChild, ADDR rect
            INVOKE BitBlt, hdc, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, SRCCOPY
            INVOKE DeleteDC, hMemDC
            INVOKE EndPaint, hChild, ADDR ps

dedndave

let me take the dog for a walk and i'll write a routine when i get back   :biggrin:

dedndave

actually, i am writing 3 routines:
BmpEdRead
BmpEdWrite
BmpEdDelete

they all use a common BMP_EDIT structure   :t

Zen

KTOSIK2, 
Dave will undoubtedly come up with some great code (he's one of our most knowledgeable programmers),...but, in the meantime,...here is a library of Bitmap and DibSection functions created years ago by EDGAR. It's excellent,...but,...will take some time to read through,...(and, I think EDGAR wrote the code in GoAsm, although it's VERY similar to normal MASM assembly),...
The MASM assembly code for the library functions is in the Modules SubDirectory,...
When you are doing this type of operation for the first time, you should check your return values from the critical functions,...
...In particular: the BitBlt Function, MSDN. Also, check: LoadBitmap Function, MSDN,...or, LoadImage Function, MSDN

...Also, I'm assuming that you've already read the MSDN GDI documentation. If not here is: Bitmaps, NSDN

Vortex

Another method is to load bitmap from files to memory without using resource files :

.386
.model flat,stdcall
option casemap:none

include   \masm32\include\windows.inc

GetDC           PROTO :DWORD
CreateDIBitmap  PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
ReleaseDC       PROTO :DWORD,:DWORD

.code

CreateBmpFromMem PROC hWnd:DWORD,pBmp:DWORD,hDCnew

    invoke  GetDC,hWnd
    test    eax,eax
    jz      @f
    push    eax
    mov     edx,hDCnew
    mov     DWORD PTR [edx],eax
    mov     edx,pBmp
    lea     ecx,[edx+sizeof(BITMAPFILEHEADER)]  ; start of the BITMAPINFOHEADER header
    mov     eax,BITMAPFILEHEADER.bfOffBits[edx]
    add     edx,eax         ; edx points the array of bytes containing the bitmap data
    pop     eax
    invoke  CreateDIBitmap,eax,ecx,CBM_INIT,edx,ecx,DIB_RGB_COLORS
@@:
    ret

CreateBmpFromMem ENDP

END

dedndave

still working on the routines

got busy with other work - and i got bogged down a little trying to make it work with all bitmap formats - lol
i'll work on it more tomorrow, if time permits   :t

my first version may only support bit-depths of 1, 4, 8, 24, and 32-bit
16-bit and some 32-bit formats can be a little hairy

ktosik2

Thank you all for your answers!
Vortex, I tried your part of code and it is working! I tested it with all BMP formats that can Paint (from Windows XP) create.
Is there any documentation of Edgar's library that Zen posted here? (thanks for this library!) I will try to do something with this library.

Zen

Hi, KTOSIK2,
I don't think there is any documentation for EDGAR's graphics library (in the formal sense). Just read through the source code and it should be obvious. If not, ask any questions that you might have.
Since a bitmap is the native image type on Microsoft Windows, it is useful to know how they work. In particular, you should understand the difference between a bitmap (the file format) and a DIBSection. The difference between a Bitmap and a DIBSection is the header structure (and, a DIBSection exists in memory only).
The only confusing aspect of using bitmaps is the color depth (bits per pixel), which is the amount of memory used to specify the color of an individual pixel. This value can be either: 1, 4, 8, 16, 24, or 32 bits. Device-Independent Bitmaps, MSDN 
Converting between a Bitmap (in file) to a DIBSection (in memory) is done alot in order to edit a Bitmap's actual pixel array.
This function is really useful: GetDIBits, MSDN

dedndave

Erol's method is much simpler than mine - lol
i'll have to play with CreateDIBitmap when i have more time  :t

ktosik2

I created an application with MDI, and I use GetPixel and SetPixel functions in ChildProc function (just testing them):
ChildProc PROC hChild:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL ps:     PAINTSTRUCT
LOCAL hdc:    HDC
LOCAL hMemDC: HDC
LOCAL colorref: COLORREF
LOCAL redvalue: BYTE
LOCAL greenvalue: BYTE
LOCAL bluevalue: BYTE

.IF uMsg==WM_MDIACTIVATE
...
.ELSEIF uMsg==WM_PAINT
INVOKE StrCmp, ADDR hChild, ADDR hwndFileLoaded ;comparison 2 strings (for every child window is another version of this function)
.IF eax==0 ;if they are equal then
INVOKE BeginPaint, hChild, ADDR ps
mov    hdc, eax
INVOKE CreateCompatibleDC, hdc
mov    hMemDC, eax
INVOKE SelectObject, hMemDC, hBitmap
mov     ecx,pBitmap
lea     edx,[ecx+sizeof(BITMAPFILEHEADER)] ; start of the BITMAPINFOHEADER header
INVOKE  BitBlt,hdc,0,0,BITMAPINFOHEADER.biWidth[edx], BITMAPINFOHEADER.biHeight[edx],hMemDC,0,0,SRCCOPY

;mov redvalue, 255
;mov greenvalue, 0
;mov bluevalue, 0
;RGB redvalue, greenvalue, bluevalue
;mov colorref, eax
;INVOKE SetPixel, hdc, 5, 5, colorref
;INVOKE SetPixel, hdc, 4, 5, colorref
;INVOKE SetPixel, hdc, 5, 4, colorref
;INVOKE SetPixel, hdc, 4, 4, colorref
;INVOKE GetPixel, hdc, 113, 114
;mov colorref, eax
;INVOKE MessageBox, hChild, ADDR colorref, ADDR closingConfirmation, MB_YESNO


INVOKE  DeleteDC, hMemDC
INVOKE  EndPaint, hChild, ADDR ps
.ENDIF

and they work fine. But I wanted to make this functionality with one position in submenu from main window:

WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
...
.IF uMsg==WM_CREATE
...
.ELSEIF uMsg==WM_COMMAND
.IF lParam==0
mov eax, wParam
.IF ax==IDM_EXIT
...
.ELSEIF ax==IDM_MODIFY
INVOKE BeginPaint, hwndFileLoaded, ADDR ps ;hwndFileLoaded is the same as hChild in ChildProc
mov    hdc, eax

mov redvalue, 255
mov greenvalue, 0
mov bluevalue, 0
RGB redvalue, greenvalue, bluevalue
mov colorref, eax
INVOKE SetPixel, hdc, 5, 5, colorref
INVOKE SetPixel, hdc, 4, 5, colorref
INVOKE SetPixel, hdc, 5, 4, colorref
INVOKE SetPixel, hdc, 4, 4, colorref
INVOKE GetPixel, hdc, 113, 114
mov colorref, eax
INVOKE MessageBox, hwndFileLoaded, ADDR colorref, ADDR closingConfirmation, MB_YESNO

INVOKE  EndPaint, hwndWczytanyPlik, ADDR ps
...

and it didn't work. But this:

.ELSEIF uMsg==WM_PAINT
INVOKE StrCmp, ADDR hChild, ADDR hwndFileLoaded
.IF eax==0
INVOKE BeginPaint, hChild, ADDR ps
mov    hdc, eax

mov redvalue, 0
mov greenvalue, 255
mov bluevalue, 0
RGB redvalue, greenvalue, bluevalue
mov colorref, eax
INVOKE SetPixel, hdc, 5, 5, colorref
INVOKE SetPixel, hdc, 4, 5, colorref
INVOKE SetPixel, hdc, 5, 4, colorref
INVOKE SetPixel, hdc, 4, 4, colorref
INVOKE GetPixel, hdc, 113, 114
mov colorref, eax
INVOKE MessageBox, hChild, ADDR colorref, ADDR closingConfirmation, MB_YESNO

INVOKE  EndPaint, hChild, ADDR ps
.ENDIF


in ChildProc works fine. Am I doing something wrong? Or maybe this shouldn't work as I want? If this would work properly the last thing to do would be to save this modified image as bmp, and this is what I can't achieve. Is there such possibility?

I have a problem with functions GetRValue, GetGValue and GetBValue. There is a RGB macro that can make a COLORREF variable, but I don't know how to get red, green and blue colors from COLORREF variable, this three functions didn't work (I don't know where they are defined).

On the other hand I look at Edgar's library and I have some questions.
What is pDIBits parameter in GetDIBPixel function? What is the type of return value? (maybe COLORREF?)
What are pDIBits and color parameters in SetDIBPixel function? (Is color COLORREF?)
I guess functions DIBSaveBitmap and SaveDIB32 are the same, but the second can save DIB section to a bmp file with 32 bits per pixel and the first can do the same but with any number of bits per pixel. Am I right?

If there is no way to save modification on a image doing in the way that I place at the beginning can someone post an example of creating DIB section that I could modify with functions written by Edgar?

dedndave

QuoteAn application should not call BeginPaint except in response to a WM_PAINT message.

https://msdn.microsoft.com/en-us/library/dd183362%28v=vs.85%29.aspx

you can update the DIB bits directly - then force a WM_PAINT message to be sent via calls to InvalidateRect and UpdateWindow

let the WM_PAINT code update the displayed image
in a way, that's kind of nice - you only have to write the paint code once

dedndave

i am not familiar with Edgar's library
he writes code using GoAsm syntax, which is a little uncomfortable for me - lol
Edgar is a great coder, though   :t

CreateDIBSection isn't hard to use, really
it creates a bitmap - and sets a DWORD pointer to the image data bits
you can then modify the image bits directly - much faster than SetPixel, etc

but - you have to understand that there are many different types of bitmaps
especially when it comes to bit-depth - different formats may apply to different bit-depths
i most often use 256-color (8 bits per pixel) and 24 bits per pixel formats
they are fairly simple to understand   :P

256-color bitmaps have a 1 KB palette
4 bytes per entry - B, G, R, and a zero byte
then, each pixel in the image data is an index into the palette array

24-bit images have no palette, but have 3 bytes for each pixel (B, G, R)

if you are working with one specific format, it will make your code very simple
let me know what you are using - maybe i can post a more specific example

attached is a little program i was playing with that uses CreateDIBSection
originally, it was a 256 gray-shade program that generated random images
i wanted to learn how end-points were defined for line-draw functions
so, i modified the code for that

ktosik2

My application should work with all bmp formats, but I think that at the beginning I can do make my application working with 24 bits per pixel images. Maybe there is a possibility to convert images with lower numbers of bits per pixel to images with 24 bits per pixel (because we don't lose any information) and then we could stop only at 24 bits per pixel.