⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dibapi.cpp

📁 vc++编写的图片验证系统 vc++编写的图片验证系统
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen);
	
	// 判断分配是否成功
	if (hCopy != NULL)
	{
		// 锁定
		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;
	}
	
	// 判断是否是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);
	// 尝试写文件
	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;
}

/*************************************************************************
 *
 * 函数名称:
 *   DIBToPCX256()
 *
 * 参数:
 *   LPSTR lpDIB        - 指向DIB对象的指针
 *   CFile& file        - 要保存的文件
 *
 * 返回值:
 *   BOOL               - 成功返回True,否则返回False。
 *
 * 说明:
 *   该函数将指定的256色DIB对象保存为256色PCX文件。
 *
 *************************************************************************/
BOOL WINAPI DIBToPCX256(LPSTR lpDIB, CFile& file)
{
	// 循环变量
	LONG	i;
	LONG	j;
	
	// DIB高度
	WORD	wHeight;
	
	// DIB宽度
	WORD	wWidth;
	
	// 中间变量
	BYTE	bChar1;
	BYTE	bChar2;
	
	// 指向源图像像素的指针
	BYTE *	lpSrc;
	
	// 指向编码后图像数据的指针
	BYTE *	lpDst;
	
	// 图像每行的字节数
	LONG	lLineBytes;
	
	// 重复像素计数
	int		iCount;
	
	// 缓冲区已使用的字节数
	DWORD	dwBuffUsed;
	
	// 指向DIB像素指针
	LPSTR   lpDIBBits;
	
	// 获取DIB高度
	wHeight = (WORD) DIBHeight(lpDIB);
	
	// 获取DIB宽度
	wWidth  = (WORD) DIBWidth(lpDIB);
	
	// 找到DIB图像像素起始位置
	lpDIBBits = FindDIBBits(lpDIB);
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(wWidth * 8);
	
	
	//*************************************************************************
	// PCX文件头
	PCXHEADER pcxHdr;
	
	// 给文件头赋值
	
	// PCX标识码
	pcxHdr.bManufacturer = 0x0A;
	
	// PCX版本号
	pcxHdr.bVersion = 5;
	
	// PCX编码方式(1表示RLE编码)
	pcxHdr.bEncoding = 1;
	
	// 像素位数(256色为8位)
	pcxHdr.bBpp = 8;
	
	// 图像相对于屏幕的左上角X坐标(以像素为单位)
	pcxHdr.wLeft = 0;
	
	// 图像相对于屏幕的左上角Y坐标(以像素为单位)
	pcxHdr.wTop = 0;
	
	// 图像相对于屏幕的右下角X坐标(以像素为单位)
	pcxHdr.wRight = wWidth - 1;
	
	// 图像相对于屏幕的右下角Y坐标(以像素为单位)
	pcxHdr.wBottom = wHeight - 1;
	
	// 图像的水平分辨率
	pcxHdr.wXResolution = wWidth;
	
	// 图像的垂直分辨率
	pcxHdr.wYResolution = wHeight;
	
	// 调色板数据(对于256色PCX无意义,直接赋值为0)
	for (i = 0; i < 48; i ++)
	{
		pcxHdr.bPalette[i] = 0;
	}
	
	// 保留域,设定为0。
	pcxHdr.bReserved = 0;
	
	// 图像色彩平面数目(对于256色PCX设定为1)。
	pcxHdr.bPlanes = 1;
	
	// 图像的宽度(字节为单位),必须为偶数。
//	if ((wWidth & 1) == 0)
//	{
		pcxHdr.wLineBytes = wWidth;
//	}
//	else
//	{
//		pcxHdr.wLineBytes = wWidth + 1;
//	}
	
	// 图像调色板的类型,1表示彩色或者单色图像,2表示图像是灰度图
	pcxHdr.wPaletteType = 1;
	
	// 制作该图像的屏幕宽度(像素为单位)
	pcxHdr.wSrcWidth = 0;
	
	// 制作该图像的屏幕高度(像素为单位)
	pcxHdr.wSrcDepth = 0;
	
	// 保留域,取值设定为0。
	for (i = 0; i < 54; i ++)
	{
		pcxHdr.bFiller[i] = 0;
	}
	
	// 写入文件头
	file.Write((LPSTR)&pcxHdr, sizeof(PCXHEADER));
	
	//*******************************************************************************
	// 开始编码
	
	// 开辟一片缓冲区(2被原始图像大小)以保存编码结果
	lpDst = new BYTE[wHeight * wWidth * 2];
	
	// 指明当前已经用了多少缓冲区(字节数)
	dwBuffUsed = 0;
	
	// 每行
	for (i = 0; i < wHeight; i++)
	{
		// 指向DIB第i行,第0个像素的指针
		lpSrc = (BYTE *)lpDIBBits + lLineBytes * (wHeight - 1 - i);
		
		// 给bChar1赋值
		bChar1 = *lpSrc;
		
		// 设置iCount为1
		iCount = 1;
		
		// 剩余列
		for (j = 1; j < wWidth; j ++)
		{
			// 指向DIB第i行,第j个像素的指针
			lpSrc++;
			
			// 读取下一个像素
			bChar2 = *lpSrc;
			
			// 判断是否和bChar1相同并且iCount < 63
			if ((bChar1 == bChar2) && (iCount < 63))
			{
				// 相同,计数加1
				iCount ++;
				
				// 继续读下一个
			}
			else
			{
				// 不同,或者iCount = 63
				
				// 写入缓冲区
				if ((iCount > 1) || (bChar1 >= 0xC0))
				{
					// 保存码长信息
					lpDst[dwBuffUsed] = iCount | 0xC0;
					
					// 保存bChar1
					lpDst[dwBuffUsed + 1] = bChar1;
					
					// 更新dwBuffUsed
					dwBuffUsed += 2;
				}
				else
				{
					// 直接保存该值
					lpDst[dwBuffUsed] = bChar1;
					
					// 更新dwBuffUsed
					dwBuffUsed ++;
				}
				
				// 重新给bChar1赋值
				bChar1 = bChar2;
				
				// 设置iCount为1
				iCount = 1;
			}
		}
		
		// 保存每行最后一部分编码
		if ((iCount > 1) || (bChar1 >= 0xC0))
		{
			// 保存码长信息
			lpDst[dwBuffUsed] = iCount | 0xC0;
			
			// 保存bChar1
			lpDst[dwBuffUsed + 1] = bChar1;
			
			// 更新dwBuffUsed
			dwBuffUsed += 2;
		}
		else
		{
			// 直接保存该值
			lpDst[dwBuffUsed] = bChar1;
			
			// 更新dwBuffUsed
			dwBuffUsed ++;
		}
	}
	
	// 写入编码结果
	file.WriteHuge((LPSTR)lpDst, dwBuffUsed);
	
	// 释放内存
	delete lpDst;
	
	//**************************************************************************
	// 写入调色板信息
	
	// 指向BITMAPINFO结构的指针(Windows 3.0)
	LPBITMAPINFO lpbmi;
	
	// 指向BITMAPCOREINFO结构的指针
	LPBITMAPCOREINFO lpbmc;
	
	// 表明是否是Windows 3.0 DIB的标记
	BOOL bWinStyleDIB;
	
	// 开辟一片缓冲区以保存调色板
	lpDst = new BYTE[769];
	
	// 调色板起始字节
	* lpDst = 0x0C;
	
	// 获取指向BITMAPINFO结构的指针(Windows 3.0)
	lpbmi = (LPBITMAPINFO)lpDIB;
	
	// 获取指向BITMAPCOREINFO结构的指针
	lpbmc = (LPBITMAPCOREINFO)lpDIB;
	
	// 判断是否是Windows 3.0的DIB
	bWinStyleDIB = IS_WIN30_DIB(lpDIB);
	
	// 读取当前DIB调色板
	for (i = 0; i < 256; i ++)
	{
		if (bWinStyleDIB)
		{
			// 读取DIB调色板红色分量
			lpDst[i * 3 + 1] = lpbmi->bmiColors[i].rgbRed;
			
			// 读取DIB调色板绿色分量
			lpDst[i * 3 + 2] = lpbmi->bmiColors[i].rgbGreen;
			
			// 读取DIB调色板蓝色分量
			lpDst[i * 3 + 3] = lpbmi->bmiColors[i].rgbBlue;
		}
		else
		{
			// 读取DIB调色板红色分量
			lpDst[i * 3 + 1] = lpbmc->bmciColors[i].rgbtRed;
			
			// 读取DIB调色板绿色分量
			lpDst[i * 3 + 2] = lpbmc->bmciColors[i].rgbtGreen;
			
			// 读取DIB调色板蓝色分量
			lpDst[i * 3 + 3] = lpbmc->bmciColors[i].rgbtBlue;
		}
	}
	
	// 写入调色板信息
	file.Write((LPSTR)lpDst, 769);
	
	// 返回
	return TRUE;
}

/*************************************************************************
 *
 * 函数名称:
 *   ReadPCX256()
 *
 * 参数:
 *   CFile& file        - 要读取的文件
 *
 * 返回值:
 *   HDIB               - 成功返回DIB的句柄,否则返回NULL。
 *
 * 说明:
 *   该函数将读取指定的256色PCX文件。将读取的结果保存在一个未压缩
 * 编码的DIB对象中。
 *
 *************************************************************************/
HDIB WINAPI ReadPCX256(CFile& file)
{
	// PCX文件头
	PCXHEADER pcxHdr;
	
	// DIB大小(字节数)
	DWORD	dwDIBSize;
	
	// DIB句柄
	HDIB	hDIB;
	
	// DIB指针
	LPSTR	pDIB;
	
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 重复像素计数
	int		iCount;
	
	// DIB高度
	WORD	wHeight;
	
	// DIB宽度
	WORD	wWidth;
	
	// 图像每行的字节数
	LONG	lLineBytes;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -