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

📄 dibapi.cpp

📁 VisualC高级编程技术精粹.rar
💻 CPP
字号:
//  DIBAPI.cpp
//

#include "stdafx.h"
#include "dibapi.h"
#include <direct.h>
#include <math.h>
#include <io.h>
#include <errno.h>


BOOL  PaintDIB(HDC  hDC,
			   LPRECT  lpDCRect,
			   HDIB    hDIB,
			   LPRECT  lpDIBRect,
			   CPalette* pPal)
{
	LPSTR    lpDIBHdr;            // 指向BITMAPINFOHEADER的指针
	LPSTR    lpDIBBits;           // 指向一个DIB位
	BOOL     bSuccess=FALSE;      // 成功与失败的标记
	HPALETTE hPal=NULL;           // DIB调色板
	HPALETTE hOldPal=NULL;        // 旧的调色板

	// 检查DIB句柄是否有效
	if (hDIB == NULL)
		return FALSE;

	//锁住DIB,取得一个起始指针
	lpDIBHdr  = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
	lpDIBBits = ::FindDIBBits(lpDIBHdr);

	// 取得DIB的调色板,并将其选进设备
	if (pPal != NULL)
	{
		hPal = (HPALETTE) pPal->m_hObject;

		// 选取背景 
		hOldPal = ::SelectPalette(hDC, hPal, TRUE);
	}

	// 确定使用模式
	::SetStretchBltMode(hDC, COLORONCOLOR);

	// 决定调用StretchDIBits()或SetDIBitsToDevice()函数
	if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDIBRect)) &&
	   (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
		bSuccess = ::SetDIBitsToDevice(hDC,			 // 显示设备上下文句柄
				   lpDCRect->left,           // 目的区左上x坐标
				   lpDCRect->top,            // 目的区左上y坐标
				   RECTWIDTH(lpDCRect),      // 原矩形宽度
				   RECTHEIGHT(lpDCRect),     // 原矩形高度
				   lpDIBRect->left,          // 原矩形左下角x坐标
				   (int)DIBHeight(lpDIBHdr) -
					  lpDIBRect->top -
					  RECTHEIGHT(lpDIBRect), // 原矩形左下角y坐标
				   0,                        // 第一扫描线位置
				   (WORD)DIBHeight(lpDIBHdr),// 扫描线数
				   lpDIBBits,                // DIB像素数据指针
				   (LPBITMAPINFO)lpDIBHdr,   // BITMAPINFO结构指针
				   DIB_RGB_COLORS);          // 使用颜色的方式
   else
	  bSuccess = ::StretchDIBits(hDC,        // 显示设备上下文句柄
				   lpDCRect->left,           // 目的区左上x坐标
				   lpDCRect->top,            // 目的区左上y坐标
				   RECTWIDTH(lpDCRect),      // 目的矩形宽度
				   RECTHEIGHT(lpDCRect),     // 目的矩形高度
				   lpDIBRect->left,          // 原矩形左下角x坐标
				   lpDIBRect->top,           // 原矩形左下角y坐标
				   RECTWIDTH(lpDIBRect),     // 原矩形宽度
				   RECTHEIGHT(lpDIBRect),    // 原矩形高度
				   lpDIBBits,                // DIB像素数据指针
				   (LPBITMAPINFO)lpDIBHdr,   // BITMAPINFO结构指针
				   DIB_RGB_COLORS,           // 使用颜色的方式
				   SRCCOPY);                 //光栅操作码
  ::GlobalUnlock((HGLOBAL) hDIB);

	// 重选旧的调色板 
	if (hOldPal != NULL)
	{
		::SelectPalette(hDC, hOldPal, TRUE);
	}

   return bSuccess;
}

BOOL  CreateDIBPalette(HDIB hDIB, CPalette* pPal)
{
	LPLOGPALETTE lpPal;      // 指向逻辑调色板的指针
	HANDLE hLogPal;          // 逻辑调色板句柄
	HPALETTE hPal = NULL;    // 调色板句柄
	int i;                   // 索引
	WORD wNumColors;         // 颜色表中的颜色数
	LPSTR lpbi;              // 指向一个DIB的指针
	LPBITMAPINFO lpbmi;      // 指向BITMAPINFO结构的指针
	LPBITMAPCOREINFO lpbmc;  // 指向BITMAPCOREINFO结构的指针
	BOOL bWinStyleDIB;       // 区分是否为Win3.0 DIB的一个标记 
	BOOL bResult = FALSE;

	// 如果DIB句柄无效, 返回FALSE

	if (hDIB == NULL)
	  return FALSE;

   lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);

   // 得到BITMAPINFO (Win 3.0)指针 
   lpbmi = (LPBITMAPINFO)lpbi;

   // 得到BITMAPCOREINFO (old 1.x)指针 
   lpbmc = (LPBITMAPCOREINFO)lpbi;

   // 得到DIB的颜色数
   wNumColors = ::DIBNumColors(lpbi);

   if (wNumColors != 0)
   {
		// 为逻辑调色板分配内存
		hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
									+ sizeof(PALETTEENTRY)
									* wNumColors);

		// 如果没有足够得空间清除并返回 NULL
		if (hLogPal == 0)
		{
			::GlobalUnlock((HGLOBAL) hDIB);
			return FALSE;
		}

		lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);

		// 设置版本号和调色板口数目 
		lpPal->palVersion = PALVERSION;
		lpPal->palNumEntries = (WORD)wNumColors;

		// 是否为Win 3.0 DIB
		bWinStyleDIB = IS_WIN30_DIB(lpbi);
		for (i = 0; i < (int)wNumColors; i++)
		{
			if (bWinStyleDIB)
			{
				lpPal->palPalEntry[i].peRed = 
					lpbmi->bmiColors[i].rgbRed;
				lpPal->palPalEntry[i].peGreen = 
					lpbmi->bmiColors[i].rgbGreen;
				lpPal->palPalEntry[i].peBlue = 
					lpbmi->bmiColors[i].rgbBlue;
				lpPal->palPalEntry[i].peFlags = 0;
			}
			else
			{
				lpPal->palPalEntry[i].peRed = 
					lpbmc->bmciColors[i].rgbtRed;
				lpPal->palPalEntry[i].peGreen = 
					lpbmc->bmciColors[i].rgbtGreen;
				lpPal->palPalEntry[i].peBlue = 
					lpbmc->bmciColors[i].rgbtBlue;
				lpPal->palPalEntry[i].peFlags = 0;
			}
		}

		// 创建调色板并得到句柄 
		bResult = pPal->CreatePalette(lpPal);
		::GlobalUnlock((HGLOBAL) hLogPal);
		::GlobalFree((HGLOBAL) hLogPal);
	}

	::GlobalUnlock((HGLOBAL) hDIB);

	return bResult;
}

LPSTR  FindDIBBits(LPSTR lpbi)
{
	return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi));
}

DWORD  DIBWidth(LPSTR lpDIB)
{
	LPBITMAPINFOHEADER lpbmi;  // 指向Win 3.0 DIB
	LPBITMAPCOREHEADER lpbmc;  // 指向其它格式 DIB

	lpbmi = (LPBITMAPINFOHEADER)lpDIB;
	lpbmc = (LPBITMAPCOREHEADER)lpDIB;

	// 如果为Win 3.0 DIB,则返回其宽度 
	if (IS_WIN30_DIB(lpDIB))
	{
		return lpbmi->biWidth;
	}
	else // 如果为其它格式的DIB, 也返回其宽度
	{ 
		return (DWORD)lpbmc->bcWidth;
	}
}

DWORD  DIBHeight(LPSTR lpDIB)
{
	LPBITMAPINFOHEADER lpbmi;  // 指向Win 3.0格式的DIB
	LPBITMAPCOREHEADER lpbmc;  // 指向其它格式的DIB

	lpbmi = (LPBITMAPINFOHEADER)lpDIB;
	lpbmc = (LPBITMAPCOREHEADER)lpDIB;

	// 如果为Win 3.0 DIB,则返回其高度
	if (IS_WIN30_DIB(lpDIB))
	{
		return lpbmi->biHeight;
	}
	else // i如果为其它格式DIB, 也返回其高度
	{ 
		return (DWORD)lpbmc->bcHeight;
	}
}

WORD  PaletteSize(LPSTR lpbi)
{
   //计算必须的尺寸
   if (IS_WIN30_DIB (lpbi))
	  return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));
   else
	  return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
}

WORD  DIBNumColors(LPSTR lpbi)
{
	WORD wBitCount;  // DIB bit count

	//如果为Windows格式的DIB,颜色数少于像素位数.
	 //  如果是这种情况,返回合适的值 。
	 
	if (IS_WIN30_DIB(lpbi))
	{
		DWORD dwClrUsed;

		dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
		if (dwClrUsed != 0)
			return (WORD)dwClrUsed;
	}

	// 计算基于像素的颜色数 
	if (IS_WIN30_DIB(lpbi))
		wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
	else
		wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;

	// 返回基于像素的颜色数
	if(wBitCount == 1 || wBitCount == 4 || wBitCount == 4)
		return 2^wBitCount;//返回的是2的倍数
	else
		return 0;
}

HGLOBAL  CopyHandle (HGLOBAL h)
{
	if (h == NULL)
		return NULL;

	DWORD dwLen = ::GlobalSize((HGLOBAL) h);
	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;
}

BOOL  SaveDIB(HDIB hDib, CFile& file)
{
	BITMAPFILEHEADER bmfHdr; // 文件头
	LPBITMAPINFOHEADER lpBI;   // 指向DIB信息结构的指针
	DWORD dwDIBSize;

	if (hDib == NULL)
		return FALSE;

	//得到指向DIB内存的指针, 包括一个BITMAPINFO结构
	
	lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
	if (lpBI == NULL)
		return FALSE;

	if (!IS_WIN30_DIB(lpBI))
	{
		::GlobalUnlock((HGLOBAL) hDib);
		return FALSE;       // 其它格式的DIB不支持 
	}

	// 填写文件头区域
	 
	// 填写文件类型 
	bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"

	// 计算DIB的大小。最简单的方法是调用GlobalSize()函数
	// 一般手工计算。
	// 先计算头和颜色表之和
	dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI); 

	// 计算图像大小

	if ((lpBI->biCompression == BI_RLE8)
		|| (lpBI->biCompression == BI_RLE4))
	{
		// 为RLE位图, 不能计算尺寸。 

		dwDIBSize += lpBI->biSizeImage;
	}
	else
	{
		DWORD dwBmBitsSize;  // 位图位的大小
		// 非RLE, 大小为 宽度*高度

		dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*
			((DWORD)lpBI->biBitCount)) * lpBI->biHeight;

		dwDIBSize += dwBmBitsSize;

		lpBI->biSizeImage = dwBmBitsSize;
	}


	// 计算文件大小

	bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
	bmfHdr.bfReserved1 = 0;
	bmfHdr.bfReserved2 = 0;

	// 计算真实的位图位的偏移量,其等于文件头+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);
	return TRUE;
}

HDIB  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))
		return NULL;

	if (bmfHeader.bfType != DIB_HEADER_MARKER)
		return NULL;

	//为DIB分配内存
	
	hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
	if (hDIB == 0)
	{
		return NULL;
	}
	pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);

	// 读位数
	
	if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=
		dwBitsSize - sizeof(BITMAPFILEHEADER) )
	{
		::GlobalUnlock((HGLOBAL) hDIB);
		::GlobalFree((HGLOBAL) hDIB);
		return NULL;
	}
	::GlobalUnlock((HGLOBAL) hDIB);
	return hDIB;
}

⌨️ 快捷键说明

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