www.pudn.com > 人体步态跟踪识别bate版.rar > Cdib.cpp
// cdib.cpp
#include "stdafx.h"
#include "cdib.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_SERIAL(CDib, CObject, 0);
////////////////////////////////////////////
//缺省构造函数
//
//创建一个空的DIB对象
/////////////////////////////////////////////
CDib::CDib()
{
m_hFile = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
m_Dest.x = 0;
m_Dest.y = 0;
m_DestSize.cx = 0;
m_DestSize.cy = 0;
m_Src.x = 0;
m_Src.y = 0;
m_SrcSize.cx = 0;
m_SrcSize.cy = 0;
InitDestroy();
}
////////////////////////////////////////////
//通过CreateDIBSection函数创建DIB项时,使用这个函数。
//它包括DIB的尺寸和颜色数。它对信息头分配内存,而对图
//像不分配内存。
//参数
//size:图像的宽度和高度;
//nBitCounts:像素的位数(为1、4、8、16、24、32)
////////////////////////////////////////////
CDib::CDib(CSize size, int nBitCounts)
{
m_hFile = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
InitDestroy();
ComputePaletteSize(nBitCounts);//为BITMAPINFOHEADER结构申请空间。
m_lpBMPHdr = (LPBITMAPINFOHEADER) new
char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries];
m_lpBMPHdr->biSize = sizeof(BITMAPINFOHEADER);//以下是为BITMAPINFOHEADER结构赋值
m_lpBMPHdr->biWidth = size.cx;
m_lpBMPHdr->biHeight = size.cy;
m_lpBMPHdr->biPlanes = 1;
m_lpBMPHdr->biBitCount = nBitCounts;
m_lpBMPHdr->biCompression = BI_RGB;
m_lpBMPHdr->biSizeImage = 0;
m_lpBMPHdr->biXPelsPerMeter = 0;
m_lpBMPHdr->biYPelsPerMeter = 0;
m_lpBMPHdr->biClrUsed = m_nColorEntries;
m_lpBMPHdr->biClrImportant = m_nColorEntries;
ComputeImage();
memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorEntries);
m_lpDIBits = NULL;
}
////////////////////////////////////////////
//析构函数,释放内存
////////////////////////////////////////////
CDib::~CDib()
{
InitDestroy();
}
////////////////////////////////////////////
//返回值:图像的高度
////////////////////////////////////////////
int CDib::GetHeight ()
{
if(m_lpBMPHdr == NULL) return 0;
return m_lpBMPHdr->biHeight;//返回图像的高度
}
////////////////////////////////////////////
//返回值:图像的宽度
////////////////////////////////////////////
int CDib::GetWidth ()
{
if(m_lpBMPHdr == NULL) return 0;
return m_lpBMPHdr->biWidth;//返回图像的宽度
}
////////////////////////////////////////////
//该函数用只读模式打开一个内存映射文件。
//参数
//strPathName:映射的文件路径
//bSharing:TRUE 以共享方式打开;FALSE 缺省值
//返回值:成功为TRUE
////////////////////////////////////////////
BOOL CDib::SetMapFile(const char* strPathname, BOOL bSharing) // 只读
{
//如果我们两次打开同一文件,Windows会把它当作两个单独的文件
//如果调色板的颜色数大于实际使用的颜色数,则不会工作
HANDLE hFile =
::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ,
bSharing ? FILE_SHARE_READ : 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileSize = ::GetFileSize(hFile, NULL);
HANDLE hMap = ::CreateFileMapping(hFile,
NULL, PAGE_READWRITE, 0, 0, NULL);
DWORD dwErr = ::GetLastError();
if(hMap == NULL) {
AfxMessageBox("Empty bitmap file");
return FALSE;
}
// 映射整个文件
LPVOID lpvFile = ::MapViewOfFile(hMap,
FILE_MAP_WRITE, 0, 0, 0);
ASSERT(lpvFile != NULL);
if(((LPBITMAPFILEHEADER) lpvFile)->bfType != 0x4d42) {
AfxMessageBox("Invalid bitmap file");
ReleaseMapFile();
return FALSE;
}
AllotDibMemory((LPBYTE) lpvFile +
sizeof(BITMAPFILEHEADER));
m_lpvFile = lpvFile;
m_hFile = hFile;
m_hMap = hMap;
return TRUE;
}
////////////////////////////////////////////
//这个函数创建一个新的内存映射文件,并把
//信息拷贝到该文件中,释放内存。
//strPathName:映射的文件路径
//返回值:成功为TRUE
////////////////////////////////////////////
BOOL CDib::CopyMapFile(const char* strPathname)
{
//将DIB拷贝到一个新的文件中,释放先前的指针
//如果以前使用过CreateSection函数,则HBITMAP为NULL
BITMAPFILEHEADER bmfh;
bmfh.bfType = 0x4d42; // 'BM'
bmfh.bfSize =
m_dwImageSize + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorEntries + sizeof(BITMAPFILEHEADER);
// meaning of bfSize open to interpretation
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
bmfh.bfOffBits =
sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
+ sizeof(RGBQUAD) * m_nColorEntries;
HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE |
GENERIC_READ, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
int size =
sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorEntries + m_dwImageSize;
HANDLE hMap = ::CreateFileMapping(hFile, NULL,
PAGE_READWRITE, 0, size, NULL);
DWORD dwErr = ::GetLastError();
ASSERT(hMap != NULL);
// 映射整个文件
LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
ASSERT(lpvFile != NULL);
LPBYTE lpbCurrent = (LPBYTE) lpvFile;
memcpy(lpbCurrent, &bmfh, sizeof(BITMAPFILEHEADER)); // 文件头
lpbCurrent += sizeof(BITMAPFILEHEADER);
LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) lpbCurrent;
memcpy(lpbCurrent, m_lpBMPHdr, sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorEntries);
lpbCurrent += sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorEntries;
memcpy(lpbCurrent, m_lpDIBits, m_dwImageSize); // bit 图像
DWORD dwSizeImage = m_dwImageSize;
InitDestroy();
m_dwImageSize = dwSizeImage;
m_lpBMPHdr = lpBMIH;
m_lpDIBits = lpbCurrent;
m_hFile = hFile;
m_hMap = hMap;
m_lpvFile = lpvFile;
ComputePaletteSize(m_lpBMPHdr->biBitCount);
ComputeImage();
SetWinPalette();
return TRUE;
}
////////////////////////////////////////////
//将内存和一个DIB对象联系起来。
//参数
//lpvMemory:内存地址
////////////////////////////////////////////
BOOL CDib::AllotDibMemory(LPVOID lpvMemory)
{
//假定一个BITMAPINFOHEADER结构,颜色表,图像
//颜色表的长度可以为0
InitDestroy();
try {
m_lpBMPHdr = (LPBITMAPINFOHEADER) lpvMemory;
ComputeImage();
ComputePaletteSize(m_lpBMPHdr->biBitCount);
m_lpDIBits = (LPBYTE) m_lpvColorTable +
sizeof(RGBQUAD) * m_nColorEntries;
SetWinPalette();
}
catch(CException* pe) {
AfxMessageBox("AllotDibMemory error");
pe->Delete();
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////
//把DIB对象的逻辑调色板选进设备环境里,然后
//实现调色板。
//参数
//pDC:设备环境指针
////////////////////////////////////////////
UINT CDib::UseLogPalette(CDC* pDC)
{
if(m_hPalette == NULL) return 0;
HDC hdc = pDC->GetSafeHdc();
::SelectPalette(hdc, m_hPalette,FALSE);//Windows作为前台调色板来实现该调色板
return ::RealizePalette(hdc);
}
/////////////////////////////////////////////
//这个函数用来显示DIB图像
//参数
//pDC:设备环境指针
//origin:显示DIB的逻辑坐标
//size:DIB的逻辑宽度和高度
////////////////////////////////////////////
BOOL CDib::Display(CDC* pDC)
{
if(m_lpBMPHdr == NULL) return FALSE;
if(m_hPalette != NULL) {
::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
}
pDC->SetStretchBltMode(COLORONCOLOR);
//取得图像文件的拷贝文件
char name[30] ;
GetCurrentDirectory(30, name) ;
CString Pathname = CString(name) ;
CopyMapFile(Pathname) ;
::StretchDIBits(pDC->GetSafeHdc(), m_Dest.x, m_Dest.y,
m_DestSize.cx, m_DestSize.cy,
m_Src.x, m_Src.y,
m_SrcSize.cx, m_SrcSize.cy,
m_lpDIBits, (LPBITMAPINFO) m_lpBMPHdr,
DIB_RGB_COLORS, SRCCOPY);
return TRUE;
}
/////////////////////////////////////////////
//调用CreateDIBSection函数来创建DIB项
//参数
//pDC:设备环境指针
////////////////////////////////////////////
//调用CreateDIBSection函数来创建DIB项
HBITMAP CDib::CreateSection(CDC* pDC )
{
if(m_lpBMPHdr == NULL) return NULL;
if(m_lpDIBits != NULL) return NULL; // 图像不存在
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
(LPVOID*) &m_lpDIBits, NULL, 0);
ASSERT(m_lpDIBits != NULL);
return m_hBitmap;
}
/////////////////////////////////////////////
//调用CreateDIBSection函数来创建DIB项
//从DIB颜色表生成逻辑调色板,在显示DIB位图之前,
//将这个调色板选入设备并实现它
////////////////////////////////////////////
BOOL CDib::SetWinPalette()
{
if(m_nColorEntries == 0) return FALSE;
if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
TRACE("CDib::MakePalette -- m_nColorEntries = %d\n", m_nColorEntries);
LPLOGPALETTE pLogPal =
(LPLOGPALETTE) new char[2 * sizeof(WORD) +
m_nColorEntries * sizeof(PALETTEENTRY)];
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = m_nColorEntries;
LPRGBQUAD pDibRGBquad = (LPRGBQUAD) m_lpvColorTable;
for(int i = 0; i < m_nColorEntries; i++) {
pLogPal->palPalEntry[i].peRed =
pDibRGBquad->rgbRed;
pLogPal->palPalEntry[i].peGreen =
pDibRGBquad->rgbGreen;
pLogPal->palPalEntry[i].peBlue =
pDibRGBquad->rgbBlue;
pLogPal->palPalEntry[i].peFlags = 0;
pDibRGBquad++;
}
m_hPalette = ::CreatePalette(pLogPal);
delete pLogPal;
return TRUE;
}
/////////////////////////////////////////////
//如果DIB没有颜色表,可以用逻辑调色板。
//参数
//pDC:设备环境指针
////////////////////////////////////////////
BOOL CDib::SetLogPalette(CDC* pDC)
{
//如果DIB没有颜色表,可以用逻辑调色板
if(m_nColorEntries != 0) return FALSE;
m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc());
return TRUE;
}
/////////////////////////////////////////////
//用DIB创建一个DDB位图。
//参数
//pDC:设备环境指针
////////////////////////////////////////////
HBITMAP CDib::CreateBitmap(CDC* pDC)
{
if (m_dwImageSize == 0) return NULL;
HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(),
m_lpBMPHdr, CBM_INIT, m_lpDIBits,
(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS);
ASSERT(hBitmap != NULL);
return hBitmap;
}
/////////////////////////////////////////////
//这个函数产生压缩或非压缩的DIB。
//参数
//pDC:设备环境指针
//BitsCompress:TRUE 表示压缩;FALSE 表示解压缩
////////////////////////////////////////////
BOOL CDib::CompressDib(CDC* pDC, BOOL BitsCompress /* = TRUE */)
{
//先将DIB转换到一个DDB
//从这个DDB来生成一个新的DIB
//清除原来的DIB
//将新的DIB放到目标中
if((m_lpBMPHdr->biBitCount != 4) &&
(m_lpBMPHdr->biBitCount != 8))
return FALSE;
// 压缩只支持4-bpp和8-bpp的方式的DIB
if(m_hBitmap) return FALSE; // 不能压缩单个DIB项
TRACE("Compress: original palette size = %d\n",
m_nColorEntries);
HDC hdc = pDC->GetSafeHdc();
HPALETTE hOldPalette =
::SelectPalette(hdc, m_hPalette, FALSE);
HBITMAP hBitmap;
if((hBitmap = CreateBitmap(pDC)) == NULL)
return FALSE;
int nSize = sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorEntries;
LPBITMAPINFOHEADER lpBMPHdr =
(LPBITMAPINFOHEADER) new char[nSize];
memcpy(lpBMPHdr, m_lpBMPHdr, nSize);
if(BitsCompress) {
switch (lpBMPHdr->biBitCount) {
case 4:
lpBMPHdr->biCompression = BI_RLE4;
break;
case 8:
lpBMPHdr->biCompression = BI_RLE8;
break;
default:
ASSERT(FALSE);
}
//调用GetDIBits函数来获得压缩的DIB的尺寸
if(!::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0,
(UINT) lpBMPHdr->biHeight,
NULL, (LPBITMAPINFO) lpBMPHdr, DIB_RGB_COLORS)) {
AfxMessageBox("Unable to compress this DIB");
//如果不能压缩则删除相应的内存空间
::DeleteObject(hBitmap);
delete [] lpBMPHdr;
::SelectPalette(hdc, hOldPalette, FALSE);
return FALSE;
}
if (lpBMPHdr->biSizeImage == 0) {
AfxMessageBox("Driver can't do compression");
::DeleteObject(hBitmap);
delete [] lpBMPHdr;
::SelectPalette(hdc, hOldPalette, FALSE);
return FALSE;
}
else {
m_dwImageSize = lpBMPHdr->biSizeImage;
}
}
else {
lpBMPHdr->biCompression = BI_RGB; //解压缩
//从bitmap的宽度和高度计算出图像的尺寸
DWORD dwBytes = ((DWORD) lpBMPHdr->biWidth *
lpBMPHdr->biBitCount) / 32;
if(((DWORD) lpBMPHdr->biWidth * lpBMPHdr->biBitCount) % 32) {
dwBytes++;
}
dwBytes *= 4;
m_dwImageSize = dwBytes * lpBMPHdr->biHeight; // 不解压
lpBMPHdr->biSizeImage = m_dwImageSize;
}
//第二次调用GetDIBits函数来生成DIB项
LPBYTE lpImage = (LPBYTE) new char[m_dwImageSize];
VERIFY(::GetDIBits(pDC->GetSafeHdc(),
hBitmap, 0, (UINT) lpBMPHdr->biHeight,
lpImage, (LPBITMAPINFO) lpBMPHdr, DIB_RGB_COLORS));
TRACE("dib successfully created - height = %d\n",
lpBMPHdr->biHeight);
::DeleteObject(hBitmap);
InitDestroy();
m_lpBMPHdr = lpBMPHdr;
m_lpDIBits = lpImage;
ComputeImage();
ComputePaletteSize(m_lpBMPHdr->biBitCount);
SetWinPalette();
::SelectPalette(hdc, hOldPalette, FALSE);
TRACE("Compress: new palette size = %d\n", m_nColorEntries);
return TRUE;
}
/////////////////////////////////////////////
//这个函数从文件中将DIB读进CDib对象中,文件
//被成功的打开。
//参数
//pFile:指向包含DIB文件的指针
////////////////////////////////////////////
BOOL CDib::ReadFile(CFile* pFile)
{
//读文件头得到BITMAPINFOHEADER和颜色表的大小
//读BITMAPINFOHEADER得到图像小、尺寸和颜色表
//读取图像信息
InitDestroy();
int counts, size;
BITMAPFILEHEADER bmfh;
try {
counts = pFile->Read((LPVOID)&bmfh, sizeof(BITMAPFILEHEADER));
if(counts != sizeof(BITMAPFILEHEADER))
{
throw new CException;
}
if(bmfh.bfType != 0x4d42)
{
throw new CException;
}
size = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
m_lpBMPHdr = (LPBITMAPINFOHEADER) new char[size];
// BITMAPINFOHEADER和颜色表
counts = pFile->Read(m_lpBMPHdr, size);
ComputeImage();
ComputePaletteSize(m_lpBMPHdr->biBitCount);
SetWinPalette();
m_lpDIBits = (LPBYTE) new char[m_dwImageSize];
counts = pFile->Read(m_lpDIBits, m_dwImageSize);
}
catch(CException* pe) {
AfxMessageBox("Read error");
pe->Delete();
return FALSE;
}
return TRUE;
}
/////////////////////////////////////////////
//读BMP文件得到信息头和颜色表的大小,用这些信息
//来创建图像,并将其读到用CreateDibSection分配
//的空间中。
//参数
//pFile:指向包含DIB文件的指针
//pDC:设备环境指针
////////////////////////////////////////////
BOOL CDib::ReadSection(CFile* pFile, CDC* pDC /* = NULL */)
{
InitDestroy();
int counts, size;
BITMAPFILEHEADER bmfh;
try {
counts = pFile->Read((LPVOID) &bmfh,
sizeof(BITMAPFILEHEADER));
if(counts != sizeof(BITMAPFILEHEADER)) {
throw new CException;
}
if(bmfh.bfType != 0x4d42) {
throw new CException;
}
size = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
m_lpBMPHdr = (LPBITMAPINFOHEADER) new char[size];
//BITMAPINFOHEADER和颜色表
counts = pFile->Read(m_lpBMPHdr, size);
if(m_lpBMPHdr->biCompression != BI_RGB) {
throw new CException;
}
ComputeImage();
ComputePaletteSize(m_lpBMPHdr->biBitCount);
SetWinPalette();
UseLogPalette(pDC);
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
(LPVOID*) &m_lpDIBits, NULL, 0);
ASSERT(m_lpDIBits != NULL);
counts = pFile->Read(m_lpDIBits, m_dwImageSize); // 图像
}
catch(CException* pe) {
AfxMessageBox("ReadSection error");
pe->Delete();
return FALSE;
}
return TRUE;
}
///////////////////////////////////////////////
//这个函数将DIB从CDib对象中写到文件中,文件
//被成功的打开。
//参数
//pFile:指向包含DIB文件的指针
///////////////////////////////////////////////
BOOL CDib::WriteFile(CFile* pFile)
{
BITMAPFILEHEADER bmfh;
bmfh.bfType = 0x4d42; // 'BM'
int sizeHdr = sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorEntries;
bmfh.bfSize = 0;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
bmfh.bfOffBits =
sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorEntries;
try {
pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
pFile->Write((LPVOID) m_lpBMPHdr, sizeHdr);
pFile->Write((LPVOID) m_lpDIBits, m_dwImageSize);
}
catch(CException* pe) {
pe->Delete();
AfxMessageBox("write error");
return FALSE;
}
return TRUE;
}
//存储图像
void CDib::Serialize(CArchive& ar)
{
DWORD pos;
pos = ar.GetFile()->GetPosition();
TRACE("CDib::Serialize -- pos = %d\n", pos);
ar.Flush();
pos = ar.GetFile()->GetPosition();
TRACE("CDib::Serialize -- pos = %d\n", pos);
if(ar.IsStoring()) {
WriteFile(ar.GetFile());
}
else {
ReadFile(ar.GetFile());
}
}
///////////////////////////////////////////////
//这个函数计算调色板的大小。
//参数
//nBitCounts:像素的位数(为1、4、8、16、24、32)
///////////////////////////////////////////////
void CDib::ComputePaletteSize(int nBitCounts)
{
if((m_lpBMPHdr == NULL) || (m_lpBMPHdr->biClrUsed == 0)) {
switch(nBitCounts) {
case 1:
m_nColorEntries = 2;
break;
case 4:
m_nColorEntries = 16;
break;
case 8:
m_nColorEntries = 256;
break;
case 16:
case 24:
case 32:
m_nColorEntries = 0;
break;
default:
ASSERT(FALSE);
}
}
else {
m_nColorEntries = m_lpBMPHdr->biClrUsed;
}
ASSERT((m_nColorEntries >= 0) && (m_nColorEntries <= 256));
}
///////////////////////////////////////////////
//这个函数计算图像的大小。
///////////////////////////////////////////////
void CDib::ComputeImage()
{
if(m_lpBMPHdr->biSize != sizeof(BITMAPINFOHEADER)) {
TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n");
throw new CException;
}
m_dwImageSize = m_lpBMPHdr->biSizeImage;
if(m_dwImageSize == 0) {
DWORD dwBytes = ((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) / 32;
if(((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) % 32) {
dwBytes++;
}
dwBytes *= 4;
// 没被压缩
m_dwImageSize = dwBytes * m_lpBMPHdr->biHeight;
}
m_lpvColorTable = (LPBYTE) m_lpBMPHdr + sizeof(BITMAPINFOHEADER);
}
///////////////////////////////////////////////
//这个函数清除所申请到的内存。
///////////////////////////////////////////////
void CDib::InitDestroy()
{
ReleaseMapFile();
if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap);
m_hGlobal = NULL;
m_lpBMPHdr = NULL;
m_lpDIBits = NULL;
m_lpvColorTable = NULL;
m_nColorEntries = 0;
m_dwImageSize = 0;
m_lpvFile = NULL;
m_hMap = NULL;
m_hFile = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
}
///////////////////////////////////////////////
//这个函数释放被映射的文件。
///////////////////////////////////////////////
void CDib::ReleaseMapFile()
{
if(m_hFile == NULL) return;
::UnmapViewOfFile(m_lpvFile);
::CloseHandle(m_hMap);
::CloseHandle(m_hFile);
m_hFile = NULL;
}