第16章 调色板管理器_16.3 调色板和现实世界中的图像

16.3.1 调色板和紧凑DIB

(1)对于16、24、32位的DIB,没有颜色表,就不必创建调色板。但在8位视频模式下,只会用标准的20种保留色来显示。由DIB颜色表创建的调色板被称为“原生调色板”

(2)dwPixel =PackedDibGetPixel(pPackedDib,x,y),当这类函数多次调用时会使程序变慢。

(3)很多函数,需要对OS/2兼容DIB作不同处理。

【ShowDib3程序】——原生(Native)调色板

效果图
//PackedDIB.h文件
/*------------------------------------------------------------------
PACKEDDIB.H -- Header file for PACKDIB.C
(c) Charles Petzold,1998
------------------------------------------------------------------*/
#pragma once

#include <windows.h>

BITMAPINFO* PackedDibLoad(PTSTR szFileName);

int PackedDibGetWidth(BITMAPINFO* pPackedDib);
int PackedDibGetHeight(BITMAPINFO* pPackedDib);
int PackedDibGetBitCount(BITMAPINFO* pPackedDib);
int PackedDibGetRowLength(BITMAPINFO* pPackedDib);

int PackedDibGetInfoHeaderSize(BITMAPINFO* pPackedDib);
int PackedDibGetColorsUsed(BITMAPINFO* pPackedDib);
int PackedDibGetNumColors(BITMAPINFO* pPackedDib);

RGBQUAD* PackedDibGetColorTableSize(BITMAPINFO* pPackedDib);
RGBQUAD* PackedDibGetColorTableEntry(BITMAPINFO*, int i);

BYTE* PackedDibGetBitsPtr(BITMAPINFO* pPackedDib);
int PackedDibGetBitsSize(BITMAPINFO* pPackedDib);

HPALETTE PackedDibCreatePalette(BITMAPINFO* pPackedDib);

//PackedDIB.c文件

/*-----------------------------------------------------------------
PACKEDDIB.C -- Routines for using packed DIBs
(c) Charles Petzold,1998
-----------------------------------------------------------------*/
#include <windows.h>

/*---------------------------------------------------------
PackedDibLoad:将DIB文件作以紧缩型格式加载进内存中
---------------------------------------------------------*/
BITMAPINFO* PackedDibLoad(PTSTR szFileName)
{
    BITMAPFILEHEADER   bmfh;
    BITMAPINFO*        pbmi;
    HANDLE  hFile;
    BOOL bSuccess;
    DWORD  dwBytesRead, dwPackedDibSize;

    //打开文件,指定读和写属性
    hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                       OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return NULL;

    //读取文件头
    bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);
    if (!bSuccess || (dwBytesRead != sizeof(BITMAPFILEHEADER))
        || (bmfh.bfType != *(WORD*)"BM"))
    {
        CloseHandle(hFile);
        return NULL;
    }

    //计算紧缩型DIB的大小
    dwPackedDibSize = bmfh.bfSize - sizeof(BITMAPFILEHEADER); //文件大小减小文件头的大小

    //分配内存,并读入信息(含信息头与像素数据)
    pbmi = malloc(dwPackedDibSize);
    bSuccess = ReadFile(hFile, pbmi, dwPackedDibSize, &dwBytesRead, NULL);
    CloseHandle(hFile);

    if (!bSuccess || (dwPackedDibSize != dwBytesRead))
    {
        free(pbmi);
        return NULL;
    }
    return pbmi;
}

/*----------------------------------------------
获取紧缩型DIB信息的函数
----------------------------------------------*/

int PackedDibGetWidth(BITMAPINFO* pPackedDib)
{
    if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
        return  ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcWidth;
    else
        return pPackedDib->bmiHeader.biWidth;
}

int PackedDibGetHeight(BITMAPINFO* pPackedDib)
{
    if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
        return  ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcHeight;
    else
        return abs(pPackedDib->bmiHeader.biHeight);  //取绝对值
}

int PackedDibGetBitCount(BITMAPINFO* pPackedDib)
{
    if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
        return  ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcBitCount;
    else
        return pPackedDib->bmiHeader.biBitCount;
}

int PackedDibGetRowLength(BITMAPINFO* pPackedDib)
{
    return ((PackedDibGetWidth(pPackedDib)*PackedDibGetBitCount(pPackedDib) + 31) & ~31) >> 3;
}

/*-----------------------------------------------------------
获取DIB信息头大小(含可能的颜色遮罩)——单位:字节
-----------------------------------------------------------*/
int PackedDibGetInfoHeaderSize(BITMAPINFO* pPackedDib)
{
    if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
        return  ((BITMAPCOREINFO*)pPackedDib)->bmciHeader.bcSize;
    else if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
        return pPackedDib->bmiHeader.biSize +
        (pPackedDib->bmiHeader.biCompression ==
        BI_BITFIELDS ? 12 : 0); //颜色遮罩
    else return pPackedDib->bmiHeader.biSize;
}

/*-------------------------------------------------------------
PackedDibGetColorsUsed:返回信息头中的bClrUse字段,表示用到的颜色数
如果没有颜色表,则该值为0
-------------------------------------------------------------*/
int PackedDibGetColorsUsed(BITMAPINFO* pPackedDib)
{
    if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
        return  0;
    else
        return pPackedDib->bmiHeader.biClrUsed;
}

/*------------------------------------------------------------------
PackedDibGetNumColors:颜色表中实际的条目数
------------------------------------------------------------------*/
int PackedDibGetNumColors(BITMAPINFO* pPackedDib)
{
    int iNumColors;

    iNumColors = PackedDibGetColorsUsed(pPackedDib);

    //iNumColor等于0时,说明实际使用的颜色由biBitCount计算出来
    //16、24、32位时获得的iNumColors的一般为0
    if (iNumColors == 0 && (PackedDibGetBitCount(pPackedDib) < 16))
        iNumColors = 1 << (PackedDibGetBitCount(pPackedDib)); //2^biBitCount个

    return iNumColors;
}

int PackedDibGetColorTableSize(BITMAPINFO* pPackedDib)
{
    if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
        return  PackedDibGetNumColors(pPackedDib)*sizeof(RGBTRIPLE);
    else
        return PackedDibGetNumColors(pPackedDib)*sizeof(RGBQUAD);
}

RGBQUAD* PackedDibGetColorTablePtr(BITMAPINFO* pPackedDib)
{
    if (PackedDibGetNumColors(pPackedDib) == 0)
        return NULL;

    return (RGBQUAD*)(((BYTE*)pPackedDib) +
                      PackedDibGetInfoHeaderSize(pPackedDib));
}

RGBQUAD* PackedDibGetColorTableEntry(BITMAPINFO* pPackedDib, int i)
{
    if (PackedDibGetNumColors(pPackedDib) == 0)
        return NULL;

    if (pPackedDib->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
        return  (RGBQUAD*)((RGBTRIPLE*)PackedDibGetColorTablePtr(pPackedDib) + i);
    else
        return PackedDibGetColorTablePtr(pPackedDib) + i;
}

/*----------------------------------
PackedDibGetBitsPtr:获取像素数据的指针
----------------------------------*/
BYTE* PackedDibGetBitsPtr(BITMAPINFO* pPackedDib)
{
    return (BYTE*)(pPackedDib)+PackedDibGetInfoHeaderSize(pPackedDib) +
        PackedDibGetColorTableSize(pPackedDib);
}

/*-----------------------------------------------------------------------
PackedDibGetBitsSize:
自动计算像素数据的空间大小(即使biSizeImage字段没有显式的指定)
-----------------------------------------------------------------------*/
int PackedDibGetBitsSize(BITMAPINFO* pPackedDib)
{
    if ((pPackedDib->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
        (pPackedDib->bmiHeader.biSizeImage != 0))
        return pPackedDib->bmiHeader.biSizeImage;

    return PackedDibGetHeight(pPackedDib)* PackedDibGetRowLength(pPackedDib);
}

/*----------------------------------------------------------------
PackedDibCreatePalette:从紧缩型DIB中创建逻辑调色板
----------------------------------------------------------------*/

HPALETTE PackedDibCreatePalette(BITMAPINFO* pPackedDib)
{
    HPALETTE hPalette;
    int i, iNumColors;
    LOGPALETTE* plp;
    RGBQUAD*  prgb;

    iNumColors = PackedDibGetNumColors(pPackedDib);
    if (0 == iNumColors) //16、24、32位时获得的iNumColors的一般为0
        return NULL;

    plp = malloc(sizeof(LOGPALETTE)*(iNumColors - 1)*sizeof(PALETTEENTRY));
    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;
    }

    hPalette = CreatePalette(plp);
    free(plp);

    return hPalette;
}

//ShowDib3.c

/*------------------------------------------------------------
SHOWDIB3.C -- Displays DIB with native palette
(c) Charles Petzold, 1998
------------------------------------------------------------*/

#include <windows.h>
#include "resource.h"
#include "PackedDIB.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static TCHAR szAppName[] = TEXT("ShowDib3");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX   wndclass;
    HACCEL       hAccel;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(hInstance, szAppName);
    wndclass.hIconSm = LoadIcon(hInstance, szAppName);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = szAppName;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("Show DIB #3:Native Palette"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    hAccel = LoadAccelerators(hInstance, szAppName);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(hwnd, hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static BITMAPINFO* pPackedDib;
    static HPALETTE hPalette;

    HDC         hdc;
    PAINTSTRUCT ps;

    static OPENFILENAME ofn;
    static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)*.bmp")
        TEXT("All Files(*.*)*.*");
    static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    static int cxClient, cyClient;


    switch (message)
    {
    case WM_CREATE:
        memset(&ofn, 0, sizeof(OPENFILENAME));
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrFile = szFileName;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFileTitle = szTitleName;
        ofn.nMaxFileTitle = MAX_PATH;
        ofn.lpstrDefExt = TEXT("bmp");
        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_FILE_OPEN:

            //显示打开文件对话框
            if (!GetOpenFileName(&ofn))
                return 0;

            //如果图像己经存在,则释放内存
            if (pPackedDib)
            {
                free(pPackedDib);
                pPackedDib = NULL;
            }

            //如果逻辑调色板己经存在,则删除
            if (hPalette)
            {
                DeleteObject(hPalette);
                hPalette = NULL;
            }


            //加载紧缩型DIB到内存中
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);

            pPackedDib = PackedDibLoad(szFileName);

            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));

            if (pPackedDib)
            {
                //创建逻辑调色板
                hPalette = PackedDibCreatePalette(pPackedDib);
            } else
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file."), szAppName, 0);
            }

            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        }
        break;

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

        if (hPalette) //16、24、32位的DIB没有颜色表,在8位视频模式下,只显示20种保留色
        {
            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, TRUE);

        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;

    case WM_DESTROY:
        if (pPackedDib)
            free(pPackedDib);

        if (hPalette)
            DeleteObject(hPalette);

        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

//resource.c

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 ShowDIB3.rc 使用
//
#define  IDM_FILE_OPEN                 40001
// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40004
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//ShowDib3.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE
BEGIN
"resource.h"
END

2 TEXTINCLUDE
BEGIN
"#include ""winres.h""
"
""
END

3 TEXTINCLUDE
BEGIN
"
"
""
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Menu
//

SHOWDIB3 MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open...	Ctrl+O", IDM_FILE_OPEN
END
END


/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//

SHOWDIB3 ACCELERATORS
BEGIN
"^O", IDM_FILE_OPEN, ASCII, NOINVERT
END

#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED
16.3.2 通用调色板(247种自定义颜色,其中有些与系统保留色重复(这些会被匹配到相应的系统色上去))

(1)31种灰度色调

  0x00,0x09, 0x11,0x1A, 0x22, 0x2B, 0x33, 0x3C, 0x44, 0x4D, 0x55, 0x5E, 0x66, 0x6F,0x77, 0x80, 0x88, 0x91, 0x99, 0xA2, 0xAA,0xB3,0xBB, 0xC4, 0xCC, 0xD5, 0xDD, 0xE6, 0xEE, 0xF9, 0xFF(其中红色的为系统20种保留色之一)

(2)216种颜色,R、G、B分别由0x00、0x33、0x66、0x99、0xCC、0xFF的所有组合。(其中8种是系统20种保留色中的颜色,还有4种是前面灰度值的重复)。

 【ShowDib4程序】——效果图与ShowDib3相似,但细节上有差异,还有在8位视频模式下,该程序正常显示!
256色下效果

 

/*------------------------------------------------------------
SHOWDIB4.C -- Displays DIB with “all - purpose” palette
(c) Charles Petzold, 1998
------------------------------------------------------------*/

#include <windows.h>
#include "..\ShowDib3\resource.h"
#include "..\ShowDib3\PackedDIB.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static TCHAR szAppName[] = TEXT("ShowDib4");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX   wndclass;
    HACCEL       hAccel;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(hInstance, szAppName);
    wndclass.hIconSm = LoadIcon(hInstance, szAppName);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = szAppName;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("Show DIB #4:All-Purpose Palette"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    hAccel = LoadAccelerators(hInstance, szAppName);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(hwnd, hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}

/*------------------------------------------------------------------------
CreateAllPurposePalette:
创建一个通用的调色板,该调色板共有247个颜色条目,其中15种是从20种保留色中
复出或匹配的。
------------------------------------------------------------------------*/
HPALETTE CreateAllPurposePalette(void)
{
    HPALETTE hPalette;
    LOGPALETTE* plp;
    int i, incr, R, G, B;

    plp = malloc(sizeof(LOGPALETTE) + 246 * sizeof(PALETTEENTRY));
    plp->palVersion = 0x0300;
    plp->palNumEntries = 247;

    //创建31级的灰阶颜色,其中3种匹配系统的20种保留色
    for (i = 0, G = 0, incr = 8; G <= 0xFF; i++, G += incr)
    {
        plp->palPalEntry[i].peRed = (BYTE)G;
        plp->palPalEntry[i].peGreen = (BYTE)G;
        plp->palPalEntry[i].peBlue = (BYTE)G;
        plp->palPalEntry[i].peFlags = 0;
        incr = (incr == 9 ? 8 : 9);
    }

    //创建216种颜色,但其中有8种匹配系统的20种保留色,另外4种匹配以上产生的灰色
    for (R = 0; R < 0xFF; R += 0x33)
        for (G = 0; G < 0xFF; G += 0x33)
            for (B = 0; B < 0xFF; B += 0x33)
            {
                plp->palPalEntry[i].peRed = (BYTE)R;
                plp->palPalEntry[i].peGreen = (BYTE)G;
                plp->palPalEntry[i].peBlue = (BYTE)B;
                plp->palPalEntry[i].peFlags = 0;
                i++;
            }

    hPalette = CreatePalette(plp);
    free(plp);
    return hPalette;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static BITMAPINFO* pPackedDib;
    static HPALETTE hPalette;

    HDC         hdc;
    PAINTSTRUCT ps;

    static OPENFILENAME ofn;
    static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)*.bmp")
        TEXT("All Files(*.*)*.*");
    static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    static int cxClient, cyClient;


    switch (message)
    {
    case WM_CREATE:
        memset(&ofn, 0, sizeof(OPENFILENAME));
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrFile = szFileName;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFileTitle = szTitleName;
        ofn.nMaxFileTitle = MAX_PATH;
        ofn.lpstrDefExt = TEXT("bmp");

        // 创建通用调色板
        hPalette = CreateAllPurposePalette();
        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_FILE_OPEN:

            //显示打开文件对话框
            if (!GetOpenFileName(&ofn))
                return 0;

            //如果图像己经存在,则释放内存
            if (pPackedDib)
            {
                free(pPackedDib);
                pPackedDib = NULL;
            }

            //如果逻辑调色板己经存在,则删除
            if (hPalette)
            {
                DeleteObject(hPalette);
                hPalette = NULL;
            }


            //加载紧缩型DIB到内存中
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);

            pPackedDib = PackedDibLoad(szFileName);

            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));

            if (!pPackedDib)
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file."), szAppName, 0);
            }

            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        }
        break;

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

        if (pPackedDib)
        {
            SelectPalette(hdc, hPalette, FALSE);
            RealizePalette(hdc);
            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, TRUE);

        ReleaseDC(hwnd, hdc);
        return TRUE;

    case WM_PALETTECHANGED:
        if ((HWND)wParam == hwnd)
            break;

        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        UpdateColors(hdc);

        ReleaseDC(hwnd, hdc);
        break;

    case WM_DESTROY:
        if (pPackedDib)
            free(pPackedDib);

        DeleteObject(hPalette);

        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

16.3.3 半色调调色板——使用抖动模式,来更好地在8位视频上模拟原始图像的颜色。

(1)系统提供API来创建半色调的调色板

hPalette= CreateHalftonePalette(hdc);

(2)当使用SetDIBitsToDevice来显示DIB时,效果与ShowDib4程序差不多

(3)使用StretchDIBits效果会很明显,但须先设置

        SetStretchBltMode(hdc,HALFTONE);

        SetBrushOrgEx(hdc,x,y,NULL);//x、y是DIB左上角的设备坐标。
【ShowDib5程序】
256色下的效果(要比通用调色板效果好得多)

/*------------------------------------------------------------
   SHOWDIB5.C -- Displays DIB with halftone palette
                 (c) Charles Petzold, 1998
------------------------------------------------------------*/

#include <windows.h>
#include "..\ShowDib3\resource.h"
#include "..\ShowDib3\PackedDIB.h"

  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static TCHAR szAppName[] = TEXT("ShowDib5");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX   wndclass;
    HACCEL       hAccel;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(hInstance, szAppName);
    wndclass.hIconSm = LoadIcon(hInstance, szAppName);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = szAppName;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("Show DIB #5:Halftone Palette"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    hAccel = LoadAccelerators(hInstance, szAppName);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(hwnd, hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static BITMAPINFO* pPackedDib;
    static HPALETTE hPalette;

    HDC         hdc;
    PAINTSTRUCT ps;

    static OPENFILENAME ofn;
    static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)*.bmp")
        TEXT("All Files(*.*)*.*");
    static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    static int cxClient, cyClient;


    switch (message)
    {
    case WM_CREATE:
        memset(&ofn, 0, sizeof(OPENFILENAME));
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrFile = szFileName;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFileTitle = szTitleName;
        ofn.nMaxFileTitle = MAX_PATH;
        ofn.lpstrDefExt = TEXT("bmp");

        // 创建通用调色板
        hdc = GetDC(hwnd);
        hPalette = CreateHalftonePalette(hdc);  //半色调调色板
        ReleaseDC(hwnd, hdc);
        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_FILE_OPEN:

            //显示打开文件对话框
            if (!GetOpenFileName(&ofn))
                return 0;

            //如果图像己经存在,则释放内存
            if (pPackedDib)
            {
                free(pPackedDib);
                pPackedDib = NULL;
            }

            //如果逻辑调色板己经存在,则删除
            if (hPalette)
            {
                DeleteObject(hPalette);
                hPalette = NULL;
            }


            //加载紧缩型DIB到内存中
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);

            pPackedDib = PackedDibLoad(szFileName);

            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));

            if (!pPackedDib)
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file."), szAppName, 0);
            }

            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        }
        break;

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

        if (pPackedDib)
        {
            //设置半色板模式
            SetStretchBltMode(hdc, HALFTONE);
            SetBrushOrgEx(hdc, 0, 0, NULL);

            //选择并实现调色板
            SelectPalette(hdc, hPalette, FALSE);
            RealizePalette(hdc);

            //用StretchDIBits而不是SetDIBitsToDevice函数
            StretchDIBits(hdc,
                          0, 0,
                          PackedDibGetWidth(pPackedDib),
                          PackedDibGetHeight(pPackedDib),
                          0, 0,
                          PackedDibGetWidth(pPackedDib),
                          PackedDibGetHeight(pPackedDib),
                          PackedDibGetBitsPtr(pPackedDib),
                          pPackedDib,
                          DIB_RGB_COLORS,
                          SRCCOPY);
        }
        EndPaint(hwnd, &ps);
        return 0;

    case WM_QUERYNEWPALETTE:
        if (!hPalette)
            return FALSE;

        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        InvalidateRect(hwnd, NULL, TRUE);

        ReleaseDC(hwnd, hdc);
        return TRUE;

    case WM_PALETTECHANGED:
        if ((HWND)wParam == hwnd)
            break;

        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        UpdateColors(hdc);

        ReleaseDC(hwnd, hdc);
        break;

    case WM_DESTROY:
        if (pPackedDib)
            free(pPackedDib);

        DeleteObject(hPalette);

        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

 16.3.4 索引调色板颜色

(1)在绘图函数中(如:SetDIBitsToDevice、StretchDIBits)中将fClrUse参数设为DIB_RGB_COLORS时,说明BITMAPINFO结构中的颜色表要按RGB值处理,如果指定为DIB_PAL_COLORS时,说明要视为一个索引值(16位,这点很重要),而不是RGB值。要利用这个索引值去匹配逻辑调色板的颜色,此逻辑调色板是当前被选入设备环境的那个调色板。

(2)为了利用索引匹配调色板,一般可以先将从DIB的颜色表中创建一个逻辑调色板,选入设备环境,再实现调色板。然后将DIB颜色表中的各项值改变逻辑调色板相应的索引号,以加快匹配速度。

(3)颜色表如果存储的是逻辑调色板的索引,则该每个颜色表项是WORD类型(16位的)。

【ShowDIB6程序】
效果图

/*------------------------------------------------------------
SHOWDIB6.C -- Displays DIB with palette indices
(c) Charles Petzold, 1998
------------------------------------------------------------*/

#include <windows.h>
#include "..\ShowDib3\resource.h"
#include "..\ShowDib3\PackedDIB.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static TCHAR szAppName[] = TEXT("ShowDib6");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX   wndclass;
    HACCEL       hAccel;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(hInstance, szAppName);
    wndclass.hIconSm = LoadIcon(hInstance, szAppName);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = szAppName;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("Show DIB #6:Palette Indices"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    hAccel = LoadAccelerators(hInstance, szAppName);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(hwnd, hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static BITMAPINFO* pPackedDib;
    static HPALETTE hPalette;

    HDC         hdc;
    PAINTSTRUCT ps;

    static OPENFILENAME ofn;
    static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)*.bmp")
        TEXT("All Files(*.*)*.*");
    static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    static int cxClient, cyClient;
    int i, iNumColors;
    WORD* pwIndex;

    switch (message)
    {
    case WM_CREATE:
        memset(&ofn, 0, sizeof(OPENFILENAME));
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrFile = szFileName;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFileTitle = szTitleName;
        ofn.nMaxFileTitle = MAX_PATH;
        ofn.lpstrDefExt = TEXT("bmp");

        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_FILE_OPEN:

            //显示打开文件对话框
            if (!GetOpenFileName(&ofn))
                return 0;

            //如果图像己经存在,则释放内存
            if (pPackedDib)
            {
                free(pPackedDib);
                pPackedDib = NULL;
            }

            //如果逻辑调色板己经存在,则删除
            if (hPalette)
            {
                DeleteObject(hPalette);
                hPalette = NULL;
            }


            //加载紧缩型DIB到内存中
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);

            pPackedDib = PackedDibLoad(szFileName);

            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));

            if (pPackedDib)
            {
                //从DIB颜色表中创建逻辑调色板
                hPalette = PackedDibCreatePalette(pPackedDib);

                //将DIB颜色表由RGB值改变相应的逻辑调色板相应项的索引,以减少
                //匹配时间——但千万注意,当DIB颜色表项表示索引时,类型是
                //代表16位的WORD型的
                if (hPalette)
                {
                    iNumColors = PackedDibGetNumColors(pPackedDib);
                    //注意这里,颜色表项存储索引号时,用的是WORD型,而不是RGBQUAD或RGBTRIPLE型
                    pwIndex = (WORD*)PackedDibGetColorTablePtr(pPackedDib);

                    for (i = 0; i < iNumColors; i++)
                    {
                        pwIndex[i] = (WORD)i;//将逻辑调色板的索引号存入颜色表项中
                    }

                }
            } else
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file."), szAppName, 0);
            }

            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        }
        break;

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

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

            //用StretchDIBits而不是SetDIBitsToDevice函数
            SetDIBitsToDevice(hdc,
                              0, 0,
                              PackedDibGetWidth(pPackedDib),
                              PackedDibGetHeight(pPackedDib),
                              0, 0,
                              0,
                              PackedDibGetHeight(pPackedDib),
                              PackedDibGetBitsPtr(pPackedDib),
                              pPackedDib,
                              DIB_PAL_COLORS); //指定颜色表项为数据为索引而不是RGB值
        }
        EndPaint(hwnd, &ps);
        return 0;

    case WM_QUERYNEWPALETTE:
        if (!hPalette)
            return FALSE;

        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        InvalidateRect(hwnd, NULL, TRUE);

        ReleaseDC(hwnd, hdc);
        return TRUE;

    case WM_PALETTECHANGED:
        if ((HWND)wParam == hwnd)
            break;

        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        UpdateColors(hdc);

        ReleaseDC(hwnd, hdc);
        break;

    case WM_DESTROY:
        if (pPackedDib)
            free(pPackedDib);

        DeleteObject(hPalette);

        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}
 16.3.5 调色板和位图对象

(1)由CreateDIBitmap函数从DIB创建一个DDB时,要先把逻辑调色板选入设备环境并实现了,这样创建出来的DDB才会使用逻辑调色板中加入的颜色。

(2)显示时,需要用相同的调色板才能正常显示出来。

(3)剪切板中最好使用紧凑DIB格式;如果要将DDB复制到剪贴板,则首先需要得到一个视频设备DC,并选择和实现一个调色板,这样才能基于当前系统调色板将DDB转为DIB

【ShowDIB7程序】效果与ShowDIB6差不多

/*------------------------------------------------------------
SHOWDIB7.C -- Shows DIB converted to DDB
(c) Charles Petzold, 1998
------------------------------------------------------------*/

#include <windows.h>
#include "..\ShowDib3\resource.h"
#include "..\ShowDib3\PackedDIB.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static TCHAR szAppName[] = TEXT("ShowDib7");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX   wndclass;
    HACCEL       hAccel;

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(hInstance, szAppName);
    wndclass.hIconSm = LoadIcon(hInstance, szAppName);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = szAppName;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("Show DIB #7:Converted to DDB"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    hAccel = LoadAccelerators(hInstance, szAppName);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(hwnd, hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    BITMAPINFO* pPackedDib = NULL;
    static HPALETTE hPalette;
    static HBITMAP  hBitmap;
    HDC         hdc, hdcMem;
    PAINTSTRUCT ps;
    BITMAP bitmap;

    static OPENFILENAME ofn;
    static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)*.bmp")
        TEXT("All Files(*.*)*.*");
    static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    static int cxClient, cyClient;

    switch (message)
    {
    case WM_CREATE:
        memset(&ofn, 0, sizeof(OPENFILENAME));
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrFile = szFileName;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFileTitle = szTitleName;
        ofn.nMaxFileTitle = MAX_PATH;
        ofn.lpstrDefExt = TEXT("bmp");

        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        return 0;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_FILE_OPEN:

            //显示打开文件对话框
            if (!GetOpenFileName(&ofn))
                return 0;

            //如果图像己经存在,则释放内存
            if (pPackedDib)
            {
                free(pPackedDib);
                pPackedDib = NULL;
            }

            //如果逻辑调色板己经存在,则删除
            if (hPalette)
            {
                DeleteObject(hPalette);
                hPalette = NULL;
            }


            //加载紧缩型DIB到内存中
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);

            pPackedDib = PackedDibLoad(szFileName);

            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));

            if (pPackedDib)
            {
                //从DIB颜色表中创建逻辑调色板
                hPalette = PackedDibCreatePalette(pPackedDib);

                hdc = GetDC(hwnd);

                //这里要选入DC,并实现这个调色板,因为从DIB创建DDB时,要基于这个调色板颜色的。
                if (hPalette)
                {
                    SelectPalette(hdc, hPalette, FALSE);
                    RealizePalette(hdc);
                }

                hBitmap = CreateDIBitmap(hdc,
                                         (BITMAPINFOHEADER*)pPackedDib,
                                         CBM_INIT,
                                         PackedDibGetBitsPtr(pPackedDib),
                                         pPackedDib,
                                         DIB_RGB_COLORS);
                ReleaseDC(hwnd, hdc);

                //释放packed-DIB内存
                free(pPackedDib);

            } else
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file."), szAppName, 0);
            }

            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        }
        break;

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

        //显示DDB时,要基于同一调色板,所以重新选入并实现调色板
        if (hPalette)
        {
            SelectPalette(hdc, hPalette, FALSE);
            RealizePalette(hdc);
        }
        if (hBitmap)
        {
            GetObject(hBitmap, sizeof(BITMAP), &bitmap);

            hdcMem = CreateCompatibleDC(hdc);
            SelectObject(hdcMem, hBitmap);

            BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);

            DeleteDC(hdcMem);
        }
        EndPaint(hwnd, &ps);
        return 0;

    case WM_QUERYNEWPALETTE:
        if (!hPalette)
            return FALSE;

        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        InvalidateRect(hwnd, NULL, TRUE);

        ReleaseDC(hwnd, hdc);
        return TRUE;

    case WM_PALETTECHANGED:
        if ((HWND)wParam == hwnd)
            break;

        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        UpdateColors(hdc);

        ReleaseDC(hwnd, hdc);
        break;

    case WM_DESTROY:
        if (hBitmap)
            DeleteObject(hBitmap);

        DeleteObject(hPalette);

        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

16.3.6 调色板和DIB区块

(1)ShowDIB8与ShowDIB7最大的区别:

①ShowDIB7必须在调用CreateDIBitmap之前,把调色板选入DC并实现调色板

②ShowDIB8通过CreateDIBSection不会将DIB转为设备相关格式,所以不必把调色板选入环境。CreateDIBSection第一个参数为设备句柄,唯一的目的就是使用DIB_PAL_COLORS标志。一般情况下,第1个参数都要设为NULL,表示创建出来的位图是设备无关的(其实是个杂种,即有DDB的好处,又有DIB的特点)。

(2)ShowDIB8与ShowDIB7的WM_PAINT消息的处理完全相同。

(3)CreateDIBSection后,像素位内存位置由该函数第4个参数返回。

【ShowDIB8程序】效果与ShowDIB7一样

/*------------------------------------------------------------
SHOWDIB8.C -- Shows DIB converted to DIB section
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#include <windows.h>
#include "..\ShowDib3\resource.h"
#include "..\ShowDib3\PackedDIB.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static TCHAR szAppName[] = TEXT("ShowDib8");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{
    HWND         hwnd;
    MSG          msg;
    WNDCLASSEX   wndclass;
    HACCEL       hAccel;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(hInstance, szAppName);
    wndclass.hIconSm = LoadIcon(hInstance, szAppName);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = szAppName;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,                  // window class name
                        TEXT("Show DIB #8:DIB Section"), // window caption
                        WS_OVERLAPPEDWINDOW,        // window style
                        CW_USEDEFAULT,              // initial x position
                        CW_USEDEFAULT,              // initial y position
                        CW_USEDEFAULT,              // initial x size
                        CW_USEDEFAULT,              // initial y size
                        NULL,                       // parent window handle
                        NULL,                       // window menu handle
                        hInstance,                  // program instance handle
                        NULL);                     // creation parameters

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    hAccel = LoadAccelerators(hInstance, szAppName);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(hwnd, hAccel, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    BITMAPINFO* pPackedDib = NULL;
    static HPALETTE hPalette;
    static HBITMAP  hBitmap;
    HDC         hdc, hdcMem;
    PAINTSTRUCT ps;
    BITMAP bitmap;
    static BYTE*  pBits;
    static OPENFILENAME ofn;
    static TCHAR szFilter[] = TEXT("Bitmap Files(*.BMP)*.bmp")
        TEXT("All Files(*.*)*.*");
    static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    static int cxClient, cyClient;
    switch (message)
    {
    case WM_CREATE:
        memset(&ofn, 0, sizeof(OPENFILENAME));
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrFile = szFileName;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFileTitle = szTitleName;
        ofn.nMaxFileTitle = MAX_PATH;
        ofn.lpstrDefExt = TEXT("bmp");
        return 0;
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        return 0;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_FILE_OPEN:
            //显示打开文件对话框
            if (!GetOpenFileName(&ofn))
                return 0;

            //如果图像己经存在,则释放内存
            if (pPackedDib)
            {
                free(pPackedDib);
                pPackedDib = NULL;
            }
            //如果逻辑调色板己经存在,则删除
            if (hPalette)
            {
                DeleteObject(hPalette);
                hPalette = NULL;
            }
            //加载紧缩型DIB到内存中
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);
            pPackedDib = PackedDibLoad(szFileName);

            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            if (pPackedDib)
            {
                //从DIB创建DIB Section
                hBitmap = CreateDIBSection(NULL,
                                           pPackedDib,
                                           DIB_RGB_COLORS,
                                           &pBits,
                                           NULL,
                                           0);
                //pBits正在的开辟空间
                CopyMemory(pBits, PackedDibGetBitsPtr(pPackedDib),
                           PackedDibGetBitsSize(pPackedDib));
                //从DIB颜色表中创建逻辑调色板
                hPalette = PackedDibCreatePalette(pPackedDib);
                //释放packed-DIB内存
                free(pPackedDib);
            } else
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file."), szAppName, 0);
            }
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);

        //显示DDB时,要基于同一调色板,所以重新选入并实现调色板
        if (hPalette)
        {
            SelectPalette(hdc, hPalette, FALSE);
            RealizePalette(hdc);
        }
        if (hBitmap)
        {
            GetObject(hBitmap, sizeof(BITMAP), &bitmap);
            hdcMem = CreateCompatibleDC(hdc);
            SelectObject(hdcMem, hBitmap);

            BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
            DeleteDC(hdcMem);
        }
        EndPaint(hwnd, &ps);
        return 0;

    case WM_QUERYNEWPALETTE:
        if (!hPalette)
            return FALSE;
        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        InvalidateRect(hwnd, NULL, TRUE);
        ReleaseDC(hwnd, hdc);
        return TRUE;
    case WM_PALETTECHANGED:
        if ((HWND)wParam == hwnd)
            break;
        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        UpdateColors(hdc);
        ReleaseDC(hwnd, hdc);
        break;
    case WM_DESTROY:
        if (hBitmap)
            DeleteObject(hBitmap);
        DeleteObject(hPalette);
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}
原文地址:https://www.cnblogs.com/5iedu/p/4701023.html