www.pudn.com > VC_CaptureTest.rar > CBitmapEx.cpp


// CBITMAPEX.CPP 
// CBitmap extention 
// 
// (c) Vadim Gorbatenko, 1997-99  
// gvv@mail.tomsknet.ru 
// All rights reserved 
// 
//___________________________________________________________________________________________ 
 
#include "stdafx.h" 
#include "CBitmapEx.h" 
 
#define WIDTHBYTES(bits)        (((bits) + 31) / 32 * 4) 
#define PALETTESIZE(lpbi)		(_DIBNumColors((LPBITMAPINFOHEADER) lpbi)* sizeof (RGBQUAD)) 
#define DIBCOLORS(lpbi)         ((LPRGBQUAD)((LPBYTE)(lpbi) + (int)(lpbi)->biSize)) 
#define DIBPTR(lpbi)            (LPBYTE)(DIBCOLORS((LPBITMAPINFOHEADER)lpbi) + (UINT)((LPBITMAPINFOHEADER)lpbi)->biClrUsed) 
 
HANDLE	_dibFromBitmap(HBITMAP hBitmap); 
BOOL	_writeDib(HANDLE hdib, LPCSTR filename); 
INT		_DIBNumColors (LPBITMAPINFOHEADER  lpbi); 
 
 
CBitmapEx::CBitmapEx():CBitmap() 
{ 
	_modBMP= NULL; 
 
} 
 
 
CBitmapEx::~CBitmapEx() 
{ 
	EndModify();//just in case:) 
} 
 
HANDLE	CBitmapEx::DibFromBitmap() 
	{return _dibFromBitmap((HBITMAP)GetSafeHandle());} 
 
HANDLE	CBitmapEx::DibFromBitmap(HBITMAP hb)	 
	{return _dibFromBitmap(hb);} 
 
BOOL	CBitmapEx::CreateFromDib(LPBITMAPINFO lpBi) 
{ 
	if(!lpBi || _modBMP)	return FALSE; 
	if(((LPBITMAPINFOHEADER)lpBi)->biCompression != BI_RGB) 
			return FALSE; 
	 
	if(GetSafeHandle( )) 
	{ 
		 
		//check existing size 
		BITMAP bmp; 
		GetObject(sizeof BITMAP, &bmp); 
		CSize sz = GetSize(); 
 
		if(bmp.bmWidth == ((LPBITMAPINFOHEADER)lpBi)->biWidth && 
			bmp.bmHeight == ((LPBITMAPINFOHEADER)lpBi)->biHeight) 
		{ 
			// special case: we don't  need to destroy existing 
			// DDB, just rewrite bits. 
			// Note: we must be sure, the color resolution is 
			// not changed, so, let's test it: 
			HDC    hdc = ::GetDC(NULL); 
			int    hdc_bits = GetDeviceCaps(hdc,BITSPIXEL); 
			if(hdc_bits == bmp.bmBitsPixel) 
			{ 
			//ok to set new bits 
			BOOL ret = ::SetDIBits( 
						hdc,					    // handle to device context 
						(HBITMAP)GetSafeHandle( ), // handle to bitmap 
						0,				   // starting scan line 
						bmp.bmHeight,    // number of scan lines 
					    DIBPTR(lpBi),   // array of bitmap bits 
						lpBi,			// address of structure with bitmap data 
						DIB_RGB_COLORS // type of color indexes to use 
						) == bmp.bmHeight; 
  
			::ReleaseDC(NULL,hdc); 
			return ret; 
			} 
			else 
				::ReleaseDC(NULL,hdc); 
		} 
		//delete existing bitmap:( 
		DeleteObject(); 
	} 
	//create a new DDB 
    HDC         hdc; 
    HBITMAP     hbm; 
 
	//Create DDB 
    hdc = ::GetDC(NULL); 
    hbm = CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)lpBi,(LONG)CBM_INIT, 
                	DIBPTR(lpBi), lpBi, DIB_RGB_COLORS	); 
 
    ::ReleaseDC(NULL,hdc); 
	if(!hbm)	return FALSE; 
 
	DeleteObject();//delete attached bitmap 
 
	if(!Attach( (HGDIOBJ) hbm )) 
		{::DeleteObject((HGDIOBJ)hbm); return FALSE;} 
 
	return TRUE; 
 
} 
 
#define sfiltr	"Image files (*.BMP)|*.BMP||" 
#define sext	"BMP" 
#define smask	NULL 
 
BOOL CBitmapEx::Open(LPCSTR filename, LPCSTR DialogTitle) 
{ 
 
	if(GetSafeHandle( )) 
		return FALSE; 
	CString Path; 
 
	if(!filename) 
	{ 
	CFileDialog openAs( TRUE,sext, 
						smask, 	OFN_NOCHANGEDIR|OFN_FILEMUSTEXIST| 
						OFN_PATHMUSTEXIST, 
						sfiltr);  
	 
	//substitude dialog title 
	if(DialogTitle) 
		openAs.m_ofn.lpstrTitle=DialogTitle; 
	 
		if(openAs.DoModal()==IDOK) 
		   
			 Path=openAs.GetPathName( ); 
		  	 
		else return FALSE; 
	} 
	else Path=	filename; 
 
	CFile file; 
      
	if(!file.Open(Path,CFile::modeRead|CFile::typeBinary)) 
		return FALSE; 
 
   BITMAPFILEHEADER   bmfHeader; 
   LPBITMAPINFOHEADER lpbi; 
   DWORD              dwBitsSize; 
   HANDLE             hDIB; 
 
 
   // get length of DIB in bytes for use when reading 
	dwBitsSize = file.GetLength(); 
 
	BOOL ret=TRUE; 
	TRY 
	{ 
		 
	  if( file.Read(&bmfHeader, sizeof (BITMAPFILEHEADER))!= 
	  	sizeof (BITMAPFILEHEADER)|| 
	  	bmfHeader.bfType!=((WORD) ('M' << 8) | 'B')) ret=FALSE; 
 
	} 
	CATCH (CFileException, e) 
	{ 
		ret=FALSE;		 
		 
	} 
	END_CATCH 
 
	if(!ret)	return FALSE; 
 
   // Allocate memory for DIB 
	dwBitsSize -= sizeof(BITMAPFILEHEADER); 
   	 
   	hDIB = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize); 
 
	if(!hDIB)	return FALSE; 
	 
	lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 
	TRY 
	{ 
		if(file.ReadHuge((LPVOID)lpbi, dwBitsSize)!=dwBitsSize) 
			ret=FALSE; 
	} 
	CATCH (CFileException, e) 
	{ 
		ret=FALSE;		 
		 
	} 
	END_CATCH 
      file.Close(); 
       
 
	if(!ret) 
		{GlobalUnlock (hDIB); GlobalFree (hDIB); return FALSE;} 
 
     
 
    HDC         hdc; 
    HBITMAP     hbm; 
 
	//Create DDB 
    hdc = ::GetDC(NULL); 
    hbm = CreateDIBitmap(hdc,(LPBITMAPINFOHEADER)lpbi,(LONG)CBM_INIT, 
                	DIBPTR(lpbi),(LPBITMAPINFO)lpbi,DIB_RGB_COLORS	); 
 
    ::ReleaseDC(NULL,hdc); 
 
	GlobalUnlock (hDIB); 
	GlobalFree (hDIB);  
 
	if(!hbm) 
	       {return FALSE;} 
 
	if(GetSafeHandle( )) 
		DeleteObject(); 
 
	if(!Attach( (HGDIOBJ) hbm )) 
		{::DeleteObject((HGDIOBJ)hbm); return FALSE;} 
	 
 
	return ret; 
} 
 
BOOL CBitmapEx::Save(LPCSTR filename, LPCSTR DialogTitle) 
{ 
	 
	if(!GetSafeHandle( )) 
		return FALSE; 
	CString Path; 
	 
	if(!filename) 
	{ 
 
	CFileDialog saveAs( FALSE,sext, 
				smask,	OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 
				sfiltr);  
	 
	if(DialogTitle) 
		saveAs.m_ofn.lpstrTitle=DialogTitle; 
 
	if(saveAs.DoModal()==IDOK) 
		Path=saveAs.GetPathName( ); 
		  	 
	else return FALSE; 
	} 
	else	Path=filename; 
 
	CFile file; 
     
	if(!file.Open((LPCSTR)Path,CFile::modeCreate|CFile::modeWrite|CFile::typeBinary)) 
		return FALSE; 
 
	HANDLE hdib=_dibFromBitmap((HBITMAP)GetSafeHandle( )); 
 
	if(!hdib)	return FALSE; 
 
    BITMAPFILEHEADER	hdr; 
    LPBITMAPINFOHEADER  lpbi; 
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock (hdib); 
 
    // Fill in the fields of the file header  
    hdr.bfType		= ((WORD) ('M' << 8) | 'B');  // "BM" 
    hdr.bfSize		= GlobalSize (hdib) + sizeof (BITMAPFILEHEADER); 
    hdr.bfReserved1     = 0; 
    hdr.bfReserved2     = 0; 
    hdr.bfOffBits       = (DWORD)sizeof(BITMAPFILEHEADER) + lpbi->biSize + 
                          PALETTESIZE((LPSTR)lpbi); 
 
	BOOL ret=TRUE; 
	TRY 
	{    
		file.Write((LPSTR)&hdr, sizeof (BITMAPFILEHEADER)); 
		file.WriteHuge((LPSTR)lpbi, GlobalSize (hdib)); 
	} 
	CATCH (CFileException, e) 
	{ 
		ret=FALSE;		 
		 
	} 
	END_CATCH 
    
   file.Close(); 
    GlobalUnlock (hdib); 
     GlobalFree (hdib); 
    
	 return ret; 
} 
 
 
// Get DC for "in-memory" drawing 
CDC	*CBitmapEx::BegingModify() 
{ 
	CWnd* dtw= CWnd::GetDesktopWindow( ); 
	CDC *dc=dtw->GetDC(); 
	 
	if(_modDC.m_hDC)	 
		_modDC.DeleteDC( ); 
	 
	_modDC.CreateCompatibleDC(dc); 
	 
	_modBMP = _modDC.SelectObject(this); 
	 
	dtw->ReleaseDC(dc); 
	return &_modDC; 
 
} 
// Create color bitmap 
BOOL 	CBitmapEx::CreateColor(int dx, int dy) 
{ 
	if(GetSafeHandle())	return FALSE; 
	HDC hScrDC	= ::GetDC(NULL); 
	HDC hMemDC	= ::CreateCompatibleDC(hScrDC); 
 
	BOOL r = CreateCompatibleBitmap(CDC::FromHandle(hScrDC), dx, dy); 
  	 
	::DeleteDC(hMemDC); 
	::ReleaseDC(NULL,hScrDC); 
	return r; 
} 
 
// Create monocolor bitmap 
BOOL 	CBitmapEx::CreateMono(int dx, int dy) 
{ 
	if(GetSafeHandle())	return FALSE; 
	CDC mDC; 
	mDC.CreateCompatibleDC(NULL); //for mono! 
 
	BOOL r = CreateCompatibleBitmap( &mDC, dx, dy ); 
	 
	mDC.DeleteDC( ); 
	return r; 
} 
 
// This was the first extention i've done! :))) 
CSize CBitmapEx::GetSize() 
{ 
	BITMAP bmp; 
	if(!GetSafeHandle())	return CSize(0,0); 
	GetObject(sizeof BITMAP, &bmp); 
	return CSize(bmp.bmWidth,bmp.bmHeight); 
} 
 
void 	CBitmapEx::BitBlt(CDC *dc_to, POINT at, DWORD rop) 
{ 
	CSize sz=GetSize(); 
 
	dc_to->BitBlt(at.x,at.y, sz.cx, sz.cy,  
					BegingModify(),//source context 
					0,0,  rop); 
	EndModify(); 
} 
 
void 	CBitmapEx::StretchBlt(CDC *dc_to, CRect to, DWORD rop) 
{ 
	CSize sz=GetSize(); 
	dc_to->StretchBlt(to.left, to.top,  
			to.Width(), to.Height(), 
			BegingModify(),//source context 
			0,0, 
			sz.cx, sz.cy,   
			rop); 
	EndModify(); 
} 
 
void	CBitmapEx::EndModify() 
{ 
    if(_modDC.m_hDC && _modBMP) 
		_modDC.SelectObject(_modBMP); 
	if(_modDC.m_hDC)	 
		_modDC.DeleteDC( ); 
	_modBMP = NULL; 
} 
 
//Copy the other bitmap to this  
BOOL CBitmapEx::CopyRect(CBitmap& bmp, CRect& rc) 
{ 
	 
	CWnd* dtw= CWnd::GetDesktopWindow( ); 
	CDC *dc=dtw->GetDC(); 
	 
 
	CDC cdc; 
	CDC cdc2; 
	 
	cdc2.CreateCompatibleDC(dc); 
	cdc.CreateCompatibleDC(dc); 
	 
	bmp.CreateCompatibleBitmap( dc, rc.Width(), rc.Height()); 
	 
	CBitmap *ob2=cdc2.SelectObject(&bmp); 
	 
	CBitmap *ob=cdc.SelectObject(this); 
 
	cdc2.BitBlt( 0, 0, rc.Width(), rc.Height(),  
			&cdc, rc.left, rc.top, SRCCOPY ); 
	 
	cdc2.SelectObject(ob2); 
	 
	cdc.SelectObject(ob); 
	 
	dtw->ReleaseDC(dc); 
	return TRUE; 
} 
 
DWORD	CBitmapEx::DibImageSize(HANDLE hDIB) 
{ 
	if(!hDIB)	return 0; 
	LPBITMAPINFOHEADER lpbmInfoHdr=(LPBITMAPINFOHEADER) GlobalLock (hDIB); 
	DWORD sz=sizeof (BITMAPINFOHEADER)+PALETTESIZE ((LPSTR) lpbmInfoHdr) + lpbmInfoHdr->biSizeImage; 
	GlobalUnlock(hDIB); 
	return sz; 
} 
 
///////////////////////////////////////////////// 
// DDB->DIB 
HANDLE _dibFromBitmap(HBITMAP hBitmap) 
{ 
   HDC                  hDC; 
   WORD			wBits; 
   HPALETTE 		hPal=NULL; 
   BITMAP               bm; 
   BITMAPINFOHEADER     bi; 
   BITMAPINFOHEADER     *lpbi; 
   DWORD                dwLen; 
   HANDLE               hDIB; 
 
   if (!hBitmap) 
      return NULL; 
 
   ::GetObject (hBitmap, sizeof (bm), (LPSTR)&bm); 
 
    wBits =  bm.bmBitsPixel; 
 
   bi.biSize               = sizeof (BITMAPINFOHEADER); 
   bi.biWidth              = bm.bmWidth; 
   bi.biHeight             = bm.bmHeight; 
   bi.biPlanes             = 1; 
   bi.biBitCount           = wBits; 
   bi.biCompression        = BI_RGB; 
   bi.biSizeImage          = 0; 
   bi.biXPelsPerMeter      = 0; 
   bi.biYPelsPerMeter      = 0; 
   bi.biClrUsed            = 0; 
   bi.biClrImportant       = 0; 
 
   dwLen  = bi.biSize + PALETTESIZE ((LPSTR) &bi); 
   hDIB	  = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,dwLen); 
 
   if (!hDIB) 
      return NULL; 
 
   lpbi   = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 
   *lpbi  = bi; 
    
   HWND hWnd= GetFocus(); 
    
   if(!hWnd) 
   {//load default system palette 
   	hPal   = (HPALETTE)GetStockObject (DEFAULT_PALETTE); 
   	hDC    = GetDC (NULL); 
   	hPal   = SelectPalette (hDC, hPal, FALSE); 
   	RealizePalette(hDC); 
	} 
   else 
   	{ 
	//or get palette from focused window 
	HDC hDCw    = GetDC (hWnd); 
	hPal   = SelectPalette (hDCw, (HPALETTE)GetStockObject (DEFAULT_PALETTE), FALSE); 
   	hDC    = GetDC (NULL); 
   	hPal   = SelectPalette (hDC, hPal, FALSE); 
	RealizePalette(hDC); 
	SelectPalette (hDCw, hPal, FALSE); 
	ReleaseDC(hWnd,hDCw); 
	} 
 
   // calculate the biSizeImage 
   GetDIBits (hDC, 
              hBitmap, 
              0, 
              (WORD) bi.biHeight, 
              NULL, 
              (LPBITMAPINFO) lpbi, 
              DIB_RGB_COLORS); 
 
   bi = *lpbi; 
   GlobalUnlock(hDIB); 
 
   // If the driver did not fill in the biSizeImage field,  
   // make one up 
 
   if (bi.biSizeImage == 0) 
      { 
      bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * wBits) * bm.bmHeight; 
 
      if (bi.biCompression != BI_RGB) 
         bi.biSizeImage = (bi.biSizeImage * 3) / 2; 
      } 
 
 
   DWORD sl =dwLen; 
   HGLOBAL hPtr =hDIB; 
   dwLen = bi.biSize + PALETTESIZE((LPSTR)&bi) + bi.biSizeImage; 
 
	// if you have plans to use DDE or clipboard, you have 
    // to allocate memory with GMEM_DDESHARE flag 
   if(!(hDIB = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,dwLen)))  
   { 
      SelectPalette(hDC,hPal,FALSE); 
      ReleaseDC(NULL,hDC); 
	  GlobalFree(hPtr); 
	  return NULL;} 
 
   lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 
	LPBITMAPINFOHEADER lpS=(LPBITMAPINFOHEADER)GlobalLock(hPtr); 
	 
	CopyMemory(lpbi,lpS,sl); 
	GlobalUnlock(hPtr); 
	GlobalFree(hPtr); 
 
 
    // actually fill lpBits 
   if (GetDIBits( hDC, 
         hBitmap, 
         0, 
         (WORD) bi.biHeight, 
         (LPSTR) lpbi + (WORD) lpbi->biSize + PALETTESIZE((LPSTR) lpbi), 
         (LPBITMAPINFO) lpbi, DIB_RGB_COLORS) == 0) 
      { 
      GlobalUnlock (hDIB); 
      hDIB = NULL; 
      SelectPalette (hDC, hPal, FALSE); 
      ReleaseDC (NULL, hDC); 
      return NULL; 
      } 
 
   bi = *lpbi; 
   GlobalUnlock (hDIB); 
   SelectPalette (hDC, hPal, FALSE); 
   ReleaseDC (NULL, hDC); 
   //OK 
   return hDIB; 
} 
 
 
 
int _DIBNumColors (LPBITMAPINFOHEADER lpbi) 
{ 
      if (lpbi->biClrUsed) 
         return (int)lpbi->biClrUsed; 
   switch (lpbi->biBitCount) 
      { 
      case 1: 
         return 2; 
      case 4: 
         return 16; 
      case 8: 
         return 256; 
      default: 
         return 0;	//16,24,32 bits bitmap has no color table 
      } 
}