📄 formatddbdata.cpp
字号:
/////////////////////////////////////////////////////////////////////////////////
//
// FormatDdbData.cpp: implementation of the CFormatDdbData class.
//
////////////////////////////////////////////////////////////////////////////////
// 版权所有(2000)
// Copyright(2000)
// 编写者: 向世明
// Author: Xiang Shiming
#include "stdafx.h"
#include "FormatDdbData.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFormatDdbData::CFormatDdbData()
{
}
CFormatDdbData::~CFormatDdbData()
{
}
//将一个24位RGB转换为16位颜色
WORD CFormatDdbData::PutRGB16(BYTE byRed, BYTE byGreen, BYTE byBlue)
{
// WORD & 0xF800 = red
// WORD & 0x07E0 = green
// WORD & 0x001F = blue
return ( (((WORD)byRed & 0x00F8) << 8) |
(((WORD)byGreen & 0x00FC) << 3) |
((WORD)byBlue >> 3) );
/*
//for other operation system
return((((WORD)byRed & 0x00F8) << 7) |
(((WORD)byGreen & 0x00F8) << 2) |
((WORD)byBlue >> 3) );
*/
}
DWORD CFormatDdbData::GetDdbWidthBytes(int nWidth, BYTE byBitCount)
{
//每行字节数必须被2整除
return ((((DWORD)nWidth * byBitCount + 15) / 16) * 2);
}
//将24位的DDB数据lpbySrcBits24转换为16位DDB数据lpbyDstBits16
//nScanWidth表示扫描宽度, 即像素个数
//nScanHeight表示区域的高度.
void CFormatDdbData::Format24To16(LPBYTE lpbySrcBits24, int nScanWidth, int nScanHeight, LPBYTE lpbyDstBits16)
{
ASSERT(lpbySrcBits24);
ASSERT(lpbyDstBits16);
//24位DDB数据字节宽度.
DWORD dwWidthBytes24 = GetDdbWidthBytes(nScanWidth, 24);
//对于16位DDB数据, 其扫描字节宽度必然为其宽度的2倍
DWORD dwBaseIndex24 = 0;
//指向24位和16每行数据的指针
WORD* pwBits16 = (WORD*)lpbyDstBits16;
for(int i = 0; i < nScanHeight; i++)
{
BYTE* pbyBits24 = lpbySrcBits24 + dwBaseIndex24;
for(int j = 0; j < nScanWidth; j++)
{
BYTE byBlue = *(pbyBits24++);
BYTE byGreen = *(pbyBits24++);
BYTE byRed = *(pbyBits24++);
*(pwBits16++) = PutRGB16(byRed, byGreen, byBlue);
}
dwBaseIndex24 += dwWidthBytes24;
}
}
//将24位的DDB数据lpbySrcBits24转换为32位DDB数据lpbyDstBits32
void CFormatDdbData::Format24To32(LPBYTE lpbySrcBits24, int nScanWidth, int nScanHeight, LPBYTE lpbyDstBits32)
{
ASSERT(lpbySrcBits24);
ASSERT(lpbyDstBits32);
//24位DDB数据
DWORD dwWidthBytes24 = GetDdbWidthBytes(nScanWidth, 24);
//对于32位DDB数据, 其扫描字节宽度必然为其宽度的2倍
//指向32每行数据的指针
DWORD dwBaseIndex24 = 0;
BYTE* pdwBits32 = lpbyDstBits32;
for(int i = 0; i < nScanHeight; i++)
{
BYTE* pbyBits24 = lpbySrcBits24 + dwBaseIndex24;
for(int j = 0; j < nScanWidth; j++)
{
*(pdwBits32++) = *(pbyBits24++); //蓝色
*(pdwBits32++) = *(pbyBits24++); //绿色
*(pdwBits32++) = *(pbyBits24++); //红色
pdwBits32++;
}
dwBaseIndex24 += dwWidthBytes24;
}
}
//将lpbySrcBits24转化为8位DDB格式的数据lpbyDstBits8, 由于8位数据需要带有调色盘,
//因而同时创建一个CPalette对象, 它是一个等同调色盘.
void CFormatDdbData::Format24To8(LPBYTE lpbySrcBits24, int nScanWidth, int nScanHeight, LPBYTE lpbyDstBits8, CPalette *pPalette)
{
ASSERT(lpbySrcBits24);
ASSERT(lpbyDstBits8);
//完成这一任务需要如下几个步骤:
//第一, 对颜色进行量化, 完成第一次映射:从24位到8位,
//第二, 建立等同调色盘,
//第三, 完成第二次映射, 使数据与等同调色盘相匹配.
//关于显示设备的例行检测
CDC dc;
//如果不是一个需调色设备, 就简单地返回
if (!dc.CreateDC ("DISPLAY", NULL, NULL, NULL))
{
AfxMessageBox("Can't create a DC");
return;
}
else if ((~dc.GetDeviceCaps (RASTERCAPS) & RC_PALETTE))
{
dc.DeleteDC ();
AfxMessageBox("The DC is not a palette device");
return;
}
//我们只处理8位256色显示模式, 对于16色显示模式, 我们不处理.
if(dc.GetDeviceCaps(BITSPIXEL) != 8)
{
AfxMessageBox("The display mode is not 256-color mode");
return;
}
dc.DeleteDC ();
//进行颜色量化, 并完成第一次映射:从24位到8位,
BYTE* pbyLogPalette = new BYTE[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
if(pbyLogPalette == NULL) return;
memset(pbyLogPalette, 0, (sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)));
LOGPALETTE* pLogPalette = (LOGPALETTE*)pbyLogPalette;
pLogPalette->palVersion = 0x300;
pLogPalette->palNumEntries = 256;
QuantizeColor(lpbySrcBits24, nScanWidth, nScanHeight, lpbyDstBits8, pLogPalette);
//创建等同调色盘
CreateIdentityPalette(pLogPalette, pPalette);
//总的数据量:字节数
DWORD dwCount = GetDdbWidthBytes(nScanWidth, 8) * nScanHeight;
//完成第二次映射
Remap(dwCount, lpbyDstBits8, pLogPalette, pPalette);
delete[] pbyLogPalette;
}
//对颜色进行量化, 最后结果放入pLogPalette之中.
//量化后的颜色索引值放入lpbyDstBits8
void CFormatDdbData::QuantizeColor(LPBYTE lpbySrcBits24, int nScanWidth, int nScanHeight, LPBYTE lpbyDstBits8, LOGPALETTE* pLogPalette)
{
ASSERT(lpbySrcBits24);
ASSERT(lpbyDstBits8);
//第一步:对颜色分布进行统计:
//COLORQUANTIZATION结构记录位于小颜色立方体中的像素个数, 颜色分量之和.
typedef struct tagCOLORQUANTIZATION
{
DWORD dwRedSum; //the sum of red
DWORD dwGreenSum; //the sum of green
DWORD dwBlueSum; //the sum of blue
DWORD dwPixelCount; //number of colors in a same box
}COLORQUANTIZATION;
//分配内存
BYTE* pbyColorBox = new BYTE[256 * sizeof(COLORQUANTIZATION)];
if(pbyColorBox == NULL) return;
memset(pbyColorBox, 0, 256 * sizeof(COLORQUANTIZATION));
//指向COLORQUANTIZATION数据的指针
COLORQUANTIZATION* pCQBox = (COLORQUANTIZATION*)pbyColorBox;
//24位数据每行的扫描字节数
DWORD dwWidthBytes24 = GetDdbWidthBytes(nScanWidth, 24);
//8位数据每行的扫描字节数
DWORD dwWidthBytes8 = GetDdbWidthBytes(nScanWidth, 8);
DWORD dwBaseIndex24 = 0;
DWORD dwBaseIndex8 = 0;
//现在进行统计
int i = 0;
for( i = 0; i < nScanHeight;i++)
{
//指向Ddb内存数据的指针(行)
BYTE* pbyDdb24 = lpbySrcBits24 + dwBaseIndex24;
BYTE* pbyDdb8 = lpbyDstBits8 + dwBaseIndex8;
for(int j = 0;j < nScanWidth;j++)
{
//获取当前点的颜色分量
BYTE byBlue = *(pbyDdb24++);
BYTE byGreen = *(pbyDdb24++);
BYTE byRed = *(pbyDdb24++);
//计算当前颜色在立方体中的位置:由颜色三分量的值决定, 因而这也是颜色量化映射关系.
BYTE byIndexR = (byRed >= 210) ? 5 : (byRed / 42);
BYTE byIndexG = (byGreen >= 216) ? 6 : (byGreen / 36);
BYTE byIndexB = (byBlue >= 210) ? 5 : (byBlue / 42);
BYTE byInBox = 42 * byIndexB + 6 * byIndexG + byIndexR;
(pCQBox + byInBox)->dwPixelCount++;
(pCQBox + byInBox)->dwRedSum += byRed;
(pCQBox + byInBox)->dwGreenSum += byGreen;
(pCQBox + byInBox)->dwBlueSum += byBlue;
*(pbyDdb8++) = byInBox;
}
dwBaseIndex24 += dwWidthBytes24;
dwBaseIndex8 += dwWidthBytes8;
}
//第二步, 填充LOGPALETTE结构中的数据, 最后四项为系统调色盘中的值.
for(i = 0;i < 252;i++)
{
COLORQUANTIZATION* pCQ = (pCQBox + i);
if((pCQ->dwPixelCount) > 0)
{
pLogPalette->palPalEntry[i].peRed = (BYTE)(pCQ->dwRedSum / pCQ->dwPixelCount);
pLogPalette->palPalEntry[i].peGreen = (BYTE)(pCQ->dwGreenSum / pCQ->dwPixelCount);
pLogPalette->palPalEntry[i].peBlue = (BYTE)(pCQ->dwBlueSum / pCQ->dwPixelCount);
}
}
//最后四个空位, 我们把它设置成系统调色盘的颜色值.
pLogPalette->palPalEntry[252].peRed = 0x00;
pLogPalette->palPalEntry[252].peGreen = 0x00;
pLogPalette->palPalEntry[252].peBlue = 0xFF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -