📄 dibapi.cpp
字号:
// 中间变量
BYTE bChar;
// 指向源图像像素的指针
BYTE * lpSrc;
// 指向编码后图像数据的指针
BYTE * lpDst;
// 临时指针
BYTE * lpTemp;
// 尝试读取PCX文件头
if (file.Read((LPSTR)&pcxHdr, sizeof(PCXHEADER)) != sizeof(PCXHEADER))
{
// 大小不对,返回NULL。
return NULL;
}
// 判断是否是256色PCX文件,检查第一个字节是否是0x0A
if ((pcxHdr.bManufacturer != 0x0A) || (pcxHdr.bBpp != 8) || (pcxHdr.bPlanes != 1))
{
// 非256色PCX文件,返回NULL。
return NULL;
}
// 获取图像高度
wHeight = pcxHdr.wBottom - pcxHdr.wTop + 1;
// 获取图像宽度
wWidth = pcxHdr.wRight - pcxHdr.wLeft + 1;
// 计算图像每行的字节数
lLineBytes = WIDTHBYTES(wWidth * 8);
// 计算DIB长度(字节)
dwDIBSize = sizeof(BITMAPINFOHEADER) + 1024 + wHeight * lLineBytes;
// 为DIB分配内存
hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize);
if (hDIB == 0)
{
// 内存分配失败,返回NULL
return NULL;
}
// 锁定
pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
// 指向BITMAPINFOHEADER的指针
LPBITMAPINFOHEADER lpBI;
// 赋值
lpBI = (LPBITMAPINFOHEADER) pDIB;
// 给lpBI成员赋值
lpBI->biSize = 40;
lpBI->biWidth = wWidth;
lpBI->biHeight = wHeight;
lpBI->biPlanes = 1;
lpBI->biBitCount = 8;
lpBI->biCompression = BI_RGB;
lpBI->biSizeImage = wHeight * lLineBytes;
lpBI->biXPelsPerMeter = pcxHdr.wXResolution;
lpBI->biYPelsPerMeter = pcxHdr.wYResolution;
lpBI->biClrUsed = 0;
lpBI->biClrImportant = 0;
// 分配内存以读取编码后的像素
lpSrc = new BYTE[file.GetLength() - sizeof(PCXHEADER) - 769];
lpTemp = lpSrc;
// 读取编码后的像素
if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(PCXHEADER) - 769) !=
file.GetLength() - sizeof(PCXHEADER) - 769 )
{
// 大小不对
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 释放内存
::GlobalFree((HGLOBAL) hDIB);
// 返回NULL
return NULL;
}
// 计算DIB中像素位置
lpDst = (BYTE *) FindDIBBits(pDIB);
// 一行一行解码
for (j = 0; j <wHeight; j++)
{
i = 0;
while (i < wWidth)
{
// 读取一个字节
bChar = *lpTemp;
lpTemp++;
if ((bChar & 0xC0) == 0xC0)
{
// 行程
iCount = bChar & 0x3F;
// 读取下一个字节
bChar = *lpTemp;
lpTemp++;
// bChar重复iCount次保存
memset(&lpDst[(wHeight - j - 1) * lLineBytes + i], bChar, iCount);
// 已经读取像素的个数加iCount
i += iCount;
}
else
{
// 保存当前字节
lpDst[(wHeight - j - 1) * lLineBytes + i] = bChar;
// 已经读取像素的个数加1
i += 1;
}
}
}
// 释放内存
delete lpSrc;
//*************************************************************
// 调色板
// 读调色板标志位
file.Read(&bChar, 1);
if (bChar != 0x0C)
{
// 出错
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 释放内存
::GlobalFree((HGLOBAL) hDIB);
// 返回NULL。
return NULL;
}
// 分配内存以读取编码后的像素
lpSrc = new BYTE[768];
// 计算DIB中调色板的位置
lpDst = (BYTE *) pDIB + sizeof(BITMAPINFOHEADER);
// 读取调色板
if (file.Read(lpSrc, 768) != 768)
{
// 大小不对
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 释放内存
::GlobalFree((HGLOBAL) hDIB);
// 返回NULL
return NULL;
}
// 给调色板赋值
for (i = 0; i < 256; i++)
{
lpDst[i * 4] = lpSrc[i * 3 + 2];
lpDst[i * 4 + 1] = lpSrc[i * 3 + 1];
lpDst[i * 4 + 2] = lpSrc[i * 3];
lpDst[i * 4 + 3] = 0;
}
// 释放内存
delete lpSrc;
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回DIB句柄
return hDIB;
}
DWORD WINAPI BytesPerLine(LPBYTE lpDIB)
{
return WIDTHBYTES(
(((LPBITMAPINFOHEADER)lpDIB)->biWidth)
*(((LPBITMAPINFOHEADER)lpDIB)->biPlanes)
*(((LPBITMAPINFOHEADER)lpDIB)->biBitCount)
);
}
void WINAPI DestroyDIB(HDIB hDib)
{
GlobalFree(hDib);
}
//合并lpDIB1,lpDIB2所代表的BINARY类型的资源
//该函数是基本的位图合并函数学,其他的函数将调用该基本函数
//合并是将两个图片连接起来,是图A+图B=图A图B的合并
HGLOBAL WINAPI MergeDIB(LPSTR lpDIB1, LPSTR lpDIB2)
{
// 源图像1的宽度和高度
LONG lWidth1;
LONG lHeight1;
// 源图像2的宽度和高度
LONG lWidth2;
LONG lHeight2;
// 缩放后图像的宽度和高度
LONG lNewWidth;
LONG lNewHeight;
// 缩放后图像的宽度(lNewWidth',必须是4的倍数)
LONG lNewLineBytes;
// 指向源图像1的指针
LPSTR lpDIBBits1;
// 指向源图像2的指针
LPSTR lpDIBBits2;
// 指向源像素的指针,可指向图像1或图像2
LPSTR lpSrc;
// 缩放后新DIB句柄
HDIB hDIB;
// 指向缩放图像对应像素的指针
LPSTR lpDst;
// 指向缩放图像的指针
LPSTR lpNewDIB;
LPSTR lpNewDIBBits;
// 指向BITMAPINFO结构的指针(Windows 3.0)
LPBITMAPINFOHEADER lpbmi;
// 指向BITMAPCOREINFO结构的指针
LPBITMAPCOREHEADER lpbmc;
// 循环变量(像素在新DIB中的坐标)
LONG i;
LONG j;
// 像素在源DIB1中的坐标
LONG i0_1;
LONG j0_1;
// 像素在源DIB2中的坐标
LONG i0_2;
LONG j0_2;
// 图像1每行的字节数
LONG lLineBytes1;
// 图像2每行的字节数
LONG lLineBytes2;
// 找到源DIB1图像像素起始位置
lpDIBBits1 = ::FindDIBBits(lpDIB1);
// 找到源DIB2图像像素起始位置
lpDIBBits2 = ::FindDIBBits(lpDIB2);
// 获取图像1的宽度
lWidth1 = ::DIBWidth(lpDIB1);
// 获取图像2的宽度
lWidth2 = ::DIBWidth(lpDIB2);
// 计算图像1每行的字节数
lLineBytes1 = WIDTHBYTES(lWidth1 * 8);
// 计算图像2每行的字节数
lLineBytes2 = WIDTHBYTES(lWidth2 * 8);
// 获取图像1的高度
lHeight1 = ::DIBHeight(lpDIB1);
// 获取图像2的高度
lHeight2 = ::DIBHeight(lpDIB2);
// 计算缩放后的图像实际宽度
// 此处直接将两个图像的宽度相加
lNewWidth = (LONG) (::DIBWidth(lpDIB1) +::DIBWidth(lpDIB2));
// 计算新图像每行的字节数
lNewLineBytes = WIDTHBYTES(lNewWidth * 8);
// 计算新图像高度,高度不取两者最大值
if(lHeight1>lHeight2){
lNewHeight = (LONG) (lHeight1);
}else{
lNewHeight = (LONG) (lHeight2);
}
// 分配内存,以保存新DIB,结构参数取第一个的
hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB1 + ::PaletteSize(lpDIB1));
// 判断是否内存分配失败
if (hDIB == NULL)
{
// 分配内存失败
return NULL;
}
// 锁定内存
lpNewDIB = (char * )::GlobalLock((HGLOBAL) hDIB);
// 复制DIB信息头和调色板,此处取第一个图的数据
// 需要保证系统提供的图片为256色图片
memcpy(lpNewDIB, lpDIB1, *(LPDWORD)lpDIB1 + ::PaletteSize(lpDIB1));
// 找到新DIB像素起始位置
lpNewDIBBits = ::FindDIBBits(lpNewDIB);
// 获取指针
lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;
// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpNewDIB))
{
// 对于Windows 3.0 DIB
lpbmi->biWidth = lNewWidth;
lpbmi->biHeight = lNewHeight;
}
else
{
// 对于其它格式的DIB
lpbmc->bcWidth = (unsigned short) lNewWidth;
lpbmc->bcHeight = (unsigned short) lNewHeight;
}
// 针对图像每行进行操作
for(i = 0; i < lNewHeight; i++)
{
// 针对图像每列进行操作
for(j = 0; j < lNewWidth; j++)
{
// 指向新DIB第i行,第j个像素的指针
// 注意此处宽度和高度是新DIB的宽度和高度
lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight - 1 - i) + j;
if(j<lWidth1)//在第一个图中
{
// 计算该像素在源DIB中的坐标
i0_1 = (LONG) (i );
j0_1 = (LONG) (j );
// 判断是否在源图范围内
if( (j0_1 >= 0) && (j0_1 < lWidth1) && (i0_1 >= 0) && (i0_1 < lHeight1))
{
// 指向源DIB第i0行,第j0个像素的指针
lpSrc = (char *)lpDIBBits1 + lLineBytes1 * (lHeight1 - 1 - i0_1) + j0_1;
// 复制像素
*lpDst = *lpSrc;
}
else
{
// 对于源图中没有的像素,直接赋值为255
* ((unsigned char*)lpDst) = 255;
}
}
else
{//在第二个图中
// 计算该像素在源DIB中的坐标
i0_2 = (LONG) (i);
j0_2 = (LONG) (j-lWidth1);
// 判断是否在源图范围内
if( (j0_2 >= 0) && (j0_2 < lWidth2) && (i0_2 >= 0) && (i0_2 < lHeight2))
{
// 指向源DIB第i0行,第j0个像素的指针
lpSrc = (char *)lpDIBBits2 + lLineBytes2 * (lHeight2 - 1 - i0_2) + j0_2;
// 复制像素
*lpDst = *lpSrc;
}
else
{
// 对于源图中没有的像素,直接赋值为255
* ((unsigned char*)lpDst) = 255;
}
}
}
}
// 返回
return hDIB;
}
//***********************************************
//函数名:LoadDIBFromResource
//功能:装载资源中的DIB图
//参数:cImage --存放在资源"BINARY"段中的DIB位图资源名
//成功:成功-返回指向DIB的数据区的指针
// 失败-返回NUll
//************************************************
HDIB WINAPI LoadDIBFromResource(CString cImage)//位图资源ID
{
//获取存放资源的实例句柄
HINSTANCE hInst=AfxGetInstanceHandle();
//装入资源
HRSRC hRes=FindResource( hInst, cImage,"BINARY");
if(hRes==NULL)
return NULL;
HGLOBAL hGlob;
CMemFile file;
DWORD dwResSize = SizeofResource(hInst,hRes);
file.Attach( (LPBYTE)LockResource( hGlob = LoadResource(hInst,hRes)), dwResSize );
HDIB hDIB=::ReadDIBFile(file);
file.Detach();
DeleteObject( hGlob );
return hDIB;
/* */
}
/*************************************************************************
*
* 函数名称:
* HDIB2ByteArray()
*
* 参数:
* HDIB hDib - 要保存的DIB
* CByteArray* pByteArray - 保存字节数组指针
*
* 返回值:
* BOOL - 成功返回TRUE,否则返回FALSE
*
* 说明:
* 该函数将指定的DIB对象转换到指定的字节数组中。
*
*************************************************************************/
BOOL WINAPI HDIB2ByteArray(HDIB hDib,CByteArray* pByteArray)
{
// 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;
}
// 判断是否是Windows 3.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);
//设置字节数组大小
pByteArray->SetSize(bmfHdr.bfSize);
// 写文件头
//file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
long iCount;
for (iCount = 0; iCount<sizeof(BITMAPFILEHEADER); iCount=iCount+1)
{
pByteArray->ElementAt(iCount)=((BYTE*)(&bmfHdr))[iCount];
}
// 写DIB头和像素
//file.WriteHuge(lpBI, dwDIBSize);
for (iCount = 0; iCount < (long)dwDIBSize; iCount=iCount+1)
{
pByteArray->ElementAt(sizeof(BITMAPFILEHEADER)+iCount)=((BYTE*)lpBI)[iCount];
}
// 解除锁定
::GlobalUnlock((HGLOBAL) hDib);
// 返回TRUE
return TRUE;
}
//res1,res2是资源名称的"IDR_NUMBER0","IDR_NUMBER1"...
//合并res1和res2所代表的"BINARY"类型的资源
BOOL WINAPI MergeDIB(CString res1, CString res2,HDIB* pHDib)
{
HDIB hDIB1=::LoadDIBFromResource(res1);
HDIB hDIB2=::LoadDIBFromResource(res2);
// 指向DIB1的指针
LPSTR lpDIB1;
// 锁定DIB1
lpDIB1 = (LPSTR) ::GlobalLock((HGLOBAL)hDIB1);
// 指向DIB2的指针
LPSTR lpDIB2;
// 锁定DIB1
lpDIB2 = (LPSTR) ::GlobalLock((HGLOBAL)hDIB2);
//在此可以判断是否是256色
//高与256色的位图其数据进行了压缩,合并函数可能并未考虑改压缩情况
//低于256色会由于图片资料问题显示不清楚
*pHDib=(HDIB)::MergeDIB(lpDIB1,lpDIB2);
// 解除锁定
::GlobalUnlock((HGLOBAL)hDIB1);
::GlobalUnlock((HGLOBAL)hDIB2);
//释放内存
::GlobalFree((HGLOBAL)hDIB1);
::GlobalFree((HGLOBAL)hDIB2);
return TRUE;
}
//res是资源名称的"IDR_NUMBER0","IDR_NUMBER1"...
//合并res所代表的"BINARY"类型的资源和hDib所代表的资源
BOOL WINAPI MergeDIB(HDIB hDib, CString res,HDIB* pHDib)
{
HDIB hDIB1=hDib;
//保存该指针,因为可能*pHDib和hDib指向同一对象,
//在以下的计算中可能会失去该*pHDib指针,
//此处保存以使得hDib对象能释放内存
HDIB hDIB2=::LoadDIBFromResource(res);
// 指向DIB1的指针
LPSTR lpDIB1;
// 锁定DIB1
lpDIB1 = (LPSTR) ::GlobalLock((HGLOBAL)hDIB1);
// 指向DIB2的指针
LPSTR lpDIB2;
// 锁定DIB1
lpDIB2 = (LPSTR) ::GlobalLock((HGLOBAL)hDIB2);
//在此可以判断是否是256色
//高与256色的位图其数据进行了压缩,合并函数可能并未考虑改压缩情况
//低于256色会由于图片资料问题显示不清楚
*pHDib=(HDIB)::MergeDIB(lpDIB1,lpDIB2);
// 解除锁定
::GlobalUnlock((HGLOBAL)lpDIB1);
::GlobalUnlock((HGLOBAL)hDIB2);
//释放内存
::GlobalFree((HGLOBAL)lpDIB1);
::GlobalFree((HGLOBAL)hDIB2);
return TRUE;
}
//合并num1、num2所代表的"BINARY"类型的资源
//其中num1、num2是资源名称的"IDR_NUMBER0","IDR_NUMBER1"...中的0,1,2,..
//的0~9的数字
BOOL WINAPI MergeDIB(int num1, int num2,HDIB* pHDib)
{
CString res1;
CString res2;
res1.Format("IDR_NUMBER%i",num1);
res2.Format("IDR_NUMBER%i",num2);
return MergeDIB(res1,res2,pHDib);
}
//合并num所代表的BINARY类型的资源和hDib所代表的资源
//其中num是资源名称的"IDR_NUMBER0","IDR_NUMBER1"...中的0,1,2,..
//的0~9的数字
BOOL WINAPI MergeDIB(HDIB hDib, int num,HDIB* pHDib)
{
CString res;
res.Format("IDR_NUMBER%i",num);
return MergeDIB(hDib,res,pHDib);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -