📄 cdib.cpp
字号:
// cdib.cpp
#include "stdafx.h"
#include "math.h"
#include "process.h"
#include "cdib.h"
/* Dib文件头标志(字符串"BM",写DIB时用到该常数)*/
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// 声明串行化过程
IMPLEMENT_SERIAL(CDib, CObject, 0);
/*************************************************************************
*
* \函数名称:
* CDib()
*
* \输入参数:
* 无
*
* \返回值:
* 无
*
* \说明:
* 构造函数
*
************************************************************************
*/
CDib::CDib()
{
m_hFile = NULL;
m_hBitmap = NULL;
m_hDib = NULL;
m_hPalette = NULL;
m_nBmihAlloc = m_nImageAlloc = noAlloc;
Empty();
}
/*************************************************************************
*
* \函数名称:
* CDib()
*
* \输入参数:
* CSize size - 位图尺寸
* int nBitCount - 象素位数
*
* \返回值:
* 无
*
* \说明:
* 构造函数
* 根据给定的位图尺寸和象素位数构造CDib对象,
* 并对信息头和调色板分配内存
* 但并没有给位图数据分配内存
*
************************************************************************
*/
CDib::CDib(CSize size, int nBitCount)
{
m_hFile = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
m_nBmihAlloc = m_nImageAlloc = noAlloc;
Empty();
// 根据象素位数计算调色板尺寸
ComputePaletteSize(nBitCount);
// 分配DIB信息头和调色板的内存
m_lpBMIH = (LPBITMAPINFOHEADER) new
char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries];
// 设置信息头内存分配状态
m_nBmihAlloc = crtAlloc;
// 设置信息头中的信息
m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER);
m_lpBMIH->biWidth = size.cx;
m_lpBMIH->biHeight = size.cy;
m_lpBMIH->biPlanes = 1;
m_lpBMIH->biBitCount = nBitCount;
m_lpBMIH->biCompression = BI_RGB;
m_lpBMIH->biSizeImage = 0;
m_lpBMIH->biXPelsPerMeter = 0;
m_lpBMIH->biYPelsPerMeter = 0;
m_lpBMIH->biClrUsed = m_nColorTableEntries;
m_lpBMIH->biClrImportant= m_nColorTableEntries;
// 计算图象数据内存的大小,并设置此DIB的调色板的指针
ComputeMetrics();
// 将此DIB的调色板初始化为0
memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries);
// 暂时不分配图象数据内存
m_lpImage = NULL;
}
/*************************************************************************
*
* \函数名称:
* ~CDib()
*
* \输入参数:
* 无
*
* \返回值:
* 无
*
* \说明:
* 析构函数,并释放所有分配的DIB内存
*
************************************************************************
*/
CDib::~CDib()
{
Empty();
}
// ************************************************************************
//
// CDib类函数:
//
// RGBQUAD GetPixel(); - 获取象素真实的颜色值
// LONG GetPixelOffset(); - 获取象素在图象数据块中的位置
// CSize GetDibSaveDim(); - 获取DIB位图数据块的存储尺寸
// BOOL IsEmpty(); - 判断DIB是否为空
// WORD PaletteSize(); - 计算调色板的表项数
// int GetSizeImage() - 获取DIB位图中数据的字节数
// int GetSizeHeader() - 获取信息头和调色板的尺寸
// CSize GetDimensions(); - 获取以象素表示的DIB的宽度和高度
// BOOL AttachMapFile(); - 以读模式打开内存映射文件,并将其与CDib对象进行关联
// BOOL CopyToMapFile(); - 创建一个新的内存映射文件,并进行数据的复制
// BOOL AttachMemory(); - 用内存中的DIB与已有的CDib对象关联
// BOOL Draw(); - 将CDib对象按照指定的尺寸输出到显示器(或者打印机)
// HBITMAP CreateSection(); - 创建一个DIB短,图象内存将不被初始化
// UINT UsePalette(); - 将CDib对象的逻辑调色板选入设备上下文,然后实现该调色板
// BOOL MakePalette(); - 如果调色板存在的话,读取调色板,并创建一个Windows调色板
// BOOL SetSystemPalette(); - 为CDib对象创建一个逻辑调色板
// BOOL Compress(); - 将DIB重新生成为压缩的或者不压缩的DIB。
// HBITMAP CreateBitmap(); - 从以后的DIB中创建DDB位图,实现DIB到DDB的转换
// BOOL ConvertFromDDB(); - 从DDB中创建DIB,实现DDB到DIB的转换
// BOOL Read(); - 从文件中读取数据,并填充文件头、信息头、调色板和位图数据
// BOOL ReadSection(); - 从BMP文件中读取信息头,调用CreateDIBSection来分配位图数据内存,然后将位图从该文件读入刚才分配的内存
// BOOL Write(); - 将DIB从CDib对象写入文件
// void Serialize(); - 串行化过程
// void Empty(); - 清空DIB,释放已经分配的内存,并且关闭映射文件
// void ComputePaletteSize(); - 计算调色板的尺寸
// BOOL ConvertDDBToDIB(); - 将源BITMAP类pDibSrc中的数据拷贝到pDibDst中,并对相应的数据成员赋值
// BOOL CopyDIB(); - 将源CDib类pDibSrc中的数据拷贝到pDibDst中,并对相应的数据成员赋值
// BOOL CopyScreenToDIB(); - 将指定矩形位置内的屏幕内容拷贝到DIB中源CDib类pDibSrc中的数据拷贝到pDibDst中
// HPALETTE GetSystemPalette() ; - 获得当前正在使用的系统调色板的句柄
// HPALETTE CopyPalette(); - 将创建一个新的调色板,并从指定的调色板拷贝调色板内容
// BOOL ReadDIB(); - 将指定文件中的DIB文件载入
// HPALETTE MakeDIBPalette(); - 产生DIB调色板
// BOOL PaintDIB(); - 将DIB图象进行显示
// ************************************************************************
/*************************************************************************
*
* \函数名称:
* GetDimensions()
*
* \输入参数:
* 无
*
* \返回值:
* CSize - DIB的宽度和高度
*
* \说明:
* 返回以象素表示的DIB的宽度和高度
*
*************************************************************************/
CSize CDib::GetDimensions()
{
if(m_lpBMIH == NULL) return CSize(0, 0);
return CSize((int) m_lpBMIH->biWidth, (int) m_lpBMIH->biHeight);
}
/*************************************************************************
*
* \函数名称:
* AttachMapFile()
*
* \输入参数:
* const char* strPathname - 映射文件的路径名
* BOOL bShare - 如果文件以共享形式打开,设置为TRUE
* - 默认值为FALSE
*
* \返回值:
* BOOL - 如果成功,则为TRUE
*
* \说明:
* 以读模式打开内存映射文件,并将其与CDib对象进行关联。因为在文件使用之前并没有读入内存,
* 所以它立即返回。不过,当访问这个DIB的时候,可能会有一些延迟,因为文件是分页的。
* DetachMapFile函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。
* 用内存中的DIB与已有的CDib对象关联。此内存可能是程序的资源,或者是可能是剪贴板
* 或者OLE数据对象内存。内存可能已经由CRT堆栈用new运算符分配了,或者可能已经由
* Windows堆栈用GlobalAlloc分配了。
* 如果打开相同的文件两次,则Windows以另一个文件来对待
*
************************************************************************
*/
BOOL CDib::AttachMapFile(const char* strPathname, BOOL bShare) // for reading
{
// 获取文件句柄,并设置打开模式为共享
HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ,
bShare ? FILE_SHARE_READ : 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ASSERT(hFile != INVALID_HANDLE_VALUE);
// 获取文件的尺寸
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;
}
// 映射整个文件,注意FILE_MAP_WRITE为读写模式
LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); // map whole file
ASSERT(lpvFile != NULL);
// 确认为bmp格式文件
if(((LPBITMAPFILEHEADER) lpvFile)->bfType != 0x4d42) {
AfxMessageBox("Invalid bitmap file");
DetachMapFile();
return FALSE;
}
// 将内存中的DIB与已有的CDib对象关联
AttachMemory((LPBYTE) lpvFile + sizeof(BITMAPFILEHEADER));
// 将这些有用的句柄设置为类数据成员
m_lpvFile = lpvFile;
m_hFile = hFile;
m_hMap = hMap;
// 返回
return TRUE;
}
/*************************************************************************
*
* \函数名称:
* CopyToMapFile()
*
* \输入参数:
* const char* strPathname - 映射文件的路径名
*
* \返回值:
* BOOL - 如果成功,则为TRUE
*
* \说明:
* 该函数可以创建一个新的内存映射文件,并将现有的CDib数据复制到该文件的内存
* 释放以前的所有内存。并关闭现有的所有内存映射文件。实际上,直到新文件
* 关闭的时候,才将这个数据写到磁盘,但是,当CDib对象被重复使用或被破坏
* 时,也会发生写磁盘操作
*
************************************************************************
*/
BOOL CDib::CopyToMapFile(const char* strPathname)
{
BITMAPFILEHEADER bmfh;
// 设置文件头信息
bmfh.bfType = 0x4d42;
bmfh.bfSize = m_dwSizeImage + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries + sizeof(BITMAPFILEHEADER);
bmfh.bfReserved1= bmfh.bfReserved2 = 0;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries;
// 创建接收数据的文件
HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
ASSERT(hFile != INVALID_HANDLE_VALUE);
// 计算文件的大小尺寸
int nSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries + m_dwSizeImage;
// 创建内存映射文件对象
HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, nSize, 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_lpBMIH,
sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries);
// 计算调色板在文件中的地址,并拷贝调色板
lpbCurrent += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
memcpy(lpbCurrent, m_lpImage, m_dwSizeImage);
// 暂时存放图象数据尺寸变量
DWORD dwSizeImage = m_dwSizeImage;
// 释放一起分配的所有内存
Empty();
// 设置图象数据尺寸并设置内存分配状态
m_dwSizeImage = dwSizeImage;
m_nBmihAlloc = m_nImageAlloc = noAlloc;
// 信息头指针重新指向文件中的位置
m_lpBMIH = lpBMIH;
// 图象数据指针重新指向文件中的数据地址
m_lpImage = lpbCurrent;
// 设置文件句柄
m_hFile = hFile;
// 设置映射对象句柄
m_hMap = hMap;
// 设置映射文件指针
m_lpvFile = lpvFile;
// 重新计算得到调色板尺寸
ComputePaletteSize(m_lpBMIH->biBitCount);
// 重新计算图象数据块大小,并设置调色板指针
ComputeMetrics();
// 如果调色板存在的话,读取并创建一个Windows调色板
MakePalette();
// 返回
return TRUE;
}
/*************************************************************************
*
* \函数名称:
* AttachMemory()
*
* \输入参数:
* LPVOID lpvMem - 要关联的内存地址
* BOOL bMustDelete - 如果CDib类负责删除这个内存,标记为TRUE
* - 默认值为FALSE
* HGLOBAL hGlobal - 如果内存是通过Win32 GlobalAlloc得到的,
* - 则CDib对象必须保存该句柄,这样,以后
* - 可以释放句柄。这里假设bMustDelete设置为TRUE
*
* \返回值:
* BOOL - 如果成功,则为TRUE
*
* \说明:
* 用内存中的DIB与已有的CDib对象关联。此内存可能是程序的资源,或者是可能是剪贴板
* 或者OLE数据对象内存。内存可能已经由CRT堆栈用new运算符分配了,或者可能已经由
* Windows堆栈用GlobalAlloc分配了。
*
************************************************************************
*/
BOOL CDib::AttachMemory(LPVOID lpvMem, BOOL bMustDelete, HGLOBAL hGlobal)
{
// 首先释放已经分配的内存
Empty();
m_hGlobal = hGlobal;
// bMustDelete为TRUE表示此CDib类分配的内存,负责删除
// 否则的设置信息头分配状态为noAlloc
if(bMustDelete == FALSE)
{
m_nBmihAlloc = noAlloc;
}
else
{
m_nBmihAlloc = ((hGlobal == NULL) ? crtAlloc : heapAlloc);
}
try
{
// 设置信息头指针
m_lpBMIH = (LPBITMAPINFOHEADER) lpvMem;
// 重新计算得到图象数据块的大小,并设置调色板的指针
ComputeMetrics();
// 计算调色板的尺寸
ComputePaletteSize(m_lpBMIH->biBitCount);
// 设置图象数据指针
m_lpImage = (LPBYTE) m_lpvColorTable + sizeof(RGBQUAD) * m_nColorTableEntries;
// 如果调色板存在的话,读取它,并创建一个Windows调色板,
// 并将调色板的句柄存放在数据成员中
MakePalette();
}
// 错误处理
catch(CException* pe)
{
AfxMessageBox("AttachMemory error");
pe->Delete();
return FALSE;
}
// 返回
return TRUE;
}
/*************************************************************************
*
* \函数名称:
* UsePalette()
*
* \输入参数:
* CDC* pDC - 要实现调色板的设备上下文指针
* BOOL bBackground - 如果标记为FALSE(默认值),并且应用
* - 程序正在前台运行,则Windows将把该调
* - 色板作为前台调色板来实现(向系统调色
* - 板中复制尽可能多的颜色)。如果标记为
* - TURE,则Windows将把该调色板作为后台
* - 调色板来实现(尽可能相系统调色板映射
* - 逻辑调色板)
*
* \返回值:
* UINT - 如果成功,则返回映射到系统调色板的逻
* - 辑调色板的表项数,否则返回GDI_ERROR
*
* \说明:
* 该函数将CDib对象的逻辑调色板选入设备上下文,然后实现该调色板。Draw成员函
* 数在绘制DIB之前调用UsePalette。
*
************************************************************************
*/
UINT CDib::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */)
{
// 判断是否存在调色板
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -