Windows DIB文件操作具体解释-5.DIB和调色板

Windows调色板是256色显卡时期的产物,如今显卡最少也是16bit的了。所以调色板基本上是用不到了的。

可是以下几种情况还是须要去使用和了解调色板:

1.在新显卡上保证256色兼容模式的正常执行

2.在256色显卡或低于256色显卡老机器上执行程序或在一些工业控制场合(为了节约成本可能採用256色显卡或低于256色显卡)执行程序

3.操作DIB的指定像素点数据


1.调色板是什么

相同採用以下一张图



如上图,我们能够调色板分为例如以下几种:

1.DIB文件里的调色板

2.内存中创建的逻辑调色板对象

3.显卡中硬件调色板


调色板顾名思义就是类似画家的调色板一样,以256色显卡来说,如今有256个小格子,每一个格子中有一种颜色,每次画图你能够用这256种颜色来画图,假设你对当前的256种颜色不惬意,能够更换当中的调色板颜色,可是每画一幅图仅仅能用确认的256中颜色来。相应到电脑的调色板来说,显卡支持显示的颜色仅仅有256种,存储在显卡硬件调色板中,你能够设置要採用的256种颜色。然后你要显示的全部颜色都会近似用256中颜色中的一种来显示,这就是所谓的调色板查表以取得近期似颜色。

能够看到。一幅图在电脑上显示的效果是什么样和当前显卡硬件调色板中的颜色是密不可分的,所以对于採用硬件调色板的的位图,保存它的最好做法就是保存位图数据的同一时候保存位图调色板

为了改变硬件调色板中的颜色我们须要先创建逻辑调色板对象,然后再将逻辑调色板映射到硬件调色板上。


2.调色板的使用


对于带有调色板的DIB来说。显示DIB的一般过程例如以下:

1.读入DIB分别为File Header、Info Header、Mask、Color Table、Bits各个区

2.利用DIB的调色板数据(Color Table区)创建逻辑调色板对象(CreatePalette)。一般在WM_CREATE中

3.在WM_PAINT显示DIB之前,将基于DIB创建的逻辑调色板对象选进当前设备描写叙述表(SelectPalette)并映射到硬件调色板上(RealizePalette)。

4.假设仅仅是想保证指定窗体为活动窗体时显示的颜色,那么做完这三歩即可了。假设想保证指定窗体不是活动窗体时的颜色,那么还要处理WM_QUERYPALETTE和WM_PALETTECHANGED消息。

这两个消息是为了帮助Windows组织系统调色板用的。这里不详述。直接依照固定模式使用,详细能够查看MSDN。


3.代码演示

演示程序为一个典型的Windows 带调色板DIB的显示过程。以下为部分代码,完整源码最后会给出下载链接。

依据DIB Color Table创建逻辑调色板

//创建数据显示调色板
HPALETTE PackedDibCreatePalette(BITMAPINFO *pPackedDib, HWND hwnd)
{
	HPALETTE	hPalete;
	HDC			hdc;
	int			i, iNumColors;
	LOGPALETTE	*plp	= NULL;
	RGBQUAD		*prgb	= NULL;

	if (0 == PackedDibGetColorTableSize(pPackedDib) && 
		PackedDibGetBitCount(pPackedDib) > 8)//没有调色板区且位深大于8,则没有必要创建调色板
	{
		return NULL;
	}
	else if (0 == PackedDibGetColorTableSize(pPackedDib))//没有调色板区且位深小于等于8,则创建通用调色板
	{
		hdc = GetDC(hwnd);
		hPalete = CreateHalftonePalette(hdc);
		ReleaseDC(hwnd, hdc);

		return hPalete;
	}
	else//使用位图自带的调色板区
	{
		iNumColors = PackedDibGetNumColors(pPackedDib);

		plp = malloc(sizeof(LOGPALETTE) + (iNumColors-1)*sizeof(PALETTEENTRY));
		if (NULL == plp)
		{
			return NULL;
		}
		
		plp->palVersion		= 0x0300;
		plp->palNumEntries	= iNumColors;
		
		for (i = 0; i < iNumColors; i++)
		{
			prgb = PackedDibGetColorTableEntry(pPackedDib, i);
			
			plp->palPalEntry[i].peRed        = prgb->rgbRed;
			plp->palPalEntry[i].peGreen      = prgb->rgbGreen;
			plp->palPalEntry[i].peBlue       = prgb->rgbBlue;
			plp->palPalEntry[i].peFlags      = 0;
		}
		
		hPalete = CreatePalette(plp);
		if (INVALID_HANDLE_VALUE == hPalete)
		{
			return NULL;
		}
		
		return hPalete;
	}
}

WM_PAINT中显示DIB及WM_QUERYPALETTE和WM_PALETTECHANGED消息的处理

    case WM_PAINT:
        hdc = BeginPaint (hwnd, &ps);

		if (hPalette)
		{
			SelectPalette(hdc, hPalette, FALSE);
			RealizePalette(hdc);
		}

		if (pPackedDib)
		{
			SetDIBitsToDevice(	hdc, 
								0, 0, PackedDibGetWidth(pPackedDib), PackedDibGetHeight(pPackedDib), 
								0, 0,
								0, PackedDibGetHeight(pPackedDib),
								PackedDibGetBitsPtr(pPackedDib),
								pPackedDib,
								DIB_RGB_COLORS);
		}

        EndPaint (hwnd, &ps);
        return (0);

	case WM_QUERYNEWPALETTE:
		if(!hPalette)
		{
			return FALSE;
		}
		
		hdc = GetDC(hwnd);
		
		SelectPalette(hdc, hPalette, FALSE);
		RealizePalette(hdc);
		InvalidateRect(hwnd, NULL, FALSE);
		
		ReleaseDC(hwnd, hdc);
		return TRUE;
		
	case WM_PALETTECHANGED:
		if(!hPalette || (HWND)wParam==hwnd)
		{
			break;
		}
		
		hdc = GetDC(hwnd);
		
		SelectPalette(hdc, hPalette, FALSE);
		RealizePalette(hdc);
		UpdateColors(hdc);
		
		ReleaseDC(hwnd, hdc);
		break;

4.DIB操作库

至此为止,关于DIB显示的所有知识点所有讲完。在给出的代码中实现了一个完整的DIB操作库,主要用于打开、显示和保存DIB。不同于实验DIB显示功能,一个完整性好的DIB操作库必须兼容各种版本号DIB格式、不标准DIB位图

1.DIB版本号的兼容主要包含对OS/2格式位图的兼容(BITMAPCOREHEADER定义带来的各种差异。RGBTRIPLE带来的差异)。

2.不标准DIB位图主要指有的DIB位图不填充ClrUsed、SizeImage项,有的小于8bit的DIB位图没有调色板须要使用通用调色板,有的16bit位图不提供掩码等等。

总之,一个实现完整的DIB库须要考虑种种繁枝末节,假设是在商业程序中使用的话。最好使用已经开源的各种实现。该博文提供的DIB库在Pelzold的实现上改动而来,但仍然有不足,比如对压缩的DIB没有考虑等,仅供技术研究用。


完整源码下载链接

原创。转载请注明来自http://blog.csdn.net/wenzhou1219

原文地址:https://www.cnblogs.com/mengfanrong/p/5183025.html