📄 formatddbdata.cpp
字号:
pLogPalette->palPalEntry[253].peRed = 0xFF;
pLogPalette->palPalEntry[253].peGreen = 0x00;
pLogPalette->palPalEntry[253].peBlue = 0xFF;
pLogPalette->palPalEntry[254].peRed = 0x00;
pLogPalette->palPalEntry[254].peGreen = 0xFF;
pLogPalette->palPalEntry[254].peBlue = 0xFF;
pLogPalette->palPalEntry[255].peRed = 0xFF;
pLogPalette->palPalEntry[255].peGreen = 0xFF;
pLogPalette->palPalEntry[255].peBlue = 0xFF;
//第三步, 以正常方式对待调色盘中的颜色.
for(i = 0; i < 256; i++)
pLogPalette->palPalEntry[i].peFlags = 0;
delete[] pbyColorBox;
}
//创建等同调色盘.等同调色盘是与当前系统主调色盘完全匹配的一个逻辑调色盘.
//事实上, 它是主调色盘的一个副本.
//pLogPalRsc--应用程序希望的逻辑调色盘;
//pPalette, 等于同调色盘, 它是一个CPalette
BOOL CFormatDdbData::CreateIdentityPalette(LOGPALETTE *pLogPalRsc, CPalette *pPalette)
{
ASSERT(pLogPalRsc);
//第一步, 检测是否为调色设备
CDC dc;
//如果不是一个需调色设备, 就简单地返回
if (!dc.CreateDC ("DISPLAY", NULL, NULL, NULL))
{
AfxMessageBox("Can't create a DC");
return FALSE;
}
else if ((~dc.GetDeviceCaps (RASTERCAPS) & RC_PALETTE))
{
dc.DeleteDC ();
AfxMessageBox("The DC is not a palette device");
return FALSE;
}
//我们只处理8位256色显示模式, 对于16色显示模式, 我们不处理.
if(dc.GetDeviceCaps(BITSPIXEL) != 8)
{
AfxMessageBox("The display mode is not 256-color mode");
return FALSE;
}
//在256色显示模式中检查颜色模式:
//nStaticColors表示静态颜色数目, 在8位颜色模式下, 该值应该等于20
int nStaticColors = dc.GetDeviceCaps (NUMCOLORS);
if (nStaticColors != 20)
{
dc.DeleteDC ();
AfxMessageBox("The number of static color is not equal to 20");
return FALSE;
}
//Number of entries in the system palette. This index is valid only if the device driver sets the RC_PALETTE bit in the RASTERCAPS index and is available only if the driver is compatible with 16-bit Windows.
//nPaletteEntries表示调色盘颜色表项的数目
int nPaletteEntries = dc.GetDeviceCaps (SIZEPALETTE);
//第二, 迫使系统包含静态颜色
//迫使系统调色盘包含两项静态颜色, 黑色和白色, 其索引号分别为0和255.
//同时, 系统调色盘将重设主颜色表, 让它必须包含静态颜色, 这些颜色将不会因为选入新的逻辑调色盘后而得到改变.
//并且, 可方便下一个将要实现的调色盘将其颜色插入主调色盘.
SetSystemPaletteUse (dc.GetSafeHdc(), SYSPAL_NOSTATIC);
SetSystemPaletteUse (dc.GetSafeHdc(), SYSPAL_STATIC);
//第三, 对希望的逻辑调色盘进行映射
//利用源调色盘信息pLogPalRsc构造一个逻辑调色盘,
pPalette->CreatePalette(pLogPalRsc);
if (!pPalette)
{
dc.DeleteDC ();
return FALSE;
}
//强制性地重新设置主调色盘, 将其完全映射到逻辑调色盘.
//选取并实现指定的逻辑调色盘.
CPalette* pOldPal = dc.SelectPalette (pPalette, FALSE);
dc.RealizePalette ();
dc.SelectPalette (pOldPal, FALSE);
//第四, 创建一个等同调色盘
//获取当前主调色盘的一个副本, 同时, 这个副本应使颜色使用PC_NOCOLLAPSE标志.
//从而当再次实现该逻辑调色盘时, 这些颜色不必重新映射.
PALETTEENTRY pe[256];
GetSystemPaletteEntries (dc.GetSafeHdc(), 0, nPaletteEntries, pe);
//设置调色盘的前10项, 中间236项, 后10项.
//系统静态颜色分别位于前10项和后10项.
int i = 0;
for (i = 0; i < nStaticColors / 2; i++)
pe[i].peFlags = 0;
for (; i < nPaletteEntries - nStaticColors / 2; i++)
pe[i].peFlags = PC_NOCOLLAPSE;
for (; i < nPaletteEntries; i++)
pe[i].peFlags = 0;
//重新设置调色盘的大小, 使之与系统匹配
pPalette->ResizePalette (nPaletteEntries);
//将系统主调色盘的一个副本 pe 拷贝到pPalette之中, 从而创建了一个等同调色盘.
pPalette->SetPaletteEntries (0, nPaletteEntries, pe);
dc.DeleteDC();
return TRUE;
}
//
void CFormatDdbData::Remap(DWORD dwCount, LPBYTE lpbyDstBits8, LOGPALETTE* pLogPalRsc, CPalette *pIdentityPal)
{
ASSERT(lpbyDstBits8);
ASSERT(pLogPalRsc);
ASSERT(pIdentityPal);
//创建一个新的索引映射表
BYTE abyMap[256];
for(int i = 0; i < 256; i++)
abyMap[i] = (BYTE) pIdentityPal->GetNearestPaletteIndex(
RGB(pLogPalRsc->palPalEntry[i].peRed,
pLogPalRsc->palPalEntry[i].peGreen,
pLogPalRsc->palPalEntry[i].peBlue));
//完成映射
DWORD dwMapNum = dwCount;
BYTE* pbyScanMap = lpbyDstBits8;
//扫描行尾的0(如果有)必然被映射映射为0.
while(dwMapNum--)
{
//单点映射
*pbyScanMap = abyMap[*pbyScanMap];
pbyScanMap++;
}
}
void CFormatDdbData::Format32To16(LPBYTE lpbySrcBits32, int nScanWidth, int nScanHeight, LPBYTE lpbyDstBits16)
{
ASSERT(lpbySrcBits32);
ASSERT(lpbyDstBits16);
//对于16, 32位DDB数据, 其扫描字节宽度必然为其宽度的2倍
//指向32位和16每行数据的指针
BYTE* pbyBits32 = lpbySrcBits32;
WORD* pwBits16 = (WORD*)lpbyDstBits16;
for(int i = 0; i < nScanHeight; i++)
{
for(int j = 0; j < nScanWidth; j++)
{
BYTE byBlue = *(pbyBits32++);
BYTE byGreen = *(pbyBits32++);
BYTE byRed = *(pbyBits32++);
pbyBits32++;
*(pwBits16++) = PutRGB16(byRed, byGreen, byBlue);
}
}
}
void CFormatDdbData::Format32To24(LPBYTE lpbySrcBits32, int nScanWidth, int nScanHeight, LPBYTE lpbyDstBits24)
{
ASSERT(lpbySrcBits32);
ASSERT(lpbyDstBits24);
//24位DDB数据
DWORD dwWidthBytes24 = GetDdbWidthBytes(nScanWidth, 24);
//对于32位DDB数据, 其扫描字节宽度必然为其宽度的2倍
//指向32每行数据的指针
DWORD dwBaseIndex24 = 0;
BYTE* pbyBits32 = lpbySrcBits32;
for(int i = 0; i < nScanHeight; i++)
{
BYTE* pbyBits24 = lpbyDstBits24 + dwBaseIndex24;
for(int j = 0; j < nScanWidth; j++)
{
*(pbyBits24++) = *(pbyBits32++); //蓝色
*(pbyBits24++) = *(pbyBits32++); //绿色
*(pbyBits24++) = *(pbyBits32++); //红色
pbyBits32++;
}
dwBaseIndex24 += dwWidthBytes24;
}
}
//将32位数据转化为8位数据
void CFormatDdbData::Format32To8(LPBYTE lpbySrcBits32, int nScanWidth, int nScanHeight, LPBYTE lpbyDstBits8, CPalette *pPalette)
{
ASSERT(lpbySrcBits32);
ASSERT(lpbyDstBits8);
//先转化为24位数据, 再转换为8位数据
//总的数据量:字节数
DWORD dwCount24 = GetDdbWidthBytes(nScanWidth, 24) * nScanHeight;
//指向位数据的指针, 在运算的过程中不改变
BYTE* pbyDdb24 = new BYTE[dwCount24];
if(pbyDdb24 == NULL) return;
memset(pbyDdb24, 0, dwCount24);
Format32To24(lpbySrcBits32, nScanWidth, nScanHeight, pbyDdb24);
Format24To8(pbyDdb24, nScanWidth, nScanHeight, lpbyDstBits8, pPalette);
delete[] pbyDdb24;
}
//找出给定颜色的最邻近颜色索引, 采用欧拉空间距离法
int CFormatDdbData::GetNearestColorIndex(BYTE byRed, BYTE byGreen, BYTE byBlue, PALETTEENTRY *pPalEntry)
{
ASSERT(pPalEntry);
int nNearestIndex = 0;
DWORD dwMin = 300000L;
for(int i = 0;i < 256;i++)
{
DWORD dwDeltaRed, dwDeltaGreen, dwDeltaBlue, dwMag;
if(byRed > pPalEntry[i].peRed)
dwDeltaRed = (DWORD)(byRed - pPalEntry[i].peRed);
else
dwDeltaRed = (DWORD)(pPalEntry[i].peRed - byRed);
if(byGreen > pPalEntry[i].peGreen)
dwDeltaGreen = (DWORD)(byGreen - pPalEntry[i].peGreen);
else
dwDeltaGreen = (DWORD)(pPalEntry[i].peGreen - byGreen);
if(byBlue > pPalEntry[i].peBlue)
dwDeltaBlue = (DWORD)(byBlue - pPalEntry[i].peBlue);
else
dwDeltaBlue = (DWORD)(pPalEntry[i].peBlue - byBlue);
dwMag = (dwDeltaRed * dwDeltaRed + dwDeltaGreen * dwDeltaGreen + dwDeltaBlue * dwDeltaBlue);
if(dwMag < dwMin)
{
if(dwMag <= 1) return (i);
dwMin = dwMag;
nNearestIndex = i;
}
}
return (nNearestIndex);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -