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

📄 formatddbdata.cpp

📁 visual c++数字图像与图形处理中的光盘内容
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/////////////////////////////////////////////////////////////////////////////////
//	
// 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 + -