SAVEBMP.C

/******************************Module*Header*******************************\ 
* Module Name: savebmp.c
*
*
* Created: 06-Jan-1992 10:59:36
*
* Copyright 1993 - 1998 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);

while(sizTmp--)
{
*(((PBYTE)pjTmp)++) = *((pjTmpBmi)++);
}
}

//
// 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