Click here to Skip to main content
11,706,477 members (32,807 online)
Click here to Skip to main content
Articles » Multimedia » GDI » General » Downloads
Add your own
alternative version

Barry's Screen Capture

, 11 Jan 2003 204.6K 11.9K 91
An article showing methods of screen capture
capit_demo.zip
CapIT.exe
capit_src.zip
CapIT.dsp
CapIT.dsw
RES
CapITDoc.ico
CapIT.ico
Toolbar.bmp
Camera.ico
Thumbs.db
// CapITView.cpp : implementation of the CCapITView class
//

#include "stdafx.h"
#include "CapIT.h"

#include "CapITDoc.h"
#include "CapITView.h"

#include "MainFrm.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

int FAR PASCAL GetMessageFunc (int nCode, WPARAM wParam, LPARAM lParam );


int hCurMsg = WH_MOUSE; //WH_GETMESSAGE;
HWND ghWnd;
HHOOK ghhk;

int gCurrentX = 0;
int gCurrentY = 0;

BOOL        gbStartUp=TRUE;
CBitmap*    gcBitmap;
HDC         gHDC=NULL;

BOOL bColorCoding = TRUE;
BOOL bCapturingControl = FALSE;
BOOL bScreenCapture = FALSE;
BOOL bCapturingWindow = FALSE; 
BOOL bCapturingClient = FALSE;

BOOL        gbTrackCodes = FALSE;
BOOL        gbTrackPosition = FALSE;

/////////////////////////////////////////////////////////////////////////////
// CCapITView

IMPLEMENT_DYNCREATE(CCapITView, CScrollView)

BEGIN_MESSAGE_MAP(CCapITView, CScrollView)
	//{{AFX_MSG_MAP(CCapITView)
	ON_WM_CAPTURECHANGED()
	ON_WM_DESTROY()
	ON_COMMAND(ID_SAVE_FILE, OnSaveFile)
	ON_UPDATE_COMMAND_UI(ID_SAVE_FILE, OnUpdateSaveFile)
	ON_COMMAND(ID_COLORCODE, OnColorcode)
	ON_UPDATE_COMMAND_UI(ID_COLORCODE, OnUpdateColorcode)
	ON_COMMAND(ID_TRACKPOS, OnTrackpos)
	ON_UPDATE_COMMAND_UI(ID_TRACKPOS, OnUpdateTrackpos)

	ON_COMMAND(ID_CLEAR, OnClear)
	ON_UPDATE_COMMAND_UI(ID_CLEAR, OnUpdateClear)

	ON_COMMAND(ID_HIDE , OnHideWindow)

	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCapITView construction/destruction

CCapITView::CCapITView()
{
	// TODO: add construction code here
	gbDrawImage = 
	gbIsCaptured = 
	gbNewRect = 
	gbIsMarking = 
	gbCaptureMode = FALSE;
	m_bHookSetup = FALSE;
//	gMainWnd = NULL;
}

CCapITView::~CCapITView()
{
}

BOOL CCapITView::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.style |= WS_HSCROLL | WS_VSCROLL;
	return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CCapITView drawing

void CCapITView::OnDraw(CDC* pDC)
{


	if(gbDrawImage)
	{
		// Fill in src/dest rectangle with width and height
	    // of captured bitmap 

		CRect  rect;
		GetClientRect(&rect);
        // Paint the captured bitmap in the client area 
//		if(!gbStartUp)
			PaintBitmap( pDC->m_hDC , &rect, ghBitmap, &rect, NULL); 
//		gbDrawImage = FALSE;
	}

}

void CCapITView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	sizeTotal.cx = 400;
	sizeTotal.cy = 200;
	SetScrollSizes(MM_TEXT, sizeTotal);

	gMainWnd = AfxGetMainWnd();
}

/////////////////////////////////////////////////////////////////////////////
// CCapITView printing

BOOL CCapITView::OnPreparePrinting(CPrintInfo* pInfo)
{
	return DoPreparePrinting(pInfo);
}

void CCapITView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{

}

void CCapITView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{

}

/////////////////////////////////////////////////////////////////////////////
// CCapITView diagnostics

#ifdef _DEBUG
void CCapITView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CCapITView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CCapITDoc* CCapITView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCapITDoc)));
	return (CCapITDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CCapITView message handlers


void CCapITView::OnDestroy() 
{
	CScrollView::OnDestroy();
	
	if(ghhk)
		::UnhookWindowsHookEx(ghhk);

    if (ghBitmap) 
       DeleteObject(ghBitmap); 
    if (ghPal) 
       DeleteObject(ghPal); 

}

void CCapITView::OnHideWindow()
{
	CMainFrame* frame = (CMainFrame*)AfxGetMainWnd();
	frame->ShowWindow(SW_HIDE);
}


void CCapITView::OnClear()
{
	ClearCapture();
}

void CCapITView::OnUpdateClear(CCmdUI* pCmdUI)
{
	pCmdUI->Enable(gbIsCaptured);	
}

void CCapITView::ClearCapture() 
{

	if(ghhk)
		::UnhookWindowsHookEx(ghhk);

	bColorCoding = TRUE;

	gbIsCaptured = FALSE;	
	ghBitmap = NULL;
	CRect rect;
	GetClientRect(&rect);
	InvalidateRect(rect,TRUE);
	gbTrackCodes = FALSE;
	gbTrackPosition = FALSE;
	UpdateStatusbar(0, gbTrackCodes , gbTrackPosition);
	UpdateCaptureStatus(FALSE);
}

void CCapITView::UpdateCaptureStatus(BOOL bCaptured)
{
	CMainFrame* frame = (CMainFrame*)AfxGetMainWnd();
	frame->g_mbImageCaptured = bCaptured;
}

void CCapITView::CaptureClient() 
{
	AfxMessageBox("Click on Client Area to be captured");
	bCapturingClient = TRUE;
	gbStartUp = FALSE;
	SetCapture();
}

void CCapITView::CaptureControl() 
{
	AfxMessageBox("Click on CONTROL to be captured");
	bCapturingControl = TRUE;
	SetCapture();
	gbStartUp=FALSE;
}

void CCapITView::CaptureDesktop()
{
	WindowCapture(GetDesktopWindow()->m_hWnd);
	gbIsCaptured = TRUE;
}

void CCapITView::CaptureWindow() 
{
	AfxMessageBox("Click on Window to be captured");
	bCapturingWindow = TRUE;
	SetCapture();
	gbStartUp = FALSE;
}

void CCapITView::WindowCapture(HWND wnd)
{

	HBITMAP hBitmap = CopyWindowToBitmap(this , wnd, 1);

    HPALETTE hPal = NULL;
    if (hBitmap) 
	{
//       hPal = GetSystemPalette(); 
	   ghBitmap = hBitmap;
       gbDrawImage = TRUE;
	   gbIsCaptured = TRUE;
	   CRect rect;
	   GetClientRect(&rect);
	   InvalidateRect(rect);
	   CCapITDoc* pDoc = GetDocument();
	   DoSize(FromHandle(this->m_hWnd) ,hBitmap);

	   UpdateCaptureStatus(TRUE);

    }
    else 
	{	
		gbIsCaptured = FALSE;
		hPal = NULL; 

	   AfxMessageBox("Sorry !!!!");
	}
}

void CCapITView::OnCaptureChanged(CWnd *pWnd) 
{

	if(gbStartUp)
		return;

	CPoint point;
    VERIFY(GetCursorPos(&point));
	ScreenToClient(&point);
	ClientToScreen(&point);
	CWnd* wnd = WindowFromPoint(point);    	

	if(wnd)
	{
		if(IsChild(wnd))
		{
			WindowCapture(wnd->GetParent()->m_hWnd);
		}
		else
		{
			if(!gbIsCaptured)
			{
				if(bCapturingClient)
				{
					CaptureClientArea(wnd);
					bCapturingClient = FALSE;
				}
				if(bCapturingWindow)
				{
					WindowCapture(wnd->GetTopLevelParent()->m_hWnd);
					bCapturingWindow = FALSE;

				}
				if(bCapturingControl)
				{
					WindowCapture(wnd->GetTopLevelOwner()->m_hWnd);
					bCapturingControl = FALSE;
				}
				gbIsCaptured = TRUE;
				UpdateCaptureStatus(TRUE);

			}	
		}
	}

	ReleaseCapture();

	CScrollView::OnCaptureChanged(pWnd);
}

void CCapITView::CaptureClientArea(CWnd* wnd)
{
	WindowCapture(wnd->m_hWnd);
	return;
}

void CCapITView::OnSaveFile() 
{

   BOOL bOpen = FALSE;
   char bigBuff[2048] = "";  // maximum common dialog buffer size
   char szFilter[] =
      "BMP Files (*.BMP)|*.bmp|*.bmp|All Files (*.*)|*.*|||";
   CFileDialog dlg(bOpen, NULL, NULL,
      OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT, szFilter);

   dlg.m_ofn.lpstrFile = bigBuff;
   dlg.m_ofn.nMaxFile = sizeof(bigBuff);

   dlg.DoModal();
   
   if(dlg.m_ofn.lpstrFile != "")
   {
		HPALETTE hPal = NULL;
        hPal = GetSystemPalette(this->m_hWnd); 
		if(!hPal)
		{
			AfxMessageBox("Error getting System Palette");
			return;
		}
		DWORD   dwFlags = NULL;
		DWORD   dCompression = BI_RLE8; // / BI_RLE4 / BI_RGB;

		HANDLE hDIB = ChangeBitmapFormat(ghBitmap, 
			                                   HIWORD(dwFlags),                  
											   dCompression, 
											   hPal , 
											   this->m_hWnd);

		SaveDIB(hDIB, dlg.m_ofn.lpstrFile);
		hPal = NULL;
   }	
}

void CCapITView::OnUpdateSaveFile(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(gbIsCaptured);	
}

void CCapITView::OnColorcode() 
{

	if(!m_bHookSetup)	
		SetupHookProc();

	bColorCoding = FALSE;
	gbTrackCodes = TRUE;
}

void CCapITView::OnUpdateColorcode(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable((gbIsCaptured) && (bColorCoding));
}

int FAR PASCAL GetMessageFunc (int nCode, WPARAM wParam, LPARAM lParam )
{

   LPMOUSEHOOKSTRUCT MouseHookParam;

   if ( nCode >= 0 ) 
   {

	  MouseHookParam = (MOUSEHOOKSTRUCT *) lParam;
	  gCurrentX = MouseHookParam->pt.x;
	  gCurrentY = MouseHookParam->pt.y;

	  CPoint point;
	  HWND wnd;

	  GetCursorPos(&point);
	  wnd = WindowFromPoint(point);
	  HDC hdc = ::GetDC(wnd); 
	  COLORREF cr = GetPixel(hdc, point.x , point.y);
      CCapITView::UpdateStatusbar(cr , gbTrackCodes , gbTrackPosition);

   }
   return CallNextHookEx(ghhk, hCurMsg, wParam , lParam);
}

void CCapITView::UpdateStatusbar(COLORREF cr , BOOL bShowCodes, BOOL bShowPosition)
{
	CMainFrame* frame = (CMainFrame*)AfxGetMainWnd();

	frame->m_bShowCodes = bShowCodes;
	frame->m_iBlueCode = GetBValue(cr);
	frame->m_iGreenCode = GetGValue(cr);
	frame->m_iRedCode= GetRValue(cr);

	frame->m_bShowPosition = bShowPosition;
	frame->m_iPosX = gCurrentX;
	frame->m_iPosY = gCurrentY;

}

void CCapITView::OnTrackpos() 
{
	if(!m_bHookSetup)	
		SetupHookProc();

	gbTrackPosition = TRUE;	
}

void CCapITView::OnUpdateTrackpos(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable((gbIsCaptured) && (!gbTrackPosition));	
}

void CCapITView::SetupHookProc()
{
	ghWnd = this->m_hWnd;
    FARPROC lpMsgFilterProc = (FARPROC)MakeProcInstance((FARPROC)GetMessageFunc, hInst);
    ghhk = SetWindowsHookEx(hCurMsg, (HOOKPROC)lpMsgFilterProc, NULL,
            GetCurrentThreadId());
	m_bHookSetup = TRUE;
}




/******************************************************************************
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993-1997 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
******************************************************************************/

HBITMAP CCapITView::CopyWindowToBitmap(CWnd* wnd , HWND hWnd, WORD fPrintArea)
{
	HBITMAP     hBitmap = NULL;  // handle to device-dependent bitmap      
	// check for a valid window handle      
	if (!hWnd)         
	    return NULL; 

    RECT    rectWnd; 
  ::GetWindowRect(hWnd, &rectWnd);  
	

	switch (fPrintArea)     
	{         
		case PW_WINDOW: // copy entire window         
		{             
          // get the window rectangle              
          // get the bitmap of that window by calling             
		  // CopyScreenToBitmap and passing it the window rect                     
//		  GetWindowRect(&rectWnd);
          hBitmap = CopyScreenToBitmap(&rectWnd);             
		  break;         
		}   
       case PW_CLIENT: // copy client area         
	   {             
	     RECT rectClient;             
	     POINT pt1, pt2;              // get client dimensions              
	     wnd->GetClientRect(&rectClient);              // convert client coords to screen coords              
	     pt1.x = rectClient.left;             
	     pt1.y = rectClient.top;             
	     pt2.x = rectClient.right;             
	     pt2.y = rectClient.bottom;             
	     wnd->ClientToScreen(&pt1);             
	     wnd->ClientToScreen(&pt2);             
	     rectClient.left = pt1.x;             
	     rectClient.top = pt1.y;             
	     rectClient.right = pt2.x;             
	     rectClient.bottom = pt2.y;  

         // get the bitmap of the client area by calling             
	     // CopyScreenToBitmap and passing it the client rect                          
	     hBitmap = CopyScreenToBitmap(&rectClient);             
	     break;         
	   }              
	   default:    // invalid print area             
	        return NULL;     
	}      // return handle to the bitmap     
	
	return hBitmap; 
}

HBITMAP CCapITView::CopyScreenToBitmap(LPRECT lpRect)
{
	HDC         hScrDC, hMemDC;         // screen DC and memory DC     
//	HBITMAP     hBitmap; //, 
//	HBITMAP     hBitmap;
//	HBITMAP     hOldBitmap;    // handles to deice-dependent bitmaps     
	int         nX, nY, nX2, nY2;       // coordinates of rectangle to grab     
	int         nWidth, nHeight;        // DIB width and height     
	int         xScrn, yScrn;           // screen resolution      

	HGDIOBJ     hOldBitmap , hBitmap;
		
		// check for an empty rectangle 
    if (IsRectEmpty(lpRect))       
	   return NULL;      
	   // create a DC for the screen and create     
	   // a memory DC compatible to screen DC          

   hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);     
   hMemDC = CreateCompatibleDC(hScrDC);      // get points of rectangle to grab  
   
   nX = lpRect->left;     
   nY = lpRect->top;     
   nX2 = lpRect->right;     
   nY2 = lpRect->bottom;      // get screen resolution      
   
   xScrn = GetDeviceCaps(hScrDC, HORZRES);     
   yScrn = GetDeviceCaps(hScrDC, VERTRES);      
   
   //make sure bitmap rectangle is visible      
   
   if (nX < 0)         
	  nX = 0;     
   
   if (nY < 0)         
      nY = 0;     
   
   if (nX2 > xScrn)         
      nX2 = xScrn;     
   
   if (nY2 > yScrn)         
      nY2 = yScrn;      

   nWidth = nX2 - nX;     
   nHeight = nY2 - nY;      
   
   // create a bitmap compatible with the screen DC     
   
   hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);      
   
   // select new bitmap into memory DC     
   
   hOldBitmap =   SelectObject (hMemDC, hBitmap);      
   
   // bitblt screen DC to memory DC     
   
   BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);     
   
   // select old bitmap back into memory DC and get handle to     
   // bitmap of the screen          
   
   hBitmap = SelectObject(hMemDC, hOldBitmap);      
   
   // clean up      
   
   DeleteDC(hScrDC);     
   DeleteDC(hMemDC);      
   
   // return handle to the bitmap      
   
   return (HBITMAP)hBitmap; 

}

BOOL CCapITView::PaintBitmap(HDC hDC, LPRECT lpDCRect, HBITMAP hDDB, LPRECT lpDDBRect, HPALETTE hPal)
{
    HDC         hMemDC;            // Handle to memory DC 
//    HBITMAP     hOldBitmap;        // Handle to previous bitmap 
    HPALETTE    hOldPal1 = NULL;   // Handle to previous palette 
    HPALETTE    hOldPal2 = NULL;   // Handle to previous palette 
    BOOL        bSuccess = FALSE;  // Success/fail flag 
	HGDIOBJ hOldBitmap;
    // Create a memory DC 
 
    hMemDC = CreateCompatibleDC (hDC); 
 
    // If this failed, return FALSE 
 
    if (!hMemDC) 
        return FALSE; 
 
    // If we have a palette, select and realize it 
 
    if (hPal) 
    { 
        hOldPal1 = SelectPalette(hMemDC, hPal, TRUE); 
        hOldPal2 = SelectPalette(hDC, hPal, FALSE); //TRUE); 
        RealizePalette(hDC); 
    } 
 
    // Select bitmap into the memory DC 
 
    hOldBitmap = SelectObject (hMemDC, hDDB); 

    // Make sure to use the stretching mode best for color pictures 
 
    SetStretchBltMode (hDC, COLORONCOLOR); 
	
    // Determine whether to call StretchBlt() or BitBlt() 
    if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDDBRect)) && 
            (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDDBRect))) 
        bSuccess = BitBlt(hDC, lpDCRect->left, lpDCRect->top, 
                lpDCRect->right - lpDCRect->left, 
                lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left, 
                lpDDBRect->top, SRCCOPY); 
    else 
        bSuccess = StretchBlt(hDC, lpDCRect->left,  lpDCRect->top,  
                lpDCRect->right - lpDCRect->left, 
                lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left,  
                lpDDBRect->top,  lpDDBRect->right - lpDDBRect->left, 
                lpDDBRect->bottom - lpDDBRect->top, SRCCOPY); 
 
    // Clean up 
 
    SelectObject(hMemDC, hOldBitmap); 
 
    if (hOldPal1) 
        SelectPalette (hMemDC, hOldPal1, FALSE); 
 
    if (hOldPal2) 
        SelectPalette (hDC, hOldPal2, FALSE); 
 
    DeleteDC (hMemDC); 
 
    // Return with success/fail flag 
 
    return bSuccess; 
}


void CCapITView::DoSize(CWnd* wnd , HBITMAP ghBitmap)
{
    BITMAP      bm;                     // Bitmap info structure 
    int         cxBitmap=0, cyBitmap=0; // Bitmap width and height 
    int         cxScroll, cyScroll;     // Scroll positions 
    RECT        rect;                   // Client rectangle 
 
    // repaint if displaying bitmap 
 
    if (ghBitmap) 
    { 
        // Get info about bitmap 
 
        GetObject(ghBitmap, sizeof(BITMAP), (LPSTR)&bm); 
 
        // Get the width and height of the bitmap 

//		CSize sizeTotal;
		// TODO: calculate the total size of this view
//		sizeTotal.cx = bm.bmWidth;
//		sizeTotal.cy = bm.bmHeight;
//		SetScrollSizes(MM_TEXT, sizeTotal);		

        cxBitmap = bm.bmWidth; 
        cyBitmap = bm.bmHeight; 
 
        // Find out the dimensions of the window, and the current thumb 
        // positions 
 
        wnd->GetClientRect(&rect); 
 
        cxScroll = wnd->GetScrollPos (SB_HORZ); 
        cyScroll = wnd->GetScrollPos (SB_VERT); 
 
        // If current thumb positions would cause blank space 
        // at right or bottom of client area, repaint 
 
        if (cxScroll + rect.right > cxBitmap || 
                cyScroll + rect.bottom > cyBitmap) 
            wnd->InvalidateRect(NULL, FALSE); 
 
        // Make sure scroll bars are updated 
 
        SetupScrollBars(wnd , (WORD)cxBitmap, (WORD)cyBitmap); 
    } 
    else //if (bStartup) 
        wnd->InvalidateRect(NULL, TRUE); 
}

void CCapITView::SetupScrollBars(CWnd* wnd , WORD cxBitmap, WORD cyBitmap)
{
    RECT        rect;                       // Client Rectangle 
    BOOL        bNeedScrollBars=FALSE;      // Need Scroll bars? 
    unsigned    cxWindow, cyWindow;         // Width and height of client area 
    int         cxRange=0, cyRange=0;       // Range needed for horz and vert 
 
    // Do some initialization 
 
    ReallyGetClientRect(wnd , &rect); 
 
    cxWindow = rect.right - rect.left; 
    cyWindow = rect.bottom - rect.top; 
 
    // Now determine if we need the scroll bars 
 
    if ((cxWindow < (unsigned)cxBitmap) || (cyWindow < (unsigned)cyBitmap)) 
        bNeedScrollBars = TRUE; 
 
 
    // Setup the scroll bar ranges.  We want to be able to 
    // scroll the window so that all the bitmap can appear 
    // within the client area.  Take into account that 
    // if the opposite scroll bar is activated, it eats 
    // up some client area. 
 
    if (bNeedScrollBars) 
    { 
        cyRange = (unsigned)cyBitmap - cyWindow - 1 + 
                GetSystemMetrics (SM_CYHSCROLL); 
        cxRange = (unsigned)cxBitmap - cxWindow - 1 + 
                GetSystemMetrics (SM_CXVSCROLL); 
    } 
 
    // Set the ranges we've calculated (0 to 0 means invisible scrollbar) 
 
    wnd->SetScrollRange(SB_VERT, 0, cyRange, TRUE); 
    wnd->SetScrollRange(SB_HORZ, 0, cxRange, TRUE); 
}


void CCapITView::ReallyGetClientRect(CWnd* wnd , LPRECT lpRect)
{
    DWORD   dwWinStyle; 
 
    dwWinStyle = GetWindowLong (wnd->m_hWnd, GWL_STYLE); 
 
    wnd->GetClientRect (lpRect); 
 
    if (dwWinStyle & WS_HSCROLL) 
        lpRect->bottom += (GetSystemMetrics (SM_CYHSCROLL) - 1); 
 
    if (dwWinStyle & WS_VSCROLL) 
        lpRect->right  += (GetSystemMetrics (SM_CXVSCROLL) - 1); 
 
}

WORD CCapITView::SaveDIB(HDIB hDib, LPSTR lpFileName)
{
	BITMAPFILEHEADER    bmfHdr;     // Header for Bitmap file     
	LPBITMAPINFOHEADER  lpBI;       // Pointer to DIB info structure     
	HANDLE              fh;         // file handle for opened file     
	DWORD               dwDIBSize;     
	DWORD               dwWritten;      
	if (!hDib)         
		return ERR_INVALIDHANDLE;  
	
   fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);      
   
   if (fh == INVALID_HANDLE_VALUE)         
		return ERR_OPEN;      
   // Get a pointer to the DIB memory, the first of which contains     
   // a BITMAPINFO structure      
   lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);     
   if (!lpBI)     
   {         
		CloseHandle(fh);         
		return ERR_LOCK;     
	}     
	// Check to see if we're dealing with an OS/2 DIB.  If so, don't     
	// save it because our functions aren't written to deal with these     
	// DIBs.  
   if (lpBI->biSize != sizeof(BITMAPINFOHEADER))     
   {         
		GlobalUnlock(hDib);         
		CloseHandle(fh);         
		return ERR_NOT_DIB;     
	}      
	// Fill in the fields of the file header      
	// Fill in file type (first 2 bytes must be "BM" for a bitmap)      
	bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM" 

 dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI);        
 // Now calculate the size of the image      
 // It's an RLE bitmap, we can't calculate size, so trust the biSizeImage     
 // field      
 
 if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))         
  dwDIBSize += lpBI->biSizeImage;     
 else     
 {         
  DWORD dwBmBitsSize;  
  // Size of Bitmap Bits only          
  // It's not RLE, so size is Width (DWORD aligned) * Height          
  dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;          
  dwDIBSize += dwBmBitsSize;          
  // Now, since we have calculated the correct size, why don't we         
  // fill in the biSizeImage field (this will fix any .BMP files which          
  // have this field incorrect).          
  lpBI->biSizeImage = dwBmBitsSize;     
 }       
 
  // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)                         
  bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);     
  bmfHdr.bfReserved1 = 0;     
  bmfHdr.bfReserved2 = 0;      
 
  // Now, calculate the offset the actual bitmap bits will be in     
  // the file -- It's the Bitmap file header plus the DIB header,     
  // plus the size of the color table.          
 
 bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +             PaletteSize((LPSTR)lpBI);      
 
 // Write the file header      
 
 WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);      
 
 // Write the DIB header and the bits -- use local version of     
  // MyWrite, so we can write more than 32767 bytes of data          
 
 WriteFile(fh, (LPSTR)lpBI, dwDIBSize, &dwWritten, NULL);      
 GlobalUnlock(hDib);     
 CloseHandle(fh);      
 
 if (dwWritten == 0)         
  return ERR_OPEN; 
 
 // oops, something happened in the write     
  else         
  return 0; // Success code 
 
}

WORD CCapITView::PaletteSize (VOID FAR * pv) 
{     
	LPBITMAPINFOHEADER lpbi;     
	WORD NumColors;      
	lpbi      = (LPBITMAPINFOHEADER)pv;     
	NumColors = DibNumColors(lpbi);      
	if (lpbi->biSize == sizeof(BITMAPCOREHEADER))         
		return NumColors * sizeof(RGBTRIPLE);     
	else         
		return NumColors * sizeof(RGBQUAD); 
} 

WORD CCapITView::DibNumColors (VOID FAR * pv)
{     
	int bits;     
	LPBITMAPINFOHEADER lpbi;     
	LPBITMAPCOREHEADER lpbc;      
	lpbi = ((LPBITMAPINFOHEADER)pv);     
	lpbc = ((LPBITMAPCOREHEADER)pv);      
	
	/*  With the BITMAPINFO format headers, the size of the palette      
	*  is in biClrUsed, whereas in the BITMAPCORE - style headers, it      
	*  is dependent on the bits per pixel ( = 2 raised to the power of      
	*  bits/pixel).      
	*/     
	
	if (lpbi->biSize != sizeof(BITMAPCOREHEADER))     
	{         
		if (lpbi->biClrUsed != 0)             
			return (WORD)lpbi->biClrUsed;         
	
		bits = lpbi->biBitCount;     
	}     
	else         
		bits = lpbc->bcBitCount;      
	
	switch (bits)     
	{     
		case 1:         
			return 2;     
		case 4:         

			return 16;     
		case 8:         
			return 256;     
		default:         
			//  A 24 bitcount DIB has no color table          
			return 0;     

	} 

	
} 

HDIB CCapITView::ChangeBitmapFormat(HBITMAP hBitmap, 
								   WORD wBitCount, 
								   DWORD dwCompression, 
                                   HPALETTE hPal,
								   HWND hwnd) 
{ 
    HDC                hDC;          // Screen DC 
    HDIB               hNewDIB=NULL; // Handle to new DIB 
    BITMAP             Bitmap;       // BITMAP data structure 
    BITMAPINFOHEADER   bi;           // Bitmap info. header 
    LPBITMAPINFOHEADER lpbi;         // Pointer to bitmap header 
    HPALETTE           hOldPal=NULL; // Handle to palette 
    WORD               NewBPP;       // New bits per pixel 
    DWORD              NewComp;      // New compression format 
 
    // Check for a valid bitmap handle 
 
    if (!hBitmap) 
        return NULL; 
 
    // Validate wBitCount and dwCompression 
    // They must match correctly (i.e., BI_RLE4 and 4 BPP or 
    // BI_RLE8 and 8BPP, etc.) or we return failure 
     
    if (wBitCount == 0) 
    { 
        NewComp = dwCompression; 
        if (NewComp == BI_RLE4) 
            NewBPP = 4; 
        else if (NewComp == BI_RLE8) 
            NewBPP = 8; 
        else // Not enough info */ 
            return NULL; 
    } 
    else if (wBitCount == 1 && dwCompression == BI_RGB) 
    { 
        NewBPP = wBitCount; 
        NewComp = BI_RGB; 
    } 
    else if (wBitCount == 4) 
    { 
        NewBPP = wBitCount; 
        if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 
            NewComp = dwCompression; 
        else 
            return NULL; 
    } 
    else if (wBitCount == 8) 
    { 
        NewBPP = wBitCount; 
        if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 
            NewComp = dwCompression; 
        else 
            return NULL; 
    } 
    else if (wBitCount == 24 && dwCompression == BI_RGB) 
    { 
        NewBPP = wBitCount; 
        NewComp = BI_RGB; 
    } 
    else 
        return NULL; 
 
    // Get info about the bitmap 
 
    GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 
 
    // Fill in the BITMAPINFOHEADER appropriately 
 
    bi.biSize               = sizeof(BITMAPINFOHEADER); 
    bi.biWidth              = Bitmap.bmWidth; 
    bi.biHeight             = Bitmap.bmHeight; 
    bi.biPlanes             = 1; 
    bi.biBitCount           = NewBPP; 
    bi.biCompression        = NewComp; 
    bi.biSizeImage          = 0; 
    bi.biXPelsPerMeter      = 0; 
    bi.biYPelsPerMeter      = 0; 
    bi.biClrUsed            = 0; 
    bi.biClrImportant       = 0; 
 
    // Go allocate room for the new DIB 
 
    hNewDIB = AllocRoomForDIB(bi, hBitmap , hwnd); 
    if (!hNewDIB) 
        return NULL; 
 
    // Get a pointer to the new DIB 
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 
 
    // If we have a palette, get a DC and select/realize it 
 
    if (hPal) 
    { 
 		hDC = CreateDC ( TEXT("DISPLAY"), NULL, NULL, NULL );
        hOldPal = SelectPalette(hDC, hPal, FALSE); 
        RealizePalette(hDC); 
    } 
 
    // Call GetDIBits and get the new DIB bits 
 
    if (!GetDIBits(hDC, hBitmap, 0, (UINT) lpbi->biHeight, (LPSTR)lpbi + 
            (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi, 
            DIB_RGB_COLORS)) 
    { 
        GlobalUnlock(hNewDIB); 
        GlobalFree(hNewDIB); 
        hNewDIB = NULL; 
    } 
 
    // Clean up and return 
 
    if (hOldPal) 
    { 
        SelectPalette(hDC, hOldPal, TRUE); 
        RealizePalette(hDC); 
		::ReleaseDC(hwnd, hDC);
     } 
 
    // Unlock the new DIB's memory block 
 
    if (hNewDIB) 
        GlobalUnlock(hNewDIB); 
 
    return hNewDIB; 
}
 
HANDLE CCapITView::AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap , HWND hwnd) 
{ 
    DWORD               dwLen; 
    HANDLE              hDIB; 
    HDC                 hDC; 
    LPBITMAPINFOHEADER  lpbi; 
    HANDLE              hTemp; 
 
    // Figure out the size needed to hold the BITMAPINFO structure 
    // (which includes the BITMAPINFOHEADER and the color table). 
 
    dwLen = bi.biSize + PaletteSize((LPSTR) &bi); 
    hDIB  = GlobalAlloc(GHND,dwLen); 
 
    // Check that DIB handle is valid 
 
    if (!hDIB) 
        return NULL; 
 
    // Set up the BITMAPINFOHEADER in the newly allocated global memory, 
    // then call GetDIBits() with lpBits = NULL to have it fill in the 
    // biSizeImage field for us. 
 
    lpbi  = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 
    *lpbi = bi; 
 
    hDC = CreateDC ( TEXT("DISPLAY"), NULL, NULL, NULL );
 
    GetDIBits(hDC, hBitmap, 0, (UINT) bi.biHeight, NULL, (LPBITMAPINFO)lpbi, 
            DIB_RGB_COLORS); 
 	::ReleaseDC(hwnd, hDC);
 
 
    // If the driver did not fill in the biSizeImage field, 
    // fill it in -- NOTE: this is a bug in the driver! 
     
    if (lpbi->biSizeImage == 0) 
        lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth * 
                lpbi->biBitCount) * lpbi->biHeight; 
 
    // Get the size of the memory block we need 
 
    dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage; 
 
    // Unlock the memory block 
 
    GlobalUnlock(hDIB); 
 
    // ReAlloc the buffer big enough to hold all the bits  
 
    if (hTemp = GlobalReAlloc(hDIB,dwLen,0)) 
        return hTemp; 
    else 
    { 
        // Else free memory block and return failure 
 
        GlobalFree(hDIB); 
        return NULL; 
    } 
} 
 
HPALETTE CCapITView::GetSystemPalette(HWND hwnd) 
{ 
    HDC hDC;                // handle to a DC 
    static HPALETTE hPal = NULL;   // handle to a palette 
    HANDLE hLogPal;         // handle to a logical palette 
    LPLOGPALETTE lpLogPal;  // pointer to a logical palette 
    int nColors;            // number of colors 
 
    // Find out how many palette entries we want. 

    hDC = CreateDC ( TEXT("DISPLAY"), NULL, NULL, NULL );
 
    if (!hDC) 
        return NULL; 
	 
    nColors = 256; //PalEntriesOnDevice(hDC);   // Number of palette entries 
 
    // Allocate room for the palette and lock it. 
 
    hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * 
            sizeof(PALETTEENTRY)); 
 
    // if we didn't get a logical palette, return NULL 
 
    if (!hLogPal) 
        return NULL; 
 
    // get a pointer to the logical palette 
 
    lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal); 
 
    // set some important fields 
 
    lpLogPal->palVersion = 0x300; //PALVERSION; 
    lpLogPal->palNumEntries = nColors; 
 
    // Copy the current system palette into our logical palette 
 
    GetSystemPaletteEntries(hDC, 0, nColors, 
            (LPPALETTEENTRY)(lpLogPal->palPalEntry)); 
 
    // Go ahead and create the palette.  Once it's created, 
    // we no longer need the LOGPALETTE, so free it.     
 
    hPal = CreatePalette(lpLogPal); 
 
    // clean up 
 
    GlobalUnlock(hLogPal); 
    GlobalFree(hLogPal); 
	::ReleaseDC(hwnd, hDC);
 
    return hPal; 
} 

int CCapITView::PalEntriesOnDevice(HDC hDC) 
{     
	int nColors;  // number of colors      
	// Find out the number of colors on this device.          
	nColors = (1 << (GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)));
	ASSERT(nColors);     
	return nColors; 
}  

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Barretto VN
India India
Nothing to boast about

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150819.1 | Last Updated 12 Jan 2003
Article Copyright 2003 by Barretto VN
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid