📄 dibapi.cpp
字号:
void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);
void* lp = ::GlobalLock((HGLOBAL) h);
// 复制
memcpy(lpCopy, lp, dwLen);
// 解除锁定
::GlobalUnlock(hCopy);
::GlobalUnlock(h);
}
return hCopy;
}
/*************************************************************************
*
* 函数名称:
* SaveDIB()
*
* 参数:
* HDIB hDib - 要保存的DIB
* CFile& file - 保存文件CFile
*
* 返回值:
* BOOL - 成功返回TRUE,否则返回FALSE或者CFileException
*
* 说明:
* 该函数将指定的DIB对象保存到指定的CFile中。该CFile由调用程序打开和关闭。
*
*************************************************************************/
BOOL WINAPI SaveDIB(HDIB hDib, CFile& file)
{
// Bitmap文件头
BITMAPFILEHEADER bmfHdr;
// 指向BITMAPINFOHEADER的指针
LPBITMAPINFOHEADER lpBI;
// DIB大小
DWORD dwDIBSize;
if (hDib == NULL)
{
// 如果DIB为空,返回FALSE
return FALSE;
}
// 读取BITMAPINFO结构,并锁定
lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
if (lpBI == NULL)
{
// 为空,返回FALSE
return FALSE;
}
// 判断是否是WIN3.0 DIB
if (!IS_WIN30_DIB(lpBI))
{
// 不支持其它类型的DIB保存
// 解除锁定
::GlobalUnlock((HGLOBAL) hDib);
// 返回FALSE
return FALSE;
}
// 填充文件头
// 文件类型"BM"
bmfHdr.bfType = DIB_HEADER_MARKER;
// 计算DIB大小时,最简单的方法是调用GlobalSize()函数。但是全局内存大小并
// 不是DIB真正的大小,它总是多几个字节。这样就需要计算一下DIB的真实大小。
// 文件头大小+颜色表大小
// (BITMAPINFOHEADER和BITMAPCOREHEADER结构的第一个DWORD都是该结构的大小)
dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);
// 计算图像大小
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
{
// 对于RLE位图,没法计算大小,只能信任biSizeImage内的值
dwDIBSize += lpBI->biSizeImage;
}
else
{
// 象素的大小
DWORD dwBmBitsSize;
// 大小为Width * Height
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
// 计算出DIB真正的大小
dwDIBSize += dwBmBitsSize;
// 更新biSizeImage(很多BMP文件头中biSizeImage的值是错误的)
lpBI->biSizeImage = dwBmBitsSize;
}
// 计算文件大小:DIB大小+BITMAPFILEHEADER结构大小
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
// 两个保留字
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
// 计算偏移量bfOffBits,它的大小为Bitmap文件头大小+DIB头大小+颜色表大小
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize
+ PaletteSize((LPSTR)lpBI);
// 尝试写文件
TRY
{
// 写文件头
file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
// 写DIB头和象素
file.WriteHuge(lpBI, dwDIBSize);
}
CATCH (CFileException, e)
{
// 解除锁定
::GlobalUnlock((HGLOBAL) hDib);
// 抛出异常
THROW_LAST();
}
END_CATCH
// 解除锁定
::GlobalUnlock((HGLOBAL) hDib);
// 返回TRUE
return TRUE;
}
/*************************************************************************
*
* 函数名称:
* ReadDIBFile()
*
* 参数:
* CFile& file - 要读取得文件文件CFile
*
* 返回值:
* HDIB - 成功返回DIB的句柄,否则返回NULL。
*
* 说明:
* 该函数将指定的文件中的DIB对象读到指定的内存区域中。除BITMAPFILEHEADER
* 外的内容都将被读入内存。
*
*************************************************************************/
HDIB WINAPI ReadDIBFile(CFile& file)
{
BITMAPFILEHEADER bmfHeader;
DWORD dwBitsSize;
HDIB hDIB;
LPSTR pDIB;
// 获取DIB(文件)长度(字节)
dwBitsSize = file.GetLength();
// 尝试读取DIB文件头
if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
{
// 大小不对,返回NULL。
return NULL;
}
// 判断是否是DIB对象,检查头两个字节是否是"BM"
if (bmfHeader.bfType != DIB_HEADER_MARKER)
{
// 非DIB对象,返回NULL。
return NULL;
}
// 为DIB分配内存
hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
if (hDIB == 0)
{
// 内存分配失败,返回NULL。
return NULL;
}
// 锁定
pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
// 读象素
if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=
dwBitsSize - sizeof(BITMAPFILEHEADER) )
{
// 大小不对。
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 释放内存
::GlobalFree((HGLOBAL) hDIB);
// 返回NULL。
return NULL;
}
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回DIB句柄
return hDIB;
}
/*************************************************************************
*
* 函数名称:
* NewDIB()
*
* 参数:
* width - 将要创建DIB的宽
* height - 将要创建DIB的高
* biBitCount - 将要创建DIB的位数。比如,如果要创建256色DIB,则此值为8
* 返回值:
* HDIB - 成功返回DIB的句柄,否则返回NULL。
*
* 说明:
* 该函数指定宽、高、颜色位数来创建一个新的DIB,并返回其句柄
*************************************************************************/
/*******************************************************************
*函数名称:
* NewDIB()
*
* 参数:
* width - 将要创建DIB的宽
* height - 将要创建DIB的高
* biBitCount - 将要创建DIB的位数。比如,如果要创建256色DIB,则此值为8
*
*返回值:
* HDIB - 成功返回DIB的句柄,否则返回NULL。
*
*说明:
* 该函数指定宽、高、颜色位数来创建一个新的DIB,并返回其句柄
*
***************************************************************/
HDIB WINAPI NewDIB(long width, long height,unsigned short biBitCount)
{
//计算新建的DIB每行所占的字节数
long dwindth = (width*biBitCount/8+3)/4*4;
//新建的DIB调色板中表项的数目
WORD color_num;
//通过输入的biBitCount值来确定调色板的表项数目
switch(biBitCount)
{
//如果用1 bit来表示一个象素那么调色板中有两个表项
case 1:
color_num=2;
break;
//如果用4 bit来表示一个象素那么调色板中有16个表项
case 4:
color_num=16;
break;
//如果用8bit来表示一个象素,那么调色板中得表项有256中(本程序大多采用这种形式)
case 8:
color_num=256;
break;
//其他的情况调色扳中没有表项,即真彩位图
default:
color_num=0;
break;
}
//计算位图数据所占的空间
//dwindth *height为象素数据所占的空间
//40为位图信息头占的空间
//color_num*4为调色板的表项所占的空间(调色板每个表项占4各个字节)
long dwBitsSize = dwindth *height + 40 + color_num*4;
//建立指向位图文件的指针
LPSTR pDIB;
//申请存储空间,并建立指向位图的句柄
HDIB hDIB=(HDIB) ::GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, dwBitsSize);
//如果申请空间不成功返回错误信息
if (hDIB == 0)
{
return NULL;
}
//如果申请空间成功锁定内存,并将内存的指针传给pDIB
pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
//建立指向位图信息头结构的指针
LPBITMAPINFO lpmf = (LPBITMAPINFO)pDIB;
//给位图信息头内的各个参量赋值
//指定位图信息头结构的大小为40字节
lpmf->bmiHeader.biSize = 40;
//指定新建位图的宽度
lpmf->bmiHeader.biWidth = width;
//指定新建位图的高度
lpmf->bmiHeader.biHeight = height;
//位平面数必须为1
lpmf->bmiHeader.biPlanes = 1;
//确定新建位图表示颜色是要用到的bit数
lpmf->bmiHeader.biBitCount = biBitCount;
//是否进行压缩
lpmf->bmiHeader.biCompression = 0;
//新建的位图中实际的位图数据所占的字节数
lpmf->bmiHeader.biSizeImage = dwindth *height;
//指定目标设备的水平分辨率
lpmf->bmiHeader.biXPelsPerMeter = 2925;
//指定目标设备的垂直分辨率
lpmf->bmiHeader.biYPelsPerMeter = 2925;
//新建图像实际用到的颜色数 如果为0则用到的颜色数为2的biBitCount次
lpmf->bmiHeader.biClrUsed = 0;
//指定新建图像中重要的颜色数,如果为0则所有的颜色都重要
lpmf->bmiHeader.biClrImportant= 0;
//如果新建的图像中含有调色板,则接下来对调色板的各种颜色分量赋初始值
if(color_num!=0)
{
for(int i=0;i<color_num;i++)
{
lpmf->bmiColors[i].rgbRed =(BYTE)i;
lpmf->bmiColors[i].rgbGreen =(BYTE)i;
lpmf->bmiColors[i].rgbBlue =(BYTE)i;
}
}
//解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
//返回新建位图的句柄
return hDIB;
}
/*************************************************************************
*
* 函数名称:
* PaletteSize()
*
* 参数:
* LPSTR lpbi - 指向DIB对象的指针
*
* 返回值:
* WORD - DIB中调色板的大小
*
* 说明:
* 该函数返回DIB中调色板的大小。对于Windows 3.0 DIB,返回颜色数目×
* RGBQUAD的大小;对于其它返回颜色数目×RGBTRIPLE的大小。
*
************************************************************************/
WORD WINAPI PaletteSize(LPSTR lpbi)
{
// 计算DIB中调色板的大小
if (IS_WIN30_DIB (lpbi))
{
//返回颜色数目×RGBQUAD的大小
return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));
}
else
{
//返回颜色数目×RGBTRIPLE的大小
return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -