第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;
}

 //未完,接下一篇

原文地址:https://www.cnblogs.com/5iedu/p/4701079.html