📄 dibapi.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 + -