Hi there,
snippet below is a port from MSDN. It already works.
But i'm a bit unhappy with 2 things :
Had to change my win32api.inc ( GetDIBits ).
Is it possible to declare a function a second time
outside win32api.inc ?
Handling 16 bit Bitmaps differs a lot from the MSDN sample.
Is it ok ?
Basic code :
Microsoft's C source :
------------------
snippet below is a port from MSDN. It already works.
But i'm a bit unhappy with 2 things :
Had to change my win32api.inc ( GetDIBits ).
Is it possible to declare a function a second time
outside win32api.inc ?
Handling 16 bit Bitmaps differs a lot from the MSDN sample.
Is it ok ?
Basic code :
Code:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' GENERATED BY ManageIncludes 09.04.2001 ' file : paintbx2.bas ' extracts function BMPsave ( BYVAL hBmp AS LONG, BYVAL hPalette AS LONG, sFileName AS STRING, flag AS LONG ) AS LONG ' function MemCopyD( BYVAL src AS LONG, BYVAL dst AS LONG, BYVAL ln AS LONG) AS LONG ' sub BMPsetPalette( BYVAL hDC AS LONG, BYVAL hPalette AS LONG ) ' from E:\pbdll60\datalink\controls\inc\paintbox.bas SUB BMPsetPalette( BYVAL hDC AS LONG, BYVAL hPalette AS LONG ) IF ISFALSE hPalette THEN EXIT SUB SelectPalette hDC, hPalette, %FALSE RealizePalette hDC END SUB FUNCTION MemCopyD(BYVAL src AS LONG, _ BYVAL dst AS LONG, _ BYVAL ln AS LONG) AS LONG #REGISTER NONE ! cld ! mov esi, src ! mov edi, dst ! mov ecx, ln ! shr ecx, 2 ! rep movsd ! mov ecx, ln ! and ecx, 3 ! rep movsb FUNCTION = 0 END FUNCTION ''*****************************Public*Routine******************************\ ' function BmpSave ' requires changes in win32api.inc : ' old : ' DECLARE FUNCTION GetDIBits LIB "GDI32.DLL" ALIAS "GetDIBits" (BYVAL aHDC AS LONG, BYVAL hBitmap AS LONG, BYVAL nStartScan AS LONG, BYVAL nNumScans AS LONG, lpBits AS ANY, lpBI AS BITMAPINFO, BYVAL wUsage AS LONG) AS LONG ' new : ' DECLARE FUNCTION GetDIBits LIB "GDI32.DLL" ALIAS "GetDIBits" (BYVAL aHDC AS LONG, BYVAL hBitmap AS LONG, BYVAL nStartScan AS LONG, BYVAL nNumScans AS LONG, BYVAL lpBits AS LONG, BYVAL lpBI AS LONG, BYVAL wUsage AS LONG) AS LONG '**************************************************************************/ FUNCTION BmpSave ( BYVAL hBmp AS LONG, BYVAL hPalette AS LONG, BYVAL flag AS LONG sFileName AS STRING ) AS LONG LOCAL hFile AS LONG LOCAL hTmpBmp AS LONG LOCAL hBmpOld AS LONG LOCAL bfh AS BITMAPFILEHEADER LOCAL pbmi AS LONG '' LOCAL bmi AS BITMAPINFO LOCAL sizBMI AS LONG LOCAL hdc AS LONG LOCAL Success AS LONG LOCAL pBits AS LONG IF ISFALSE hBmp THEN EXIT FUNCTION IF ISFALSE hPalette THEN EXIT FUNCTION hdc = getDC ( %hWnd_Desktop ) IF ISFALSE hdc THEN EXIT FUNCTION BMPsetPalette hDC, hPalette Success = %true '' '' LET the graphics engine TO retrieve the dimension of the bitmap FOR us '' GetDIBits uses the SIZE TO determine IF it's BITMAPCOREINFO or BITMAPINFO '' IF BitCount != 0, color table will be retrieved bmi.bmiHeader.biSize = SIZEOF(bmi.bmiHeader) '' GDI need this TO work bmi.bmiHeader.biBitCount = 0 '' don't get the color table IF ISFALSE GetDIBits (hDC, hBmp, 0, 0, 0, VARPTR( bmi ), %DIB_RGB_COLORS) THEN ReleaseDC %hWnd_DESKTOP, hDC EXIT FUNCTION END IF '' Now that we know the SIZE of the IMAGE, alloc enough memory TO retrieve '' the actual bits pBits = GlobalAlloc( %GMEM_FIXED, bmi.bmiHeader.biSizeImage ) IF ISFALSE pBits THEN ReleaseDC %hWnd_DESKTOP, hDC EXIT FUNCTION END IF '' Note: 24 bits per pixel has no COLOR table. So, we don't have to '' allocate memory FOR retrieving that. Otherwise, we do. SELECT CASE bmi.bmiHeader.biBitCount '' has COLOR table CASE 24 : sizBMI = LEN(BITMAPINFOHEADER) CASE 16 : sizBMI = LEN( BITMAPINFO ) CASE 32 : sizBMI = LEN(BITMAPINFOHEADER) + LEN(RGBQUAD) * 3 CASE ELSE LOCAL i AS LONG i = 1 SHIFT LEFT i, bmi.bmiHeader.biBitCount sizBMI = LEN(BITMAPINFOHEADER) + 4 * i END SELECT '' '' Allocate memory FOR BITMAPINFOHEADER '' and COLOR table IF it is NOT 24bpp... '' pbmi = GlobalAlloc( %GMEM_FIXED OR %GMEM_ZEROINIT, sizBMI ) IF ISFALSE pbmi THEN Success = %FALSE : GOTO ErrExit1 '' Now that we've a bigger chunk of memory, let's copy the Bitmap '' info header DATA over memCopyD VARPTR(bmi), pbmi, LEN ( BITMAPINFOHEADER ) '' '' fill IN the info FOR the BitmapFileHeader '' bfh.bfType = CVWRD("BM") bfh.bfSize = LEN(bfh) + LEN(BITMAPINFOHEADER) + sizBMI + bmi.bmiHeader.biSizeImage bfh.bfOffBits = LEN(bfh) + sizBMI '' Bitmap can't be selected into a DC when calling GetDIBits '' Assume that the hDC is the DC where the bitmap would have been selected '' IF indeed it has been selected '' hTmpBmp = CreateCompatibleBitmap( hDC, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight ) IF ISFALSE hTmpBmp THEN Success = %FALSE : GOTO ErrExit3 hBmpOld = SelectObject(hDC, hTmpBmp) IF ISFALSE GetDIBits(hDC, hBmp, 0, bmi.bmiHeader.biHeight, pBits, pbmi, %DIB_RGB_COLORS) THEN _ Success = %FALSE : GOTO ErrExit4 '' '' LET's open the file and get ready for writing '' hFile = FREEFILE OPEN sFileName FOR OUTPUT AS hFile IF ERR THEN Success = %FALSE : GOTO ErrExit4 PRINT #hfile, PEEK$( VARPTR( bfh ), LEN (bfh) ) & _ ' BitmapFileHeader PEEK$( pbmi, sizBMI ) & _ ' BitmapInfoHeader AND COLOR table, IF ANY PEEK$( pBits, bmi.bmiHeader.biSizeImage ) ' WRITE the bits also IF ERR THEN Success = %FALSE : GOTO ErrExit4 ErrExit4: SelectObject hDC, hBmpOld DeleteObject hTmpBmp ErrExit3: CLOSE hFile ErrExit2: GlobalFree pbmi ErrExit1: GlobalFree pBits ReleaseDC %hWnd_DESKTOP, hDC FUNCTION = Success END FUNCTION
Microsoft's C source :
Code:
/******************************Module*Header*******************************\ * Module Name: savebmp.c * * * Created: 06-Jan-1992 10:59:36 * * Copyright (C) 1993-1996 Microsoft Corporation * * Contains the main routine, SaveBitmapFile, for saving a DDB into file * in DIB format. * * Dependencies: * * (#defines) * (#includes) * #include <windows.h> * #include "jtypes.h" * \**************************************************************************/ #include <windows.h> #include "julia.h" extern HPALETTE ghPal; extern HWND ghwndMain; extern char gtext[256]; BOOL SaveBitmapFile(HDC, HBITMAP, PSTR); // void ErrorOut(char errstring[30]); /******************************Public*Routine******************************\ * SaveBitmapFile * * * Effects: Save pInfo->hBmpSaved into disk specified by pszFileName * * Warnings: assumes hBmpSaved is not selected into window's DC other than * pInfo->hwnd's DC * \**************************************************************************/ BOOL SaveBitmapFile(HDC hDC, HBITMAP hBmp, PSTR pszFileName) { int hFile; OFSTRUCT ofReOpenBuff; HBITMAP hTmpBmp, hBmpOld; BOOL bSuccess; BITMAPFILEHEADER bfh; PBITMAPINFO pbmi; PBYTE pBits; BITMAPINFO bmi; PBYTE pjTmp, pjTmpBmi; ULONG sizBMI; bSuccess = TRUE; #if 0 if (ghPal) { SelectPalette(hDC, ghPal, FALSE); RealizePalette(hDC); } #endif if (!hBmp) { MessageBox(ghwndMain, GetStringRes (IDS_NO_BITMAP_TO_SAVE), NULL, MB_OK); return FALSE; } // // Let the graphics engine to retrieve the dimension of the bitmap for us // GetDIBits uses the size to determine if it's BITMAPCOREINFO or BITMAPINFO // if BitCount != 0, color table will be retrieved // bmi.bmiHeader.biSize = 0x28; // GDI need this to work bmi.bmiHeader.biBitCount = 0; // don't get the color table if ((GetDIBits(hDC, hBmp, 0, 0, (LPSTR)NULL, &bmi, DIB_RGB_COLORS)) == 0) { return FALSE; } // // Now that we know the size of the image, alloc enough memory to retrieve // the actual bits // if ((pBits = (PBYTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, bmi.bmiHeader.biSizeImage)) == NULL) { return FALSE; } // // Note: 24 bits per pixel has no color table. So, we don't have to // allocate memory for retrieving that. Otherwise, we do. // pbmi = &bmi; // assume no color table switch (bmi.bmiHeader.biBitCount) { case 24: // has color table sizBMI = sizeof(BITMAPINFOHEADER); break; case 16: case 32: sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3; break; default: sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*(1<<bmi.bmiHeader.biBitCount); break; } // // Allocate memory for color table if it is not 24bpp... // if (sizBMI != sizeof(BITMAPINFOHEADER)) { ULONG sizTmp; // // I need more memory for the color table // if ((pbmi = (PBITMAPINFO)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizBMI )) == NULL) { bSuccess = FALSE; goto ErrExit1; } // // Now that we've a bigger chunk of memory, let's copy the Bitmap // info header data over // pjTmp = (PBYTE)pbmi; pjTmpBmi = (PBYTE)&bmi; sizTmp = sizeof(BITMAPINFOHEADER); #ifdef __LCC__ memcpy(pjTmp,pjTmpBmi,sizTmp); #else while(sizTmp--) { *(((PBYTE)pjTmp)++) = *((pjTmpBmi)++); } #endif } // // Let's open the file and get ready for writing // if ((hFile = OpenFile(pszFileName, (LPOFSTRUCT)&ofReOpenBuff, OF_CREATE | OF_WRITE)) == -1) { MessageBox(ghwndMain, GetStringRes(IDS_FILE_OPEN_FAILED), NULL, MB_OK); goto ErrExit2; } // // But first, fill in the info for the BitmapFileHeader // bfh.bfType = 0x4D42; // 'BM' bfh.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizBMI+ pbmi->bmiHeader.biSizeImage; bfh.bfReserved1 = bfh.bfReserved2 = 0; bfh.bfOffBits = sizeof(BITMAPFILEHEADER)+sizBMI; // // Write out the file header now // if (_lwrite(hFile, (LPSTR)&bfh, sizeof(BITMAPFILEHEADER)) == -1) { bSuccess = FALSE; goto ErrExit3; } // // Bitmap can't be selected into a DC when calling GetDIBits // Assume that the hDC is the DC where the bitmap would have been selected // if indeed it has been selected // if (hTmpBmp = CreateCompatibleBitmap(hDC, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight)) { hBmpOld = SelectObject(hDC, hTmpBmp); if ((GetDIBits(hDC, hBmp, 0, pbmi->bmiHeader.biHeight, (LPSTR)pBits, pbmi, DIB_RGB_COLORS))==0){ bSuccess = FALSE; goto ErrExit4; } } else { MessageBox(ghwndMain, GetStringRes (IDS_BITMAP_NOT_CREATED), NULL, MB_OK); bSuccess = FALSE; goto ErrExit3; } // // Now write out the BitmapInfoHeader and color table, if any // if (_lwrite(hFile, (LPSTR)pbmi, sizBMI) == -1) { bSuccess = FALSE; goto ErrExit4; } // // write the bits also // if (_lwrite(hFile, (LPSTR)pBits, pbmi->bmiHeader.biSizeImage) == -1) { bSuccess = FALSE; goto ErrExit4; } ErrExit4: SelectObject(hDC, hBmpOld); DeleteObject(hTmpBmp); ErrExit3: _lclose(hFile); ErrExit2: GlobalFree(pbmi); ErrExit1: GlobalFree(pBits); return bSuccess; } #if 0 /************************************************************************ * void ErrorOut(char errstring[30]) * * Purpose: Print out an meainful error code by means of * GetLastError and printf * * Inputs: errstring - the action that failed, passed by the * calling proc. * * Returns: none * * Calls: GetLastError * * History: * 09-13-91 Pete Grey Created. * \************************************************************************/ void ErrorOut(char errstring[30]) { DWORD Error; CHAR str[80]; Error= GetLastError(); wsprintf((LPSTR) str, "Error on %s = %d\n", errstring, Error); OutputDebugString(str); } #endif
------------------
Comment