This routine will save a bitmap in a DC to a file. Pass the name of the destination file and a handle to the device context. It will create a 24 bit DIB section and copy the image into it then save the image. It can be adapted to pass a bitmap handle directly.



.data
; For some reason these *must* be globally defined
lpBITMAPFILEHEADER BITMAPFILEHEADER <0>
lpBITMAPINFOHEADER BITMAPINFOHEADER <0>

.code
WriteBitmapToFile proc pszFile:DWORD,hTransDC:DWORD
LOCAL hTempDC :DWORD
LOCAL hMemBmp :DWORD
LOCAL hFile :DWORD
LOCAL cbWrite :DWORD
LOCAL hTempBmp :DWORD
LOCAL ppvBits :DWORD
LOCAL bmp :BITMAP
LOCAL DataSize :DWORD
LOCAL bmi :BITMAPINFO

invoke GetCurrentObject,hTransDC,OBJ_BITMAP
mov hTempBmp,eax
invoke GetObject,hTempBmp,SIZEOF BITMAP,ADDR bmp

invoke CreateCompatibleDC,NULL
mov hTempDC,eax

mov bmi.bmiHeader.biSize,SIZEOF bmi.bmiHeader
mov eax,bmp.bmWidth
mov bmi.bmiHeader.biWidth,eax
mov eax,bmp.bmHeight
mov bmi.bmiHeader.biHeight,eax
mov bmi.bmiHeader.biPlanes,1
mov bmi.bmiHeader.biBitCount,24
mov bmi.bmiHeader.biCompression,BI_RGB
invoke CreateDIBSection,hTempDC,ADDR bmi,DIB_RGB_COLORS,ADDR ppvBits ,0,0
mov hMemBmp,eax
invoke SelectObject,hTempDC,hMemBmp
invoke GetObject,hMemBmp,SIZEOF BITMAP,ADDR bmp
invoke BitBlt,hTempDC,0,0,bmp.bmWidth,bmp.bmHeight,hTransDC,0,0,SRCCOPY

invoke RtlZeroMemory,ADDR lpBITMAPFILEHEADER,SIZEOF BITMAPFILEHEADER
invoke RtlZeroMemory,ADDR lpBITMAPINFOHEADER,SIZEOF BITMAPINFOHEADER
mov lpBITMAPFILEHEADER.bfType,"MB"

mov eax,bmp.bmWidthBytes
imul bmp.bmHeight
mov DataSize,eax

add eax,54
mov lpBITMAPFILEHEADER.bfSize,eax
mov lpBITMAPFILEHEADER.bfReserved1,0
mov lpBITMAPFILEHEADER.bfReserved2,0
mov lpBITMAPFILEHEADER.bfOffBits,54
mov lpBITMAPINFOHEADER.biSize,40
mov eax,bmp.bmWidth
mov lpBITMAPINFOHEADER.biWidth,eax
mov eax,bmp.bmHeight
mov lpBITMAPINFOHEADER.biHeight,eax
mov lpBITMAPINFOHEADER.biPlanes,1
mov lpBITMAPINFOHEADER.biBitCount,24
mov lpBITMAPINFOHEADER.biCompression,0 ;BI_RGB
mov lpBITMAPINFOHEADER.biClrImportant,0
mov lpBITMAPINFOHEADER.biXPelsPerMeter,0
mov lpBITMAPINFOHEADER.biYPelsPerMeter,0
mov lpBITMAPINFOHEADER.biClrUsed,0
mov eax,DataSize
mov lpBITMAPINFOHEADER.biSizeImage,eax

invoke CreateFile, pszFile, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile,eax

invoke WriteFile,hFile,OFFSET lpBITMAPFILEHEADER,
SIZEOF BITMAPINFOHEADER + SIZEOF BITMAPFILEHEADER,
ADDR cbWrite,NULL

invoke WriteFile,hFile,ppvBits,DataSize,ADDR cbWrite,NULL

invoke CloseHandle,hFile
invoke DeleteDC,hTempDC
invoke DeleteObject,hMemBmp

ret
WriteBitmapToFile endp
Posted on 2003-08-13 10:24:47 by donkey
Well, the first attempt above had some fundamental flaws. It did not translate the colors properly in some cases. This version will save as 4,8 or 24 bit.

There is no longer a need to have the BITMAPFILEHEADER or BITMAPINFOHEADER structures at all.

Syntax:

invoke WriteIMLtoFile, hIml, cClrBits, hFile

hIml = Handle to the image list
cClrBits = Number of bits of color depth (4,8,24)
hFile = the handle to an open file used to save the imagelist

WriteIMLtoFile Proc hIml:DWORD,cClrBits:DWORD,hFile:DWORD

LOCAL cbWrite :DWORD
LOCAL bmp :BITMAP
LOCAL dwNumColors :DWORD
LOCAL hDC :DWORD
LOCAL hDC_DIB :DWORD
LOCAL nImages :DWORD
LOCAL ImageWidth :DWORD
LOCAL pBMI :DWORD
LOCAL RGBQuadSize :DWORD
LOCAL DataSize :DWORD
LOCAL OldObject :DWORD
LOCAL pBFH :DWORD
LOCAL hBmp :DWORD
LOCAL pData :DWORD
LOCAL pRGBQuad :DWORD
LOCAL imgX :DWORD
LOCAL imgY :DWORD

invoke ImageList_GetIconSize,hIml,ADDR imgX,ADDR imgY

invoke ImageList_GetImageCount,hIml
mov nImages,eax
imul imgX
mov ImageWidth,eax

.IF nImages < 1
invoke MessageBox,hDlg,OFFSET NoImages,OFFSET GenTitle,MB_OK
ret
.endif

; Calculate Data size
mov eax,ImageWidth
imul imgX
imul cClrBits
shr eax,3
mov DataSize,eax

; Calculate size of RGBQUAD array
mov ecx,cClrBits
mov eax,1
shl eax,cl
mov dwNumColors,eax
mov edx,SIZEOF RGBQUAD
imul edx
mov RGBQuadSize,eax

; Create a memory buffer
.IF cClrBits == 24 ; There is no RGBQUAD array for 24 bit
mov RGBQuadSize,0
mov eax,0
.ENDIF
add eax,SIZEOF BITMAPINFOHEADER
add eax,SIZEOF BITMAPFILEHEADER
add eax,DataSize
invoke GlobalAlloc,GMEM_FIXED,eax

mov pBFH,eax
add eax,SIZEOF BITMAPFILEHEADER
mov pBMI,eax
add eax,SIZEOF BITMAPINFOHEADER
mov pRGBQuad,eax
add eax,RGBQuadSize
mov pData,eax

invoke GetDC,hDlg
mov hDC,eax
invoke CreateCompatibleDC,hDC
mov hDC_DIB,eax
invoke CreateCompatibleBitmap,hDC,ImageWidth,imgY
mov hBmp,eax
invoke ReleaseDC,hDlg,hDC

invoke SelectObject,hDC_DIB,hBmp
mov OldObject,eax

mov edi,0
mov esi,0
.REPEAT
invoke ImageList_Draw, hIml, edi, hDC_DIB, esi, 0, ILD_NORMAL
inc edi
add esi,imgX
.UNTIL edi == nImages

invoke SelectObject,hDC_DIB,OldObject

invoke GdiFlush

invoke GetObject,hBmp,SIZEOF BITMAP,ADDR bmp

mov edi,pBMI
mov [edi].BITMAPINFO.bmiHeader.biXPelsPerMeter,0
mov [edi].BITMAPINFO.bmiHeader.biYPelsPerMeter,0
mov eax,dwNumColors
mov [edi].BITMAPINFO.bmiHeader.biClrUsed,eax
mov [edi].BITMAPINFO.bmiHeader.biClrImportant,0

mov [edi].BITMAPINFO.bmiHeader.biSize,SIZEOF BITMAPINFOHEADER
mov eax,bmp.bmWidth
mov [edi].BITMAPINFO.bmiHeader.biWidth,eax
mov eax,bmp.bmHeight
mov [edi].BITMAPINFO.bmiHeader.biHeight,eax
mov [edi].BITMAPINFO.bmiHeader.biPlanes,1
mov [edi].BITMAPINFO.bmiHeader.biCompression,BI_RGB
mov eax,cClrBits
mov [edi].BITMAPINFO.bmiHeader.biBitCount,ax
mov eax,DataSize
mov [edi].BITMAPINFO.bmiHeader.biSizeImage,eax

invoke GetDIBits, hDC_DIB, hBmp, 0, imgY, pData, pBMI, DIB_RGB_COLORS

mov esi,pBFH
mov [esi].BITMAPFILEHEADER.bfType,"MB"
mov eax,RGBQuadSize
add eax,DataSize
add eax,SIZEOF BITMAPINFOHEADER + SIZEOF BITMAPFILEHEADER
mov [esi].BITMAPFILEHEADER.bfSize,eax
mov [esi].BITMAPFILEHEADER.bfReserved1,0
mov [esi].BITMAPFILEHEADER.bfReserved2,0
mov eax,RGBQuadSize
add eax,sizeof BITMAPFILEHEADER
add eax,sizeof BITMAPINFOHEADER
mov [esi].BITMAPFILEHEADER.bfOffBits,eax

invoke GlobalSize,pBFH
mov ecx,eax
invoke WriteFile,hFile,pBFH,ecx,ADDR cbWrite,NULL

invoke DeleteDC,hDC_DIB
invoke GlobalFree,pBFH
invoke DeleteObject,hBmp

invoke SetForegroundWindow,hDlg

ret
WriteIMLtoFile endp
Posted on 2003-08-20 15:51:32 by donkey