/**
@defgroup COMPARE_GDI_GDIPlus
@brief 比較與整理GDI與GDIPlus在抓取、合併和保存位圖之間的不同
@author 華仔103
@date 2009-01-14
@{
\*/
在stdafx.h文件中定義
#ifndef _UNICODE
#define _UNICODE
#endif
#ifndef UNICODE
#define UNICODE
#endif
#pragma comment(lib,"gdiplus.lib")
#include <gdiplus.h>
using namespace Gdiplus;
//如果原項目爲非UNICODE編碼環境,那麼修改項目爲UNICODE編碼環境的方法爲:
//在項目屬性對話框的鏈接器->高級->入口點中設置值爲wWinMainCRTStartup。
在*.cpp文件中
#include "stdafx.h"
//通過GDI方法進行屏幕抓圖,用GDI+方法保存Bitmap文件
#define USE_GDI_GDIPLUS_STORE_BMP
////通過GDI方法進行屏幕抓圖和保存Bitmap文件
//#define USE_GDI_STORE_BMP
//將Bitmap文件保存在Windows的剪貼版中
#define STORE_IN_CLIPBOARD
//@brief 用GDI+的方法將Bitmap圖片保存爲文件
//@date 1-13-2009
//@param [in] hBitmap hBitmap的句柄(handle)
//@param [in] lpszFileName 保存圖片的完整路徑
//@return 成功返回TRUE,失敗返回FALSE
BOOL C**Dlg::GDIPlus_SaveBitmapToFile(HBITMAP hBitmap, LPCTSTR lpszFileName)
{
CLSID pngClsid;
Bitmap bmp(hBitmap,NULL);
//獲取BMP文件的編碼方式(如果希望獲取JPEG的編碼方式,
//那麼參數一要設置爲:_TEXT("image/jpeg"),其他支持的圖片格式類似)
int nResult = GetEncoderClsid(_TEXT("image/bmp"),&pngClsid);
if(nResult >= 0)
{
//保存所截取的屏幕圖片
bmp.Save(lpszFileName,&pngClsid);
}
else
{
return FALSE;
}
return TRUE;
}
//@brief 獲取圖片文件的編碼方式,支持bmp、jpg、jpeg、gif、tiff和png等格式圖片
//@date 1-13-2009
//@param [in] format 圖片格式 值可以爲以下幾種
//@"image/bmp"
//@"image/jpeg"
//@"image/gif"
//@"image/tiff"
//@"image/png"
//@param [in] pClsid
//@return 成功則返回值 >= 0,失敗則返回值爲-1
int C**Dlg::GetEncoderClsid(const WCHAR* format, CLSID *pClsid)
{
int nRet = -1;
ImageCodecInfo* pCodecInfo = NULL;
UINT nNum = 0,nSize = 0;
GetImageEncodersSize(&nNum,&nSize);
if (nSize<0)
{
return nRet;
}
pCodecInfo= new ImageCodecInfo[nSize];
if (pCodecInfo==NULL)
{
return nRet;
}
GetImageEncoders(nNum,nSize,pCodecInfo);
for (UINT i=0; i<nNum;i++)
{
if (wcscmp(pCodecInfo[i].MimeType,format)==0)
{
*pClsid= pCodecInfo[i].Clsid;
nRet = i;
delete[] pCodecInfo;
return nRet;
}
else
{
continue;
}
}
delete[] pCodecInfo;
return nRet;
}
//@brief 用GDI+的方法將兩個圖片(strSrcImage1,strSrcImage2)組合成一個strDestImage
//@date 1-13-2009
//@param [in] format 圖片格式 值可以爲以下幾種
//@"image/bmp"
//@"image/jpeg"
//@"image/gif"
//@"image/tiff"
//@"image/png"
//@param [in] strDestImage表示目的圖片路徑
//@param [in] strSrcImage1表示源圖片路徑1
//@param [in] strSrcImage2表示源圖片路徑2
//@return TRUE表示合成圖片成功,FALSE表示合成圖片失敗
BOOL C**Dlg::GDIPlus_CombineImage(const WCHAR *format, WCHAR* strDestImage,\
WCHAR* strSrcImage1,WCHAR* strSrcImage2)
{
BOOL bCombine = FALSE;
int nRet = 0;
CLSID clsid;
nRet= GetEncoderClsid(format,&clsid);
if (nRet >= 0)
{
Bitmap srcbmp1(strSrcImage1);
Bitmap srcbmp2(strSrcImage2);
int nWidth = 0, nHeight = 0;
nWidth = srcbmp1.GetWidth();
nHeight= srcbmp1.GetHeight();
//高不變,寬*2,水平合併
Bitmap bmpCombine(2*nWidth,nHeight);
Graphics * pG = NULL;
pGraphics = Graphics::FromImage(&bmpCombine);
if (pGraphics!=NULL)
{
//將srcbmp1畫到畫布pGraphics上
pGraphics->DrawImage(&srcbmp1,0,0);
//將srcbmp2畫到畫布pGraphics上
pGraphics->DrawImage(&srcbmp2,nWidth,0);
//保存圖片bmpCombine到路徑strDestImage
bmpCombine.Save(strDestImage,&clsid,NULL);
bCombine = TRUE;
}
}
return bCombine;
}
//@brief 用GDI的方法將Bitmap圖片保存爲文件
//@date 1-13-2009
//@param [in] hDC DC設備的句柄
//@param [in] bitmap 被保存的Bitmap圖片
//@param [in] lpszFileName 被保存Bitmap圖片的完整路徑
//@return 返回TRUE表示保存圖片成功,FALSE表示保存圖片失敗
BOOL C**Dlg::GDI_SaveBitmapToFile(HDC hDC, CBitmap &bitmap, LPCTSTR lpszFileName)
{
BOOL ret = TRUE;
BITMAP btm;
bitmap.GetBitmap(&btm);
DWORD size = btm.bmWidthBytes * btm.bmHeight;
//接下來要使用GlobalAlloc()函數從堆中分配指定大小的內存,並返回指向這塊內存的指針,
//分配內存是將內存的內容初始化爲全零。
HGLOBAL hMem = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,size);
if(hMem == NULL)
{
return FALSE;
}
//爲了保護我們分配的這塊內存,我們要調用GlobalLock來鎖定這塊內存,
//避免被其他的進程佔用,這個函數返回指向內存鎖的第一個指針
LPSTR lpData = (LPSTR)GlobalLock(hMem);
//定義位圖頭,並對這個結構體變量初始化,這個結構之後初始化之後才能使用,
//尤其要指定位圖的大小和位圖的高度寬度
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = btm.bmWidth;
bih.biHeight = btm.bmHeight;
bih.biPlanes = 1;
bih.biBitCount = btm.bmBitsPixel;
bih.biCompression = 0;
bih.biSizeImage = size;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
//將位圖中的數據以bits的形式放入lpData指向的位圖數組中,這裏用到了GetDIBits()函數。
if(GetDIBits(hDC,bitmap,0,bih.biHeight,lpData,(BITMAPINFO*)&bih,DIB_RGB_COLORS) == 0)
{
GlobalFree(hMem);
return FALSE;
}
int iRes = GetDeviceCaps(hDC, SIZEPALETTE);
long plSize = iRes * sizeof(RGBQUAD);
//位圖文件和普通的文件使用起來有區別,爲了保存位圖,我們這裏定義了一個位圖文件,
//用它來專門保存位圖文件,在使用之前,也要填充位圖文件的頭部信息。Bfh的bfType成員沒有選擇,
//必須賦值爲BM,bfReserved1和bfReserved2都必須指定爲0。
BITMAPFILEHEADER bfh;
bfh.bfType = ((WORD)('M'<< 8)|'B') ;//BM
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfSize = sizeof(bfh)+size;
bfh.bfOffBits = plSize + sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
CFile bf;
//對於位圖文件的寫入,我們可以使用下面的方法
if(bf.Open(lpszFileName, CFile::modeCreate|CFile::modeWrite))
{
bf.Write(&bfh,sizeof(BITMAPFILEHEADER));
bf.Write(&bih,sizeof(BITMAPINFOHEADER));
bf.Write(lpData,size);
bf.Close();
}
else
{
ret = FALSE;
}
//釋放掉從堆中分配的內存,避免內存泄露
GlobalFree(hMem);
return ret;
}
//@brief 用GDI的方法將兩張Bitmap圖片合併起來
//@date 1-13-2009
//@param [in] pDC DC設備
//@param [in] pBitmap1 被合併的Bitmap圖片1
//@param [in] pBitmap2 被合併的Bitmap圖片2
//@return void
void C**Dlg::GDI_CombineBitmap(CDC *pDC, CBitmap *pBitmap1, CBitmap *pBitmap2)
{
CDC m_dcBk; ///<繪製背景圖設備
CDC m_dcFore; ///<繪製前景圖設備
CClientDC dc(this); //獲得當前客戶區設備環境
m_dcBk.CreateCompatibleDC(&dc); //創建與當前設備相兼容的設備
m_dcFore.CreateCompatibleDC(&dc);
CBitmap *poldBk = m_dcBk.SelectObject(pBitmap1); //選入背景圖
CBitmap *poldFore = m_dcFore.SelectObject(pBitmap2);
CRect rect;
CListCtrl m_NavigationList; ///<列表型控件變量
m_NavigationList.GetClientRect(&rect); //得到客戶區矩形
CDC maskDc; //創建設備環境maskDc
maskDc.CreateCompatibleDC(pDC); //創建與當前設備相兼容的設備
CBitmap maskBitmap;
maskBitmap.CreateBitmap(rect.Width(), rect.Height(), 1, 1, NULL ); //創建一個單色圖
CBitmap* pOldMaskDCBitmap = maskDc.SelectObject( &maskBitmap ); //選入單色圖
CBrush brush(RGB(255,255,255));
CBrush * oldbrush = NULL;
oldbrush = maskDc.SelectObject(&brush);
maskDc.FillRect(&rect,&brush);
//取得要消除的背景色值
COLORREF clrTrans = m_dcFore.GetPixel(2, 2);
//設置前景圖的背景色
COLORREF clrSaveBk = m_dcFore.SetBkColor(clrTrans);
//將前景圖拷貝到maskDc
maskDc.BitBlt(0,0,rect.Width(),rect.Height(), &m_dcFore, 0,0,SRCCOPY);
//前景圖與mask做‘與’運算
m_dcFore.SetBkColor(RGB(0,0,0));
m_dcFore.SetTextColor(RGB(255,255,255));
m_dcFore.BitBlt(0,0,rect.Width(), rect.Height(),&maskDc,0,0,SRCAND);
//背景圖與mask做‘與’運算
m_dcBk.SetBkColor(RGB(255,255,255));
m_dcBk.SetTextColor(RGB(0,0,0));
m_dcBk.BitBlt(0,0,rect.Width(),rect.Height(),&maskDc,0,0,SRCAND);
//背景圖與前景圖做‘或’運算
m_dcBk.BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&m_dcFore,0,0,SRCPAINT);
////將合成後的圖像顯示出來
//pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_dcBk,0,0,SRCCOPY);
pDC->SelectObject(oldbrush);
m_dcBk.SelectObject(poldBk);
m_dcFore.SelectObject(poldFore);
}
//@brief 實現屏幕抓圖功能,並將抓取的圖片保存爲Bitmap文件
//@date 1-12-2009
//@return 返回TRUE表示操作成功
BOOL C**Dlg::GetScreenBmpImage()
{
#ifdef USE_GDI_STORE_BMP
//定義源圖片(屏幕抓圖)的Left、Top、Width和Height
int nSrcImageLeft = 200;
int nSrcImageTop = 200;
int nSrcImageWidth = 0;
int nSrcImageHeight = 0;
//獲取源圖片(屏幕抓圖)Bitmap的寬高
nSrcImageWidth = GetSystemMetrics(SM_CXSCREEN);
nSrcImageHeight= GetSystemMetrics(SM_CYSCREEN);
//定義被保存的圖片的Left、Top、Width和Height
int nDestImageLeft = 0;
int nDestImageTop = 0;
int nDestImageWidth = 500;
int nDestImageHeight = 500;
CDC dc;
//獲取整個屏幕的dc(設備場景)
dc.CreateDC(_TEXT("DISPLAY"),NULL,NULL,NULL);
//爲屏幕dc創建兼容的內存dcMem
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
//創建一個與屏幕dc兼容的位圖
CBitmap bitmap;
bitmap.CreateCompatibleBitmap(&dc, nSrcImageWidth, nSrcImageHeight);
//把新位圖選到內存dc中,並保存原位圖
CBitmap *pOldBitmap = dcMem.SelectObject(&bitmap);
//將屏幕圖像從屏幕dc拷到內存dc,其實拷到到bitmap中
dcMem.BitBlt(nDestImageLeft,nDestImageTop,nDestImageWidth,nDestImageHeight,&dc,
nSrcImageLeft,nSrcImageTop,SRCCOPY);
//恢復內存dc中的原位圖
dcMem.SelectObject(pOldBitmap);
WCHAR strFileFullPath[MAX_PATH] = {0};
wcscpy(strFileFullPath,_TEXT("c:\\GDI_Screen.bmp"));
this->GDI_SaveBitmapToFile(dc.GetSafeHdc(), bitmap, strFileFullPath);
dc.DeleteDC();
#endif
#ifdef USE_GDI_GDIPLUS_STORE_BMP
//定義源圖片(屏幕抓圖)的Left、Top、Width和Height
int nSrcImageLeft = 200;
int nSrcImageTop = 200;
int nSrcImageWidth = 0;
int nSrcImageHeight = 0;
//獲取源圖片(屏幕抓圖)Bitmap的寬高
nSrcImageWidth = GetSystemMetrics(SM_CXSCREEN);
nSrcImageHeight= GetSystemMetrics(SM_CYSCREEN);
//定義被保存的圖片的Left、Top、Width和Height
int nDestImageLeft = 0;
int nDestImageTop = 0;
int nDestImageWidth = 400;
int nDestImageHeight = 500;
HDC hdcScreen,hMemDC;
HBITMAP hBitmap,hOldBitmap;
//建立一個屏幕設備環境句柄
hdcScreen = CreateDC(_TEXT("DISPLAY"),NULL,NULL,NULL);
//建立一個與屏幕設備環境句柄兼容的內存DC
hMemDC = CreateCompatibleDC(hdcScreen);
//建立一個與屏幕設備環境句柄兼容、寬高爲nSrcImageWidth,nSrcImageHeight的畫布,用於將各個圖像添加上去
hBitmap = CreateCompatibleBitmap(hdcScreen,nSrcImageWidth,nSrcImageHeight);
//把新位圖選到內存設備描述表中
hOldBitmap = (HBITMAP)SelectObject(hMemDC,hBitmap);
//把屏幕設備描述表拷貝到內存設備描述表中
BitBlt(hMemDC,nDestImageLeft,nDestImageTop,nDestImageWidth,nDestImageHeight,
hdcScreen,nSrcImageLeft,nSrcImageTop,SRCCOPY);
nDestImageLeft = 500;
nDestImageTop = 500;
nDestImageWidth = 600;
nDestImageHeight = 700;
nSrcImageLeft = 500;
nSrcImageTop = 500;
//把屏幕設備描述表拷貝到內存設備描述表中
BitBlt(hMemDC,nDestImageLeft,nDestImageTop,nDestImageWidth,
nDestImageHeight,hdcScreen,nSrcImageLeft,nSrcImageTop,SRCCOPY);
DeleteDC(hdcScreen);
DeleteDC(hMemDC);
WCHAR strFileFullPath[MAX_PATH] = {0};
wcscpy(strFileFullPath,_TEXT("c:\\GDIPlus_Screen.bmp"));
//保存的圖片大小由hBitmap的nSrcImageWidth和nSrcImageHeight決定
this->GDIPlus_SaveBitmapToFile(hBitmap, strFileFullPath);
#else
//定義源圖片(屏幕抓圖)的Left、Top、Width和Height
int nSrcImageLeft = 0;
int nSrcImageTop = 0;
int nSrcImageWidth = 0;
int nSrcImageHeight = 0;
//獲取源圖片(屏幕抓圖)Bitmap的寬高
nSrcImageWidth = GetSystemMetrics(SM_CXSCREEN);
nSrcImageHeight= GetSystemMetrics(SM_CYSCREEN);
//定義被保存的圖片的Left、Top、Width和Height
int nDestImageLeft = 0;
int nDestImageTop = 0;
int nDestImageWidth = GetSystemMetrics(SM_CXSCREEN);
int nDestImageHeight = GetSystemMetrics(SM_CYSCREEN);
CDC dc;
HDC hScreenBmpDC;
//獲取整個屏幕的dc(設備場景)
dc.CreateDC(_TEXT("DISPLAY"),NULL,NULL,NULL);
Graphics ScreenGraghics(dc.m_hDC) ;
//創建以屏幕大小爲標準的位圖
Bitmap SrcBitmap1(nSrcImageWidth , nSrcImageHeight , &ScreenGraghics ) ;
this->GDIPlus_GetBitmap(nDestImageLeft,nDestImageTop,nDestImageWidth,nDestImageHeight);
//Image是Bitmap的父類
Graphics* DestBitmapGraphics = Graphics::FromImage( &SrcBitmap1 ) ;
hScreenBmpDC = ScreenGraghics.GetHDC();
HDC hDestBmpDC = DestBitmapGraphics->GetHDC();
BitBlt ( hDestBmpDC , nDestImageLeft , nDestImageTop , nDestImageWidth ,
nDestImageHeight , hScreenBmpDC , nSrcImageLeft , nSrcImageTop , SRCCOPY ) ;
//釋放Bitmap的DC
DestBitmapGraphics->ReleaseHDC( hDestBmpDC ) ;
//釋放屏幕的DC
ScreenGraghics.ReleaseHDC(hScreenBmpDC);
//獲取整個屏幕的dc(設備場景)
dc.CreateDC(_TEXT("DISPLAY"),NULL,NULL,NULL);
Graphics ScreenGraghics2(dc.m_hDC) ;
//定義被保存的圖片的Left、Top、Width和Height
nDestImageLeft = 0;
nDestImageTop = 0;
nDestImageWidth = 1280;
nDestImageHeight = 1024;
//創建以屏幕大小爲標準的位圖
Bitmap SrcBitmap2(nSrcImageWidth , nSrcImageHeight , &ScreenGraghics2 ) ;
//Image是Bitmap的父類
Graphics* DestBitmapGraphics2 = Graphics::FromImage( &SrcBitmap2 ) ;
hScreenBmpDC = ScreenGraghics2.GetHDC();
HDC hDestBmpDC2 = DestBitmapGraphics2->GetHDC();
BitBlt ( hDestBmpDC2 , nDestImageLeft , nDestImageTop ,nDestImageWidth ,
nDestImageHeight ,hScreenBmpDC , nSrcImageLeft , nSrcImageTop , SRCCOPY ) ;
//釋放Bitmap的DC
DestBitmapGraphics2->ReleaseHDC( hDestBmpDC2 ) ;
//釋放屏幕的DC
ScreenGraghics2.ReleaseHDC(hScreenBmpDC);
int nbmpCombineWidth = GetSystemMetrics(SM_CXSCREEN);
int nbmpCombineHeight= GetSystemMetrics(SM_CYSCREEN);
//用於Bitmap合併的畫布
Bitmap bmpCombine(2*nbmpCombineWidth,nbmpCombineHeight);
Graphics * pG = NULL;
pG = Graphics::FromImage(&bmpCombine);
if (pG != NULL)
{
pG->DrawImage(&SrcBitmap1,0,0,1280,1024);
pG->DrawImage(&SrcBitmap2,500,0,1280,1024);
CLSID pngClsid;
//獲取BMP文件的編碼方式
int nResult = GetEncoderClsid(_TEXT("image/bmp"),&pngClsid);
bmpCombine.Save(_TEXT("c:\\Capture2.bmp"),&pngClsid,NULL);
}
#endif
#ifdef STORE_IN_CLIPBOARD
//屏幕已拷到兼容位圖bitmap上,下面將它保存到剪貼板
if((::OpenClipboard(NULL) != 0) && (::EmptyClipboard() != 0))
{
::SetClipboardData(CF_BITMAP,bitmap.GetSafeHandle());
::CloseClipboard();
}
#endif
return TRUE;
}
//@brief 創建一個畫布,在上面任意畫圖形,並且返回該畫布的縮略圖
//@date 1-13-2009
//@return 返回縮略圖指針
Bitmap * C**Dlg::GetThumbnailPageImage()
{
int nScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
//定義寬爲nScreenWidth,高爲nScreenHeight的位圖
Bitmap pPageImage(nScreenWidth, nScreenHeight, PixelFormat16bppRGB565);
//Imagegraphics作爲pPageImage的畫布,接受繪畫的信息
Graphics Imagegraphics(&pPageImage);
SolidBrush bkbrush(Color(255,255,255,0));
//填充畫布背景Imagegraphics
Imagegraphics.FillRectangle(&bkbrush, 0, 0, nScreenWidth, nScreenHeight);
Pen pen(Color(255,255,0,0), 4.0f);
//在畫布上畫個矩形
Imagegraphics.DrawRectangle(&pen, 200, 200, 500, 500);
////在畫布上畫圖形(這是GDI+合併圖片的方法之一)
//Imagegraphics.DrawImage()
//縮略圖的寬
int nThumbnailWidth = 90;
//縮略圖的高
int nThumbnailHeight = 90;
Bitmap *pThumbnailImage = NULL;
//獲取Bitmap(pPageImage)的縮略圖
pThumbnailImage = (Bitmap *)pPageImage.GetThumbnailImage(nThumbnailWidth, nThumbnailHeight,NULL, NULL);
//返回縮略圖指針
return pThumbnailImage;
}