zoukankan      html  css  js  c++  java
  • 第15章 设备无关位图_15.3 DIB和DDB的结合

    第15章 设备相关位图_15.3 DIB和DDB的结合
    15.3.1 从DIB创建DDB

    (1)hBitmap =CreateDIBitmap(…)——注意这名称会误导,实际上创建的是DDB

    参数

    说明

    hdc

    设备环境句柄,可以为NULL。

    pInfoHdr

    指向DIB信息头的指针,即BITMAPINFOHEADER

    fInit

    0或CBM_INIT。CBM_INIT指定用后面3个参数来初始化DDB中的像素位

    pBits

    DIB像素位的指针

    pInfo

    DIB信息指针,即BITMAPINFO(包含BITMAPINFOHEADER和颜色表)

    fClrUse

    颜色使用标志位:DIB_RGB_COLORS(0)或DIB_PAL_COLORS(1)

    注意:①返回值:跟CreateBitmap一样都返回一个GDI位图对象,可以直接选入DC中,并在上面绘图,以改变像素位。

         ②名称会误导,它是从一个DIB中创建一个DDB。

    (2)CreateDIBitmap函数内部大致的代码实现

    HBITMAP CreateDIBitmap(HDC hdc, CONST BITMAPINFOHEADER* pbmih,
         DWORD fInit, CONST VOID* pBits,CONST BITMAPINFO* pbmi, UINT fUsage)
    {
         HBITMAP hBitmap;
         HDC     hdc,hdcMem;
    
         int     cx, cy, iBitCount;
    
         //从第2个参数读取DIB信息头的信息
         if (pbmih->biSize == sizeof(BITMAPCOREHEADER))
         {
             cx = ((PBITMAPCOREHEADER)pbmih)->bcWidth;
             cy = ((PBITMAPCOREHEADER)pbmih)->bcHeight;
    
             iBitCount = ((PBITMAPCOREHEADER)pbmih)->bcBitCount;
         }
         else
         {
             cx = pbmih->biWidth;
             cy = pbmih->biHeight;
             iBitCount = pbmih->biBitCount;
         }
     
         //创建DDB
         if (hdc)
             hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
         else
             hBitmap = CreateBitmap(cx, cy, 1, 1, NULL);//单色位图
    
         //后面4个参数是用来初始化DDB的
         if (fInit == CBM_INIT)
         {
             hdcMem = CreateCompatibleDC(hdc);
             SelectObject(hdcMem, hBitmap);
    
             //在内存位图表面绘图,注意这里是DDB位图,己被选入内存DC
             SetDIBitsToDevice(hdcMem, 0, 0, cx, cy, 0, 0, 0, cy, pBits, pbmi, fUsage);
             DeleteDC(hdcMem);
         }
         return hBitmap;
    }

    (3)应用举例

      ①创建单色GDI位图:hBitmap =CreateDIBitmap(NULL,pbmih,0,NULL,NULL,0);

      ②DC兼容位图:hBitmap = CreateDIBitmap(hdc,pbmih,0,NULL,NULL,0);//未初始化

    (4)当CreateDIBitmap时未初始化像素位,后期可调用SetDIBits初始化DDB像素位

    参数

    说明

    hdc

    设备环境句柄,当DIB_PAL_COLORS时才需要设备hdc

    hBitmap

    要设置像素位的位图句柄

    yScan

    要转换的第一行扫描线

    cyScans

    扫描线的行数

    pBits

    将该像素位设给hBitmap的像素位。

    pInfo

    指向DIB信息头的指针

    fClrUse

    颜色使用标志

    【DIBCONV程序】

    /*------------------------------------------------------------
    DIBCONV.C --Converts a DIB to a DDB
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #include <windows.h>
    #include "resource.h"
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    static TCHAR szAppName[] = TEXT("DibConv");
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       PSTR szCmdLine, int iCmdShow)
    {
        HWND         hwnd;
        MSG          msg;
        WNDCLASSEX     wndclass;
        HACCEL       hAccel;
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.cbSize = sizeof(WNDCLASSEX);
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(hInstance, szAppName);
        wndclass.hIconSm = LoadIcon(hInstance, szAppName);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName = szAppName;
        wndclass.lpszClassName = szAppName;
        if (!RegisterClassEx(&wndclass))
        {
            MessageBox(NULL, TEXT("This program requires Windows NT!"),
                       szAppName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(szAppName,                  // window class name
                            TEXT("DIB to DDB Conversion"), // window caption
                            WS_OVERLAPPEDWINDOW,        // window style
                            CW_USEDEFAULT,              // initial x position
                            CW_USEDEFAULT,              // initial y position
                            CW_USEDEFAULT,              // initial x size
                            CW_USEDEFAULT,              // initial y size
                            NULL,                       // parent window handle
                            NULL,                       // window menu handle
                            hInstance,                  // program instance handle
                            NULL);                     // creation parameters
    
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
        hAccel = LoadAccelerators(hInstance, szAppName);
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if (!TranslateAccelerator(hwnd, hAccel, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return msg.wParam;
    }
    HBITMAP   CreateBitmapObjectFromDibFile(HDC hdc, PTSTR szFileName)
    {
        HBITMAP hBitmap;
        BITMAPFILEHEADER* pbmfh;
        BOOL    bSuccess;
        HANDLE  hFile;
        DWORD   dwFileSize, dwHighSize, dwBytesRead;
        //打开位图,可读可写
        hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                           OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
            return NULL;
        //读入整个文件
        dwFileSize = GetFileSize(hFile, &dwHighSize);
        if (dwHighSize)
        {
            CloseHandle(hFile);
            return NULL;
        }
        pbmfh = malloc(dwFileSize);
        if (!pbmfh)
        {
            CloseHandle(hFile);
            return NULL;
        }
        bSuccess = ReadFile(hFile, pbmfh, dwFileSize, &dwBytesRead, NULL);
        CloseHandle(hFile);
        //检验是否是位图
        if (!bSuccess || (dwBytesRead != dwFileSize) || (pbmfh->bfType != *(WORD*)"BM"))
        {
            free(pbmfh);
            return NULL;
        }
        //创建DDB——注意,这里读入整个文件,并从该DIB文件读入信息头、像素位等信息
        hBitmap = CreateDIBitmap(hdc, (BITMAPINFOHEADER*)(pbmfh + 1),
                                 CBM_INIT,
                                 (BYTE*)pbmfh + pbmfh->bfOffBits,
                                 (BITMAPINFO*)(pbmfh + 1),
                                 DIB_RGB_COLORS);
        free(pbmfh);
        return hBitmap;
    }
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static TCHAR szFilter[] = TEXT("Bitmap File(*.bmp)*.bmp")
            TEXT("All Files(*.*)*.*");
        static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
        static cxClient, cyClient;
        static HBITMAP hBitmap;
        HDC         hdc, hdcMem;
        PAINTSTRUCT ps;
        BITMAP  bitmap;
        static OPENFILENAME  ofn;
        switch (message)
        {
        case WM_CREATE:
            memset(&ofn, 0, sizeof(OPENFILENAME));
            ofn.lStructSize = sizeof(OPENFILENAME);
            ofn.hwndOwner = hwnd;
            ofn.lpstrFilter = szFilter;
            ofn.lpstrFile = szFileName;
            ofn.nMaxFile = MAX_PATH;
            ofn.lpstrTitle = szTitleName;
            ofn.nMaxFileTitle = MAX_PATH;
            ofn.lpstrDefExt = TEXT("*.bmp");
            return 0;
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            return 0;
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case IDM_FILE_OPEN:
                //显示打开对话框
                if (!GetOpenFileName(&ofn))
                    return 0;
                //删除己经打开的位图
                if (hBitmap)
                {
                    DeleteObject(hBitmap);
                    hBitmap = NULL;
                }
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
                //从DIB位图文件中创建DDB
                hdc = GetDC(hwnd);
                hBitmap = CreateBitmapObjectFromDibFile(hdc, szFileName);
                ReleaseDC(hwnd, hdc);
                ShowCursor(FALSE);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
                //更新客户区内容
                InvalidateRect(hwnd, NULL, TRUE);
                //错误提示
                if (hBitmap == NULL)
                {
                    MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, MB_OK | MB_ICONEXCLAMATION);
                }
                return 0;
            }
            break;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            if (hBitmap)
            {
                GetObject(hBitmap, sizeof(BITMAP), &bitmap);
                hdcMem = CreateCompatibleDC(hdc);
                SelectObject(hdcMem, hBitmap);
                BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
                DeleteDC(hdcMem);
            }
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            if (hBitmap)
                DeleteObject(hBitmap);
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    //resource.h

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

    //DibConv.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
    //
    DIBCONV MENU
    BEGIN
    POPUP "&File"
    BEGIN
    MENUITEM "&Open...	Ctrl+O", IDM_FILE_OPEN
    END
    END
    /////////////////////////////////////////////////////////////////////////////
    //
    // Accelerator
    //
    DIBCONV ACCELERATORS
    BEGIN
    "^O", IDM_FILE_OPEN, ASCII, NOINVERT
    END
    #endif    // 中文(简体,中国) resources
    /////////////////////////////////////////////////////////////////////////////
    #ifndef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 3 resource.
    //
    /////////////////////////////////////////////////////////////////////////////
    #endif    // not APSTUDIO_INVOKED

    15.3.2 从DDB到DIB

    (1)GetDIBits函数——将DDB转成DIB(即从hBitmap中获得pInfo,pBits等信息)

    参数

    说明

    hdc

    设备环境句柄

    hBitmap

    要获取像素位的位图句柄

    yScan

    要转换的第一行扫描线

    cyScans

    扫描线的行数

    pBits

    将hBitmap的像素位读入该内存中。

    pInfo

    指向DIB信息头的指针

    fClrUse

    颜色使用标志

    注意:

    ①这个函数并不是SetDIBits的简单逆运算而己。因为DIB转为设备相关的格式时,会有信息的丢失。

    ②实际上很少用到这个函数,因为如果有能拿hBitmap句柄,却没有位图数据信息的情况很少(如剪贴板),但剪贴板提供了自动转换为DIB的功能。

    15.3.3 DIB 区块(DIB Section)

    (1)DDB和DIB的区别

    区别

    DDB(Windows内部结构)

    DIB(数据结构是己公布的)

    颜色组织

    必须是黑白或与实际输出设备一样的格式(不含颜色表,,像素值表示索引或黑白,因数据结构未公布,不能直接访问像素位)

    采用几种颜色格式之一(可以有自己的颜色表,像素位可直接访问)

    每行像素数

    2的倍数

    4的倍数

    对象构成

    一个GDI位图对象,要通过选入内存dc来更改像素位或绘图.用一个hBitmap位图句柄来表示。

    使用方法:

    //加载或创建DDB,而资源位图本身是DIB

    hBitmap =LoadBitmap(…)

    //创建兼容DC,因为是设备相关的。

    hdcMem = CreateCompatibleDC(hdc);

    //选入dc

    SelectObject(hdc,hBitmap);

    //画图,改变hBitmap像素位

    Rectange(hdcMem…)

    //显示到设备环境中

    BitBlt(hdc,…,hdcMem…,SRCCOPY);

    //删除等

    DeleteDC(hdcMem);

    是个文件或内存区域,内存结构与文件结构类似,可直接通过pBits更改像素位。

    使用方法:

    //读入位图文件

    hFile = CreateFile(…);

    //从文件中DIB位图读入整个或部分DIB的信息

    //分配文件头内存,读入信息

    pbmhf =malloc(…);//文件头

    pbmi = malloc(…);//信息头

    pBits = malloc(…); //像素位数据

    //读入各部分的信息

    ReadFile(hFile,&pbmhf,….)

    //显示

    SetDIBtoDevice(hdc,…);//输出,可以不需要内存兼容DC(因为设备无关)

    存在形式

    只能存在于内存中

    可存在于内存或文件中

    转换

    可相互转换,但涉及设备无关的像素位与设备相关像素位的转换

    (2)CreateDIBSection函数——返回的对象是个“杂种”:即是GDI位图对象(DDB),又更像DIB(有pBits和pInfo),意味着可以选入设备环境修改像素位,也可以直接修改像素位。

    参数

    说明

    hdc

    设备环境句柄,只有在fClrUse设为DIB_PAL_COLORS时才可以要设置hdc。当fClrUse设为DIB_RGB_COLORS时,hdc将被忽略。

    pInfo

    指向DIB信息的指针

    fClrUse

    颜色使用标志——DIB_RGB_COLORS或DIB_PAL_COLORS。

    ppBits

    指向像素位指针的指针。

    1、该函数调用时,会把pBits设置成指向某个内存块的指针(该内存由系统管理,DeleteObject(hBitmap)时自动释放,调用函数时,实际上并未为该空间预留大小,只有在赋值时,才会占用空间,我们的程序也不需要自己为pBits分配空间),在调用该函数完后,程序可以从DIB文件中读入像素位到pBits指向的这块内存里。

    2、可以将位图选入内存设备中,然后用GDI在上面绘图,其结果反映在由pBits指向的DIB像素位中,但因GDI采用批量处理,所以绘图结束后,要调用GDIFlush,以便真正的保存起来,也可以“手工”地访问像素位。

    hSection

    文件映射对象句柄

    dwOffSet

    像素位数据在上述对象中的偏移。MSDN指出,这个参数必须是4的倍数。

    注意:创建出来的位图对象,是每行的字节数是4的倍数,也就是更像DIB。

    (3)应用举例

       /*创建384*256像素的DIB,每个像素为24位*/   
         BITMAPINFOHEADER bmih;
         BYTE*            pBits;
         HBITMAP          hBitmap;
     
         bmih.biSize = sizeof(BITMAPINFOHEADER);
         bmih.biWidth = 384;
         bmih.biHeight = 256;
         bmih.biPlanes = 1;
         bmih.biBitCount = 24;
         bmih.biCompression = BI_RGB;
         bmih.biSizeImage = 0;
         bmih.biXPelsPerMeter = 0;
         bmih.biYPelsPerMeter = 0;
         bmih.biClrUsed = 0;
         bmih.biClrImportant = 0;
    /* 1、因24位,没颜色表,所以可以直接将bmih指针转为BITMAPINFO指针。 2、初始时pBits等于NULL,该函数会把pBits指针掰过来指向由系统维护的某内存块,我们的程序不必为pBits分配空间大小,在赋值是操作系统会自行分配,删除位图对象后该空间也会自行释放,程序不必自己释放。 */ hBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmih, 0, &pBits, NULL, 0);
    //从DIB文件中读入像素位到pBits中。 ReadFile(hFile, &pBits, ...);

    (4)获取DIB区块信息——GetObject(hBitmap,sizeof(DIBSECTION),&dibsection);

    DIBSECTION字段

    含义

    BITMAP dsBm

    BITMAP结构

    BITMAPINFOHEADER dsBmih

    DIB信息头

    DWORD    dsBitfields[3]

    颜色遮罩

    HANDLE   dshSection

    文件映射对象句柄

    DWORD    dsOffset

    像素位数据的位移

    注意:

    1、该函数只能用在CreateDIBSection创建的位图对象,不能用在其他创建位图的函数返回的句柄上。

    2、CreateDIBSection也可以通过GetObject(hBitmap,sizeof(BITMAP),&bm)返回位图信息。

    3、该结构体不包括颜色表,如果用获得颜色表,可以将位图选入内存DC后,调用GetDIBColorTable来获得。

    (5)DIB显示到屏幕——必须从设备无关的像素转换到设备相关的像素

    函数

    格式转换时机

    SetDIBitsToDevice

    StretchDIBits

    发生在函数中

    CreateDIBitmap

    SetDIBits

    1、未设置CBM_INIT时,发生在用 BitBlt或StretchBlt显示的时候或SetDIBits时

    2、设置CBM_INIT时:发生在CreateDIBitmap函数中

    CreateDIBSection创建区块

    发生在用BitBlt或StretchBlt显示函数中。(注意:CreateDIBSection返回句柄实际上是DIB,但可以用BitBlt和StretchBlt函数显示),再次说明该返回值是个杂种,兼有DDB和DIB的特点。

    (6)文件映射选项——CreateDIBSection的最后两个参数

    ①文件映射:把文件当作是己经存在于内存中,可以通过内存指针来访问,但并不需要把文件完全放到内存中。

    ②这项技术可减少内存需要。DIB像素位可保存在磁盘上,但却可以像内存一样的访问。但像素位必须保存在另外的文件中,不能是实际DIB文件的一部分。

      hFile = CreateFile(szFileName,…);

      …… //读入文件头(BITMAPFILEINFO)和信息头(BITMAPINFOHEADER)

      hFileMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,NULL);

      hBitmap = CreateDIBSection(NULL,pbmi,DIB_RGB_COLORS,&pBits,

      hFileMap,bmfh.bfOffBits);//bfOffBits永远不会是4的倍数!

                                             //与MSDN要求不符,该代码不能用。


    【DIBSecion程序】
    效果图

    /*------------------------------------------------------------
    DIBSECTION.C --Displays a DIB Section in the Client area
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #include <windows.h>
    #include "resource.h"
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    static TCHAR szAppName[] = TEXT("DibSection");
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       PSTR szCmdLine, int iCmdShow)
    {
        HWND         hwnd;
        MSG          msg;
        WNDCLASSEX     wndclass;
        HACCEL       hAccel;
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.cbSize = sizeof(WNDCLASSEX);
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(hInstance, szAppName);
        wndclass.hIconSm = LoadIcon(hInstance, szAppName);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName = szAppName;
        wndclass.lpszClassName = szAppName;
        if (!RegisterClassEx(&wndclass))
        {
            MessageBox(NULL, TEXT("This program requires Windows NT!"),
                       szAppName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(szAppName,                  // window class name
                            TEXT("DIB Section Display"), // window caption
                            WS_OVERLAPPEDWINDOW,        // window style
                            CW_USEDEFAULT,              // initial x position
                            CW_USEDEFAULT,              // initial y position
                            CW_USEDEFAULT,              // initial x size
                            CW_USEDEFAULT,              // initial y size
                            NULL,                       // parent window handle
                            NULL,                       // window menu handle
                            hInstance,                  // program instance handle
                            NULL);                     // creation parameters
    
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
        hAccel = LoadAccelerators(hInstance, szAppName);
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if (!TranslateAccelerator(hwnd, hAccel, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return msg.wParam;
    }
    HBITMAP   CreateDibSectionFromDibFile(PTSTR szFileName)
    {
        HBITMAP hBitmap;
        BITMAPFILEHEADER  bmfh;
        BITMAPINFO*       pbmi;
        BYTE*             pBits;
        BOOL    bSuccess;
        HANDLE  hFile;
        DWORD   dwInfoSize, dwBytesRead;
        //打开位图,可读可写
        hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                           OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
            return NULL;
        //与前一个程序(DIBConv)不同,这里不读入整个文件,而是只读取文件头
        bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);
        if (!bSuccess || (dwBytesRead != sizeof(BITMAPFILEHEADER))
            || (bmfh.bfType != *(WORD*)"BM"))
        {
            CloseHandle(hFile);
            return NULL;
        }
        //为BITMAPINFO分配内存,并读入数据
        dwInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
        pbmi = malloc(dwInfoSize);
        bSuccess = ReadFile(hFile, pbmi, dwInfoSize, &dwBytesRead, NULL);
        //创建DDB——函数调用后,pBits指针会被掰向,一个存放像素数的内存,该内存由系统维护。
        hBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0);
        //为像素位内存写入像素数据
        ReadFile(hFile, pBits, bmfh.bfSize - bmfh.bfOffBits, &dwBytesRead, NULL);
    
        free(pbmi);
        CloseHandle(hFile);
        return hBitmap;
    }
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static TCHAR szFilter[] = TEXT("Bitmap File(*.bmp)*.bmp")
            TEXT("All Files(*.*)*.*");
        static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
        static cxClient, cyClient;
        static HBITMAP hBitmap;
        HDC         hdc, hdcMem;
        PAINTSTRUCT ps;
        BITMAP  bitmap;
        static OPENFILENAME  ofn;
        switch (message)
        {
        case WM_CREATE:
            memset(&ofn, 0, sizeof(OPENFILENAME));
            ofn.lStructSize = sizeof(OPENFILENAME);
            ofn.hwndOwner = hwnd;
            ofn.lpstrFilter = szFilter;
            ofn.lpstrFile = szFileName;
            ofn.nMaxFile = MAX_PATH;
            ofn.lpstrTitle = szTitleName;
            ofn.nMaxFileTitle = MAX_PATH;
            ofn.lpstrDefExt = TEXT("*.bmp");
            return 0;
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            return 0;
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case IDM_FILE_OPEN:
                //显示打开对话框
                if (!GetOpenFileName(&ofn))
                    return 0;
                //删除己经打开的位图
                if (hBitmap)
                {
                    DeleteObject(hBitmap);
                    hBitmap = NULL;
                }
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
                //从DIB位图文件中创建DDB(或DIB区块)
                hdc = GetDC(hwnd);
                hBitmap = CreateDibSectionFromDibFile(szFileName);
                ReleaseDC(hwnd, hdc);
                ShowCursor(FALSE);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
                //更新客户区内容
                InvalidateRect(hwnd, NULL, TRUE);
                //错误提示
                if (hBitmap == NULL)
                {
                    MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, MB_OK | MB_ICONEXCLAMATION);
                }
                return 0;
            }
            break;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            if (hBitmap)
            {
                GetObject(hBitmap, sizeof(BITMAP), &bitmap);
                hdcMem = CreateCompatibleDC(hdc);
                SelectObject(hdcMem, hBitmap);
                BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);
                DeleteDC(hdcMem);
            }
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            if (hBitmap)
                DeleteObject(hBitmap);
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    //resource.h

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

    //DibSection.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
    //
    DIBSECTION MENU
    BEGIN
    POPUP "&File"
    BEGIN
    MENUITEM "&Open...	Ctrl+O", IDM_FILE_OPEN
    END
    END
    /////////////////////////////////////////////////////////////////////////////
    //
    // Accelerator
    //
    DIBSECTION ACCELERATORS
    BEGIN
    "^O", IDM_FILE_OPEN, ASCII, NOINVERT
    END
    #endif    // 中文(简体,中国) resources
    /////////////////////////////////////////////////////////////////////////////
    #ifndef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 3 resource.
    //
    /////////////////////////////////////////////////////////////////////////////
    #endif    // not APSTUDIO_INVOKED
  • 相关阅读:
    bzoj5137 [Usaco2017 Dec]Standing Out from the Herd
    bzoj2434 [Noi2011]阿狸的打字机
    【20181024T2】小C的序列【GCD性质+链表】
    【20181024T3】小C的宿舍【分治】
    【20181024T1】小C的数组【二分+dp】
    【20181023T2】行星通道计划【二维BIT】
    【20181023T1】战争【反向并查集】
    【20181020T1】蛋糕
    【20181019T2】硬币【矩阵快速幂优化DP】
    【20181019T3】比特战争【最小生成树思想】
  • 原文地址:https://www.cnblogs.com/5iedu/p/4699072.html
Copyright © 2011-2022 走看看