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.
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:
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
let me take the dog for a walk and i'll write a routine when i get back :biggrin:
actually, i am writing 3 routines:
BmpEdRead
BmpEdWrite
BmpEdDelete
they all use a common BMP_EDIT structure :t
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)
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
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
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.
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)
Erol's method is much simpler than mine - lol
i'll have to play with CreateDIBitmap when i have more time :t
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?
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
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
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.
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)
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:
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
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:
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?
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
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
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.
jae >.EXIT
is the GoAsm syntax for "jump forward"; replace with a jae MyExitLabel
Thank you all for your help! Tomorrow I will try to do something with these functions.
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?
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
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)?
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
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"?
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
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
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
;***********************************************************************************************
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.
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
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
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.
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
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?
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 :(
@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:
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.
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
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.
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
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.
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:
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
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?
Quote
push BYTE PTR bluevalued
couldn't push byte must be word (taking care of stack align 32..),DWORD
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
rrr314159, thanks for your help (and for congratulations)!
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?
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
i think this one shows you what i mean
it's not a 24-bit DIB, but the code is otherwise the same
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.
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
Thank you for this example, thank you all for your help!
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