第16章 调色板管理器_16.4 一个DIB位图库的实现(1)

16.4.1自定义的 DIBSTRUCT结构体


字段


含义


PBYTE *ppRow


指向位图视觉上最上面的一行像素。(不管是自下而上,还是自上而下)

②放在第一个字段,为的是后面定义宏时可方便访问到


int iSignature


=“Dib ”,是这个结构体的标志


HBITMAP hBitmap


存储了由CreateDIBSection返回的位图句柄(注意,实质是DIB,但兼有DDB的特点,可直接BitBlt)


BYTE *pBits


指向像素阵列的指针,其指针值在CreateDIBSection中设定,而所指向的内存由操作系统管理,删除位图句柄后会自动释放。


DIBSECTION


在DibCreateFromInfo中调用GetObject来填充该结构体,以方便使用(注意DibCreateFromInfo函数被本例所有创建DIB的函数所调用)


int iRShift[3]


是个数组,3个元素分别为R、G、B颜色遮罩需右移的位数


int iLShift[3]


是个数组,3个元素分别为R、G、B颜色遮罩需左移的位数

16.4.2 信息获取函数

(1)DibIsValid函数——用来确保DIBSTRUCT结构的有效性

(2)DibIsAddressable(也可定义为DibIsNotCompression):判断位图是否被压缩

(3)DibInfoHeaderSize等一组函数用于获取DIB区块各部分大小,这些函数可用来将一个DIB Section转换为紧凑DIB。

(4)获得各类指针的函数:如DibInfoHeaderPtr(获取BITMAPINFOHEADER指针)

16.4.3 读写像素信息

(1)DibPixelPtr:用来获取像素的内存指针。注意DIBSTRUCT结构的ppRow是一个指向从上向下排列的DIB像素行的指针,即ppRow[0]是位图视觉上的最上面的一行。如果位图被压缩时返回NULL。

(2)DibGetColor和DibSetColor:像素点在颜色表的值。对于1、4、8位,其RGB值就是要通过颜色表来查找。(对于16、24、32位的,不能通过这两个函数获取,其RGB值要通过掩码和位移获得)

16.4.4 创建和转换

(1)DibCreateFromInfo函数:是DIBHELP库中唯一一个调用CreateDIBSection并为DIBSTRUCT分配内存的函数。其他所有创建或复制都要通过调用该函数来完成

  ①参数:BITMAPINFO结构的指针

  ②该函数调用CreateDIBSeciton后会初始化DIBSTRUCT的所有字段,第一个字段ppRow总是指向DIB的最上面的一行。

(2)DibDelete用来删除由DibCreateFromInfo创建的位图,并释放内存。

(3)DibCopyToPackedDib和DibCopyFromPackedDib常用于应用程序与剪贴板交换DIB

(4)DibCopyToDdb:从一个DIB创建一个GDI位图对象。

16.4.5 宏——快速读写像素位的宏(在DIBHELP.H头文件中)

16.4.6 Dibble程序

(1)三个重要的静态变量hdib、hPalette、hBitmap

(2)WM_USER_SETSCROLL和WM_USER_CREATEPAL消息:用来重置滚动条和创建调色板

(3)DisplayDib:显示位图,提供正常、居中、满拉到客户区、各向同性等4种方式。

①WM_PAINT消息中:位图句柄来自于DibCopyToDdb函数。(因可能要用调色板来显示)

②打印时:从DitbitmapHandle得到DIB Section位图的句柄。

(4)剪贴板:调用DibCopyToPackedDib和DibCopyFromPackedDib函数

(5)Flip函数——上下翻转;Rotate——顺时针转90度。

  ①DibFlipHorizontal函数:演示通过DibGetPixel和DibSetPixel,效率较低

  ②DibRotateRight函数:通过DIBHELP.H中定义的宏来读写像素,效率高。

16.4.7 简单的调色板和优化的调色板——在256色的视频模式下,可选择不同调色板

(1)创建调色板的函数

  ①半色调调色板——系统API提供的。会使用万能调色板与抖动技术来实现该调色板。

  ②DibPalDibTable:根据DIB颜色表来创建调色板

  ③DibPalAllPurpose:创建通用的调色板,其颜色见DibPal.C文件

  ④DibPalUniformGrays:创建一个只有灰度色阶的调色板

(2)优化调色板

  ①均匀分布算法:DibPalUniformColors——创建iNumR×iNumG×iNumB调色板,一般8级红色、8级绿色和4级蓝色,因为人眼为蓝色比较不敏感。

  ②流行度算法——DibPalPopularity函数

  A、使用位图中被使用最多的256种RGB色值来构成调色板。但24位RGB,可表示2^24种颜色,如果每种颜色用1个int型保存使用次数的话,共需要64M左右,内存消耗大。

  B、解决办法是只用RGB权重最高的几位,如用6位而非8位表示R值(因为显示器的解析度也是6位)。这样只需1M,而5位时只需32768字节。

③中分算法——DibPalMedianCut(PaulHeckbert发明)

  A、中分算法中RGB值被映射到一个三维坐标中,三个坐标轴分别表示R、G、B

  B、每个像素点的RGB值都能在这个坐标系中找到相应的点

  C、找到一个能包含所有图像像素的长方体,取最长的一条边,将长方体分成两部分,使划分后的每个部分含有相同的像素数量。

  D、然后对这两个盒子做同样的划分,这样2个分为4个、4个分为8个,8个分为16个,然后是32个,64个、128个、256个。

  E、现在得到256个盒子,每个都包含了相等的像素数。对每个盒子的颜色取其平均值,并利用这个结构来改变调色板。

16.4.8 格式转换——参考DIbConv.c文件

(1)GetNearestPaletteIndex返回获得调色板中最接近的颜色的索引值

  UINT GetNearestPaletteIndex

  (

  HPALETTE hpal,     // 逻辑调色板

  COLORREF crColor   // 要匹配的颜色

  )

(2)DibPalVga:获取标准16色显示器颜色值

(3)HDIBDibConvert(HDIB hdibSrc, int iBitCountDst);用来进行格式转换的函数
【Dibble程序】
效果图

//Dibble.c主程序

/*------------------------------------------------------------
DIBBLE.C -- Bitmap and Palette Program
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#include <windows.h>
#include "resource.h"
#include "DibHelp.h"
#include "DibConv.h"
#include "DibPal.h"
#define WM_USER_SETSCROLLS   (WM_USER + 1)
#define WM_USER_DELETEDIB    (WM_USER + 2)
#define WM_USER_DELETEPAL    (WM_USER + 3)
#define WM_USER_CREATEPAL    (WM_USER + 4)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static TCHAR szAppName[] = TEXT("Dibble");
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
                        szAppName, // window caption
                        WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,        // 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;
}
/*-------------------------------------------------------------------------------
DisplayDib:根据菜单项的选择来显示(打印)DIB的实际大小图像或缩放的图像
--------------------------------------------------------------------------------*/
int DisplayDib(HDC hdc, HBITMAP hBitmap, int x, int y,
               int cxClient, int cyClient,
               WORD wShow, BOOL fHalftonePalette)
{
    BITMAP bitmap;
    HDC  hdcMem;
    int cxBitmap, cyBitmap, iReturn;
    GetObject(hBitmap, sizeof(BITMAP), &bitmap);
    cxBitmap = bitmap.bmWidth;
    cyBitmap = bitmap.bmHeight;
    SaveDC(hdc);
    if (fHalftonePalette)
        SetStretchBltMode(hdc, HALFTONE);
    else
        SetStretchBltMode(hdc, COLORONCOLOR);
    hdcMem = CreateCompatibleDC(hdc);
    SelectObject(hdcMem, hBitmap);
    switch (wShow)
    {
    case IDM_SHOW_NORMAL:
        if (fHalftonePalette)
        {
            iReturn = StretchBlt(hdc, 0, 0,
                                 min(cxClient, cxBitmap - x),
                                 min(cyClient, cyBitmap - y),
                                 hdcMem, x, y,
                                 min(cxClient, cxBitmap - x),
                                 min(cyClient, cyBitmap - y),
                                 SRCCOPY);
        } else
        {
            iReturn = BitBlt(hdc, 0, 0,
                             min(cxClient, cxBitmap - x),
                             min(cyClient, cyBitmap - y),
                             hdcMem, x, y, SRCCOPY);
        }
        break;
    case IDM_SHOW_CENTER:
        if (fHalftonePalette)
        {
            iReturn = StretchBlt(hdc, (cxClient - cxBitmap) / 2, (cyClient - cyBitmap) / 2,
                                 cxBitmap, cyBitmap,
                                 hdcMem, 0, 0,
                                 cxBitmap, cyBitmap,
                                 SRCCOPY);
        } else
        {
            iReturn = BitBlt(hdc, (cxClient - cxBitmap) / 2, (cyClient - cyBitmap) / 2,
                             cxBitmap, cyBitmap,
                             hdcMem, 0, 0, SRCCOPY);
        }
        break;
    case IDM_SHOW_STRETCH:
        iReturn = StretchBlt(hdc, 0, 0,
                             cxClient, cyClient,
                             hdcMem, 0, 0,
                             cxBitmap, cyBitmap,
                             SRCCOPY);
        break;
    case IDM_SHOW_ISOSTRETCH:
        SetMapMode(hdc, MM_ISOTROPIC);
        SetWindowExtEx(hdc, cxBitmap, cyBitmap, NULL);
        SetViewportExtEx(hdc, cxClient, cyClient, NULL);
        SetWindowOrgEx(hdc, cxBitmap / 2, cyBitmap / 2, NULL);
        SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);
        //iReturn = StretchBlt(hdc, 0, 0,
        //                   cxBitmap, cyBitmap,
        //                   hdcMem, 0, 0,
        //                   cxBitmap, cyBitmap,
        //                   SRCCOPY);
        iReturn = BitBlt(hdc, 0, 0,
                         cxBitmap, cyBitmap,
                         hdcMem, 0, 0,
                         SRCCOPY);
        break;
    }
    DeleteDC(hdcMem);
    RestoreDC(hdc, -1);
    return iReturn;
}
/*-------------------------------------------------------------------------------
PaletteMenu:设置“Palette”各菜单项的Check属性
--------------------------------------------------------------------------------*/
void PaletteMenu(HMENU hMenu, WORD wItemNew)
{
    static WORD wItem = IDM_PAL_NONE;
    CheckMenuItem(hMenu, wItem, MF_UNCHECKED);
    wItem = wItemNew;
    CheckMenuItem(hMenu, wItem, MF_CHECKED);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static OPENFILENAME ofn;
    static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
    static TCHAR szFilter[] = TEXT("Bitmap Files (*.BMP)\0*.bmp\0")
        TEXT("All Files (*.*)\0*.*\0\0");
    static TCHAR*  szCompression[] = {
        TEXT("BI_RGB"), TEXT("BI_RLE8"),
        TEXT("BI_RLE4"), TEXT("BI_BITFIELDS"),
        TEXT("Unknown") };
    static HDIB hdib;
    static HPALETTE hPalette;
    static HBITMAP hBitmap;
    static BOOL fHalftonePalette;
    static HMENU hMenu;
    BOOL   fSuccess;
    static int cxClient, cyClient, iHscroll, iVscroll;
    static WORD wShow = IDM_SHOW_NORMAL;

    static PRINTDLG   printdlg = { sizeof(PRINTDLG) };
    static DOCINFO di = { sizeof(DOCINFO), TEXT("Dibble:Printing") };
    int cxPage, cyPage;
    HDC         hdc, hdcPrn;
    HGLOBAL  hGlobal;
    BYTE*    pGlobal;
    HDIB  hdibNew;
    PAINTSTRUCT ps;
    SCROLLINFO  si;
    int iEnable, iConvert = 0;
    TCHAR szBuffer[256];
    switch (message)
    {
    case WM_CREATE:
        //将菜单句柄保存在静态变量hMenu中
        hMenu = GetMenu(hwnd);
        //初始化打开文件对话框
        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.Flags = OFN_OVERWRITEPROMPT;
        ofn.lpstrDefExt = TEXT("bmp");
        return 0;
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);

        wParam = FALSE;   //贯穿功能,继续执行下面的代码

        //用户自定义消息,设置滚动条,如果显示模式是正常模式,则隐藏滚动条。如果
        //wParam==TRUE,则复位滚动条的位置
    case WM_USER_SETSCROLLS:
        if (hdib == NULL || wShow != IDM_SHOW_NORMAL)
        {
            si.cbSize = sizeof(SCROLLINFO);
            si.fMask = SIF_RANGE;
            si.nMin = 0;
            si.nMax = 0;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);  //隐藏
            SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
        } else
        {
            //垂直滚动条
            si.cbSize = sizeof(SCROLLINFO);
            si.fMask = SIF_ALL;
            GetScrollInfo(hwnd, SB_VERT, &si);
            si.nMin = 0;
            si.nMax = DibHeight(hdib);
            si.nPage = cyClient;
            if ((BOOL)wParam)  //恢复到0的默认位置
                si.nPos = 0;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
            GetScrollInfo(hwnd, SB_VERT, &si);
            iVscroll = si.nPos;
            //水平滚动条
            GetScrollInfo(hwnd, SB_HORZ, &si);
            si.nMin = 0;
            si.nMax = DibWidth(hdib);
            si.nPage = cxClient;
            if ((BOOL)wParam)  //恢复到0的默认位置
                si.nPos = 0;
            SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
            GetScrollInfo(hwnd, SB_HORZ, &si);
            iHscroll = si.nPos;
        }
        return 0;
    case WM_VSCROLL:
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_ALL;
        GetScrollInfo(hwnd, SB_VERT, &si);
        iVscroll = si.nPos;
        switch (LOWORD(wParam))
        {
        case SB_LINEUP:     si.nPos -= 1;             break;
        case SB_LINEDOWN:   si.nPos += 1;             break;
        case SB_PAGEUP:     si.nPage -= si.nPage;      break;
        case SB_PAGEDOWN:   si.nPage += si.nPage;      break;
        case SB_THUMBTRACK: si.nPos = si.nTrackPos;    break;
        default:                                       break;
        }
        si.fMask = SIF_POS;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
        GetScrollInfo(hwnd, SB_VERT, &si);
        if (si.nPos != iVscroll)
        {
            ScrollWindow(hwnd, 0, iVscroll - si.nPos, NULL, NULL);
            iVscroll = si.nPos;
            UpdateWindow(hwnd);  //立即更新窗口,这行可以注释掉
        }
        return 0;
    case WM_HSCROLL:
        si.cbSize = sizeof(SCROLLINFO);
        si.fMask = SIF_ALL;
        GetScrollInfo(hwnd, SB_HORZ, &si);
        iHscroll = si.nPos;
        switch (LOWORD(wParam))
        {
        case SB_LINELEFT:     si.nPos -= 1;                break;
        case SB_LINERIGHT:    si.nPos += 1;                break;
        case SB_PAGELEFT:     si.nPage -= si.nPage;        break;
        case SB_PAGERIGHT:    si.nPage += si.nPage;        break;
        case SB_THUMBTRACK:   si.nPos = si.nTrackPos;      break;
        default:                                           break;
        }
        si.fMask = SIF_POS;
        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
        GetScrollInfo(hwnd, SB_HORZ, &si);
        if (si.nPos != iHscroll)
        {
            ScrollWindow(hwnd, iHscroll - si.nPos, 0, NULL, NULL);
            iHscroll = si.nPos;
            UpdateWindow(hwnd);  //立即更新窗口,这行可以注释掉
        }
        return 0;
    case WM_INITMENUPOPUP:
        if (hdib)
            iEnable = MF_ENABLED;
        else
            iEnable = MF_GRAYED;
        EnableMenuItem(hMenu, IDM_FILE_SAVE, iEnable);
        EnableMenuItem(hMenu, IDM_FILE_PRINT, iEnable);
        EnableMenuItem(hMenu, IDM_FILE_PROPERTIES, iEnable);
        EnableMenuItem(hMenu, IDM_EDIT_CUT, iEnable);
        EnableMenuItem(hMenu, IDM_EDIT_COPY, iEnable);
        EnableMenuItem(hMenu, IDM_EDIT_DELETE, iEnable);
        if (DibIsAddressable(hdib))
            iEnable = MF_ENABLED;
        else
            iEnable = MF_GRAYED;
        EnableMenuItem(hMenu, IDM_EDIT_ROTATE, iEnable);
        EnableMenuItem(hMenu, IDM_EDIT_FLIP, iEnable);
        EnableMenuItem(hMenu, IDM_CONVERT_01, iEnable);
        EnableMenuItem(hMenu, IDM_CONVERT_04, iEnable);
        EnableMenuItem(hMenu, IDM_CONVERT_08, iEnable);
        EnableMenuItem(hMenu, IDM_CONVERT_16, iEnable);
        EnableMenuItem(hMenu, IDM_CONVERT_24, iEnable);
        EnableMenuItem(hMenu, IDM_CONVERT_32, iEnable);
        switch (DibBitCount(hdib))
        {
        case 1:    EnableMenuItem(hMenu, IDM_CONVERT_01, MF_GRAYED); break;
        case 4:    EnableMenuItem(hMenu, IDM_CONVERT_04, MF_GRAYED); break;
        case 8:    EnableMenuItem(hMenu, IDM_CONVERT_08, MF_GRAYED); break;
        case 16:   EnableMenuItem(hMenu, IDM_CONVERT_16, MF_GRAYED); break;
        case 24:   EnableMenuItem(hMenu, IDM_CONVERT_24, MF_GRAYED); break;
        case 32:   EnableMenuItem(hMenu, IDM_CONVERT_32, MF_GRAYED); break;
        }
        if (hdib && DibColorSize(hdib) > 0)
            iEnable = MF_ENABLED;
        else
            iEnable = MF_GRAYED;
        EnableMenuItem(hMenu, IDM_PAL_DIBTABLE, iEnable);
        if (DibIsAddressable(hdib) && DibBitCount(hdib)>8)
            iEnable = MF_ENABLED;
        else
            iEnable = MF_GRAYED;
        EnableMenuItem(hMenu, IDM_PAL_OPT_POP4, iEnable);
        EnableMenuItem(hMenu, IDM_PAL_OPT_POP5, iEnable);
        EnableMenuItem(hMenu, IDM_PAL_OPT_POP6, iEnable);
        EnableMenuItem(hMenu, IDM_PAL_OPT_MEDCUT, iEnable);
        EnableMenuItem(hMenu, IDM_EDIT_PASTE, IsClipboardFormatAvailable(CF_DIB) ? MF_ENABLED : MF_GRAYED);
        return 0;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_FILE_OPEN:
            //显示“打开文件”对话框
            if (!GetOpenFileName(&ofn))
                return 0;
            //如果DIB和调色板己经存在,则删除它们
            SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0);
            //加载DIB文件到内存
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);
            hdib = DibFileLoad(szFileName);
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            ShowCursor(FALSE);
            //重置滚动条
            SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0);
            //创建调色板和DDB
            SendMessage(hwnd, WM_USER_CREATEPAL, TRUE, 0); //根据调色板,创建DDB——hBitmap

            if (!hdib)
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file!"),
                           szAppName, MB_OK | MB_ICONEXCLAMATION);
            }
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        case IDM_FILE_SAVE:
            //打开“保存”对话框
            if (!GetSaveFileName(&ofn))
                return 0;
            //将DIB保存到文件中
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);
            fSuccess = DibFileSave(hdib, szFileName);
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            ShowCursor(FALSE);
            if (!fSuccess)
            {
                MessageBox(hwnd, TEXT("Cannot Save DIB file!"),
                           szAppName, MB_OK | MB_ICONEXCLAMATION);
            }
            return 0;
        case IDM_FILE_PRINT:
            if (!hdib)
                return 0;
            //获得打印机DC
            printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION;
            if (!PrintDlg(&printdlg))
                return 0;
            if (NULL == (hdcPrn = printdlg.hDC))
            {
                MessageBox(hwnd, TEXT("Cannot obtain Printer DC"), szAppName, MB_ICONEXCLAMATION | MB_OK);
                return 0;
            }

            //检查打印机是否支持打印位图
            if (!(RC_BITBLT & GetDeviceCaps(hdcPrn, RASTERCAPS)))
            {
                DeleteDC(hdcPrn);
                MessageBox(hwnd, TEXT("Printer cannot print bitmaps"), szAppName, MB_ICONEXCLAMATION | MB_OK);
                return 0;
            }
            //获取打机印的可打印区域
            cxPage = GetDeviceCaps(hdcPrn, HORZRES);
            cyPage = GetDeviceCaps(hdcPrn, VERTRES);

            fSuccess = FALSE;
            //将DIB发送到打印机
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);
            if ((StartDoc(hdcPrn, &di) > 0) && (StartPage(hdcPrn) > 0))
            {
                DisplayDib(hdcPrn, DibBitmapHandle(hdib), 0, 0, cxPage, cyPage, wShow, FALSE);
                if (EndPage(hdcPrn) > 0)
                {
                    fSuccess = TRUE;
                    EndDoc(hdcPrn);
                }
            }
            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            DeleteDC(hdcPrn);
            if (!fSuccess)
                MessageBox(hwnd, TEXT("Cannot print bitmaps"),
                szAppName, MB_ICONEXCLAMATION | MB_OK);
            return 0;
        case IDM_FILE_PROPERTIES:
            if (!hdib)
                return 0;
            wsprintf(szBuffer, TEXT("Pixel width:\t%i\n")  //%i与%d一样的
                     TEXT("Pixel Height:\t%i\n")
                     TEXT("Bits per pixel:\t%i\n")
                     TEXT("Number of colors:\t%i\n")
                     TEXT("Compression:\t%s\n"),
                     DibWidth(hdib), DibHeight(hdib),
                     DibBitCount(hdib), DibNumColors(hdib),
                     szCompression[min(3, DibCompression(hdib))]);
            MessageBox(hwnd, szBuffer, szAppName, MB_ICONEXCLAMATION | MB_OK);
            return 0;
        case IDM_APP_EXIT:
            SendMessage(hwnd, WM_CLOSE, 0, 0);
            return 0;
        case IDM_EDIT_COPY:
        case IDM_EDIT_CUT:
            if (!(hGlobal = DibCopyToPackedDib(hdib, TRUE)))
                return 0;
            OpenClipboard(hwnd);
            EmptyClipboard();
            SetClipboardData(CF_DIB, hGlobal);
            CloseClipboard();
            if (LOWORD(wParam) == IDM_EDIT_COPY)
                return 0;
            //剪切时,继续执行下去
        case IDM_EDIT_DELETE:
            SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0);
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        case IDM_EDIT_PASTE:
            OpenClipboard(hwnd);
            hGlobal = GetClipboardData(CF_DIB);
            pGlobal = GlobalLock(hGlobal);
            //如果己经存在DIB位图和调色板,则删除它们
            if (pGlobal)
            {
                SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0);
                hdib = DibCopyFromPackedDib((BITMAPINFO*)pGlobal);
                SendMessage(hwnd, WM_USER_CREATEPAL, TRUE, 0);
            }
            GlobalUnlock(hGlobal);
            CloseClipboard();
            //重置滚动条
            SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0);
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        case IDM_EDIT_ROTATE:
            if (hdibNew = DibRotateRight(hdib))
            {
                DibDelete(hdib);
                DeleteObject(hBitmap);
                hdib = hdibNew;
                hBitmap = DibCopyToDdb(hdib, hwnd, hPalette);
                SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0);
                InvalidateRect(hwnd, NULL, TRUE);
            } else
            {
                MessageBox(hwnd, TEXT("Not enough memory"),
                           szAppName, MB_OK | MB_ICONEXCLAMATION);
            }
            return 0;
        case IDM_EDIT_FLIP:
            if (hdibNew = DibFlipHorizontal(hdib))
            {
                DibDelete(hdib);
                DeleteObject(hBitmap);
                hdib = hdibNew;
                hBitmap = DibCopyToDdb(hdib, hwnd, hPalette);
                InvalidateRect(hwnd, NULL, TRUE);
            } else
            {
                MessageBox(hwnd, TEXT("Not enough memory"),
                           szAppName, MB_OK | MB_ICONEXCLAMATION);
            }
            return 0;

        case IDM_SHOW_NORMAL:
        case IDM_SHOW_STRETCH:
        case IDM_SHOW_CENTER:
        case IDM_SHOW_ISOSTRETCH:
            CheckMenuItem(hMenu, wShow, MF_UNCHECKED);
            wShow = LOWORD(wParam);
            CheckMenuItem(hMenu, wShow, MF_CHECKED);
            SendMessage(hwnd, WM_USER_SETSCROLLS, TRUE, 0);
            InvalidateRect(hwnd, NULL, TRUE);
            return 0;
        case IDM_CONVERT_32:iConvert += 8;
        case IDM_CONVERT_24:iConvert += 8;
        case IDM_CONVERT_16:iConvert += 8;
        case IDM_CONVERT_08:iConvert += 4;
        case IDM_CONVERT_04:iConvert += 3;
        case IDM_CONVERT_01:iConvert += 1;
            SetCursor(LoadCursor(NULL, IDC_WAIT));
            ShowCursor(TRUE);
            hdibNew = DibConvert(hdib, iConvert);
            ShowCursor(FALSE);
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            if (hdibNew)
            {
                SendMessage(hwnd, WM_USER_DELETEDIB, 0, 0);
                hdib = hdibNew;
                SendMessage(hwnd, WM_USER_CREATEPAL, TRUE, 0);
                InvalidateRect(hwnd, NULL, TRUE);
            } else
            {
                MessageBox(hwnd, TEXT("Not enough memory"),
                           szAppName, MB_OK | MB_ICONEXCLAMATION);
            }
            return 0;
        case IDM_APP_ABOUT:
            MessageBox(hwnd, TEXT("Dibble (c) Charles Petzold,1998"),
                       szAppName, MB_OK | MB_ICONEXCLAMATION);
            return 0;
        }

        //其余所有的WM_COMMAND消息都是来自调色板项目。如果删除己经存在的调色板,光标将被
        //设置为沙漏的形状
        SendMessage(hwnd, WM_USER_DELETEPAL, 0, 0);
        SetCursor(LoadCursor(NULL, IDC_WAIT));
        ShowCursor(TRUE);
        //提醒,所有的调色板消息都以break结束而不是return,这允许后面进行一些额外的处理
        switch (LOWORD(wParam))
        {
        case IDM_PAL_DIBTABLE:
            hPalette = DibPalDibTable(hdib);
            break;
        case IDM_PAL_HALFTONE:
            hdc = GetDC(hwnd);
            if (hPalette = CreateHalftonePalette(hdc))
                fHalftonePalette = TRUE;
            ReleaseDC(hwnd, hdc);
            break;
        case IDM_PAL_ALLPURPOSE:
            hPalette = DibPalAllPurpose();
            break;

        case IDM_PAL_GRAY2:   hPalette = DibPalUniformGrays(2);   break;
        case IDM_PAL_GRAY3:   hPalette = DibPalUniformGrays(3);   break;
        case IDM_PAL_GRAY4:   hPalette = DibPalUniformGrays(4);   break;
        case IDM_PAL_GRAY8:   hPalette = DibPalUniformGrays(8);   break;
        case IDM_PAL_GRAY16:  hPalette = DibPalUniformGrays(16);  break;
        case IDM_PAL_GRAY32:  hPalette = DibPalUniformGrays(32);  break;
        case IDM_PAL_GRAY64:  hPalette = DibPalUniformGrays(64);  break;
        case IDM_PAL_GRAY128: hPalette = DibPalUniformGrays(128); break;
        case IDM_PAL_GRAY256: hPalette = DibPalUniformGrays(256); break;
        case IDM_PAL_RGB222:   hPalette = DibPalUniformColors(2, 2, 2);   break;
        case IDM_PAL_RGB333:   hPalette = DibPalUniformColors(3, 3, 3);   break;
        case IDM_PAL_RGB444:   hPalette = DibPalUniformColors(4, 4, 4);   break;
        case IDM_PAL_RGB555:   hPalette = DibPalUniformColors(5, 5, 5);   break;
        case IDM_PAL_RGB666:   hPalette = DibPalUniformColors(6, 6, 6);   break;
        case IDM_PAL_RGB775:   hPalette = DibPalUniformColors(7, 7, 5);   break;
        case IDM_PAL_RGB757:   hPalette = DibPalUniformColors(7, 5, 7);   break;
        case IDM_PAL_RGB577:   hPalette = DibPalUniformColors(5, 7, 7);   break;
        case IDM_PAL_RGB884:   hPalette = DibPalUniformColors(8, 8, 4);   break;
        case IDM_PAL_RGB848:   hPalette = DibPalUniformColors(8, 4, 8);   break;
        case IDM_PAL_RGB488:   hPalette = DibPalUniformColors(4, 8, 8);   break;
        case IDM_PAL_OPT_POP4:
            hPalette = DibPalPopularity(hdib, 4);
            break;
        case IDM_PAL_OPT_POP5:
            hPalette = DibPalPopularity(hdib, 5);
            break;
        case IDM_PAL_OPT_POP6:
            hPalette = DibPalPopularity(hdib, 6);
            break;
        case IDM_PAL_OPT_MEDCUT:
            hPalette = DibPalMedianCut(hdib, 6);
            break;
        }
        //当处理完菜单中的调色板项目后,光标恢复为箭头的形状,该项被设为Checked,并
        //且刷新客户区
        hBitmap = DibCopyToDdb(hdib, hwnd, hPalette);
        ShowCursor(FALSE);
        SetCursor(LoadCursor(NULL, IDC_ARROW));
        if (hPalette)
            PaletteMenu(hMenu, (LOWORD(wParam)));
        InvalidateRect(hwnd, NULL, TRUE);
        return 0;  //WM_COMMAND消息处理完毕
        //该消息中删除一个己经存在的DIB,为获取一个新DIB作准备。
        //该消息会被打开、粘贴或其它菜单命令所调用
    case WM_USER_DELETEDIB:
        if (hdib)
        {
            DibDelete(hdib);
            hdib = NULL;
        }
        SendMessage(hwnd, WM_USER_DELETEPAL, 0, 0);
        return 0;
        //基于一个新DIB创建一个调色板。如果wParam==TRUE,则同时创建DDB
    case WM_USER_CREATEPAL:
        if (hdib)
        {
            hdc = GetDC(hwnd);
            if (!(RC_PALETTE & GetDeviceCaps(hdc, RASTERCAPS)))  //不支持调色调
            {
                PaletteMenu(hMenu, IDM_PAL_NONE);
            } else if (hPalette = CreateHalftonePalette(hdc)) //创建半色调调色板
            {
                fHalftonePalette = TRUE;
                PaletteMenu(hMenu, IDM_PAL_HALFTONE);
            }
            ReleaseDC(hwnd, hdc);
            if ((BOOL)wParam)
                hBitmap = DibCopyToDdb(hdib, hwnd, hPalette);
        }
        return 0;

        //删除一个己经存在的调色板,为创建新调色板做准备
    case WM_USER_DELETEPAL:
        if (hPalette)
        {
            DeleteObject(hPalette);
            hPalette = NULL;
            fHalftonePalette = FALSE;
            PaletteMenu(hMenu, IDM_PAL_NONE);
        }
        if (hBitmap)
        {
            DeleteObject(hBitmap);
        }
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        if (hPalette)
        {
            SelectPalette(hdc, hPalette, FALSE);
            RealizePalette(hdc);
        }
        if (hBitmap)
        {
            DisplayDib(hdc,
                       fHalftonePalette ? DibBitmapHandle(hdib) : hBitmap,
                       iHscroll, iVscroll,
                       cxClient, cyClient,
                       wShow, fHalftonePalette);
        }

        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)
            return FALSE;
        hdc = GetDC(hwnd);
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
        UpdateColors(hdc);
        ReleaseDC(hwnd, hdc);
        break;
    case WM_DESTROY:
        if (hdib)
            DibDelete(hdib);
        if (hBitmap)
            DeleteObject(hBitmap);
        if (hPalette)
            DeleteObject(hPalette);

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

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 Dibble.rc 使用
//
#define IDM_FILE_OPEN                   40001
#define IDM_FILE_SAVE                   40002
#define IDM_FILE_PRINT                  40003
#define IDM_FILE_PROPERTIES             40004
#define IDM_APP_EXIT                    40005
#define IDM_EDIT_CUT                    40006
#define IDM_EDIT_COPY                   40007
#define IDM_EDIT_PASTE                  40008
#define IDM_EDIT_DELETE                 40009
#define IDM_EDIT_FLIP                   40010
#define IDM_EDIT_ROTATE                 40011
#define IDM_SHOW_NORMAL                 40012
#define IDM_SHOW_CENTER                 40013
#define IDM_SHOW_STRETCH                40014
#define IDM_SHOW_ISOSTRETCH             40015
#define IDM_PAL_NONE                    40016
#define IDM_PAL_DIBTABLE                40017
#define IDM_PAL_HALFTONE                40018
#define IDM_PAL_ALLPURPOSE              40019
#define IDM_PAL_GRAY2                   40020
#define IDM_PAL_GRAY3                   40021
#define IDM_PAL_GRAY4                   40022
#define IDM_PAL_GRAY8                   40023
#define IDM_PAL_GRAY16                  40024
#define IDM_PAL_GRAY32                  40025
#define IDM_PAL_GRAY64                  40026
#define IDM_PAL_GRAY128                 40027
#define IDM_PAL_GRAY256                 40028
#define IDM_PAL_RGB222                  40029
#define IDM_PAL_RGB333                  40030
#define IDM_PAL_RGB444                  40031
#define IDM_PAL_RGB555                  40032
#define IDM_PAL_RGB666                  40033
#define IDM_PAL_RGB775                  40034
#define IDM_PAL_RGB757                  40035
#define IDM_PAL_RGB577                  40036
#define IDM_PAL_RGB884                  40037
#define IDM_PAL_RGB848                  40038
#define IDM_PAL_RGB488                  40039
#define IDM_CONVERT_01                  40040
#define IDM_CONVERT_04                  40041
#define IDM_CONVERT_08                  40042
#define IDM_CONVERT_16                  40043
#define IDM_CONVERT_24                  40044
#define IDM_CONVERT_32                  40045
#define IDM_APP_ABOUT                   40046
#define IDM_PAL_OPT_POP4                40047
#define IDM_PAL_OPT_POP5                40048
#define IDM_PAL_OPT_POP6                40049
#define IDM_PAL_OPT_MEDCUT              40050
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40040
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//Dibble.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\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif    // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
DIBBLE MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open...\tCtrl+O", IDM_FILE_OPEN
MENUITEM "&Save...\tCtrl+S", IDM_FILE_SAVE
MENUITEM SEPARATOR
MENUITEM "&Print...\tCtrl+P", IDM_FILE_PRINT
MENUITEM SEPARATOR
MENUITEM "Propert&ies...", IDM_FILE_PROPERTIES
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_APP_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT
MENUITEM "&Copy\tCtrl+C", IDM_EDIT_COPY
MENUITEM "&Paste\tCtrl+V", IDM_EDIT_PASTE
MENUITEM "&Delete\tDelete", IDM_EDIT_DELETE
MENUITEM SEPARATOR
MENUITEM "&Flip", IDM_EDIT_FLIP
MENUITEM "&Rotate", IDM_EDIT_ROTATE
END
POPUP "&Show"
BEGIN
MENUITEM "&Actual Size", IDM_SHOW_NORMAL, CHECKED
MENUITEM "&Center", IDM_SHOW_CENTER
MENUITEM "&Stretch to Window", IDM_SHOW_STRETCH
MENUITEM "Stretch &Isotropically", IDM_SHOW_ISOSTRETCH
END
POPUP "&Palette"
BEGIN
MENUITEM "&None", IDM_PAL_NONE, CHECKED
MENUITEM "&Dib ColorTable", IDM_PAL_DIBTABLE
MENUITEM "&Halftone", IDM_PAL_HALFTONE
MENUITEM "&All-Purpose", IDM_PAL_ALLPURPOSE
POPUP "&Gray Shades"
BEGIN
MENUITEM "&1. 2 Grays ", IDM_PAL_GRAY2
MENUITEM "&2. 3 Grays", IDM_PAL_GRAY3
MENUITEM "&3. 4 Grays", IDM_PAL_GRAY4
MENUITEM "&4. 8 Grays", IDM_PAL_GRAY8
MENUITEM "&5. 16 Grays", IDM_PAL_GRAY16
MENUITEM "&6. 32 Grays", IDM_PAL_GRAY32
MENUITEM "&7. 64 Grays", IDM_PAL_GRAY64
MENUITEM "&8. 128 Grays", IDM_PAL_GRAY128
MENUITEM "&9. 256 Grays", IDM_PAL_GRAY256
END
POPUP "&Uniform Colors"
BEGIN
MENUITEM "&1. 2R×2G×2B (8)", IDM_PAL_RGB222
MENUITEM "&2. 3R×3G×3B (27)", IDM_PAL_RGB333
MENUITEM "&3. 4R×4G×4B (64)", IDM_PAL_RGB444
MENUITEM "&4. 5R×5G×5B (125)", IDM_PAL_RGB555
MENUITEM "&5. 6R×6G×6B (216)", IDM_PAL_RGB666
MENUITEM "&6. 7R×7G×5B (245)", IDM_PAL_RGB775
MENUITEM "&7. 7R×5G×7B (245)", IDM_PAL_RGB757
MENUITEM "&8. 5R×7G×7B (245)", IDM_PAL_RGB577
MENUITEM "&9. 8R×8G×4B (256)", IDM_PAL_RGB884
MENUITEM "&A. 8R×4G×8B (256)", IDM_PAL_RGB848
MENUITEM "&B. 4R×8G×8B (256)", IDM_PAL_RGB488
END
POPUP "&Optimized"
BEGIN
MENUITEM "&1. Popularity Algorithm (4 bits)", IDM_PAL_OPT_POP4
MENUITEM "&2. Popularity Algorithm (5 bits)", IDM_PAL_OPT_POP5
MENUITEM "&3. Popularity Algorithm (6 bits)", IDM_PAL_OPT_POP6
MENUITEM "&4. Median Cut Algorithm (4 bits)", IDM_PAL_OPT_MEDCUT
END
END
POPUP "Con&vert"
BEGIN
MENUITEM "&1. to 1  bit per pixel", IDM_CONVERT_01
MENUITEM "&2. to 4  bits per Pixel", IDM_CONVERT_04
MENUITEM "&3. to 8  bit per pixel", IDM_CONVERT_08
MENUITEM "&4. to 16 bits per Pixel", IDM_CONVERT_16
MENUITEM "&5. to 24 bit per pixel", IDM_CONVERT_24
MENUITEM "&6. to 32 bits per Pixel", IDM_CONVERT_32
END
POPUP "&Help"
BEGIN
MENUITEM "&About", IDM_APP_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
DIBBLE ACCELERATORS
BEGIN
"C", IDM_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
"X", IDM_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT
VK_DELETE, IDM_EDIT_DELETE, VIRTKEY, NOINVERT
"V", IDM_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
"O", IDM_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
"P", IDM_FILE_PRINT, VIRTKEY, CONTROL, NOINVERT
"S", IDM_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
END
#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//

/*--------------------------------------------------------
DIBHELP.H Header file for DIBHELP.C
--------------------------------------------------------*/
#pragma once
#include <windows.h>
typedef void* HDIB;
//DIBHELP.C中的函数
BOOL DibIsValid(HDIB hdib);  //Dib文件是否有效
HBITMAP  DibBitmapHandle(HDIB hdib);
int DibWidth(HDIB hdib);
int DibHeight(HDIB hdib);
int DibBitCount(HDIB hdib);
int DibRowLength(HDIB hdib); //每行像素数:4的倍数
int DibNumColors(HDIB hdib);
DWORD DibMask(HDIB hdib, int i);//获取颜色掩码
int DibRShift(HDIB hdib, int i);//
int DibLShift(HDIB hdib, int i);
int DibCompression(HDIB hdib); //获取biCompression字段的值
BOOL DibIsAddressable(HDIB hdib);//是否被压缩,DibIsNotCompressed
DWORD DibInfoHeaderSize(HDIB hdib);
DWORD DibMaskSize(HDIB hdib);
DWORD DibColorSize(HDIB hdib);
DWORD DibInfoSize(HDIB hdib);
DWORD DibBitsSize(HDIB hdib);
DWORD DibTotalSize(HDIB hdib);
BITMAPINFOHEADER* DibInfoHeaderPtr(HDIB hdib);
DWORD* DibMaskPtr(HDIB hdib);
void* DibBitsPtr(HDIB hdib);
BOOL DibGetColor(HDIB hdib, int index, RGBQUAD* prgb);
BOOL DibSetColor(HDIB hdib, int index, RGBQUAD*prgb);
BYTE* DibPixelPtr(HDIB hdib, int x, int y);
DWORD DibGetPixel(HDIB hdib, int x, int y);
BOOL  DibSetPixel(HDIB hdib, int x, int y, DWORD dwPixel);
BOOL  DibGetPixelColor(HDIB hdib, int x, int y, RGBQUAD* prgb);
BOOL  DibSetPixelColor(HDIB hdib, int x, int y, RGBQUAD* prgb);
HDIB DibCreateFromInfo(BITMAPINFO* pbmi);
BOOL DibDelete(HDIB hdib);
HDIB DibCreate(int cx, int cy, int cBits, int cColors);
HDIB DibCopy(HDIB hdibSrc, BOOL fRotate);
BITMAPINFO* DibCopyToPackedDib(HDIB hdib, BOOL fUsedGlobal);
HDIB DibCopyFromPackedDib(BITMAPINFO* pPackedDib);
HDIB DibFileLoad(const TCHAR* szFileName);
BOOL DibFileSave(HDIB hdib, const TCHAR* szFileName);
HBITMAP DibCopyToDdb(HDIB hdib, HWND hwnd, HPALETTE hPalette);
HDIB DibCreateFromDdb(HBITMAP hBitmap);  //该函数课本没有给出实现
/*----------------------------------------------------------
DibFlipHorizontal:调用没有优化的DibSetPixel和DibGetPixel
----------------------------------------------------------*/
HDIB DibFlipHorizontal(HDIB hdibSrc);
/*----------------------------------------------------------
DibRotateRight:调用优化过的DibSetPixelx和DibGetPixelx
----------------------------------------------------------*/
HDIB DibRotateRight(HDIB hdibSrc);
/*----------------------------------------------------------
快速无边界检查的gets和Sets宏
----------------------------------------------------------*/
#define DibPixelPtr1(hdib,x,y)     (((*(PBYTE**)hdib)[y]) +((x)>>3))
#define DibPixelPtr4(hdib,x,y)     (((*(PBYTE**)hdib)[y]) +((x)>>1))
#define DibPixelPtr8(hdib,x,y)     (((*(PBYTE**)hdib)[y]) + (x)    )
#define DibPixelPtr16(hdib,x,y)    ((WORD*)(((*(PBYTE**)hdib)[y]) + (x)*2  ))
#define DibPixelPtr24(hdib,x,y)    ((RGBTRIPLE*)(((*(PBYTE**)hdib)[y]) + (x)*3  ))
#define DibPixelPtr32(hdib,x,y)    ((DWORD*)(((*(PBYTE**)hdib)[y]) + (x)*4 ))
#define DibGetPixel1(hdib,x,y)     (0x01&(*DibPixelPtr1(hdib,x,y) >> (7 -((x)&7))))
#define DibGetPixel4(hdib,x,y)     (0x0F &(*DibPixelPtr4(hdib,x,y)>>((x)&1 ? 0 : 4)))
#define DibGetPixel8(hdib,x,y)     (*DibPixelPtr8(hdib,x,y))
#define DibGetPixel16(hdib,x,y)    (*DibPixelPtr16(hdib,x,y))
#define DibGetPixel24(hdib,x,y)    (*DibPixelPtr24(hdib,x,y))
#define DibGetPixel32(hdib,x,y)    (*DibPixelPtr32(hdib,x,y))
#define DibSetPixel1(hdib, x, y, p)                                        \
                   ((*DibPixelPtr1(hdib, x, y) &= ~(1 << (7 - ((x)& 7)))),                    (*DibPixelPtr1(hdib, x, y) |= ((p) << (7 - ((x)& 7)))))
#define DibSetPixel4(hdib, x, y, p)                                        \
               ((*DibPixelPtr4(hdib, x, y) &= (0x0F << ((x)& 1 ? 4 : 0))),                (*DibPixelPtr4(hdib, x, y) |= ((p) << ((x)& 1 ? 0 : 4))))
#define DibSetPixel8(hdib, x, y, p)  (* DibPixelPtr8 (hdib, x, y) = p)
#define DibSetPixel16(hdib, x, y, p) (* DibPixelPtr16 (hdib, x, y) = p)
#define DibSetPixel24(hdib, x, y, p) (* DibPixelPtr24 (hdib, x, y) = p)
#define DibSetPixel32(hdib, x, y, p) (* DibPixelPtr32 (hdib, x, y) = p)

//DibHelp.c

/*-------------------------------------------------------------
DIBHELP.C -- DIB Section Helper Routines
(c)Charles Petzold,1998
-------------------------------------------------------------*/
#include <windows.h>
#include "DibHelp.h"
#define HDIB_SIGNATURE  (*(int*)"Dib ")
typedef struct
{
    PBYTE* ppRow; //像素位的行指针,必须是第一个字段,为后面的宏操作更容易设计的。
    //第一个指针指向DIB位图视觉上最上面的一行像素,最后一个指针指向
    //DIB图像最后一行的像素,和pBits字段一样(也就是pBits也要被存成
    //这样的格式)
    int    iSignature;  //="Dib "
    HBITMAP hBitmap;//接收从CreateDIBSection返回的句柄,明显返回的是设备无关的位图,
    //但可以直接被BitBlt或StretchBlt
    BYTE*  pBits;   //指向位图的像素数据,其值在CreateDIBSection函数中被设定。其所指
    //的内存块由操作系统管理,但应用程序可以访问该内存块。删除位图
    //句柄后,该内存块自动被删除
    DIBSECTION ds;  //可以用GetObject获得位图信图,存入该结构体
    int     iRShift[3];  //分别存入R、G、B3种颜色遮罩需左移的值
    int     iLShift[3];  //
}DIBSTRUCT, *PDIBSTRUCT;
/*----------------------------------------------------------------------------------
DibIsValid:如果hdib指向一个有效的DIBSTRUCT结构体时返回TRUE
-----------------------------------------------------------------------------------*/
BOOL DibIsValid(HDIB hdib)
{
    DIBSTRUCT*  pdib = hdib;
    if (pdib == NULL)
        return FALSE;
    //检查是否有读取指定内存的内容的权限,参数1为要检查的内存指针,参数2为要检查的内存块大小
    if (IsBadReadPtr(pdib, sizeof(DIBSTRUCT)))
        return FALSE;
    if (pdib->iSignature != HDIB_SIGNATURE)  //自定义的DIB位图标识符
        return FALSE;
    return TRUE;
}
/*----------------------------------------------------------------------------------
DibBitmapHandle:返回DIB Section位图对象的句柄hBitmap
-----------------------------------------------------------------------------------*/
HBITMAP  DibBitmapHandle(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return NULL;
    return ((PDIBSTRUCT)hdib)->hBitmap;
}
/*----------------------------------------------------------------------------------
DibWidth:返回位图的宽度(单位字节)
-----------------------------------------------------------------------------------*/
int DibWidth(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return 0;
    return  ((PDIBSTRUCT)hdib)->ds.dsBm.bmWidth;
}
/*----------------------------------------------------------------------------------
DibHeight:返回位图的高度(单位字节)
-----------------------------------------------------------------------------------*/
int DibHeight(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return 0;
    return  ((PDIBSTRUCT)hdib)->ds.dsBm.bmHeight;
}
/*----------------------------------------------------------------------------------
DibBitCount:返回每像素的位数
-----------------------------------------------------------------------------------*/
int DibBitCount(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return 0;
    return  ((PDIBSTRUCT)hdib)->ds.dsBm.bmBitsPixel;
}
/*----------------------------------------------------------------------------------
DibRowLength:返回每行像素的大小(单位:字节):4的倍数
-----------------------------------------------------------------------------------*/
int DibRowLength(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return 0;
    return  4 * ((DibWidth(hdib)*DibBitCount(hdib) + 31) / 32);
}
/*----------------------------------------------------------------------------------
DibNumColors:返回颜色表的颜色数目,无颜色表时返回0
-----------------------------------------------------------------------------------*/
int DibNumColors(HDIB hdib)
{
    PDIBSTRUCT pdib = hdib;
    if (!DibIsValid(hdib))
        return 0;
    if (pdib->ds.dsBmih.biClrUsed != 0)
    {
        return pdib->ds.dsBmih.biClrUsed;
    } else if (DibBitCount(hdib) <= 8)
    {
        return 1 << DibBitCount(hdib); //2^bBitCount,如1位则2种颜色,8位256色
    }
    return  0;
}
/*----------------------------------------------------------------------------------
DibMask:返回3种颜色遮罩其中的一种,如红色遮罩
-----------------------------------------------------------------------------------*/
DWORD DibMask(HDIB hdib, int i)
{
    PDIBSTRUCT pdib = hdib;
    if (!DibIsValid(hdib) || i<0 || i>2)
        return 0;
    return  pdib->ds.dsBitfields[i];//0—红色;1—绿色;2—蓝色
}
/*----------------------------------------------------------------------------------
DibRShift:返回需右移的位数
-----------------------------------------------------------------------------------*/
int DibRShift(HDIB hdib, int i)
{
    PDIBSTRUCT pdib = hdib;
    if (!DibIsValid(hdib) || i<0 || i>2)
        return 0;
    return pdib->iRShift[i];
}
/*----------------------------------------------------------------------------------
DibLShift:返回需左移的位数
-----------------------------------------------------------------------------------*/
int DibLShift(HDIB hdib, int i)
{
    PDIBSTRUCT pdib = hdib;
    if (!DibIsValid(hdib) || i<0 || i>2)
        return 0;
    return pdib->iLShift[i];
}
/*----------------------------------------------------------------------------------
DibCompression: 获取biCompression字段的值
-----------------------------------------------------------------------------------*/
int DibCompression(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return 0;
    return ((PDIBSTRUCT)hdib)->ds.dsBmih.biCompression;
}
//是否被压缩,DibIsNotCompressed
/*----------------------------------------------------------------------------------
DibIsAddressable: 如果DIB没压缩则返回TRUE
-----------------------------------------------------------------------------------*/
BOOL DibIsAddressable(HDIB hdib)
{
    int iCompression;
    if (!DibIsValid(hdib))
        return 0;
    iCompression = DibCompression(hdib);

    if (iCompression == BI_RGB || iCompression == BI_BITFIELDS)
        return TRUE;
    return FALSE;
}
/*----------------------------------------------------------------------------------
下面这些函数返回DIB Section可能出现的各种变量信息,这些函数的目的是为了将DIB Section
转换为紧凑DIB或保存文件时使用
-----------------------------------------------------------------------------------*/
DWORD DibInfoHeaderSize(HDIB hdib)  //文件信息头BITMAPINFOHEADER(不含颜色遮罩、颜色表)等
{
    if (!DibIsValid(hdib))
        return 0;

    return ((PDIBSTRUCT)hdib)->ds.dsBmih.biSize;
}
DWORD DibMaskSize(HDIB hdib)
{
    PDIBSTRUCT pdib = hdib;
    if (!DibIsValid(hdib))
        return 0;
    if (pdib->ds.dsBmih.biCompression == BI_BITFIELDS)
        return 3 * sizeof(DWORD);
    return 0;
}
DWORD DibColorSize(HDIB hdib)
{
    return DibNumColors(hdib)*sizeof(RGBQUAD);
}
DWORD DibInfoSize(HDIB hdib)
{
    return DibInfoHeaderSize(hdib) + DibMaskSize(hdib) + DibColorSize(hdib);
}
DWORD DibBitsSize(HDIB hdib)
{
    PDIBSTRUCT pdib = hdib;
    if (!DibIsValid(hdib))
        return 0;
    if (pdib->ds.dsBmih.biSizeImage != 0)
    {
        return pdib->ds.dsBmih.biSizeImage;
    }
    return DibHeight(hdib)*DibRowLength(hdib);
}
DWORD DibTotalSize(HDIB hdib)  //整个紧凑型DIB的大小
{
    return DibInfoSize(hdib) + DibBitsSize(hdib);
}
/*----------------------------------------------------------------------------------
下面这些函数返回DIB Section各部分的指针
-----------------------------------------------------------------------------------*/
BITMAPINFOHEADER* DibInfoHeaderPtr(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return NULL;
    return &(((PDIBSTRUCT)hdib)->ds.dsBmih);
}
DWORD* DibMaskPtr(HDIB hdib)
{
    PDIBSTRUCT pdib = hdib;
    if (!DibIsValid(hdib))
        return NULL;
    return  pdib->ds.dsBitfields;//因为这个字段是个数组,数组名是个指针。
}
void* DibBitsPtr(HDIB hdib)
{
    if (!DibIsValid(hdib))
        return NULL;
    return ((PDIBSTRUCT)hdib)->pBits;
}
/*----------------------------------------------------------------------------------
DibGetColor:从DIB颜色表中获得指定索引号处的颜色,放在prgb结构体中
-----------------------------------------------------------------------------------*/
BOOL DibGetColor(HDIB hdib, int index, RGBQUAD* prgb)
{
    PDIBSTRUCT pdib = hdib;
    HDC hdcMem;
    int iReturn;
    if (!DibIsValid(hdib))
        return FALSE;
    hdcMem = CreateCompatibleDC(NULL);
    SelectObject(hdcMem, pdib->hBitmap);
    iReturn = GetDIBColorTable(hdcMem, index, 1, prgb); //API函数
    DeleteDC(hdcMem);
    return iReturn ? TRUE : FALSE;
}
/*----------------------------------------------------------------------------------
DibSetColor:prgb结构体颜色设置到DIB颜色表中
-----------------------------------------------------------------------------------*/
BOOL DibSetColor(HDIB hdib, int index, RGBQUAD*prgb)
{
    PDIBSTRUCT pdib = hdib;
    HDC hdcMem;
    int iReturn;
    if (!DibIsValid(hdib))
        return FALSE;
    hdcMem = CreateCompatibleDC(NULL);
    SelectObject(hdcMem, pdib->hBitmap);
    iReturn = SetDIBColorTable(hdcMem, index, 1, prgb); //API函数
    DeleteDC(hdcMem);
    return iReturn ? TRUE : FALSE;
}
/*----------------------------------------------------------------------------------
DibPixelPtr:返回(x,y)处的像素位指针
-----------------------------------------------------------------------------------*/
BYTE* DibPixelPtr(HDIB hdib, int x, int y)
{
    if (!DibIsAddressable(hdib))
        return NULL;
    if (x < 0 || x >= DibWidth(hdib) || y < 0 || y >= DibHeight(hdib))
        return NULL;
    //x每次加1时,指针后移BitCount/8个字节,所以对于每像素1或4位时,
    //获取每个字节的像素还需移位才能读出像素值
    //对于8、16、24或32位的,每bitCount/8个字节
    //具体的处理 见DibGetPixel或DibSetPixel函数的处理。
    return (((PDIBSTRUCT)hdib)->ppRow)[y] + (x* DibBitCount(hdib) >> 3);
}
/*----------------------------------------------------------------------------------
DibGetPixel:返回(x,y)处的像素值
-----------------------------------------------------------------------------------*/
DWORD DibGetPixel(HDIB hdib, int x, int y)
{
    PBYTE pPixel;
    pPixel = DibPixelPtr(hdib, x, y);
    if (!pPixel)
        return 0;
    switch (DibBitCount(hdib))
    {
        //快速求余法:X % (2^N) == X & (2^N - 1),
    case 1: return 0x01 & (*pPixel >> (7 - (x & 7)));
    case 4: return 0x0F & (*pPixel >> (x & 1 ? 0 : 4));//x为奇数是,取低4位,偶数取高4位
    case 8: return *pPixel;
    case 16:return *(WORD*)pPixel;
    case 24:return 0x00FFFFFF & *(DWORD*)pPixel;
    case 32:return  *(DWORD*)pPixel;
    }
    return 0;
}
/*----------------------------------------------------------------------------------
DibSetPixel:设置(x,y)处的像素值
-----------------------------------------------------------------------------------*/
BOOL  DibSetPixel(HDIB hdib, int x, int y, DWORD dwPixel)
{
    PBYTE pPixel;
    pPixel = DibPixelPtr(hdib, x, y);
    if (!pPixel)
        return FALSE;
    switch (DibBitCount(hdib))
    {
    case 1:
        *pPixel &= ~(1 << (7 - (x & 7))); //取出该字节中除x处外的其余像素数
        *pPixel |= dwPixel << (7 - (x & 7));//将颜色值加入上述的X处。
        break;
    case 4:
        *pPixel &= 0x0F << (x & 1 ? 4 : 0);
        *pPixel |= dwPixel << (x & 1 ? 0 : 4);
        break;

    case 8:
        *pPixel = (BYTE)dwPixel;
        break;
    case 16:
        *(WORD*)pPixel = (WORD)dwPixel;
        break;
    case 24:
        *(RGBTRIPLE*)pPixel = *(RGBTRIPLE*)&dwPixel;
        break;
    case 32:
        *(DWORD*)pPixel = dwPixel;
        break;
    default:
        return FALSE;
    }
    return TRUE;
}
/*----------------------------------------------------------------------------------
DibGetPixelColor:获得(x,y)处的颜色值,并放入prgb所指的结构体中
-----------------------------------------------------------------------------------*/
BOOL  DibGetPixelColor(HDIB hdib, int x, int y, RGBQUAD* prgb)
{
    DWORD dwPixel;
    int iBitCount;
    PDIBSTRUCT pdib = hdib;
    //获得每像素位的大小,也可以使用它来作有效性验证
    if (0 == (iBitCount = DibBitCount(hdib)))
        return FALSE;
    //获取像素位的值,返回DWORD,该值可能是索引或里面含有RGB值
    dwPixel = DibGetPixel(hdib, x, y);
    //如果是8位或以下的,该值为颜色表索引
    if (iBitCount <= 8)
        return DibGetColor(hdib, (int)dwPixel, prgb);
    else if (iBitCount == 24)
    {
        *(RGBTRIPLE*)prgb = *(RGBTRIPLE*)&dwPixel;
        prgb->rgbReserved = 0;
    } else if (iBitCount == 32 && pdib->ds.dsBmih.biCompression == BI_RGB)
    {
        *prgb = *(RGBQUAD*)&dwPixel;
    }
    //此外的情况,使用颜色遮罩和移位
    else
    {
        //下面等号右边的式子,执行顺序先用掩码取出dwPixel的相应颜色,再右移,最后左移。
        prgb->rgbRed = (BYTE)((pdib->ds.dsBitfields[0] & dwPixel) >> pdib->iRShift[0] << pdib->iLShift[0]);
        prgb->rgbGreen = (BYTE)((pdib->ds.dsBitfields[1] & dwPixel) >> pdib->iRShift[1] << pdib->iLShift[1]);
        prgb->rgbBlue = (BYTE)((pdib->ds.dsBitfields[2] & dwPixel) >> pdib->iRShift[2] << pdib->iLShift[2]);
    }
    return TRUE;
}
/*----------------------------------------------------------------------------------
DibSetPixelColor:获得(x,y)处的颜色值
-----------------------------------------------------------------------------------*/
BOOL  DibSetPixelColor(HDIB hdib, int x, int y, RGBQUAD* prgb)
{
    DWORD dwPixel;
    int iBitCount;
    PDIBSTRUCT pdib = hdib;
    //不要利用DIBs的颜色表来执行该函数的操作
    iBitCount = DibBitCount(hdib);
    if (iBitCount <= 8)
        return FALSE;
    //剩下来的步骤与GetPixelColor相反
    else if (iBitCount == 24)
    {
        *(RGBTRIPLE*)&dwPixel = *(RGBTRIPLE*)prgb;
        dwPixel &= 0x00FFFFFF;
    } else if (iBitCount == 32 && pdib->ds.dsBmih.biCompression == BI_RGB)
    {
        *(RGBQUAD*)&dwPixel = *prgb;
    } else
    {
        //先将rgbRed由字节转为DWORD,再右移,最后左移
        dwPixel = (((DWORD)prgb->rgbRed >> pdib->iLShift[0]) << pdib->iRShift[0]);
        dwPixel |= (((DWORD)prgb->rgbGreen >> pdib->iLShift[1]) << pdib->iRShift[1]);
        dwPixel |= (((DWORD)prgb->rgbBlue >> pdib->iLShift[2]) << pdib->iRShift[2]);
    }
    DibSetPixel(hdib, x, y, dwPixel);
    return TRUE;
}
/*----------------------------------------------------------------------------------
根据遮罩颜色计算移位值,这些颜色遮罩来自于DibCreateFromInfo函数
-----------------------------------------------------------------------------------*/
static int MaskToRShift(DWORD dwMask)
{
    int iShift;
    if (0 == dwMask)
        return 0;
    for (iShift = 0; !(dwMask & 1); iShift++) //最低位为0,则右移1位
        dwMask >>= 1;
    return iShift;
}
static int MaskToLShift(DWORD dwMask)
{
    int iShift;
    if (0 == dwMask)
        return 0;
    while (!(dwMask & 1))  //dwMask右侧的0移掉
        dwMask >>= 1;
    for (iShift = 0; dwMask & 1; iShift++) //统计1的个数
        dwMask >>= 1;
    return 8 - iShift;
}
/*----------------------------------------------------------------------------------
DibCreateFromInfo:
所有创建DIB的函数最后都要调用该函数。这个函数负责调用CreateDIBSection,
为DIBSTRUCT分配内存,并设置行指针
-----------------------------------------------------------------------------------*/
HDIB DibCreateFromInfo(BITMAPINFO* pbmi)
{
    DIBSTRUCT* pdib;
    BYTE* pBits;
    HBITMAP hBitmap;
    int i, y, cy, iRowLength;
    //根据pbmi创建DIB Section位图,pBits指向今后要存入的像素位的空间地址(由系统管理)
    hBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0);
    if (NULL == hBitmap)
        return NULL;
    if (NULL == (pdib = malloc(sizeof(DIBSTRUCT))))
    {
        DeleteObject(hBitmap);
        return NULL;
    }
    pdib->iSignature = HDIB_SIGNATURE;
    pdib->hBitmap = hBitmap;
    pdib->pBits = pBits;

    //填充DIBSECTION结构
    GetObject(hBitmap, sizeof(DIBSECTION), &pdib->ds);
    //现在可以使用自定义的DIB信息函数,如DibCompression
    //如果压缩格式是BI_BITFIELDS,则计算掩码的移位
    if (DibCompression(pdib) == BI_BITFIELDS)
    {
        for (i = 0; i < 3; i++)
        {
            pdib->iLShift[i] = MaskToLShift(pdib->ds.dsBitfields[i]);
            pdib->iRShift[i] = MaskToRShift(pdib->ds.dsBitfields[i]);
        }
    }
    //如果是BI_RGB,但是16位或32位的,则设置bitFields和masks字段
    else if (DibCompression(pdib) == BI_RGB)
    {
        if (DibBitCount(pdib) == 16) //RGB分别使用5-5-5型遮罩
        {
            pdib->ds.dsBitfields[0] = 0x00007C00; //R Mask
            pdib->ds.dsBitfields[1] = 0x000003E0; //G Mask
            pdib->ds.dsBitfields[2] = 0x0000001F; //B Mask
            pdib->iRShift[0] = 10;
            pdib->iRShift[1] = 5;
            pdib->iRShift[2] = 0;
            pdib->iLShift[0] = 3;
            pdib->iLShift[1] = 3;
            pdib->iLShift[2] = 3;
        } else if (DibBitCount(pdib) == 24 || DibBitCount(pdib) == 32) //使用8-8-8型
        {
            pdib->ds.dsBitfields[0] = 0x00FF0000; //R Mask
            pdib->ds.dsBitfields[1] = 0x0000FF00; //G Mask
            pdib->ds.dsBitfields[2] = 0x000000FF; //B Mask
            pdib->iRShift[0] = 16;
            pdib->iRShift[1] = 8;
            pdib->iRShift[2] = 0;
            pdib->iLShift[0] = 0;
            pdib->iLShift[1] = 0;
            pdib->iLShift[2] = 0;
        }
    }
    //分配DIB像素行指针数组
    cy = DibHeight(pdib);
    pdib->ppRow = malloc(cy*sizeof(BYTE*));
    if (NULL == pdib->ppRow)
    {
        free(pdib);
        DeleteObject(hBitmap);
        return NULL;
    }
    //初始化像素行指针数组,ppRow[0]设为图像视觉上的最顶行。
    iRowLength = DibRowLength(pdib);
    if (pbmi->bmiHeader.biHeight>0) //位图从下到上存储
    {
        for (y = 0; y < cy; y++)
            pdib->ppRow[y] = pBits + (cy - 1 - y)*iRowLength;
    } else //从上到下存储
    {
        for (y = 0; y < cy; y++)
            pdib->ppRow[y] = pBits + y*iRowLength;
    }
    return pdib;
}
/*----------------------------------------------------------------------------------
DibDelete:删除DIBSTRUCT和在其中分配的内存
-----------------------------------------------------------------------------------*/
BOOL DibDelete(HDIB hdib)
{
    DIBSTRUCT* pdib = hdib;
    if (!DibIsValid(hdib))
        return FALSE;
    free(pdib->ppRow);
    DeleteObject(pdib->hBitmap);
    free(pdib);
    return TRUE;
}
/*-----------------------------------------------------------------------------------
DibCreate:  通过显式指定参数来构建HDIB()
-----------------------------------------------------------------------------------*/
HDIB DibCreate(int cx, int cy, int cBits, int cColors)
{
    HDIB hdib;
    BITMAPINFO* pbmi;
    DWORD  dwInfoSize;
    int cEntries = 1;
    if (cx <= 0 || cy <= 0 ||
        ((cBits != 1) && (cBits != 4) && (cBits != 8) &&
        (cBits != 16) && (cBits != 24) && (cBits != 32)))
    {
        return NULL;
    }
    if (cColors != 0)
        cEntries = cColors;
    else if (cBits <= 8)
        cEntries = 1 << cBits;
    dwInfoSize = sizeof(BITMAPINFOHEADER) + (cEntries - 1)*sizeof(RGBQUAD);
    if (NULL == (pbmi = malloc(dwInfoSize)))
    {
        return NULL;
    }
    ZeroMemory(pbmi, dwInfoSize);
    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = cx;
    pbmi->bmiHeader.biHeight = cy;
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biBitCount = cBits;
    pbmi->bmiHeader.biCompression = BI_RGB;
    pbmi->bmiHeader.biSizeImage = 0;
    pbmi->bmiHeader.biXPelsPerMeter = 0;
    pbmi->bmiHeader.biYPelsPerMeter = 0;
    pbmi->bmiHeader.biClrUsed = cColors;
    pbmi->bmiHeader.biClrImportant = 0;
    hdib = DibCreateFromInfo(pbmi);
    free(pbmi);
    return hdib;
}
/*-----------------------------------------------------------------------------------
DibCopyToInfo:  构建BITMAPINFO结构体.(主要供DibCopy和DibCopyToDdb函数使用)
-----------------------------------------------------------------------------------*/
static BITMAPINFO* DibCopyToInfo(HDIB hdib)
{
    BITMAPINFO* pbmi;
    RGBQUAD*    prgb;
    int i, iNumColors;
    if (!DibIsValid(hdib))
        return NULL;
    if (NULL == (pbmi = malloc(DibInfoSize(hdib))))
        return NULL;

    //复制BITMAPINFO信息头部分
    CopyMemory(pbmi, DibInfoHeaderPtr(hdib), sizeof(BITMAPINFOHEADER));
    //复制可能的颜色遮罩
    prgb = (RGBQUAD*)((BYTE*)pbmi + sizeof(BITMAPINFOHEADER));
    if (DibMaskSize(hdib))
    {
        CopyMemory(prgb, DibMaskPtr(hdib), 3 * sizeof(DWORD));
        prgb = (RGBQUAD*)((BYTE*)prgb + 3 * sizeof(DWORD));//将指针移到遮罩后,指向颜色表
    }
    //复制颜色表
    iNumColors = DibNumColors(hdib);
    for (i = 0; i < iNumColors; i++)
    {
        DibGetColor(hdib, i, prgb + i); //每种颜色都是32位的。RGRQUAD也是32位的
    }
    return pbmi;
}
/*-----------------------------------------------------------------------------------
DibCopy:  从一个己经存在的DIB Section去创建一个新的DIB Section(注意:可以会交换
宽度与高度)
-----------------------------------------------------------------------------------*/
HDIB DibCopy(HDIB hdibSrc, BOOL fRotate)
{
    BITMAPINFO* pbmi;
    BYTE    *pBitsSrc, *pBitsDst;
    HDIB  hdibDst;
    if (!DibIsValid(hdibSrc))
        return NULL;
    if (NULL == (pbmi = DibCopyToInfo(hdibSrc)))
        return NULL;
    if (fRotate)
    {
        pbmi->bmiHeader.biWidth = DibHeight(hdibSrc);
        pbmi->bmiHeader.biHeight = DibWidth(hdibSrc);
    }
    hdibDst = DibCreateFromInfo(pbmi);
    free(pbmi);
    if (!fRotate) //不旋转时直接复制像素数据。旋转时,需自行处理
    {
        pBitsSrc = DibBitsPtr(hdibSrc);
        pBitsDst = DibBitsPtr(hdibDst);
        CopyMemory(pBitsDst, pBitsSrc, DibBitsSize(hdibSrc));
    }
    return hdibDst;
}
/*-----------------------------------------------------------------------------------
DibCopyToPackedDib:
通常用于保存DIBs或将DIBs传输到剪贴板。当传输到剪贴板时,第2个参数必须设为TRUE,以便
分配一个全局共享内存
-----------------------------------------------------------------------------------*/
BITMAPINFO* DibCopyToPackedDib(HDIB hdib, BOOL fUsedGlobal)
{
    BITMAPINFO* pPackedDib;
    DWORD  dwDibSize;
    HGLOBAL  hGlobal = NULL;
    PDIBSTRUCT pdib = hdib;
    RGBQUAD* prgb;
    BYTE*    pBits;
    int iNumColors;
    HDC hdcMem;
    if (!DibIsValid(hdib))
        return NULL;
    //为紧凑型DIB分配内存
    dwDibSize = DibTotalSize(hdib);

    if (fUsedGlobal)
    {
        hGlobal = GlobalAlloc(GHND | GMEM_SHARE, dwDibSize);
        pPackedDib = GlobalLock(hGlobal);
    } else
    {
        pPackedDib = malloc(dwDibSize);
    }

    if (NULL == pPackedDib)
        return NULL;
    //复制信息头
    CopyMemory(pPackedDib, &pdib->ds.dsBmih, sizeof(BITMAPINFOHEADER));

    prgb = (RGBQUAD*)((BYTE*)pPackedDib + sizeof(BITMAPINFOHEADER));

    //复制可能的颜色遮罩
    if (pdib->ds.dsBmih.biCompression == BI_BITFIELDS)
    {
        CopyMemory(prgb, pdib->ds.dsBitfields, 3 * sizeof(DWORD));
        prgb = (RGBQUAD*)((BYTE*)prgb + 3 * sizeof(DWORD));
    }
    //复制颜色表
    if (iNumColors = DibNumColors(hdib))
    {
        hdcMem = CreateCompatibleDC(NULL);
        SelectObject(hdcMem, pdib->hBitmap);
        GetDIBColorTable(hdcMem, 0, iNumColors, prgb);
        DeleteDC(hdcMem);
    }

    //复制像素数据
    pBits = (BYTE*)(prgb + iNumColors);
    CopyMemory(pBits, pdib->pBits, DibBitsSize(hdib));
    //如果最后一个参数是TRUE,解锁全局内存块,并将全局句块转化为指针返回
    if (fUsedGlobal)
    {
        GlobalUnlock(hGlobal);
        pPackedDib = (BITMAPINFO*)hGlobal;
    }
    return pPackedDib;
}
/*-----------------------------------------------------------------------------------
DibCopyFromPackedDib:通常用于从剪贴板中粘贴DIBs
-----------------------------------------------------------------------------------*/
HDIB DibCopyFromPackedDib(BITMAPINFO* pPackedDib)
{
    BYTE*  pBits;
    DWORD  dwInfoSize, dwMaskSize, dwColorSize;
    int iBitCount;
    PDIBSTRUCT pdib;
    //获取信息头类型,并做有效性验证
    dwInfoSize = pPackedDib->bmiHeader.biSize;
    if (dwInfoSize != sizeof(BITMAPCOREHEADER) &&
        dwInfoSize != sizeof(BITMAPINFOHEADER) &&
        dwInfoSize != sizeof(BITMAPV4HEADER) &&
        dwInfoSize != sizeof(BITMAPV5HEADER))
    {
        return NULL;
    }
    //获取可能的颜色遮罩的大小
    if (dwInfoSize == sizeof(BITMAPINFOHEADER) &&
        pPackedDib->bmiHeader.biCompression == BI_BITFIELDS)
    {
        dwMaskSize = 3 * sizeof(DWORD);
    } else
    {
        dwMaskSize = 0;
    }
    //获取颜色表的大小
    if (dwInfoSize == sizeof(BITMAPCOREHEADER))
    {
        iBitCount = ((BITMAPCOREHEADER*)pPackedDib)->bcBitCount;
        if (iBitCount <= 8)
        {
            dwColorSize = (1 << (iBitCount))*sizeof(RGBTRIPLE);
        } else
            dwColorSize = 0;
    } else   //所有非OS/2的DIBs
    {
        if (pPackedDib->bmiHeader.biClrUsed >0)
        {
            dwColorSize = pPackedDib->bmiHeader.biClrUsed*sizeof(RGBQUAD);
        } else if (pPackedDib->bmiHeader.biBitCount <= 8)
        {
            dwColorSize = (1 << pPackedDib->bmiHeader.biBitCount)*sizeof(RGBQUAD);
        } else
        {
            dwColorSize = 0;
        }
    }
    //最后,获得pPackedDIB像素位的指针
    pBits = (BYTE*)pPackedDib + dwInfoSize + dwMaskSize + dwColorSize;
    //创建HDIB
    pdib = DibCreateFromInfo(pPackedDib);
    //复制像素位数据
    CopyMemory(pdib->pBits, pBits, DibBitsSize(pdib));
    return pdib;
}
/*----------------------------------------------------------------------------------
DibFileLoad:从DIB文件中创建DIB Section
-----------------------------------------------------------------------------------*/
HDIB DibFileLoad(const TCHAR* szFileName)
{
    HANDLE hFile;
    BITMAPFILEHEADER bmfh;
    BITMAPINFO* pbmi;
    BOOL bSuccess;
    DWORD dwInfoSize, dwBytesRead, dwBitsSize;
    HDIB hDib;
    //打开文件(设为可读可写)
    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;
    }
    //分配信息头大小,并读入数据
    dwInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
    pbmi = malloc(dwInfoSize);
    if (NULL == pbmi)
    {
        CloseHandle(hFile);
        return NULL;
    }
    bSuccess = ReadFile(hFile, pbmi, dwInfoSize, &dwBytesRead, NULL);
    if (!bSuccess || (dwBytesRead != dwInfoSize))
    {
        CloseHandle(hFile);
        free(pbmi);
        return NULL;
    }
    //根据BITMAPINFO结构体来创建DIB
    hDib = DibCreateFromInfo(pbmi);
    free(pbmi);
    if (NULL == hDib)
    {
        CloseHandle(hFile);
        return NULL;
    }
    //读取像素位数据,放到DIBSTRUCT结构中pBits字段指向的空间中去
    dwBitsSize = bmfh.bfSize - bmfh.bfOffBits;
    bSuccess = ReadFile(hFile, ((PDIBSTRUCT)hDib)->pBits, dwBitsSize, &dwBytesRead, NULL);
    CloseHandle(hFile);
    if (!bSuccess || (dwBytesRead != dwBitsSize))
    {
        DibDelete(hDib);
        return NULL;
    }
    return hDib;
}
/*----------------------------------------------------------------------------------
DibFileSave:将DIB Section位图保存到文件中
-----------------------------------------------------------------------------------*/
BOOL DibFileSave(HDIB hdib, const TCHAR* szFileName)
{
    BITMAPFILEHEADER bmfh;
    BITMAPINFO*  pbmi;
    BOOL   bSuccess;
    DWORD  dwTotalSize, dwBytesWritten;
    HANDLE  hFile;
    hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL,
                       CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hFile)
        return FALSE;
    dwTotalSize = DibTotalSize(hdib);
    bmfh.bfType = *(WORD*)"BM";
    bmfh.bfSize = sizeof(BITMAPFILEHEADER) + dwTotalSize;
    bmfh.bfReserved1 = 0;
    bmfh.bfReserved2 = 0;
    bmfh.bfOffBits = bmfh.bfSize - DibBitsSize(hdib);
    //写入BITMAPFILEHEADER
    bSuccess = WriteFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
    if (!bSuccess || (dwBytesWritten != sizeof(BITMAPFILEHEADER)))
    {
        CloseHandle(hFile);
        DeleteFile(szFileName);
        return FALSE;
    }
    //获取整个紧凑型DIB格式
    pbmi = DibCopyToPackedDib(hdib, FALSE);
    if (NULL == pbmi)
    {
        CloseHandle(hFile);
        DeleteFile(szFileName);
        return FALSE;
    }
    //写入pbmi指定的整个紧凑型DIB
    bSuccess = WriteFile(hFile, pbmi, dwTotalSize, &dwBytesWritten, NULL);
    CloseHandle(hFile);
    free(pbmi);
    if (!bSuccess || (dwBytesWritten != dwTotalSize))
    {
        DeleteFile(szFileName);
        return FALSE;
    }
    return TRUE;
}
/*----------------------------------------------------------------------------------
DibCopyToDdb:更高效的屏幕显示
-----------------------------------------------------------------------------------*/
HBITMAP DibCopyToDdb(HDIB hdib, HWND hwnd, HPALETTE hPalette)
{
    HBITMAP  hBitmap;
    BITMAPINFO* pbmi;
    HDC hdc;

    if (!DibIsValid(hdib))
        return NULL;
    if (NULL == (pbmi = DibCopyToInfo(hdib)))
        return NULL;
    hdc = GetDC(hwnd);
    if (hPalette)
    {
        SelectPalette(hdc, hPalette, FALSE);
        RealizePalette(hdc);
    }
    hBitmap = CreateDIBitmap(hdc, DibInfoHeaderPtr(hdib), CBM_INIT,
                             DibBitsPtr(hdib), pbmi, DIB_RGB_COLORS);
    ReleaseDC(hwnd, hdc);
    free(pbmi);
    return hBitmap;
}
/*----------------------------------------------------------------------------------
DibFlipHorizontal:调用没有优化的DibSetPixel和DibGetPixel
----------------------------------------------------------------------------------*/
HDIB DibFlipHorizontal(HDIB hdibSrc)
{
    HDIB hdibDst;
    int cx, cy, x, y;
    if (!DibIsAddressable(hdibSrc))
        return NULL;
    if (NULL == (hdibDst = DibCopy(hdibSrc, FALSE)))
        return NULL;
    cx = DibWidth(hdibSrc);
    cy = DibHeight(hdibSrc);
    for (x = 0; x < cx; x++)
        for (y = 0; y < cy; y++)
        {
            DibSetPixel(hdibDst, x, cy - 1 - y, DibGetPixel(hdibSrc, x, y));
        }

    return  hdibDst;
}
/*----------------------------------------------------------------------------------
DibRotateRight:调用优化过的DibSetPixelx和DibGetPixelx
----------------------------------------------------------------------------------*/
HDIB DibRotateRight(HDIB hdibSrc)
{
    HDIB hdibDst;
    int cx, cy, x, y;
    if (!DibIsAddressable(hdibSrc))
        return NULL;
    if (NULL == (hdibDst = DibCopy(hdibSrc, TRUE)))
        return NULL;
    cx = DibWidth(hdibSrc);
    cy = DibHeight(hdibSrc);
    switch (DibBitCount(hdibSrc))
    {
    case 1:
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibSetPixel1(hdibDst, cy - 1 - y, x, DibGetPixel1(hdibSrc, x, y)); //坐标旋转
            }
        break;
    case 4:
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibSetPixel4(hdibDst, cy - 1 - y, x, DibGetPixel4(hdibSrc, x, y));
            }
        break;
    case 8:
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibSetPixel8(hdibDst, cy - 1 - y, x, DibGetPixel8(hdibSrc, x, y));
            }
        break;
    case 16:
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibSetPixel16(hdibDst, cy - 1 - y, x, DibGetPixel16(hdibSrc, x, y));
            }
        break;
    case 24:
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibSetPixel24(hdibDst, cy - 1 - y, x, DibGetPixel24(hdibSrc, x, y));
            }
        break;
    case 32:
        for (x = 0; x < cx; x++)
            for (y = 0; y < cy; y++)
            {
                DibSetPixel32(hdibDst, cy - 1 - y, x, DibGetPixel32(hdibSrc, x, y));
            }
        break;
    }
    return hdibDst;
}

//未完,接下一篇

时间: 2024-11-07 04:06:36

第16章 调色板管理器_16.4 一个DIB位图库的实现(1)的相关文章

第16章 调色板管理器_16.4 一个DIB位图库的实现(2)

//接上一篇 //DibPal.h /*----------------------------------------------------------------- DIBPAL.H header file for DIBPAL.C -----------------------------------------------------------------*/ #pragma once; #include <windows.h> #include "DibHelp.h&q

第16章 调色板管理器_16.1 调色板原理和使用

16.1 调色板的使用 16.1.1 调色板原理 注意: ①使用调色板前要创建逻辑调色板,选入并实现调色板.在映射过程中,逻辑调色板中的颜色会被相等匹配.或近似匹配.或新增加进系统调色板中(见后面分析) ②Windows规定,活动窗口(标题栏高亮显示的程序)的逻辑调色板(如果有的话)具有最高的实现优先权,这是因为活动窗口是当前与用户交互的窗口,应该保证其有最佳的颜色显示.非活动窗口的优先权是按Z顺序自上到下确定的(Z顺序就是重叠窗口的重叠顺序).活动窗口有权将其逻辑调色板作为前景调色板实现,非活

第16章 调色板管理器_16.2 调色板动画

16.2.1 弹球 (1)AnimatePallette(hPalette,uStart,uNum,&pe); ①必须运行在支持调色板的视频模式下(即256色,兼容256色不行) ②每个调色板条目PALETTEENTRY的peFlags要设为pC_RESERVED,才能出现动画 ③uStart是原始逻辑调色板表的索引,不是PALETTEENTRY数组的索引 ④该函数即改变了逻辑调色板的条目,又改变了系统调色板和映射表.所有窗口无需重绘,更改结果直接从视频显示器上反映出来.(可与SetPalett

第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文件 /*--------

流畅的python第十五章上下文管理器和else块学习记录

with 语句和上下文管理器for.while 和 try 语句的 else 子句 with 语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文.这么做能避免错误并减少样板代码,因此 API 更安全,而且更易于使用.除了自动关闭文件之外,with 块还有很多用途 else 子句不仅能在 if 语句中使用,还能在 for.while 和 try 语句中使用 for 仅当 for 循环运行完毕时(即 for 循环没有被 break 语句中止)才运行 else 块.while 仅

转:OGRE场景管理器介绍

一个场景代表在虚拟世界中显示的物品.场景可以包括静态几何体(比如地形或者室内),模型(比如树.椅子等),光和摄像机.场景有下面种类.室内场景:可能由走廊.有家具的屋子和挂着装饰品的墙组成.室外场景:可能由山,树木,微微摇动的草地,飘着云彩的天空组成.Ogre提供了一套不同的场景管理器,每一种特别支持某种场景,本文档将列出Ogre提供的场景管理器和它们的优缺点. 1 选择一个场景管理器 2 八叉树场景管理器(Octree Scene Manager) 3 地形场景管理器(Terrain Scene

AWT布局管理器

布局管理器 容器内可以存放各种组件,而组件的位置和大小是由容器内的布局管理器来决定的.在AWT中为我们提供了以下5种布局管理器: ①   FlowLayout 流式布局管理器 ②   BorderLayout 边界布局管理器 ③   GridLayout 网格布局管理器 ④   CradLayout 卡片布局管理器 ⑤   GridBagLayout 网格包布局管理器 容器中组件的布局通常由布局管理器控制.每个Container(比如一个Panel或一个Frame)都有一个与他相关的缺省布局管理

HttpClient 4.3.6教程 第2章 连接管理 【翻译】

第2章 连接管理 2.1 持久连接 一个主机与另一端建立连接是十分复杂的,并且两个终端间要交换多个信息包,这会耗费不少时间.对于低级的HTTP消息来说握手连接是尤其重要的.如果在执行多个请求时重复使用公共的连接,那么就能大大提高数据吞吐率.HTTP/1.1默认允许HTTP连接可以被多个请求复用.HTTP/1.0也兼容终端为了多个请求去使用一个明确的机制来优先保持活跃的连接.HTTP代理也能在一定的同期时间里保持活跃的空闲连接,以免同样的目标主机随后还要请求.这种保持活跃连接的能力通常都会涉及持续

【java】浅析java组件中的布局管理器

这篇博文笔者介绍一下java组件中,常用的布局管理器.java组件中的布局方式有好几十种,所有的这些布局管理器都实现了java.awt.LayoutManager接口.接下来笔者介绍一下常用的5种布局管理器,FlowLayout.BorderLayout.GridLayout.GridBagLayout.CardLayout.BoxLayout.如果不希望使用布局管理器,可以调用组件的 setLayout(null); ,但是不建议设置layout为null,因为这样就失去了跨平台特性,和jav