?? bmpproc.cpp
字號:
///////////////////////////////////////////////////////////////////////
/*
目的:BMP位圖處理類。(源代碼文件)
創(chuàng)建:張偉(SXZ)
日期:2000.01
版本:2.4
SXZ software workgroup. No.200001
*/
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/*
注釋:
# 類中的位圖都是兼容于當前顯示器顏色格式的DDB位圖
# 如果讀入的位圖格式與當前顯示器的顏色格式不同,則讀入函數(shù)會先將其轉(zhuǎn)換
為兼容于當前顯示器顏色格式的位圖之后才放入類中
# 對于所有BOOL型返回的函數(shù),TRUE表示成功,F(xiàn)ALSE表示失敗
*/
///////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <math.h>
#include <io.h>
#include <errno.h>
#include <direct.h>
#include "BmpProc.h"
////////////////////////////// defines ///////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// 用于調(diào)試目的計數(shù)變量,它表示程序中構造的CBmpProc類實例個數(shù)
// 可以用類中static DWORD GetObjectCount()成員函數(shù)訪問該變量
// 注意:該變量和訪問它的函數(shù)都只是在調(diào)試模式下才會有效,如果
// 轉(zhuǎn)換為發(fā)布模式,它們都會失效。所以在使用GetObjectCount()
// 這個成員函數(shù)時,應加入#ifdef _DEBUG .... #endif語句塊
#ifdef _DEBUG
DWORD CBmpProc::m_ObjectCount = 0;
#endif
/*************************************************************************
* 構造函數(shù)。初始化類為空。
*************************************************************************/
CBmpProc::CBmpProc()
{
// 初始化核心數(shù)據(jù)為空
m_mark = FALSE; // 有效標志。(TRUE-有有效位圖,否則為FALSE)
m_type = IT_NULL; // 圖像類型。
m_addInfo = 0; // 附加信息。
m_cFileName.Empty(); // 文件路徑。
m_pInfo = NULL; // DIB信息結(jié)構
m_hObject = NULL; // 清除核心DDB位圖句柄。(基類成員)
#ifdef _DEBUG
CBmpProc::m_ObjectCount++;
#endif
}
/*************************************************************************
* 調(diào)試用函數(shù),獲取進程中CBmpProc類目標的個數(shù)。
*************************************************************************
#ifdef _DEBUG
DWORD CBmpProc::GetObjectCount()
{
return m_ObjectCount;
}
#endif
*************************************************************************/
/*************************************************************************
* 析構函數(shù)。如果類不為空則清空它。
*************************************************************************/
CBmpProc::~CBmpProc()
{
Clear();
#ifdef _DEBUG
CBmpProc::m_ObjectCount--;
#endif
}
/*************************************************************************
*
* operator=()
*
* 參數(shù)說明:
*
* const CBmpProc& ds - 源位圖類
*
* 返回值:
*
* CBmpProc& - 類自身引用
*
* 描述:
*
* 復制取指定的位圖類
*
* 如果函數(shù)成功,則類中原來的位圖(如果有的話)將被刪除,如果不成功,它保留
* 原位圖。執(zhí)行本函數(shù)之后,可調(diào)用該類的IsValid()函數(shù)判斷是否成功復制(這種
* 情況只使用于沒有圖像的類,如果復制前類中就存在圖像,可用==操作符判斷該類
* 與源位圖類是否相同,如果相同則表示復制成功,不同就說明失敗)
*
************************************************************************/
CBmpProc& CBmpProc::operator=(const CBmpProc& ds)
{
// 如果類中沒有圖像,直接返回
if (!ds.IsValid())
return *this;
ASSERT(ds.m_pInfo);
ASSERT(ds.m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
// 復制源圖信息塊
LPBITMAPINFO pInfo = (LPBITMAPINFO)CreateMemoryBlockFromAddress(
(LPVOID)ds.m_pInfo);
if (!pInfo)
return *this;
// 復制源圖
CBitmap tempBmp;
HBITMAP hBmp;
HWND hWnd = ::GetDesktopWindow();
ASSERT(hWnd);
HDC hDC = ::GetDC(hWnd);
CDC dc;
dc.Attach(hDC);
if (tempBmp.CreateCompatibleBitmap(&dc, ds.Width(), ds.Height()))
{
CDC compDC, compDC2;
CBitmap *pOldBmp, *pOldBmp2;
// 創(chuàng)建與當前顯示設備兼容的內(nèi)存設備描述表
compDC.CreateCompatibleDC(NULL);
compDC2.CreateCompatibleDC(NULL);
pOldBmp = compDC.SelectObject((CBitmap*)&tempBmp);
pOldBmp2= compDC2.SelectObject((CBitmap*)&ds);
// 復制指定尺寸的源位圖到目標位圖
compDC.BitBlt(0, 0, ds.Width(), ds.Height(),
&compDC2, 0, 0, SRCCOPY);
compDC2.SelectObject(pOldBmp2);
compDC.SelectObject(pOldBmp);
hBmp = (HBITMAP)tempBmp.Detach();
// 如果分離操作失敗,返回FALSE
ASSERT(hBmp);
if (!hBmp)
{
::ReleaseDC(hWnd, dc.Detach());
::free((void*)pInfo);
return *this;;
}
::ReleaseDC(hWnd, dc.Detach());
// 刪除原來的圖像,并且設置新的位圖
if (!ClearAndSetData(IT_MEMORY,0,(LPCTSTR)"",pInfo,hBmp))
{
::free((void*)pInfo);
::DeleteObject(hBmp);
return *this;
}
return *this;
}
else
{
::ReleaseDC(hWnd, dc.Detach());
::free((void*)pInfo);
return *this;;
}
}
/*************************************************************************
*
* operator=()
*
* 參數(shù)說明:
*
* const HBITMAP sou - 源位圖句柄
*
* 返回值:
*
* CBmpProc& - 類自身引用
*
* 描述:
*
* 復制取指定的位圖
*
* 如果函數(shù)成功,則類中原來的位圖(如果有的話)將被刪除,如果不成功,它保留
* 原位圖。執(zhí)行本函數(shù)之后,可調(diào)用該類的IsValid()函數(shù)判斷是否成功復制(這種
* 情況只使用于沒有圖像的類,如果復制前類中就存在圖像,可用==操作符判斷該類
* 與源位圖類是否相同,如果相同則表示復制成功,不同就說明失敗)
* 如果入口參數(shù)指定的位圖句柄無效,則函數(shù)失敗。
*
************************************************************************/
CBmpProc& CBmpProc::operator=(const HBITMAP sou)
{
// 入口檢測
if (!sou)
return *this;
CBmpProc tmp;
if (!tmp.Attach(sou))
return *this;
ASSERT(sou == (HBITMAP)tmp);
// 調(diào)用類賦值操作符函數(shù)
*this = tmp;
// 分離源位圖,防止析構函數(shù)將其刪除
tmp.Detach();
return *this;
}
/*************************************************************************
*
* operator==()
*
* 參數(shù)說明:
*
* const CBmpProc& ds - 源位圖類
*
* 返回值:
*
* BOOL - 如果相同返回TRUE,不同返回FALSE
*
* 描述:
*
* 判斷源位圖類與本身類是否相同
*
* 該函數(shù)通過比較兩個類的位圖來判定它們是否具有相同的圖像。
*
* 注:# 如果兩個類都是空的(即都沒有圖像),則該函數(shù)將視它們是不相同的
*
************************************************************************/
BOOL CBmpProc::operator==(const CBmpProc& ds)
{
// 如果兩個類中有一個或都是空的(即都沒有圖像),則該函數(shù)將視它們
// 是不相同的
if ((ds.IsValid()==FALSE)||(IsValid()==FALSE))
return FALSE;
// 如果是與自身比較,則直接返回TRUE
if (this == &ds)
return TRUE;
ASSERT(m_pInfo);
ASSERT(ds.m_pInfo);
ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
ASSERT(ds.m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
// 信息塊長度比較
if (::_msize(m_pInfo) != ::_msize(ds.m_pInfo))
return FALSE;
// 信息塊內(nèi)容比較
if (::memcmp((const void*)m_pInfo, \
(const void*)ds.m_pInfo,::_msize(m_pInfo)))
return FALSE;
// 創(chuàng)建存放DIB位數(shù)據(jù)的緩沖區(qū)
LPSTR pBits1 = (LPSTR)CreateMemoryBlockFromAddress((LPVOID)NULL,
CalculateDIBitsSize((LPBITMAPINFOHEADER)m_pInfo));
if (!pBits1)
return FALSE;
LPSTR pBits2 = (LPSTR)CreateMemoryBlockFromAddress((LPVOID)NULL,
CalculateDIBitsSize((LPBITMAPINFOHEADER)m_pInfo));
if (!pBits2)
{
::free((void*)pBits1);
return FALSE;
}
// 復制位圖信息塊,因為GetDIBits()函數(shù)有可能會改變顏色表數(shù)據(jù)
LPBITMAPINFO pInfo = (LPBITMAPINFO)CreateMemoryBlockFromAddress(
(LPVOID)m_pInfo);
if (!pInfo)
{
::free((void*)pBits1);
::free((void*)pBits2);
return FALSE;
}
ASSERT(pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
HWND hWnd = ::GetDesktopWindow();
ASSERT(hWnd);
HDC hDC;
// 獲取位圖的DIB位數(shù)據(jù)
hDC = ::GetDC(hWnd);
ASSERT(m_hObject);
ASSERT(ds.m_hObject);
if (!::GetDIBits(hDC,(HBITMAP)m_hObject,0,pInfo->bmiHeader.biHeight, \
(LPVOID)pBits1,pInfo,DIB_RGB_COLORS))
{
::free((void*)pBits1);
::free((void*)pBits2);
::free((void*)pInfo);
::ReleaseDC(hWnd, hDC);
return FALSE;
}
if (!::GetDIBits(hDC,(HBITMAP)ds.m_hObject,0,pInfo->bmiHeader.biHeight, \
(LPVOID)pBits2,pInfo,DIB_RGB_COLORS))
{
::free((void*)pBits1);
::free((void*)pBits2);
::free((void*)pInfo);
::ReleaseDC(hWnd, hDC);
return FALSE;
}
::ReleaseDC(hWnd, hDC);
::free((void*)pInfo);
// 位內(nèi)容比較
LONG leng = (LONG)CalculateDIBitsSize((LPBITMAPINFOHEADER)m_pInfo)/4;
LPDWORD lp1 = (LPDWORD)pBits1; // DIB位數(shù)據(jù)是DWORD對齊的
LPDWORD lp2 = (LPDWORD)pBits2;
// 因為不清楚memcmp()函數(shù)是否可以比較大于64K的數(shù)據(jù),所以才采用這種
// 老笨的方法。
while(leng--)
{
if (*lp1 != *lp2) break;
lp1++; lp2++;
}
// 比較完之后,位數(shù)據(jù)已無用,釋放
::free((void*)pBits1);
::free((void*)pBits2);
if (leng != -1L)
return FALSE; // 位數(shù)據(jù)不同返回FALSE
return TRUE;
}
/*************************************************************************
*
* operator!=()
*
* 參數(shù)說明:
*
* const CBmpProc& ds - 源位圖類
*
* 返回值:
*
* BOOL - 如果不同返回TRUE,相同返回FALSE
*
* 描述:
*
* 判斷源位圖類是否與本身類不同
*
* 該函數(shù)通過比較兩個類的位圖來判定它們是否具有相同的圖像。
*
* 注:# 如果兩個類都是空的(即都沒有圖像),則該函數(shù)將視它們是不相同的
*
************************************************************************/
BOOL CBmpProc::operator!=(const CBmpProc& ds)
{
return ((*this) == ds) ? FALSE:TRUE;
}
/*************************************************************************
*
* Draw()
*
* 參數(shù)說明:
*
* CDC& dc - 顯示位圖的設備描述表
* const CRect* rcDst - 目標矩形
* const CRect* rcSrc - 源矩形
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否則返回FALSE
*
* 描述:
*
* 將類中指定區(qū)域的圖像繪入目標設備描述表的指定區(qū)域,如果源區(qū)域(即矩形)
* 和目標區(qū)域不同,將產(chǎn)生拉伸或壓縮動作
*
* 如果源矩形和目標矩形是NULL,則函數(shù)將視這兩個矩形都等于類中圖像的尺寸
*
* 如果類中沒有圖像,它什么也不作,直接返回
* 如果待繪制的圖像不在當前剪貼區(qū)域內(nèi),則直接返回
*
************************************************************************/
BOOL CBmpProc::Draw(CDC& dc, const CRect* rcDst, const CRect* rcSrc)
{
// 如果類中沒有圖像,直接返回
if (!IsValid())
return TRUE;
ASSERT(m_hObject);
// 缺省矩形等于圖像尺寸
CRect DCRect(Rect()); // 目標位置數(shù)據(jù)
CRect DibRect(Rect()); // 源位置數(shù)據(jù)
if (rcDst)
DCRect = *rcDst;
if (rcSrc)
DibRect = *rcSrc;
// 如果待繪制的圖像不在當前剪貼區(qū)域內(nèi),則直接返回
if (!dc.RectVisible(&DCRect))
return TRUE;
CDC compDC;
CBitmap *pOldBmp;
compDC.CreateCompatibleDC(NULL);
pOldBmp = compDC.SelectObject((CBitmap*)this);
/* 設置目標DC的拉伸模式為STRETCH_DELETESCANS,也就是不顯示拉伸掉的圖像 */
int srlold = dc.SetStretchBltMode(STRETCH_DELETESCANS);
// 顯示位圖
dc.StretchBlt(DCRect.left, DCRect.top, DCRect.Width(), DCRect.Height(),
&compDC, DibRect.left, DibRect.top,
DibRect.Width(), DibRect.Height(), SRCCOPY);
// 恢復設備描述表原來的設置
dc.SetStretchBltMode(srlold);
compDC.SelectObject(pOldBmp);
return TRUE;
}
/*************************************************************************
*
* DrawTile()
*
* 參數(shù)說明:
*
* CDC& dc - 顯示位圖的設備描述表
* CRect* crArea - 鋪設范圍(矩形坐標)
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否則返回FALSE
*
* 描述:
*
* 將類中的圖像以平鋪方式排滿指定區(qū)域
*
* 如果入口參數(shù)crArea是NULL,則函數(shù)返回FALSE,如果矩形坐標不符合規(guī)范(比如
* 左邊的坐標大于右邊的坐標)則函數(shù)將自動將其規(guī)范化。如果矩形坐標的寬度
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -