The parameters:
Quote
hImgBitmap is a valid handle on the image. It can has been got by LoadImage, LoadBitmap...
__lpdwImageSize is a valid pointer on a variable that will receive the number of bytes of the image. Before calling the function set it to 0
__dwImageWidth & __dwImageHeight are image dimensions that you can get by calling GetObject like this GetObject(_hBitmap,sizeof(BITMAP),&_Bitmap)
LPBYTE BitmapToImage(HBITMAP __hImgBitmap,LPDWORD __lpdwImageSize,DWORD __dwImageWidth,DWORD __dwImageHeight)
{
register LPBYTE _lpImageBits ;
alignas(HANDLE) BITMAPINFO _BitmapInfo ;
alignas(HANDLE) HDC _hDC ;
_hDC = GetDC(NULL) ; // *** Get a DC on the screen ***
if(_hDC)
{
__stosq((unsigned long long *) &_BitmapInfo,0,sizeof(BITMAPINFO) / 8) ; // *** Fill the BITMAPINFO structure with 0 ***
_BitmapInfo.bmiHeader.biBitCount = 32 ; // *** Filling correctly these fields is required by GetDIBits ***
_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER) ;
_BitmapInfo.bmiHeader.biWidth = __dwImageWidth ; // *** Image Width ***
_BitmapInfo.bmiHeader.biHeight = __dwImageHeight ; // *** Image Height ***
_BitmapInfo.bmiHeader.biPlanes = 1 ; // *** Must always be set to 1 ***
// **************************************************************************************************************
// *** When calling GetDIBits with these minimum datas, it will fill correctly the BITMAPINFOHEADER structure ***
// **************************************************************************************************************
if(GetDIBits(_hDC,__hImgBitmap,0,_BitmapInfo.bmiHeader.biHeight,NULL,(LPBITMAPINFO) &_BitmapInfo,DIB_RGB_COLORS))
{
// ***************************************************
// *** Allocate memory to receive the bitmap bits ****
// ***************************************************
_lpImageBits = (LPBYTE) VirtualAlloc(NULL,_BitmapInfo.bmiHeader.biSizeImage + 4095,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE) ;
if(_lpImageBits)
{
// *****************************************************************
// *** Now call GetDIBits again but for receiving the image bits ***
// *****************************************************************
if(GetDIBits(_hDC,__hImgBitmap,0,_BitmapInfo.bmiHeader.biHeight,_lpImageBits,(LPBITMAPINFO) &_BitmapInfo,DIB_RGB_COLORS))
{
// ************************************************************************
// *** The bitmap datas we got is under the form ARGB. A 32 bits bitmap ***
// ************************************************************************
DeleteDC(_hDC) ; // Delete the DC
*__lpdwImageSize = _BitmapInfo.bmiHeader.biSizeImage ; // *** Copy the imagesize (in bytes) into the variable passed in parameter ***
return (_lpImageBits) ; *** returns the image bits buffer address
}
VirtualFree(_lpImageBits,0,MEM_RELEASE) ; // *** GetDIBits failed so free the memory ***
}
// *** If you arrive here this is because the memory allocation failed ***
}
DeleteDC(_hDC) ; // *** The first call to GetDIBits has failed ***
} // *** Don't forget to free the memory ***
return (NULL) ; // *** return a NULL pointer to indicate it was not possible to do the job ***
}
One thing we could do is to call SetLastError with 0 has an error code, that will clear the Last Error code
https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror (https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror)
Like this we would be sure that the error code was really set by our function
GetDIBits : https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdibits (https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdibits)
VirtualAlloc : https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc (https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc)
To get a strong function you can add these lines at the beginning of the function:
if(__hImgBitmap) return (NULL) ;
if(!__lpdwImageSize) return (NULL) ;
if((!__dwImageWidth) || (!__dwImageHeight)) return (NULL) ;
We could declare a register pointer on the BITMAPINFOHEADER structure
register BITMAPINFOHEADER * _lpBmih ; or register LPBITMAPINFOHEADER _lpBmih ;
and initialize it as _lpBmih = &_BitmapInfo.bmiHeader ;
now replace all the occurences of _BitmapInfo.bmiHeader. with "_lpBmih ->"
Final function
LPBYTE BitmapToImageEx(HBITMAP __hImgBitmap,LPDWORD __lpdwImageSize,DWORD __dwImageWidth,DWORD __dwImageHeight)
{
register LPBYTE _lpImageBits ;
register LPBITMAPINFOHEADER _lpBmih ;
alignas(HANDLE) BITMAPINFO _BitmapInfo ;
alignas(HANDLE) HDC _hDC ;
if(!__hImgBitmap) return (NULL) ;
if(!__lpdwImageSize) return (NULL) ;
if((!__dwImageWidth) || (!__dwImageHeight)) return (NULL) ;
*__lpdwImageSize = 0 ;
SetLastError(0) ;
/*
alignas(HANDLE) BITMAP _Bitmap ;
if(!GetObject(__hImgBitmap,sizeof(BITMAP),&_Bitmap)) return (NULL) ;
If you add these two lines remove "DWORD __dwImageWidth,DWORD __dwImageHeight"
and replace
_lpBmih->biWidth = __dwImageWidth ;
_lpBmih->biHeight = __dwImageHeight ;
with
_lpBmih->biWidth = _Bitmap.bmWidth ;
_lpBmih->biHeight = _Bitmap.bmHeight ;
*/
_hDC = GetDC(NULL) ;
if(_hDC)
{
__stosq((unsigned long long *) &_BitmapInfo,0,sizeof(BITMAPINFO) / 8) ;
_lpBmih = &_BitmapInfo.bmiHeader ;
_lpBmih->biBitCount = 32 ;
_lpBmih->biSize = sizeof(BITMAPINFOHEADER) ;
_lpBmih->biWidth = __dwImageWidth ;
_lpBmih->biHeight = __dwImageHeight ;
_lpBmih->biPlanes = 1 ;
if(GetDIBits(_hDC,__hImgBitmap,0,_lpBmih->biHeight,NULL,(LPBITMAPINFO) &_BitmapInfo,DIB_RGB_COLORS))
{
_lpImageBits = (LPBYTE) VirtualAlloc(NULL,_BitmapInfo.bmiHeader.biSizeImage + 4095,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE) ;
if(_lpImageBits)
{
if(GetDIBits(_hDC,__hImgBitmap,0,_BitmapInfo.bmiHeader.biHeight,_lpImageBits,(LPBITMAPINFO) &_BitmapInfo,DIB_RGB_COLORS))
{
DeleteDC(_hDC) ;
*__lpdwImageSize = _lpBmih->biSizeImage ;
return (_lpImageBits) ;
}
VirtualFree(_lpImageBits,0,MEM_RELEASE) ;
}
}
DeleteDC(_hDC) ;
}
return (NULL) ;
}
Now here is a function that has all the optimizations and corrections.
I did not want to give this function from the beginning to make you see all the steps when writing a function.
LPBYTE NewBitmapToImageEx(HBITMAP __hImgBitmap,LPDWORD __lpdwImageSize)
{
register LPBYTE _lpImageBits ;
register LPBITMAPINFOHEADER _lpBmih ;
alignas(HANDLE) BITMAPINFO _BitmapInfo ;
alignas(HANDLE) HDC _hDC ;
alignas(HANDLE) BITMAP _Bitmap ;
if(!__hImgBitmap) return (NULL) ;
if(!__lpdwImageSize) return (NULL) ;
*__lpdwImageSize = 0 ;
if(!GetObject(__hImgBitmap,sizeof(BITMAP),&_Bitmap)) return (NULL) ;
SetLastError(0) ;
_hDC = GetDC(NULL) ;
if(_hDC)
{
__stosq((unsigned long long *) &_BitmapInfo,0,sizeof(BITMAPINFO) / ;
_lpBmih = &_BitmapInfo.bmiHeader ;
_lpBmih->biBitCount = 32 ;
_lpBmih->biSize = sizeof(BITMAPINFOHEADER) ;
_lpBmih->biWidth = _Bitmap.bmWidth ;
_lpBmih->biHeight = _Bitmap.bmHeight ;
_lpBmih->biPlanes = 1 ;
if(GetDIBits(_hDC,__hImgBitmap,0,_lpBmih->biHeight,NULL,(LPBITMAPINFO) &_BitmapInfo,DIB_RGB_COLORS))
{
_lpImageBits = (LPBYTE) VirtualAlloc(NULL,_BitmapInfo.bmiHeader.biSizeImage + 4095,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE) ;
if(_lpImageBits)
{
if(GetDIBits(_hDC,__hImgBitmap,0,_BitmapInfo.bmiHeader.biHeight,_lpImageBits,(LPBITMAPINFO) &_BitmapInfo,DIB_RGB_COLORS))
{
DeleteDC(_hDC) ;
*__lpdwImageSize = _lpBmih->biSizeImage ;
return (_lpImageBits) ;
}
VirtualFree(_lpImageBits,0,MEM_RELEASE) ;
}
}
DeleteDC(_hDC) ;
}
return (NULL) ;
}
Hello,
Thanks for sharing. Back home, I will have a closer look. I have similar functions coded with Masm and Poasm.
Hi Vortex,
I saw your routine to write image on disk, this gave me the idea to share image work in C
Thank you for sharing
Philippe
Another idea, creating a bitmap from memory :
hWnd : Handle of the parent window
pBmp : Pointer to the memory portion storing the bitmap
HBITMAP CreateBmpFromMem (HWND hWnd,LPBYTE pBmp)
{
HDC hDC;
HBITMAP hBmp={0};
VOID* ppvBits;
BITMAPINFOHEADER* StartOfBmpInfoHdr;
hDC=GetDC(0);
if(!(hDC)){
return 0;
}
StartOfBmpInfoHdr=(BITMAPINFOHEADER*)(pBmp+sizeof(BITMAPFILEHEADER));
ppvBits=(pBmp+((BITMAPFILEHEADER*)pBmp)->bfOffBits);
hBmp=CreateDIBitmap(hDC,StartOfBmpInfoHdr,CBM_INIT,ppvBits,(BITMAPINFO*)StartOfBmpInfoHdr,DIB_RGB_COLORS);
ReleaseDC(hWnd,hDC);
return hBmp;
}
I have no time for that now but we could save an image from clipboard
Hi Philippe,
Here is an example for you :
include SaveClipBoard.inc
.data
IID_IPicture GUID <7BF80980h,0BF32h,101Ah,<8Bh,0BBh,00h,0AAh,00h,30h,0Ch,0ABh>>
message db 'SaveClipBoard.exe filename.bmp',0
.data?
buffer db 512 dup(?)
.code
start:
call main
invoke ExitProcess,0
main PROC uses esi
LOCAL hBmp :DWORD
LOCAL pBitmap :DWORD
LOCAL hGlobal :DWORD
LOCAL pcbSize :DWORD
LOCAL pStream :DWORD
LOCAL pd :PICTDESC
lea esi,buffer
invoke ParseCmdLine,esi
cmp eax,2
je @f
invoke StdOut,ADDR message
ret
@@:
invoke GetDesktopWindow
invoke OpenClipboard,eax
invoke GetClipboardData,CF_BITMAP
mov hBmp,eax
invoke CloseClipboard
mov pd.cbSizeofstruct,SIZEOF PICTDESC ; initialize the PICTDESC structure
mov pd.picType,PICTYPE_BITMAP
push hBmp
pop pd.bmp.hbitmap
invoke OleCreatePictureIndirect,ADDR pd,\
ADDR IID_IPicture,TRUE,ADDR pBitmap
; create the OLE image
invoke CreateStreamOnHGlobal,NULL,TRUE,ADDR pStream
; create the destination stream
; to save the icon
lea eax,pcbSize
coinvoke pBitmap,IPicture,SaveAsFile,pStream,\
TRUE,eax
invoke GetHGlobalFromStream,pStream,\
ADDR hGlobal
invoke GlobalLock,hGlobal ; get the address pointing
; the icon in memory
invoke WriteFileToDisc,DWORD PTR [esi+4],\
eax,pcbSize
; save the bitmap to disc
coinvoke pBitmap,IPicture,Release
coinvoke pStream,IStream,Release
ret
main ENDP
END start
Thank You Vortex now we have all the functions
Philippe