• 第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)*.bmp")
            TEXT("All Files (*.*)*.*");
        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 	%i
    ")  //%i与%d一样的
                         TEXT("Pixel Height:	%i
    ")
                         TEXT("Bits per pixel:	%i
    ")
                         TEXT("Number of colors:	%i
    ")
                         TEXT("Compression:	%s
    "),
                         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"
    END
    2 TEXTINCLUDE
    BEGIN
    "#include ""winres.h""
    "
    ""
    END
    3 TEXTINCLUDE
    BEGIN
    "
    "
    ""
    END
    #endif    // APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Menu
    //
    DIBBLE MENU
    BEGIN
    POPUP "&File"
    BEGIN
    MENUITEM "&Open...	Ctrl+O", IDM_FILE_OPEN
    MENUITEM "&Save...	Ctrl+S", IDM_FILE_SAVE
    MENUITEM SEPARATOR
    MENUITEM "&Print...	Ctrl+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	Ctrl+X", IDM_EDIT_CUT
    MENUITEM "&Copy	Ctrl+C", IDM_EDIT_COPY
    MENUITEM "&Paste	Ctrl+V", IDM_EDIT_PASTE
    MENUITEM "&Delete	Delete", 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;
    }

     //未完,接下一篇

  • 相关阅读:
    【LeetCode每天一题】Rotate List(旋转链表)
    【LeetCode每天一题】Permutation Sequence(排列序列)
    【LeetCode每天一题】Length of Last Word(字符串中最后一个单词的长度)
    【LeetCode每天一题】Merge Intervals(合并区间)
    【LeetCode每天一题】Spiral Matrix II(螺旋数组II)
    Ajax基础
    git的命令行操作
    新闻发布系统之登录和注销
    JSTL和EL
    servlet模板的修改
  • 原文地址:https://www.cnblogs.com/5iedu/p/4701079.html
Copyright © 2020-2023  润新知