News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Operations on bitmap file

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

Previous topic - Next topic

dedndave

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/dd183376%28v=vs.85%29.aspx

when you call CreateDIBSection, it populates a pvBits DWORD, which points to the scan line data (less headers)

Zen

#16
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). 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

...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:
Zen

dedndave

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

Zen

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

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

If you can understand C++,...you may find this useful:
Zen

ktosik2

#19
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?

rrr314159

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
I am NaN ;)

dedndave

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

ktosik2

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.

jj2007

jae >.EXIT

is the GoAsm syntax for "jump forward"; replace with a jae MyExitLabel

ktosik2

Thank you all for your help! Tomorrow I will try to do something with these functions.

ktosik2

#25
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?

jj2007

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

ktosik2

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)?

dedndave

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

ktosik2

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"?