The MASM Forum

General => The Campus => Topic started by: ktosik2 on July 13, 2015, 07:25:32 PM

Title: Operations on bitmap file
Post by: ktosik2 on July 13, 2015, 07:25:32 PM
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.
Title: Re: Operations on bitmap file
Post by: dedndave on July 13, 2015, 07:38:48 PM
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 (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:
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 14, 2015, 01:41:37 AM
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
Title: Re: Operations on bitmap file
Post by: dedndave on July 14, 2015, 02:24:09 AM
let me take the dog for a walk and i'll write a routine when i get back   :biggrin:
Title: Re: Operations on bitmap file
Post by: dedndave on July 14, 2015, 03:25:17 AM
actually, i am writing 3 routines:
BmpEdRead
BmpEdWrite
BmpEdDelete

they all use a common BMP_EDIT structure   :t
Title: Re: Operations on bitmap file
Post by: Zen on July 14, 2015, 03:57:49 AM
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 (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183370(v=vs.85).aspx). Also, check: LoadBitmap Function, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/dd145033(v=vs.85).aspx),...or, LoadImage Function, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx)

...Also, I'm assuming that you've already read the MSDN GDI documentation. If not here is: Bitmaps, NSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183377(v=vs.85).aspx)
Title: Re: Operations on bitmap file
Post by: Vortex on July 14, 2015, 05:15:46 AM
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
Title: Re: Operations on bitmap file
Post by: dedndave on July 14, 2015, 01:15:00 PM
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
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 16, 2015, 11:46:40 PM
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.
Title: Re: Operations on bitmap file
Post by: Zen on July 17, 2015, 03:21:23 AM
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 (https://msdn.microsoft.com/en-us/library/dd183567(v=vs.85).aspx). 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 (https://msdn.microsoft.com/en-us/library/dd183562(v=vs.85).aspx) 
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 (https://msdn.microsoft.com/en-us/library/dd144879(v=vs.85).aspx)
Title: Re: Operations on bitmap file
Post by: dedndave on July 17, 2015, 10:40:20 AM
Erol's method is much simpler than mine - lol
i'll have to play with CreateDIBitmap when i have more time  :t
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 17, 2015, 11:53:55 PM
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?
Title: Re: Operations on bitmap file
Post by: dedndave on July 18, 2015, 12:26:11 AM
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 (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
Title: Re: Operations on bitmap file
Post by: dedndave on July 18, 2015, 12:41:39 AM
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
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 18, 2015, 03:59:11 AM
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.
Title: Re: Operations on bitmap file
Post by: dedndave on July 18, 2015, 05:36:26 AM
that would simplify things
of course, it won't handle the alpha channel stuff (transparency)

some programmers even prefer 32-bit images because each pixel is a DWORD
that makes address calculation easy, but requires more memory of course

creating a 24-bit DIB is very similar to a 256-color DIB, but with no palette
also - the image size calculation is a little different

in ALL BMP formats, each scan line contains bytes in multiples of 4
so, if the image is 201 pixels wide, 3 bytes per pixel
3 x 201 = 603 bytes
the end of each line is padded with 0's to make it a multiple of 4 bytes
so, each line would be 604 bytes

the header for a 24-bit image contains a BITMAPFILEHEADER (14 bytes) and a (BITMAPINFOHEADER 40 bytes)
image data starts immediately after the structures
the bottom image scanline is typically the first line of data
in that case, the image height value is positive

in some cases, you may see an image where the image height is negative
this means the top scan line is first in the file

https://msdn.microsoft.com/en-us/library/dd183374%28v=vs.85%29.aspx (https://msdn.microsoft.com/en-us/library/dd183374%28v=vs.85%29.aspx)
https://msdn.microsoft.com/en-us/library/dd183376%28v=vs.85%29.aspx (https://msdn.microsoft.com/en-us/library/dd183376%28v=vs.85%29.aspx)

when you call CreateDIBSection, it populates a pvBits DWORD, which points to the scan line data (less headers)
Title: Re: Operations on bitmap file
Post by: Zen on July 18, 2015, 05:51:20 AM
Quote from: KTOSIK2On 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?

I'm also unfamiliar with the GoAsm syntax (sorry). But,...The pDIBits parameter in GetDIBPixel is undoubtedly a DWORD. It would be a pointer (address) to the DIB array of pixel data (Bits),...at least that's how the pointer is expressed in all other DIB Section functions (on the MSDN site). If you look at the DIBBlurImage.asm file, you can see how EDGAR uses the routine,...he calls it in a routine that then calls SetDIBPixel. The return type of GetDIBPixel is the pixel to be written to (apparently this is a DWORD sized pixel).
Bitmaps that are 16-, 24-, or 32-bpp do not require color tables (Bitmap Header Types, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183386(v=vs.85).aspx)). So,... the color parameters in SetDIBPixel (and, I'm guessing here) is probably a value in the Color Table (which is either a RGBQUAD structure or a RGBTRIPLE structure). Bitmaps that are 1, 4, or 8 bpp must have a color table (MSDN).
I've always avoided the bitmap types that have a color table embedded in the header structure because these types of bitmaps don't have a natural appearing color spectrum. Bitmaps with 24 and 32 bits per pixel not only look better than the more primitive bitmaps, but, are a lot more common in this post-modern era.
...Concerning the difference between  DIBSaveBitmap and SaveDIB32:
The SaveDIB32 routine is the simpler of the two, and appears to be intended to save a DIB (with 32 bits per pixel) to a BITMAP file format.
DIBSaveBitmap allows you to specify the bits per pixel (cClrBits),...and then, EDGAR calls:
invoke CreateStreamOnHGlobal, [pGlobal], TRUE, ADDR pStream
invoke OleCreatePictureIndirect, ADDR pDesc, ADDR IID_IPicture, FALSE, ADDR pPicture

EDGAR is one of the original MASM Forum COM pros,...He's just showing off here,...:icon_cool:
...And,...to be perfectly honest with you,...there are sections of his code in DIBSaveBitmap that I don't understand what the heck he's thinking,...

This is a good synopsis of the procedure for saving a BITMAP to file: Bitmap Storage, MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/dd183391(v=vs.85).aspx)

...As Dennis Miller used to say at the end of his rants,...'I could be wrong',...
IMPORTANT NOTE: (You know,...I'm somewhat embarrassed to admit that I have NEVER ACTUALLY USED EDGAR's Graphics Library,...:dazzled:)

:bgrin:...DAVE knows all about BITMAPS and DEVICE CONTEXTS,...He's our all-around, resident genius,...:bgrin:
Title: Re: Operations on bitmap file
Post by: dedndave on July 18, 2015, 06:44:53 AM
256 color bitmaps have some advantages, if that's enough colors to do the job...

simple pixel address calculation (1 pixel = 1 byte)
require much less memory than a 24-bit of the same size
if you select a 256-color DIB into a DC for WM_PAINT, it blits very fast

while 256-colors may not be great for, say, a person's face,
it is usually good enough for drawing lines and circles, etc
Title: Re: Operations on bitmap file
Post by: Zen on July 18, 2015, 09:46:31 AM
When I was first learning graphics (in C++), I had a book that is probably the ultimate reference for Windows Bitmaps.
Windows Graphics Programming: Win32 GDI and DirectDraw, Feng Yuan, 2000 (http://www.fengyuan.com/)

It's now considered a little bit obsolete,...but, his original source code is fabulous,...
If I wasn't borderline demented,...I'd translate the most useful stuff to a MASM compatible library,...

You can download the source code for the entire book here: www.fengyuan.com/sample/Samples.zip (http://www.fengyuan.com/sample/Samples.zip)

If you can understand C++,...you may find this useful:
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 18, 2015, 09:45:12 PM
I tried to implement few functions from Edgar's library and I got several errors. Few of them I resolved, but the one I can't.
ROP.inc

comment $
Reverse Polish notation

Operand Meaning
D Destination bitmap
P Selected brush (also called pattern)
S Source bitmap

Boolean operators used in these operations follow.

Operator Meaning
a Bitwise AND
n Bitwise NOT (inverse)
o Bitwise OR
x Bitwise exclusive OR (XOR)
$

#Define ROP_0 00000042h ; BLACKNESS
#Define ROP_DPSoon 00010289h
#Define ROP_DPSona 00020C89h
#Define ROP_PSon 000300AAh
;... next are only #Define instructions


Graphics.inc

; Raster op codes for BitBlt
include ROP.inc

#Define TRUE 1
#Define FALSE 0
#Define NULL 0

#Define DIB_RGB_COLORS 0
#Define BI_RGB 0
#Define BI_BITFIELDS 3
#Define DST_BITMAP 4
#Define DSS_DISABLED 20h
#Define OPEN_EXISTING 3
#Define GENERIC_READ 80000000h
#Define GMEM_ZEROINIT 40h
#Define GMEM_FIXED 0
#Define HEAP_ZERO_MEMORY 00000008h
#Define FILE_BEGIN 0

#define HIMETRIC_INCH 2540
#define PICTYPE_UNINITIALIZED -1
#define PICTYPE_NONE 0
#define PICTYPE_BITMAP 1
#define PICTYPE_METAFILE 2
#define PICTYPE_ICON 3
#define PICTYPE_ENHMETAFILE 4

Iwmf STRUCT
hmeta DD
xExt DD
yExt DD
ENDS
;... next are only definitions of structs

While assembling SaveDIB32.asm (that includes Graphics.inc) I got errors:
ROP.inc(18) : error A2044: invalid character in file
ROP.inc(19) : error A2044: invalid character in file
...
I fought that maybe I should remove "#", but then I got error:
ROP.inc(18) : error A2008: syntax error : Define
How to correct these errors?
Title: Re: Operations on bitmap file
Post by: rrr314159 on July 19, 2015, 01:36:44 AM
Hi ktosik2,

#define is not legal MASM syntax. Change them to to "equ" statements like this:

#Define ROP_0 00000042h      ; CHANGE THIS TO

ROP_0 equ 00000042h

Furthermore the Structure end statements have to be changed:

Iwmf STRUCT      
   hmeta      DD
   xExt      DD
   yExt      DD
ENDS

; change this to:

Iwmf STRUCT      
   hmeta      DD
   xExt      DD
   yExt      DD
Iwmf ENDS

No doubt you will run into more issues with GoAsm syntax
Title: Re: Operations on bitmap file
Post by: dedndave on July 19, 2015, 02:48:27 AM
they are probably legal for the GoAsm assembler, which allows some C statements
however, for C, the 0????????h form for hex may not be allowed
instead, try 0x????????

MASM and GoAsm are different enough that it is difficult to switch from one to the other
if you want to assemble the library, use GoAsm   :t
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 19, 2015, 11:06:51 AM
I had more errors while assembling asm files from Edgar's library and I solved all but two:

SetDIBPixel PROC x,y,pDIBits,_width,height,color

mov eax,[_width]
mov ecx,[height]

cmp [x],eax
jae >.EXIT           ;here is the first error

cmp [y],ecx
jae >.EXIT           ;here is the same error as the first

sub ecx,[y]
dec ecx
mul ecx
shl eax,2 ; adjust for DWORD size
mov edx,eax

mov eax,[x]
shl eax,2 ; adjust for DWORD size
add eax,edx

add eax,[pDIBits] ; add the offset to the DIB bit
mov ecx,[color]
mov DWORD PTR [eax],ecx

.EXIT                       ;and here is the second error
RET
SetDIBPixel ENDP

The first error is:
error A2008: syntax error : >
and the second error is:
error A2198: .EXIT does not work with 32-bit segments

I found in this forum that .EXIT generates the following code:

        mov     ah,4Ch
        int     21h

Should I repleace instruction .EXIT with the above code? Or maybe should I just remove it?
And unfortunately I have no idea what to do with the first error.
Title: Re: Operations on bitmap file
Post by: jj2007 on July 19, 2015, 11:11:00 AM
jae >.EXIT

is the GoAsm syntax for "jump forward"; replace with a jae MyExitLabel
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 19, 2015, 11:51:04 AM
Thank you all for your help! Tomorrow I will try to do something with these functions.
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 20, 2015, 03:49:06 AM
I tried to use functions from Edgar's library, and I have some problems.
Firstly, I tried to use GetDIBPixel function. I show you the code below.
Variables:

hBitmap             DD ?
pBitmap             DD ?
hDC1                 DD ?
ppvBits              DD ?


Opening the bmp file:

INVOKE GetOpenFileName, ADDR ofn
.IF eax==TRUE
INVOKE RtlZeroMemory, ADDR FilePath, MAXSIZE
INVOKE lstrcat, ADDR FilePath, ofn.lpstrFile
INVOKE  ReadFileToMem, ADDR FilePath, ADDR pBitmap, ADDR pNumbOfBytesRead ;loading image by Vortex
INVOKE CreateBmpFromMem, hWnd, pBitmap, ADDR hDC1

mov    hBitmap, eax
mov    mdicreate.szTitle, OFFSET FilePath
INVOKE lstrcat, mdicreate.szTitle, OFFSET MDIChildTitle
INVOKE SendMessage, hwndClient, WM_MDICREATE, 0, ADDR mdicreate
mov hwndFileLoaded, eax
.ENDIF

Calling GetDIBPixel function:

lea     eax,[pBitmap+14]
INVOKE  CreateDIBSection,0,eax,DIB_RGB_COLORS,ppvBits,0,0

INVOKE  GetDIBPixel, 10, 10, ppvBits, 284, 277
mov quadStructure, eax
INVOKE lstrcat, ADDR colorsInfo, OFFSET red
INVOKE lstrcat, colorsInfo, quadStructure.rgbRed
INVOKE lstrcat, ADDR colorsInfo, OFFSET green
INVOKE lstrcat, colorsInfo, quadStructure.rgbGreen
INVOKE lstrcat, ADDR colorsInfo, OFFSET blue
INVOKE lstrcat, colorsInfo, quadStructure.rgbBlue
INVOKE MessageBox, hWnd, ADDR colorsInfo, ADDR AppName, MB_OK

When I call the last block of functions the application stops working (I have to close it), when I put GetDIBPixel function in comment, the application is working, so there is a problem with this function. Maybe I should declare ppvBits as another type of variable?

Secondly, I tried to use SaveDIB32 function. Variables and opening the bmp file are the same, so I show calling SaveDIB32 function only:

lea     eax,[pBitmap+14]
INVOKE  CreateDIBSection,0,eax,DIB_RGB_COLORS,ppvBits,0,0

;INVOKE  CreateFile,offset newFileName,GENERIC_WRITE,FILE_SHARE_READ, NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
;mov     hFile,eax
;INVOKE  SaveDIB32, ppvBits, hFile
;INVOKE  CloseHandle, hFile

Here when I call SaveDIB32 function, application is working, but the size of bmp file that is created is 54 bytes. I think that it is: a BITMAPFILEHEADER - 14 bytes and a BITMAPINFOHEADER - 40 bytes. Maybe I call this function with wrong parameters?
Title: Re: Operations on bitmap file
Post by: jj2007 on July 20, 2015, 04:32:42 AM
HBITMAP CreateDIBSection(
    HDC hdc,   // handle to device context
    CONST BITMAPINFO *pbmi,   // pointer to structure containing bitmap size, format, and color data
    UINT iUsage,   // color data type indicator: RGB values or palette indices
    VOID *ppvBits,   // pointer to variable to receive a pointer to the bitmap's bit values
    HANDLE hSection,   // optional handle to a file mapping object
    DWORD dwOffset   // offset to the bitmap bit values within the file mapping object
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 20, 2015, 06:43:26 AM
Ok, I modified code a little, but it still didn't work.
Variables:

.DATA
pvBits                LPVOID ?

.DATA?
hBitmap             DD ?
pBitmap             DD ?
hDC1                DD ?

Opening the bmp file is the same as in the previous post.

Calling GetDIBPixel function:

lea     eax,[pBitmap+14]
INVOKE  CreateDIBSection,0,eax,DIB_RGB_COLORS, OFFSET pvBits,0,0

INVOKE  GetDIBPixel, 10, 10, OFFSET pvBits, 284, 277
mov quadStructure, eax
INVOKE lstrcat, ADDR colorsInfo, OFFSET blue
INVOKE lstrcat, colorsInfo, quadStructure.rgbBlue
INVOKE lstrcat, ADDR colorsInfo, OFFSET green
INVOKE lstrcat, colorsInfo, quadStructure.rgbGreen
INVOKE lstrcat, ADDR colorsInfo, OFFSET red
INVOKE lstrcat, colorsInfo, quadStructure.rgbRed
INVOKE MessageBox, hWnd, ADDR colorsInfo, ADDR AppName, MB_OK

It works in the same way.

Calling SaveDIB32 function:

lea     eax,[pBitmap+14]
INVOKE  CreateDIBSection,0,eax,DIB_RGB_COLORS, OFFSET pvBits,0,0

INVOKE  CreateFile,OFFSET newFileName,GENERIC_WRITE,FILE_SHARE_READ, NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
mov     hFile,eax
INVOKE  SaveDIB32, OFFSET pvBits, hFile
INVOKE  CloseHandle, hFile

And the behavior is the same. Size of the file is 54 bytes.

Did I define pvBits right? Or maybe the problem is with other thing (things)?
Title: Re: Operations on bitmap file
Post by: dedndave on July 20, 2015, 07:27:39 AM
i am guessing that pBitmap is a pointer to the bitmap file header (etc) buffer

if that's the case, you have to dereference the pointer

lea     eax,[pBitmap+14]
EAX now points to the address of the pBitmap DWORD variable, plus 14 bytes
that's lala land   :P

try this, instead
    mov     eax,pBitmap
    add     eax,sizeof BITMAPFILEHEADER ;14 bytes
Title: Re: Operations on bitmap file
Post by: ktosik2 on July 20, 2015, 07:43:52 PM
I changed this:

lea     eax,[pBitmap+14]

into this:

    mov     eax,pBitmap
    add     eax,sizeof BITMAPFILEHEADER ;14 bytes

and nothing changed in application performance.

DednDave, what do you mean by "dereference the pointer"?
Title: Re: Operations on bitmap file
Post by: dedndave on July 21, 2015, 01:12:33 AM
well - that may not be the only mistake
and - i am not sure that pBitmap points to a BITMAPFILEHEADER
i only made a guess based on the previous code

again, guessing....
pBitmap is probably a pointer to a buffer
i.e., it is a DWORD that holds an address of a buffer
i also guess you read an entire BMP file into the buffer

it's a reference pointer, that's why we use the term "dereference"
intel processors do not have instructions that allow you to access the buffer from a pointer in memory
(can't think of any processors that do, actually)
so, to access the buffer, you must first dereference it by loading the address into a register
Title: Re: Operations on bitmap file
Post by: dedndave on July 21, 2015, 04:18:34 AM
here is a little example of creating a 24-bit DIB section
in the WM_CREATE code, i set a few pixels at the bottom of the image for test purposes
Title: Re: Operations on bitmap file
Post by: dedndave on July 21, 2015, 08:48:58 PM
2 small improvements in the CreateDIB24 PROC...

1) it allows for negative height values, creating "upside-down" bitmaps
2) it returns bytes per line in ECX

;***********************************************************************************************

CreateDIB24 PROC USES EDI dwDibWidth:DWORD,dwDibHeight:DWORD

;  Returns: EAX = HBITMAP, DIB section handle
;           ECX = dwBytesPerLine, bytes per image line
;           EDX = pvBits, pointer to DIB section pixel data

;------------------------------

    LOCAL   _bmi24      :BITMAPINFOHEADER

;BITMAPINFOHEADER <>
;  biSize          dd ?               ;BITMAPINFOHEADER structure size
;  biWidth         dd ?               ;image width in pixels
;  biHeight        dd ?               ;signed image height in pixels
;  biPlanes        dw ?               ;= 1
;  biBitCount      dw ?               ;= 24 for 24-bit images
;  biCompression   dd ?               ;= BI_RGB
;  biSizeImage     dd ?               ;image data bytes
;  biXPelsPerMeter dd ?               ;= 0
;  biYPelsPerMeter dd ?               ;= 0
;  biClrUsed       dd ?               ;= 0
;  biClrImportant  dd ?               ;= 0

;------------------------------

    xor     edi,edi                                           ;EDI = 0
    mov     edx,dwDibHeight
    mov     eax,dwDibWidth
    mov     _bmi24.biSize,sizeof BITMAPINFOHEADER
    mov     _bmi24.biWidth,eax
    mov     _bmi24.biHeight,edx
    inc     eax
    imul    eax,3
    and     al,-4
    or      edx,edx
    push    eax                                               ;save bytes per line
    .if SIGN?
        neg     edx
    .endif
    mov     _bmi24.biPlanes,1
    mul     edx
    mov     _bmi24.biBitCount,24
    mov     _bmi24.biCompression,edi                          ;BI_RGB = 0
    mov     _bmi24.biSizeImage,eax
    mov     _bmi24.biXPelsPerMeter,edi
    mov     _bmi24.biYPelsPerMeter,edi
    mov     _bmi24.biClrUsed,edi
    mov     _bmi24.biClrImportant,edi
    push    edi                                               ;initialize pvBits to 0
    INVOKE  GetDC,edi                                         ;HWND_DESKTOP = 0
    xchg    eax,edi                                           ;EDI = hdcDesktop, EAX = 0
    mov     edx,esp                                           ;EDX = pointer to pvBits
    INVOKE  CreateDIBSection,edi,addr _bmi24,DIB_PAL_COLORS,edx,eax,eax
    push    eax                                               ;save hbmpDIBSection
    INVOKE  ReleaseDC,HWND_DESKTOP,edi
    pop     eax                                               ;EAX = hbmpDIBSection
    pop     edx                                               ;EDX = pvBits
    pop     ecx                                               ;ECX = dwBytesPerLine
    ret

CreateDIB24 ENDP

;***********************************************************************************************
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 25, 2015, 04:14:47 AM
At the beginning I want to apologise that I didn't respond for so long. This is because I hadn't time to work on my project. Now I have a little more time.

Yesterday I was trying to make function SaveDIB32 from Edgar's Library working (we discuss about it few posts earlier) and I managed it! Here is code:
INVOKE  CreateFile,OFFSET newFileName,GENERIC_ALL,FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
mov     hFile,eax
INVOKE ConvertToDIB32, hBitmapNegatyw
mov hBitmap32Save, eax
INVOKE  SaveDIB32, hBitmap32Save, hFile
INVOKE  CloseHandle, hFile

I think you see that SaveDIB32 need hBitmap object as first parameter, NOT pvBits, as I thought earlier. It works perfectly.

DednDave, thanks for help, I tested your sample of code:
mov     ecx,pBitmap
lea     edx,[ecx+sizeof(BITMAPFILEHEADER)] ; start of the BITMAPINFOHEADER header

INVOKE CreateDIB24, BITMAPINFOHEADER.biWidth[edx], BITMAPINFOHEADER.biHeight[edx]
mov hBitmapNegatyw, eax ;hBMP

mov dword ptr [edx],0FFh       ;blue
mov dword ptr [edx+3],0FF00h   ;green
mov dword ptr [edx+6],0FF0000h ;red

yesterday and it worked, but when I write:
mov     ecx,pBitmap
lea     edx,[ecx+sizeof(BITMAPFILEHEADER)] ; start of the BITMAPINFOHEADER header

INVOKE CreateDIB24, BITMAPINFOHEADER.biWidth[edx], BITMAPINFOHEADER.biHeight[edx]
mov hBitmapNegatyw, eax ;hBMP
mov pvBits, edx ;<<<<<<<<<
mov dword ptr [pvBits],0FFh       ;blue
mov dword ptr [pvBits+3],0FF00h   ;green
mov dword ptr [pvBits+6],0FF0000h ;red

the bitmap is created, but the pixels are not set. What am I doing wrong?

Next, is there a possibility to write something like this?:

.DATA
imageWidth DD 0
imageHeight DD 0
(...)
mov     ecx,pBitmap
lea     edx,[ecx+sizeof(BITMAPFILEHEADER)] ; start of the BITMAPINFOHEADER header
;mov imageWidth, BITMAPINFOHEADER.biWidth[edx]
;mov imageHeight, BITMAPINFOHEADER.biHeight[edx]

I get error:  "error A2070: invalid instruction operands"  in commented lines. If there is such possibility, it would simplify getting size of the image.
Title: Re: Operations on bitmap file
Post by: dedndave on August 25, 2015, 04:56:07 AM
mov pvBits, edx ;<<<<<<<<<
mov dword ptr [pvBits],0FFh       ;blue
mov dword ptr [pvBits+3],0FF00h   ;green
mov dword ptr [pvBits+6],0FF0000h ;red


that is invalid addressing
[pvBits] is a dword - the address of it is assigned by the assembler in your .DATA section
[pvBits+3] is that address, plus 3 (bad)

in order to address the bits, the value pvBits needs to be in a register
Title: Re: Operations on bitmap file
Post by: MichaelW on August 25, 2015, 09:25:12 AM
Most of the instructions, and this includes MOV, support only one memory operand. A common way around this limitation is to do the move through a suitable register, in two instructions.

include \masm32\include\masm32rt.inc
.data
    bmih          BITMAPINFOHEADER <SIZEOF BITMAPINFOHEADER,1,2>
    imageWidth    DD 0
    imageHeight   DD 0   
.code
start:
    lea   edx, bmih
    mov   eax, [edx].BITMAPINFOHEADER.biWidth
    mov   imageWidth, eax
    mov   eax, [edx].BITMAPINFOHEADER.biHeight
    mov   imageHeight, eax
    printf( "%d\n%d\n\n", imageWidth, imageHeight)
    inkey
    exit
end start
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 27, 2015, 05:18:53 AM
Thanks for your replies!

Next I try to create dib section and get pvBits to the image that I load to my application.
Load an image: (thanks Vortex for these functions)

INVOKE GetOpenFileName, ADDR ofn
.IF eax==TRUE
INVOKE RtlZeroMemory, ADDR FilePath, MAXSIZE
INVOKE lstrcat, ADDR FilePath, ofn.lpstrFile
INVOKE  ReadFileToMem, ADDR FilePath, ADDR pBitmap, ADDR pNumbOfBytesRead
INVOKE CreateBmpFromMem, hWnd, pBitmap, ADDR hDC1
mov    hBitmap, eax
.ENDIF


This code:

mov     ecx,pBitmap
lea     edx,[ecx+sizeof(BITMAPFILEHEADER)] ; start of the BITMAPINFOHEADER header
mov eax, BITMAPINFOHEADER.biWidth[edx]
mov imageWidth, eax
mov eax, BITMAPINFOHEADER.biHeight[edx]
mov imageHeight, eax

generates image size properly, so I think that pBitmap is right generated by ReadFileToMem function.

Then I wrote CreateDIBSection call:

mov     ecx,pBitmap
lea     edx,[ecx+sizeof(BITMAPFILEHEADER)] ; start of the BITMAPINFOHEADER header
mov eax, edx
xor edx, edx

INVOKE CreateDIBSection, 0, eax, DIB_RGB_COLORS, edx, 0, 0

and when I call these instructions:

mov dword ptr [edx],0FF00h
mov dword ptr [edx + 3],0FF00h
mov dword ptr [edx + 6],0FF00h
mov dword ptr [edx + 9],0FF00h

the program stops working and I have to close it. What am I doing wrong?
These lines:

.DATA?
pvBits              LPVOID ?
(...)
INVOKE CreateDIBSection, 0, eax, DIB_RGB_COLORS, OFFSET pvBits, 0, 0
mov edx, pvBits
mov dword ptr [edx],0FF00h
mov dword ptr [edx + 3],0FF00h
mov dword ptr [edx + 6],0FF00h
mov dword ptr [edx + 9],0FF00h

don't work too. Program stops working and I have to close it.
These lines:

INVOKE CreateDIBSection, 0, eax, DIB_RGB_COLORS, ADDR pvBits, 0, 0 ;ADDR instead of OFFSET
mov edx, pvBits
mov dword ptr [edx],0FF00h
mov dword ptr [edx + 3],0FF00h
mov dword ptr [edx + 6],0FF00h
mov dword ptr [edx + 9],0FF00h

don't work. The application is working, but there is no effect on the image.
Title: Re: Operations on bitmap file
Post by: rrr314159 on August 27, 2015, 10:11:54 AM
The last version with "addr pvBits" is right, except you're not using a device context. Normally you'd use CreateCompatibleDC to get a handle to a device context, then supply that as the first argument to CreateDIBSection. After writing to the address contained in pvBits, as you are doing, that DC handle is used to send the bitmap to the screen's DC - normally using BitBlt - then you can finally see the image.

It's a little complicated, ask for further help if this doesn't make sense yet. Or just wait for dedndave to post the complete program
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 28, 2015, 04:54:01 AM
I tried this: (this is modificaton of CreateDIB24 function from DednDave)

xor     edi,edi                                                          ;EDI = 0
mov     _bmi24.biSize,sizeof BITMAPINFOHEADER
mov     eax,imageWidth
mov     _bmi24.biWidth,eax
mov     edx,imageHeight
mov     _bmi24.biHeight,edx
inc     eax
imul    eax,3
and     al,-4
mov     _bmi24.biPlanes,1
mul     edx
mov     _bmi24.biBitCount,24
mov     _bmi24.biCompression,edi                          ;BI_RGB = 0
mov     _bmi24.biSizeImage,eax
mov     _bmi24.biXPelsPerMeter,edi
mov     _bmi24.biYPelsPerMeter,edi
mov     _bmi24.biClrUsed,edi
mov     _bmi24.biClrImportant,edi

push edi
INVOKE GetDC,edi
xchg eax,edi
mov     edx,esp
INVOKE  CreateDIBSection,edi,addr _bmi24,DIB_PAL_COLORS,edx,eax,eax
push    eax                                                             ;save hbmpDIBSection
INVOKE  ReleaseDC,hwnd,edi
pop     eax                                                              ;EAX = hbmpDIBSection
pop     edx                                                              ;EDX = pvBits

mov dword ptr [edx],0FF00h
mov dword ptr [edx + 3],0FF00h
mov dword ptr [edx + 6],0FF00h
mov dword ptr [edx + 9],0FF00h



The program is running, there are not any errors, but the four pixels are not set into green.
I tried a lot of possibilities and none of them worked fine. Can someone help?
Title: Re: Operations on bitmap file
Post by: dedndave on August 28, 2015, 05:19:01 AM
you really need to post a complete working program
we need to see, not only how the DIB section is created,
but also, how it is displayed - we need to see your WM_PAINT code
if you show us partial code, we have to write a working program to test it   :(
Title: Re: Operations on bitmap file
Post by: rrr314159 on August 28, 2015, 06:18:19 AM
@ktosik2,

You're still not using the "proper" approach. AFAIK you can't write directly to screen video memory as you're trying to do. (I should review my notes but am busy; could be wrong about that.) Anyway one way that works (could be others) is, as I said, use CreateCompatibleDC to create a DC (the "background" or "in-memory" DC). Then write to that, finally use BitBlt to put it "forward" to the screen (which is the DC you're using here). This is more flexible technique anyway, and avoids flicker. Apart from that your code appears correct, but dedndave is (of course) right, post the complete prog including WM_PAINT code. Another thing u could do, hope I get around to posting the code to perform the above steps, after cleaning the gutters and mowing the lawn :icon_confused:
Title: Re: Operations on bitmap file
Post by: jj2007 on August 28, 2015, 06:32:56 AM
Quote from: rrr314159 on August 28, 2015, 06:18:19 AMyou can't write directly to screen video memory

Indeed. Search the old (http://www.masmforum.com/board/index.php?action=search;advanced) and new (http://masm32.com/board/index.php?action=search;advanced;search=) forums for setdibits - there is more than enough material to keep you busy for a week.
Title: Re: Operations on bitmap file
Post by: rrr314159 on August 28, 2015, 09:36:07 AM
No, that's not "writing directly to the screen" as I meant it (let's not split hairs). It's just another way to BitBlt, evidently. The actual modifying of pixels - as, for instance, "mov dword ptr [edx],0FF00h" must be done to a "drawing surface", a DIB, in memory, then sent to the screen. The only way to "write directly to the screen" would be SetPixel and similar functions; for real image manipulation of course they're out of the question being so slow. Saw this comment in old thread (http://www.masmforum.com/board/index.php?topic=17934.0)

Quote from: MichaelW, long agoI posted an example here that uses a DIB as a drawing surface for a fast set-pixel routine, and SetDIBits to copy the bitmap bits from the DIB to a DDB for display.

- And many other comments, plus MSDN, make the point clear. In fact zemtex in that thread gives a chart showing a memory DIB being modified and then BitBlt'ed to the screen. It's not clear, he may be doing exactly my technique or a slight mod of that.

- I studied SetDIBits many months ago and wound up with my approach ... one big advantage, there's no flicker this way; pretty sure there were other advantages as well. They're very similar techniques, equal amounts of work; perhaps SetDIBits has advantages in some applications

- Finally - you left out of my quote both "AFAIK" and "could be wrong about that". But I'm still pretty sure my (or, call it zemtek's since apparently he was using it long before me) way is as good as any ... based on research which I don't have time to look up now. That's why I have to be a bit vague at the moment
Title: Re: Operations on bitmap file
Post by: jj2007 on August 28, 2015, 10:18:12 AM
Quote from: rrr314159 on August 28, 2015, 09:36:07 AM
No, that's not "writing directly to the screen"

I didn't write that ::)

SetDiBits is certainly not writing directly to the screen, but you can POKE pixels via mov byte ptr [reg], al or similar. That is as fast as writing directly to the screen, except that you need to BitBlt it afterwards. If you know a better alternative to awfully slow SetPixel, let us know.
Title: Re: Operations on bitmap file
Post by: rrr314159 on August 28, 2015, 11:03:06 AM
you can POKE pixels via mov byte ptr [reg], al or similar

- we only "POKE" with Basic :biggrin:

But seriously, you're talking about "poking" into a bitmap in memory then BitBlt (or StretchBlt, whatever) to the screen. The problem is that initial bitmap must be set up with API functions as a "compatible bitmap" in a device context. If you already have the pixels you want to send to the screen in memory, 2 bad, they can't be sent directly to the screen. Instead u must make a DIB: and it allocates its own memory, you can't tell it to use yours. Then you first transfer your existing picture into that in-memory DIB, finally to the screen. There are actually good reasons for this but it's frustrating for us old guys, who used to write direct to video. Anyway the right thing to do is make the DIB in a DC - it will give you a handle to mem - then "poke" (draw your picture) into it, and send to screen. Assuming you're doing a pretty large picture, like the whole screen, it's actually fast enough (for a few pixels it's a lot of overhead of course, SetPixel is better). The whole mechanism (to use the example of my prog, "MathMovie") takes as little as a couple milliseconds, while the drawing takes at least 5 or 10, up to 50 and more for a "really cool" picture - so the whole DC / DIB / Blt business is pretty negligible. I believe that couple milliseconds is as fast as possible

That's assuming your picture is "free-form". If it's composed of triangles, squares, fill areas, bmps, 3-d "reality" constructs, various other things, then there are many specialized APIs in GDI, DirectDraw to do it faster. But for a non-standard, unique picture zemtek's technique is the best, AFAIK
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 28, 2015, 12:09:59 PM
The main file (PNPZ.ASM) is a little big, there are many places where I put CreateDIBSection calls, names of menu items are in polish language, and they are doing something different than their names suggest.
Title: Re: Operations on bitmap file
Post by: dedndave on August 28, 2015, 01:19:44 PM
usually, you can just make a small test program
once that code is working, adapt it into your larger project

you can imagine how many man-hours it would take if all the forum members wrote a test piece   :biggrin:
Title: Re: Operations on bitmap file
Post by: dedndave on August 28, 2015, 01:32:07 PM
the paint code in the child proc looks, well, ok
it should draw the bitmap to the display DC, provided it makes it through the if/then/else stuff   :P

if you feel the program isn't reaching that point, you can put something in there to verify
i sometimes use a very short beep
    INVOKE  Beep,800,30
for example - that lets me know that the if/then/else structure is allowing the paint code to happen

not sure i really like that particular code, where you use strcmp to compare a dword handle   :redface:

another way is to use a debugger, set up as the JIT exception handler
you can temporarily insert INT 3 and, if you are getting to that point, the debugger will come up
    INT     3    ;stop code and open JIT handler

of course, you can do that with no JIT debugger, and the program will terminate with an invalid instruction exception
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 29, 2015, 03:49:03 AM
Ok, I try to do something else.
This is code in WM_PAINT section:

LOCAL redvalue: BYTE
LOCAL greenvalue: BYTE
LOCAL bluevalue: BYTE
(...)
.ELSEIF uMsg==WM_PAINT
INVOKE BeginPaint, hChild, ADDR ps
mov    hdc, eax
.IF czyWczytanoPlik==1
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
INVOKE  BitBlt,hdc,0,0,imageWidth, imageHeight,hMemDC,0,0,SRCCOPY

mov redvalue, 0
mov greenvalue, 0
mov bluevalue, 255
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, 5, 5
mov colorref, eax
movzx eax, BYTE PTR [colorref + 2]
PrintDec eax ;blue color
INVOKE  DeleteDC, hMemDC
.ENDIF

and it is working right, when window is repainted, text eax = 255 appears in Debug Window.
But if I want to do this:

INVOKE GetPixel, hdc, 5, 5
mov colorref, eax

movzx eax, BYTE PTR [colorref + 2]
mov bluevalue, eax
PrintDec bluevalue

and this:

INVOKE GetPixel, hdc, 5, 5
mov colorref, eax

movzx eax, BYTE PTR [colorref + 2]
push eax
pop bluevalue

PrintDec bluevalue

I get: error A2070: invalid instruction operands in:

mov bluevalue, eax

and

pop bluevalue

What is wrong with this instructions? Is there a possibility to store for example blue color in bluevalue variable?

If I use:

LOCAL bluevalued: DWORD

instead of bluevalue after GetPixel it is working, but if I write

push BYTE PTR bluevalued

it is not working (invalid instruction operands). Why?
Title: Re: Operations on bitmap file
Post by: TouEnMasm on August 29, 2015, 04:12:26 AM
Quote
push BYTE PTR bluevalued

couldn't  push byte must be word (taking care of stack align 32..),DWORD
Title: Re: Operations on bitmap file
Post by: rrr314159 on August 29, 2015, 04:27:07 AM
Hi ktosik2,

congrats on getting the picture to display! :t Your new problem is much simpler, you're using byte where it must be dword.

LOCAL bluevalue: BYTE ; fine
mov bluevalue, eax   ; no good, dword can't go into a byte location

push eax        ; fine - these two lines another attempt to put eax into bluevalue
pop bluevalue ; no good, byte's can't be pushed / popped.


- Obvious fix is simply:

mov bluevalue, al

- Apparently because of these problems you tried making bluevalue a DWORD (bluevalued), which I think is not the right way to go. Without running the code, I think you should leave bluevalue a BYTE and always mov al, not eax, into it.

When reading from the bytes you're using

movzx eax, BYTE PTR [colorref + 2]

- That's fine but apparently u could simply

mov al, BYTE PTR [colorref + 2]

Bottom line use al when dealing with bytes and if needed, push / pop eax
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 29, 2015, 06:15:16 PM
rrr314159, thanks for your help (and for congratulations)!
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 29, 2015, 09:29:00 PM
Because I can't make a dib section (in pvBits) from loaded image,  I want to do something different.

1. Load an image.
2. When it is displaying for the first time in WM_PAINT section, create blank dib section with CreateDIB24 (thanks DednDave!).
3. In loop:  use GetPixel to get color of the pixel and write it to pvBits of the new blank one created by CreateDIB24.

I have few problems with this and I can't solve 2 of them.
The code should looks more or less like this:

.IF firstShow==1
INVOKE CreateCompatibleDC, hdc
mov    hMemDC, eax
INVOKE SelectObject, hMemDC, hBitmap
INVOKE  BitBlt,hdc,0,0,imageWidth, imageHeight,hMemDC,0,0,SRCCOPY

INVOKE CreateDIB24, imageWidth, imageHeight
mov hBitmapOryginal, eax ;hBMP
mov pvBitsOryginal, edx

mov ypos,0
mov ecx, imageHeight
.WHILE ypos < ecx
mov xpos, 0
mov ecx, imageWidth
.WHILE xpos < ecx
INVOKE GetPixel, hdc, xpos, ypos
mov colorref, eax
INVOKE GetRValue, colorref
mov redvalue, al
INVOKE GetGValue, colorref
mov greenvalue, al
INVOKE GetBValue, colorref
mov bluevalue, al

mov eax, ypos
mul imageHeight
add eax, xpos

mov edx, pvBitsOryginal
xor ebx, ebx
mov bl, bluevalue
;mov bh, greenvalue

; mov DWORD ptr [edx+eax], ebx not working properly with eax
; mov DWORD ptr [edx+ypos*imageHeight+xpos], ebx

mov DWORD ptr [edx], ebx
mov DWORD ptr [edx+3], ebx
mov DWORD ptr [edx+6], ebx
mov DWORD ptr [edx+9], ebx
mov DWORD ptr [edx+12], ebx

inc xpos
mov ecx, imageWidth
.ENDW

inc ypos
mov ecx, imageHeight
.ENDW
INVOKE  DeleteDC, hMemDC
mov firstShow,0
.ENDIF



First problem is connected with calculating positions of next pixels. If I write something like this:

mov DWORD ptr [edx+eax], ebx

it is not really the position of the pixel, the image looks strange, and at this line:

mov DWORD ptr [edx+ypos*imageHeight+xpos], ebx

there is an error: constant expected. How to do it properly?

And the second problem. In code I have BYTE variables and I can do such things:

mov bl, bluevalue
; mov bh, greenvalue
mov DWORD ptr [edx], ebx

I can put bluevalue and greenvalue into pixel in pvBits, but I don't know how to put all three color components into pixel in pvBits. How to do it?
Title: Re: Operations on bitmap file
Post by: dedndave on August 29, 2015, 09:39:24 PM
the way i usually use a DIB section

create the DIB section in WM_CREATE code
delete the DIB section in WM_DESTROY code

in WM_PAINT code...
BeginPaint
create compatible DC (memory DC)
select the DIB section into the memory DC
then BitBlt from the memory DC to the display DC
delete the memory DC
EndPaint

optionally, you can create the memory DC in WM_CREATE and "keep it alive"
but - that uses system resources
and, creating and deleting a memory DC is very fast, so it doesn't slow paint down
Title: Re: Operations on bitmap file
Post by: dedndave on August 29, 2015, 09:59:59 PM
i think this one shows you what i mean
it's not a 24-bit DIB, but the code is otherwise the same
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 29, 2015, 11:41:47 PM
Thanks DednDave for tips and the example.
Could someone help me to solve the first problem that I described in my previous post (the second I solved)? Later I will need it because I will have to modify the images, and I will have to access to the pixels.
Title: Re: Operations on bitmap file
Post by: TouEnMasm on August 30, 2015, 12:19:18 AM

This example is made for you,he modify the bitmap with c++(It's a mix code asm,c++)
See the .cpp
It's an animated region who can use all the graphic format supported by Windows (in resource or file)
http://masm32.com/board/index.php?topic=1917.msg19916#msg19916
Title: Re: Operations on bitmap file
Post by: ktosik2 on August 30, 2015, 05:04:03 AM
Thank you for this example, thank you all for your help!
Title: Re: Operations on bitmap file
Post by: dedndave on August 30, 2015, 05:53:18 AM
unless you specify a negative value for DIB height, rows are written in bottom-to-top order
this is the "natural" order for BMP files (an old windows 1.0 thing - upside down and backwards)

because it is a 24-bit DIB, each pixel uses 3 bytes: blue, green, red (backwards - lol)
so, the first 3 bytes of the buffer are for the bottom row, left column

there is a rule that applies to ALL BMP files and DIB's
the number of bytes for each row must be evenly divisable by 4

so, if you have a DIB that is 11 pixels wide (11x3 = 33), each row will use 36 bytes
the extra bytes are usually filled with 0's

from that information, you can calculate the buffer offset for any X,Y position