zoukankan      html  css  js  c++  java
  • 第15章 设备无关位图_15.2 显示和打印DIB

    15.2.1 探究DIB

    (1)DIB文件的结构

    整个文件

    紧凑DIB(整个文件除文件头)

    文件头(File Header)

    信息头(Information Header)

    信息头(Information Header)

    颜色表(Color Table)

    颜色表(Color Table)

    像素位(Pixel Bits)

    像素位(Pixel Bits)

     注意:①紧凑DIB在内存中是连续的,即整个DIB存在单个内存块中

               ②DIB载入内存时,像素位与信息头可以分别存在两个内存块,即内存不连续。

    (2)像素位指针的求法

    15.2.2 从像素到像素

    (1)SetDIBitsToDevice函数——显示没有拉伸和压缩的DIB

    参数

    含义

    hdc

    设备环境句柄

    xDst

    目标矩形左上角x坐标(逻辑单位),这里的“左上角”指视觉上图像的左上角。

    yDst

    目标矩形左上角y坐标(逻辑单位)

    cxSrc

    源矩形宽度

    1、这四个参数可以决定是显示整个DIB或只显示一部分。

    2、对于自上而下的DIB,因BITMAPINFOHEADER的biHeight为负数,所以cySrc应设置为biHeight的绝对值,即biHeight永远要设为正数。

    3、无论映射模式怎样,在输出设备上显示的DIB总是cxSrc像素宽,cySrc像素高。

    cySrc

    源矩形高度

    xSrc

    源x坐标

    ySrc

    源y坐标

    yScan

    指定DIB中起始扫描线的编号(见后面的详细分析)。

    用来每次按顺序显示DIB的一部分。

    通常yScan=0,cyScan=DIB的高度。

    cyScan

    DIB扫描线数目

    pBits

    像素位指针

    pInfo

    DIB信息头指针

    fClrUse

    指向BITMAPINFO结构中的成员bmiColors是否包含明确的RGB值或对调色板进行索引的值。取值为下列之一,这些值的含义如下:

    DIB_PAL_COLORS(1):表示颜色表由16位的索引值数组组成,利用这些值可对当前选中的逻辑调色板进行索引。

    DIB_RGB_COLORS(0):表示颜色表包含原义的RGB值。

    返回值:返回函数调用后,显示DIB的所用的扫描行个数。

    【ShowDib1程序】
    效果图

    /*------------------------------------------------------------
    SHOWDIB1.C -- Show a DIB in the client area
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    
    #include <windows.h>
    #include "resource.h"
    #include "DibFile.h"
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    static TCHAR szAppName[] = TEXT("ShowDib1");
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       PSTR szCmdLine, int iCmdShow)
    {
        HWND         hwnd;
        MSG          msg;
        WNDCLASSEX   wndclass;
        HACCEL       hAccel;
    
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.cbSize = sizeof(WNDCLASSEX);
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(hInstance, szAppName);
        wndclass.hIconSm = LoadIcon(hInstance, szAppName);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName = szAppName;
        wndclass.lpszClassName = szAppName;
    
        if (!RegisterClassEx(&wndclass))
        {
            MessageBox(NULL, TEXT("This program requires Windows NT!"),
                       szAppName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(szAppName,                  // window class name
                            TEXT("Show DIB #1"), // window caption
                            WS_OVERLAPPEDWINDOW,        // window style
                            CW_USEDEFAULT,              // initial x position
                            CW_USEDEFAULT,              // initial y position
                            CW_USEDEFAULT,              // initial x size
                            CW_USEDEFAULT,              // initial y size
                            NULL,                       // parent window handle
                            NULL,                       // window menu handle
                            hInstance,                  // program instance handle
                            NULL);                     // creation parameters
    
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
        hAccel = LoadAccelerators(hInstance, szAppName);
        while (GetMessage(&msg, NULL, 0, 0))
        {
            if (!TranslateAccelerator(hwnd, hAccel, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        return msg.wParam;
    }
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static BITMAPFILEHEADER* pbmfh;
        static BITMAPINFO*       pbmi;
        static BYTE*             pBits;
    
        static TCHAR   szFileName[MAX_PATH], szTitleName[MAX_PATH];
        static int     cxClient, cyClient, cxDib, cyDib;
        HDC    hdc;
        PAINTSTRUCT ps;
        BOOL         bSuccess;
    
        switch (message)
        {
        case WM_CREATE:
    
            DibFileInitialize(hwnd);
            return 0;
    
        case WM_INITMENUPOPUP:
            EnableMenuItem((HMENU)wParam, IDM_FILE_SAVE, pbmfh ? MF_ENABLED : MF_GRAYED);
            return 0;
    
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            return 0;
    
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case IDM_FILE_OPEN:
                //显示打开对话框
                if (!DibFileOpenDlg(hwnd, szFileName, szTitleName))
                    return 0;
    
                //如果DIB文件己被载入,释放内存
                if (pbmfh)
                {
                    free(pbmfh);
                    pbmfh = NULL;
                }
    
                //将整个DIB加载到内存中
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
    
                pbmfh = DibLoadImage(szFileName);
    
                ShowCursor(FALSE);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
    
                //使客户区无效,以便后面的绘图并擦除以前客户区显示的内容
                InvalidateRect(hwnd, NULL, TRUE);
    
                if (pbmfh == NULL)
                {
                    MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, 0);
                    return 0;
                }
    
                //获取指向DIB信息头的指针和指向像素位的指针
                pbmi = (BITMAPINFO*)(pbmfh + 1);
                pBits = (BYTE*)pbmfh + pbmfh->bfOffBits;
    
                //获取图像的宽度和高度
                if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
                {
                    cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth;
                    cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight;
                } else
                {
                    cxDib = pbmi->bmiHeader.biWidth;
                    cyDib = abs(pbmi->bmiHeader.biHeight);
                }
                return 0;
    
            case IDM_FILE_SAVE:
    
                //显示保存对话框
                if (!DibFileSaveDlg(hwnd, szFileName, szTitleName))
                    return 0;
    
                //将DIB位图保存到文件中
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
    
                bSuccess = DibSaveImage(szFileName, pbmfh);
    
                ShowCursor(FALSE);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
    
                if (!bSuccess)
                    MessageBox(hwnd, TEXT("Cannot save DIB file"), szAppName, 0);
    
                return 0;
            }
            break;
    
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            if (pbmfh)
            {
                SetDIBitsToDevice(hdc,
                                  0,
                                  0,
                                  cxDib,   //像素宽度
                                  cyDib,   //像素高度
                                  0,       //xSrc
                                  0,       //ySrc
                                  0,       //第一扫描线
                                  cyDib,   //扫描线数目
                                  pBits,   //像素位
                                  pbmi,
                                  DIB_RGB_COLORS);
            }
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            if (pbmfh)
                free(pbmfh);
    
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    //DibFile.h

    /*-----------------------------------------------------
    DIBFILE.H ----  Header File for DIBFILE.C
    ------------------------------------------------------*/
    #pragma  once
    #include <windows.h>
    
    void DibFileInitialize(HWND hwnd);
    
    BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName);
    BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName);
    
    BITMAPFILEHEADER*  DibLoadImage(PTSTR pstrFileName);
    
    BOOL               DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER*);

    //DibFile.c

    #include "DibFile.h"
    
    static OPENFILENAME ofn;
    void DibFileInitialize(HWND hwnd)
    {
        static TCHAR szFilter[] = TEXT("Bitmap Files (*.BMP)*.bmp")
            TEXT("All Files(*.*)*.*");
    
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.hInstance = NULL;
        ofn.lpstrFilter = szFilter;
        ofn.lpstrCustomFilter = NULL;
        ofn.nMaxCustFilter = 0;
        ofn.nFilterIndex = 0;
        ofn.lpstrFile = NULL;  //在打开和关闭中设置
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFileTitle = NULL; //在打开和关闭函数中设置
        ofn.nMaxFileTitle = MAX_PATH;
        ofn.lpstrInitialDir = NULL;
        ofn.lpstrTitle = NULL;
        ofn.Flags = 0;     //在打开和关闭函数中设置
        ofn.nFileOffset = 0;
        ofn.nFileExtension = 0;
        ofn.lpstrDefExt = TEXT("bmp"); //默认扩展名
        ofn.lCustData = 0;
        ofn.lpfnHook = NULL;
        ofn.lpTemplateName = NULL;
    }
    
    BOOL DibFileOpenDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
    {
        ofn.hwndOwner = hwnd;
        ofn.lpstrFile = pstrFileName;
        ofn.lpstrFileTitle = pstrTitleName;
        ofn.Flags = 0;
        return GetOpenFileName(&ofn);
    }
    
    BOOL DibFileSaveDlg(HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
    {
        ofn.hwndOwner = hwnd;
        ofn.lpstrFile = pstrFileName;
        ofn.lpstrFileTitle = pstrTitleName;
        ofn.Flags = OFN_OVERWRITEPROMPT;
        return GetSaveFileName(&ofn);
    }
    
    BITMAPFILEHEADER*  DibLoadImage(PTSTR pstrFileName)
    {
        BOOL                bSuccess;
        DWORD               dwFileSize, dwHighSize, dwBytesRead;
        HANDLE              hFile;
        BITMAPFILEHEADER*   pbmfh;
    
        hFile = CreateFile(pstrFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
                           OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    
        if (hFile == INVALID_HANDLE_VALUE)
            return NULL;
    
        //返回文件大小的低位字,保存在dwFileSize中,高位字保存在dwHighSize中
        dwFileSize = GetFileSize(hFile, &dwHighSize);
    
        if (dwHighSize)  //文件太大,超过4G则dwHighSize不为0,退出
        {
            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") ||   //位图标志“BM”
            (pbmfh->bfSize != dwFileSize))
        {
            free(pbmfh);
            return NULL;
        }
    
        return pbmfh;
    }
    
    BOOL               DibSaveImage(PTSTR pstrFileName, BITMAPFILEHEADER* pbmfh)
    {
        BOOL     bSuccess;
        DWORD    dwBytesWritten;
        HANDLE   hFile;
    
        hFile = CreateFile(pstrFileName, GENERIC_WRITE, 0, NULL,
                           CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    
        if (hFile == INVALID_HANDLE_VALUE)
            return FALSE;
    
        bSuccess = WriteFile(hFile, pbmfh, pbmfh->bfSize, &dwBytesWritten, NULL);
        CloseHandle(hFile);
    
        if ((!bSuccess) || (dwBytesWritten != pbmfh->bfSize))
        {
            DeleteFile(pstrFileName);
            return FALSE;
        }
        return TRUE;
    }

    //resource.h

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

    //ShowDib1.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
    //
    
    SHOWDIB1 MENU
    BEGIN
    POPUP "&File"
    BEGIN
    MENUITEM "&Open...	Ctrl+O", IDM_FILE_OPEN
    MENUITEM "&Save...	Ctrl+S", IDM_FILE_SAVE
    END
    END
    
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // Accelerator
    //
    
    SHOWDIB1 ACCELERATORS
    BEGIN
    "^O", IDM_FILE_OPEN, ASCII, NOINVERT
    "^S", IDM_FILE_SAVE, ASCII, NOINVERT
    END
    
    #endif    // 中文(简体,中国) resources
    /////////////////////////////////////////////////////////////////////////////
    
    
    
    #ifndef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 3 resource.
    //
    
    
    /////////////////////////////////////////////////////////////////////////////
    #endif    // not APSTUDIO_INVOKED
     15.2.3 DIB的颠倒世界

    (1)自下而上DIB坐标说明

     

    源矩形

    目标矩形

    ①(xSrc,ySrc)—内存中第一个像素!

    ①(xDst,yDst+cySrc-1)

    ②(xSrc+cxSrc-1,ySrc)

    ②(xDst+cxSrc-1,yDst+cySrc-1)

    ③(xSrc,ySrc+cySrc-1)

    ③(xDst,yDst)

    ④(xSrc+cxSrc-1,ySrc+cySrc-1)—内存最后1个像素

    ④(xDst+cxSrc-1,yDst)

    注意:1、cxSrc,cySrc为区域宽度和高度,因为坐标从0开始,所以上面式子出现减1现象。

          2、原点(0,0)位于DIB图的左下角(左图中的①),第一行的第1个像素。

    (2)自上而下DIB坐标说明

     

    源矩形

    目标矩形

    ①(xSrc,ySrc+cySrc-1)—内存中第1个像素!

    ①(xDst,yDst)

    ②(xSrc+cxSrc-1,ySrc+cySrc-1)

    ②(xDst+cxSrc-1,yDst)

    ③(xSrc,ySrc)—这里不是第1 个像素!

    ③(xDst,yDst+cySrc-1)

    ④(xSrc+cxSrc-1,ySrc)—内存中最后1个像素

    ④(xDst+cxSrc-1,yDst+cySrc-1)

    注意:1、cxSrc,cySrc为区域宽度和高度,因为坐标从0开始,所以上面式子出现减1现象。

          2、原点(0,0)或(xSrc,ySrc)不是DIB图中第1 个像素,也不是最后1个像素,而是③,在图的左下角,即最后一行的第1个像素。

    【Apollo11程序】
     效果图
     
    /*------------------------------------------------------------
    APOLLO11.C -- Program for screen captures
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    
    #include <windows.h>
    #include "..\DibHeads\DibFile.h"
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    static TCHAR szAppName[] = TEXT("Apollo11");
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       PSTR szCmdLine, int iCmdShow)
    {
        HWND         hwnd;
        MSG          msg;
        WNDCLASSEX     wndclass;
    
        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 = NULL;
        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("Apollo 11"), // 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);
    
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        HDC         hdc;
        PAINTSTRUCT ps;
        static BITMAPFILEHEADER* pbmfh[2];
        static BITMAPINFO* pbmi[2];
        static BYTE* pBits[2];
        static int cxClient, cyClient, cxDib[2], cyDib[2];
    
        switch (message)
        {
        case WM_CREATE:
            pbmfh[0] = DibLoadImage(TEXT("Apollo11.bmp"));
            pbmfh[1] = DibLoadImage(TEXT("ApolloTD.bmp"));
            if (pbmfh[0] == NULL || pbmfh[1] == NULL)
            {
                MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, 0);
                return 0;
            }
    
            //获得信息头和像素位指针
            pbmi[0] = (BITMAPINFO*)(pbmfh[0] + 1);
            pbmi[1] = (BITMAPINFO*)(pbmfh[1] + 1);
    
            pBits[0] = (BYTE*)pbmfh[0] + pbmfh[0]->bfOffBits;
            pBits[1] = (BYTE*)pbmfh[1] + pbmfh[1]->bfOffBits;
    
            //获取图像大小(为方便,这里只处理BITMAPINFOHEADER结构的DIB)
            cxDib[0] = pbmi[0]->bmiHeader.biWidth;
            cyDib[0] = abs(pbmi[0]->bmiHeader.biHeight);  //绝对值!
    
            cxDib[1] = pbmi[1]->bmiHeader.biWidth;
            cyDib[1] = abs(pbmi[1]->bmiHeader.biHeight);  //绝对值!
            return 0;
    
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            return 0;
    
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            //从下到上DIB整图显示
            SetDIBitsToDevice(hdc,
                              0,
                              cyClient / 4, //yDst
                              cxDib[0],   //整幅图宽度
                              cyDib[0],   //整幅图高度
                              0,
                              0,
                              0,          //第一扫描线
                              cyDib[0],   //扫描线数量
                              pBits[0],
                              pbmi[0],
                              DIB_RGB_COLORS);
    
            //从下到上DIB局部图显示
            SetDIBitsToDevice(hdc,
                              240,
                              cyClient / 4, //yDst
                              80,          //图的局部(宽度)
                              166,         //图的局部(高度)
                              80,          //源的X坐标,在图左下角的附近
                              60,          //源的Y坐标,在图左下角附近
                              0,           //第一扫描线
                              cyDib[0],    //扫描线数量
                              pBits[0],
                              pbmi[0],
                              DIB_RGB_COLORS);
    
            //从上到下DIB整图显示
            SetDIBitsToDevice(hdc,
                              340,
                              cyClient / 4, //yDst
                              cxDib[1],   //整幅图宽度
                              cyDib[1],   //整幅图高度
                              0,
                              0,
                              0,          //第一扫描线
                              cyDib[1],   //扫描线数量
                              pBits[1],
                              pbmi[1],
                              DIB_RGB_COLORS);
    
            //从上到下DIB局部图显示
            SetDIBitsToDevice(hdc,
                              580,
                              cyClient / 4, //yDst
                              80,          //图的局部(宽度)
                              166,         //图的局部(高度)
                              80,          //源的X坐标,在图左下角的附近
                              60,          //源的Y坐标,在图左下角附近
                              0,           //第一扫描线
                              cyDib[1],    //扫描线数量
                              pBits[1],
                              pbmi[1],
                              DIB_RGB_COLORS);
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
     //DibFile.h和DibFile.C文件见【ShowDib1程序】

     15.2.4 顺序显示——扫描线

    (1)SetDIBitsToDevice扫描线的工作原理

    SetDIBitsToDevice(hdc,xDst,yDst,cxSrc,cySrc,xSrc,ySrc,yScan,cyScans,pBits,fClrUse);

      ①根据xSrc,ySrc,cxSrc,cySrc确定要显示的源矩形的范围(如图1),再根据xDst,yDst,cxSrc,cySrc确定DIB图像在逻辑坐标系中的输出位置和范围(如图2,用红色虚线框表示的矩形范围)。

      ②为pBits所在数据块按像素行划分出若干条扫描线第1行(也称为第一扫描线)编号为yScan号(一般为0,但这里为了更具普遍性,假设yScan等于20,即第1条扫描线编号为20号),第2条为21号,第3条为22号,以此类推……。直到pBits所有的像素行(或叫扫描线)都编号完毕。本例中DIB位图的高度为240,所以最后一行编号为20+240,即260号。

      ③开始扫描,此时当前扫描线会从A扫描到B。由图中可知,它将扫过从编号60到240的之间范围。假设当前的扫描位置是在编号为70的绿线上。

      ④当在图1中确定好当前扫描线编号以后,再根据当前扫描线的位置,计算出在逻辑坐标系中的输出位置(假设在图2中的绿线位置),而该处输出的数据来自于pBits中扫描线被编号为70号的那行数据,即pBits中第90行的数据。

      ⑤继续扫描其他行,直至AB间的所有像素行都扫描完毕,即结束。

    【注意】

      ①本例中,pBits像素的扫描线编号(20-260),但源矩形中只要求输出编号为60至240号的扫描行数据。也就是说,pBits中第40行至220行的数据。所以最终结果如图2所示(要特别注意,源和目标中,显示的图像己经不同了(见红色虚线框内的内容),主要原因是我们将pBits的第1行编号为20,如果编为0(即yScan=0)则显示的内容就会完全相同)。

      ②由于pBits扫描线编号在20-260之间,所以如果当前扫描线要扫描图1中y轴20以下的那些范围,则在pBits中会因找不到对应的扫描线,从而导致那部分的数据在逻辑坐标系中会显示为空白

    (2)SetDIBitsToDevice实例分析

     

     【SeqDisp程序】
    效果图

    /*------------------------------------------------------------
    SEQDISP.C -- Sequential Display of DIBs
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    
    #include <windows.h>
    #include "resource.h"
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    static TCHAR szAppName[] = TEXT("SeqDisp");
    
    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 Sequential 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;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        HDC         hdc;
        PAINTSTRUCT ps;
        static BITMAPINFO* pbmi;
        static BYTE* pBits;
        static int cxDib, cyDib, cBits;
        static OPENFILENAME ofn;
        static TCHAR   szFileName[MAX_PATH], szTitleName[MAX_PATH];
        static TCHAR   szFilter[] = TEXT("Bitmap Files(*.BMP)*.bmp")
            TEXT("All Files(*.*)*.*");
    
        BITMAPFILEHEADER  bmfh;
        BOOL bSuccess, bTopDown;
        DWORD dwBytesRead;
        HANDLE hFile;
        int    iInfoSize, iBitsSize, iRowLength;
    
        switch (message)
        {
        case WM_CREATE:
            ofn.lStructSize = sizeof(OPENFILENAME);
            ofn.hwndOwner = hwnd;
            ofn.hInstance = NULL;
            ofn.lpstrFilter = szFilter;
            ofn.lpstrCustomFilter = NULL;
            ofn.nMaxCustFilter = 0;
            ofn.nFilterIndex = 0;
            ofn.lpstrFile = szFileName;
            ofn.nMaxFile = MAX_PATH;
            ofn.lpstrFileTitle = szTitleName;
            ofn.nMaxFileTitle = MAX_PATH;
            ofn.lpstrInitialDir = NULL;
            ofn.lpstrTitle = NULL;
            ofn.Flags = 0;     //在打开和关闭函数中设置
            ofn.nFileOffset = 0;
            ofn.nFileExtension = 0;
            ofn.lpstrDefExt = TEXT("bmp"); //默认扩展名
            ofn.lCustData = 0;
            ofn.lpfnHook = NULL;
            ofn.lpTemplateName = NULL;
            return 0;
    
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case IDM_FILE_OPEN:
    
                //显示打开文件对话框
                if (!GetOpenFileName(&ofn))
                    return 0;
    
                //清除之前打开的位图文件
                if (pbmi)
                {
                    free(pbmi);
                    pbmi = NULL;
                }
    
                if (pBits)
                {
                    free(pBits);
                    pBits = NULL;
                }
    
                //擦掉客户区上的位图
                InvalidateRect(hwnd, NULL, TRUE);
                UpdateWindow(hwnd); //可注释掉看下
    
                //打开文件
                hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    
                if (hFile == INVALID_HANDLE_VALUE)
                {
                    MessageBox(hwnd, TEXT("Cannot open file."), szAppName, MB_ICONWARNING | MB_OK);
                    return 0;
                }
    
                //读取BITMAPFILEHEADER
                bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);
    
                if (!bSuccess || dwBytesRead != sizeof(BITMAPFILEHEADER))
                {
                    MessageBox(hwnd, TEXT("Cannot open file."), szAppName, MB_ICONWARNING | MB_OK);
                    CloseHandle(hFile);
                    return 0;
                }
    
                //检验是否是位图文件,第1-2个字节为“BM”
                if (bmfh.bfType != *(WORD*)"BM")
                {
                    MessageBox(hwnd, TEXT("File is not a bitmap."), szAppName, MB_ICONWARNING | MB_OK);
                    CloseHandle(hFile);
                    return 0;
                }
    
                //为文件信息头和像素位数据分配内存
                iInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
                iBitsSize = bmfh.bfSize - bmfh.bfOffBits;
    
                pbmi = malloc(iInfoSize);
                pBits = malloc(iBitsSize);
    
                if (pbmi == NULL || pBits == NULL)
                {
                    MessageBox(hwnd, TEXT("Cannot allocate memory."), szAppName, MB_ICONWARNING | MB_OK);
                    if (pbmi)
                    {
                        free(pbmi);
                        pbmi = NULL;
                    }
    
                    if (pBits)
                    {
                        free(pBits);
                        pBits = NULL;
                    }
    
                    CloseHandle(hFile);
                    return 0;
                }
    
                //读取信息头
                bSuccess = ReadFile(hFile, pbmi, iInfoSize, &dwBytesRead, NULL);
                if (!bSuccess || iInfoSize != dwBytesRead)
                {
                    MessageBox(hwnd, TEXT("Cannot allocate memory."), szAppName, MB_ICONWARNING | MB_OK);
                    if (pbmi)
                    {
                        free(pbmi);
                        pbmi = NULL;
                    }
    
                    if (pBits)
                    {
                        free(pBits);
                        pBits = NULL;
                    }
    
                    CloseHandle(hFile);
                    return 0;
                }
    
                //获取像素数据和高度
                bTopDown = FALSE;
                if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
                {
                    cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth;
                    cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight;
                    cBits = ((BITMAPCOREHEADER*)pbmi)->bcBitCount;
                } else
                {
                    bTopDown = (pbmi->bmiHeader.biHeight < 0);
    
                    cxDib = pbmi->bmiHeader.biWidth;
                    cyDib = abs(pbmi->bmiHeader.biHeight);
                    cBits = pbmi->bmiHeader.biBitCount;
    
                    if (pbmi->bmiHeader.biCompression != BI_RGB && pbmi->bmiHeader.biCompression != BI_BITFIELDS)
                    {
                        MessageBox(hwnd, TEXT("File is compressed."), szAppName, MB_ICONWARNING | MB_OK);
                        if (pbmi)
                        {
                            free(pbmi);
                            pbmi = NULL;
                        }
    
                        if (pBits)
                        {
                            free(pBits);
                            pBits = NULL;
                        }
    
                        CloseHandle(hFile);
                        return 0;
                    }
                }
    
                //计算每行像素宽度,4的倍数
                iRowLength = ((cxDib*cBits + 31)& ~31) >> 3;
    
                //显示位图
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
    
                hdc = GetDC(hwnd);
    
                for (int y = 0; y < cyDib; y++)
                {
                    ReadFile(hFile, pBits + y*iRowLength, iRowLength, &dwBytesRead, NULL);
                    /*
                    1、每次扫描时,源矩形0,y,cxDib,cyDib-y,目标矩形0,0,cxDib,cyDib-y
                    2、每次调用函数时,像素的数据在改变,pBits+y*iRowLength;
                    3、每次都为像素位的第一行数据编号为y或cyDib-y-1
                    */
                    SetDIBitsToDevice(hdc,
                                      0,           //xDst
                                      0,           //yDst
                                      cxDib,       //cxSrc
                                      cyDib - y,     //cySrc,课本这里为cyDib。
                                      0,           //xSrc
                                      y,           //ySrc,课本这里为0,这两处的更改,效率更高
                                      bTopDown ? cyDib - y - 1 : y, //给第一行扫描行编号
                                      1,                          //每次扫描一行
                                      pBits + y*iRowLength,         //第一行扫描行的数据
                                      pbmi,
                                      DIB_RGB_COLORS);
                }
    
                ReleaseDC(hwnd, hdc);
                CloseHandle(hFile);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
                ShowCursor(FALSE);
    
                return 0;
            }
            break;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            if (pbmi && pBits)
            {
                SetDIBitsToDevice(hdc,
                                  0,           //xDst
                                  0,           //yDst
                                  cxDib,       //cxSrc
                                  cyDib,      //cySrc
                                  0,           //xSrc
                                  0,           //ySrc
                                  0,           //第一行扫描行编号
                                  cyDib,
                                  pBits,
                                  pbmi,
                                  DIB_RGB_COLORS);
            }
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            if (pbmi)  free(pbmi);
    
            if (pBits) free(pBits);
    
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    //resouce.h

    //{{NO_DEPENDENCIES}}
    // Microsoft Developer Studio generated include file.
    // Used by SeqDisp.rc
    //
    #define IDM_FILE_OPEN                   40001
    
    // Next default values for new objects
    // 
    #ifdef APSTUDIO_INVOKED
    #ifndef APSTUDIO_READONLY_SYMBOLS
    #define _APS_NEXT_RESOURCE_VALUE        101
    #define _APS_NEXT_COMMAND_VALUE         40002
    #define _APS_NEXT_CONTROL_VALUE         1000
    #define _APS_NEXT_SYMED_VALUE           101
    #endif
    #endif

    //SeqDisp.rc

    //Microsoft Developer Studio generated resource script.
    //
    #include "resource.h"
    
    #define APSTUDIO_READONLY_SYMBOLS
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 2 resource.
    //
    #include "afxres.h"
    
    /////////////////////////////////////////////////////////////////////////////
    #undef APSTUDIO_READONLY_SYMBOLS
    
    /////////////////////////////////////////////////////////////////////////////
    // English (U.S.) resources
    
    #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
    #ifdef _WIN32
    LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
    #pragma code_page(1252)
    #endif //_WIN32
    
    #ifdef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // TEXTINCLUDE
    //
    
    1 TEXTINCLUDE DISCARDABLE 
    BEGIN
        "resource.h"
    END
    
    2 TEXTINCLUDE DISCARDABLE 
    BEGIN
        "#include ""afxres.h""
    "
        ""
    END
    
    3 TEXTINCLUDE DISCARDABLE 
    BEGIN
        "
    "
        ""
    END
    
    #endif    // APSTUDIO_INVOKED
    
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // Accelerator
    //
    
    SEQDISP ACCELERATORS DISCARDABLE 
    BEGIN
        "O",            IDM_FILE_OPEN,          VIRTKEY, CONTROL, NOINVERT
    END
    
    
    /////////////////////////////////////////////////////////////////////////////
    //
    // Menu
    //
    
    SEQDISP MENU DISCARDABLE 
    BEGIN
        POPUP "&File"
        BEGIN
            MENUITEM "&Open...	Ctrl+O",            IDM_FILE_OPEN
        END
    END
    
    #endif    // English (U.S.) resources
    /////////////////////////////////////////////////////////////////////////////
    
    
    
    #ifndef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 3 resource.
    //
    
    
    /////////////////////////////////////////////////////////////////////////////
    #endif    // not APSTUDIO_INVOKED

    15.2.5 拉伸到合适大小

    (1)StretchDIBits函数说明

    参数

    说明

    hdc

    设备环境句柄

    xDst

    目标x坐标

    yDst

    目标y坐标

    cxDst

    目标图像的像素宽度(字节),可正可负,实现翻转

    cyDst

    目标图像的像素高度(字节),可正可负,实现翻转

    xSrc

    源x坐标(有符号)

    ySrc

    源y坐标

    cxSrc

    源图像的像素宽度(字节),可正可负,实现翻转

    cySrc

    源图像的像素高度(字节),可正可负,实现翻转

    pBits

    像素位数据

    fClrUse

    使用颜色标记:DIB_PAL_COLORS或DIB_RGB_COLORS

    dwRop

    光栅操作

    (2)StretchDIBits坐标说明

    源矩形

    目标矩形

    ①(xSrc,ySrc)—内存中第一个像素!

    ①(xDst,yDst+cyDst-1)

    ②(xSrc+cxSrc-1,ySrc)

    ②(xDst+cxDst-1,yDst+cyDst-1)

    ③(xSrc,ySrc+cySrc-1)

    ③(xDst,yDst)

    ④(xSrc+cxSrc-1,ySrc+cySrc-1)—内存最后1个像素

    ④(xDst+cxDst-1,yDst)

    注意:1、右列式子出现减1并不准确,因为拉伸和映射模式的影响。

          2、原点(0,0)位于DIB图的左下角(左图中的①),第一行的第1个像素。

    (3)判断图像是否上下翻转或左右翻转

    if(!Sign(xMM*cxSrc*cxDst))

         DIB沿垂直轴翻转(镜像)

    1、xMM为映射模式x从左到右增加,取1,相反取-1。

    2、yMM为映射模式y从上到下增加,取1,相反取-1。

    if(!Sign(yMM*cySrc*cyDst))

    DIB沿水平轴翻转(上下翻转)

    【ShowDib2程序】

    /*------------------------------------------------------------
    SHOWDIB2.C -- Shows a DIB in the client area
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    
    #include <windows.h>
    #include "resource.h"
    #include "..\ShowDib1\DibFile.h"
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    static TCHAR szAppName[] = TEXT("ShowDib2");
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       PSTR szCmdLine, int iCmdShow)
    {
        HWND         hwnd;
        MSG          msg;
        WNDCLASSEX   wndclass;
        HACCEL       hAccel;
    
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.cbSize = sizeof(WNDCLASSEX);
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(hInstance, szAppName);
        wndclass.hIconSm = LoadIcon(hInstance, szAppName);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName = szAppName;
        wndclass.lpszClassName = szAppName;
    
        if (!RegisterClassEx(&wndclass))
        {
            MessageBox(NULL, TEXT("This program requires Windows NT!"),
                       szAppName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(szAppName,                  // window class name
                            TEXT("Show DIB #2"), // 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;
    }
    
    int ShowDib(HDC hdc, BITMAPINFO* pbmi, BYTE* pBits, int cxDib, int cyDib, int cxClient, int cyClient, WORD wShow)
    {
        switch (wShow)
        {
        case IDM_SHOW_NORMAL: //正常显示
            return SetDIBitsToDevice(hdc, 0, 0, cxDib, cyDib, 0, 0, 0, cyDib, pBits, pbmi, DIB_RGB_COLORS);
    
        case IDM_SHOW_CENTER: //居中显示
            return SetDIBitsToDevice(hdc, (cxClient - cxDib) / 2,
                                     (cyClient - cyDib) / 2,
                                     cxDib, cyDib, 0, 0,
                                     0, cyDib, pBits, pbmi, DIB_RGB_COLORS);
        case IDM_SHOW_STRETCH: //拉伸到整个客户区
            SetStretchBltMode(hdc, COLORONCOLOR); //缩小时,直接去掉颜色值
            return StretchDIBits(hdc, 0, 0, cxClient, cyClient,
                                 0, 0, cxDib, cyDib,
                                 pBits, pbmi, DIB_RGB_COLORS, SRCCOPY);
        case IDM_SHOW_ISOSTRETCH:
            SetStretchBltMode(hdc, COLORONCOLOR);
            SetMapMode(hdc, MM_ISOTROPIC);
            SetWindowExtEx(hdc, cxDib, cyDib, NULL);
            SetViewportExtEx(hdc, cxClient, cyClient, NULL);
            SetWindowOrgEx(hdc, cxDib / 2, cyDib / 2, NULL);
            SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);
    
            return StretchDIBits(hdc, 0, 0, cxDib, cyDib,  //逻辑坐标系的范围
                                 0, 0, cxDib, cyDib,
                                 pBits, pbmi, DIB_RGB_COLORS, SRCCOPY);
        }
        return 0;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static BITMAPFILEHEADER* pbmfh;
        static BITMAPINFO*       pbmi;
        static BYTE*             pBits;
    
        static TCHAR   szFileName[MAX_PATH], szTitleName[MAX_PATH];
        static int     cxClient, cyClient, cxDib, cyDib;
        HDC    hdc, hdcPrn;
        static DOCINFO   di = { sizeof(DOCINFO), TEXT("ShowDib2:Printing") };
        PAINTSTRUCT ps;
        BOOL         bSuccess;
        int          iEnable, cxPage, cyPage;
        static WORD wShow = IDM_SHOW_NORMAL;
        HMENU hMenu;
        HGLOBAL  hGlobal;
        BYTE     *pGlobal;
    
        static PRINTDLG  printdlg = { sizeof(PRINTDLG) };
    
    
        switch (message)
        {
        case WM_CREATE:
    
            DibFileInitialize(hwnd);
            return 0;
    
        case WM_INITMENUPOPUP:
            if (pbmfh)
                iEnable = MF_ENABLED;
            else
                iEnable = MF_GRAYED;
    
            EnableMenuItem((HMENU)wParam, IDM_FILE_SAVE, iEnable);
            EnableMenuItem((HMENU)wParam, IDM_FILE_PRINT, iEnable);
            EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, iEnable);
            EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, iEnable);
            EnableMenuItem((HMENU)wParam, IDM_EDIT_DELETE, iEnable);
            return 0;
    
        case WM_SIZE:
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            return 0;
    
        case WM_COMMAND:
            hMenu = GetMenu(hwnd);
    
            switch (LOWORD(wParam))
            {
            case IDM_FILE_OPEN:
                //显示打开对话框
                if (!DibFileOpenDlg(hwnd, szFileName, szTitleName))
                    return 0;
    
                //如果DIB文件己被载入,释放内存
                if (pbmfh)
                {
                    free(pbmfh);
                    pbmfh = NULL;
                }
    
                //将整个DIB加载到内存中
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
    
                pbmfh = DibLoadImage(szFileName);
    
                ShowCursor(FALSE);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
    
                //使客户区无效,以便后面的绘图并擦除以前客户区显示的内容
                InvalidateRect(hwnd, NULL, TRUE);
    
                if (pbmfh == NULL)
                {
                    MessageBox(hwnd, TEXT("Cannot load DIB file"), szAppName, 0);
                    return 0;
                }
    
                //获取指向DIB信息头的指针和指向像素位的指针
                pbmi = (BITMAPINFO*)(pbmfh + 1);
                pBits = (BYTE*)pbmfh + pbmfh->bfOffBits;
    
                //获取图像的宽度和高度
                if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
                {
                    cxDib = ((BITMAPCOREHEADER*)pbmi)->bcWidth;
                    cyDib = ((BITMAPCOREHEADER*)pbmi)->bcHeight;
                } else
                {
                    cxDib = pbmi->bmiHeader.biWidth;
                    cyDib = abs(pbmi->bmiHeader.biHeight);
                }
                return 0;
    
            case IDM_FILE_SAVE:
    
                //显示保存对话框
                if (!DibFileSaveDlg(hwnd, szFileName, szTitleName))
                    return 0;
    
                //将DIB位图保存到文件中
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
    
                bSuccess = DibSaveImage(szFileName, pbmfh);
    
                ShowCursor(FALSE);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
    
                if (!bSuccess)
                    MessageBox(hwnd, TEXT("Cannot save DIB file"), szAppName, 0);
                return 0;
    
            case IDM_FILE_PRINT:
                if (!pbmfh)
                    return 0;
    
                //获取打印机DC
                printdlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION;
                if (!PrintDlg(&printdlg))
                    return 0;
                hdcPrn = printdlg.hDC;
                if (NULL == hdcPrn)
                {
                    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);
    
                bSuccess = FALSE;
    
                //将位图输程打印机
                SetCursor(LoadCursor(NULL, IDC_WAIT));
                ShowCursor(TRUE);
                //StartDoc、StartPage、EndPage、EndDoc返回值>0说明执行成功。
                if ((StartDoc(hdcPrn, &di)>0) && (StartPage(hdcPrn)>0))
                {
                    ShowDib(hdcPrn, pbmi, pBits, cxDib, cyDib, cxPage, cyPage, wShow);
                    if (EndPage(hdcPrn)>0)
                    {
                        bSuccess = TRUE;
                        EndDoc(hdcPrn);
                    }
                }
                ShowCursor(FALSE);
                SetCursor(LoadCursor(NULL, IDC_ARROW));
                DeleteDC(hdcPrn);
                if (!bSuccess)
                    MessageBox(hwnd, TEXT("Could not  print bitmap"),
                    szAppName, MB_ICONEXCLAMATION | MB_OK);
                return 0;
    
            case IDM_EDIT_COPY:
            case IDM_EDIT_CUT:
                if (!pbmfh)
                    return 0;
    
                //生成一个紧凑型DIB
                hGlobal = GlobalAlloc(GHND | GMEM_SHARE,
                                      pbmfh->bfSize - sizeof(BITMAPFILEHEADER));
                pGlobal = GlobalLock(hGlobal);
                CopyMemory(pGlobal, (BYTE*)pbmfh + sizeof(BITMAPFILEHEADER),
                           pbmfh->bfSize - sizeof(BITMAPFILEHEADER));
                GlobalUnlock(hGlobal);
    
                //传输到剪贴板
                OpenClipboard(hwnd);
                EmptyClipboard();
                SetClipboardData(CF_DIB, hGlobal);
                CloseClipboard();
    
                if (LOWORD(wParam) == IDM_EDIT_COPY)
                    return 0;
                //IDM_EDIT_CUT则继续执行下去
    
            case IDM_EDIT_DELETE:
                if (pbmfh)
                {
                    free(pbmfh);
                    pbmfh = NULL;
                    InvalidateRect(hwnd, NULL, TRUE);
                }
    
                return 0;
    
            case IDM_SHOW_CENTER:
            case IDM_SHOW_ISOSTRETCH:
            case IDM_SHOW_NORMAL:
            case IDM_SHOW_STRETCH:
                CheckMenuItem(hMenu, wShow, MF_GRAYED);
                wShow = LOWORD(wParam);
                CheckMenuItem(hMenu, wShow, MF_CHECKED);
                InvalidateRect(hwnd, NULL, TRUE);
                return 0;
            }
            break;
    
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            if (pbmfh)
            {
                ShowDib(hdc, pbmi, pBits, cxDib, cyDib, cxClient, cyClient, wShow);
            }
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            if (pbmfh)
                free(pbmfh);
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    //resource.h

    //{{NO_DEPENDENCIES}}
    // Microsoft Visual C++ 生成的包含文件。
    // 供 ShowDib2.rc 使用
    //
    #define IDM_FILE_OPEN                   40001
    #define IDM_FILE_SAVE                   40002
    #define IDM_FILE_PRINT                  40003
    #define IDM_EDIT_CUT                    40004
    #define IDM_EDIT_COPY                   40005
    #define IDM_EDIT_CLEAR                  40006
    #define IDM_EDIT_DELETE                 40007
    #define IDM_SHOW_NORMAL                 40008
    #define IDM_SHOW_CENTER                 40009
    #define IDM_SHOW_STRETCH                40010
    #define IDM_SHOW_ISOSTRETCH             40011
    // Next default values for new objects
    // 
    #ifdef APSTUDIO_INVOKED
    #ifndef APSTUDIO_READONLY_SYMBOLS
    #define _APS_NEXT_RESOURCE_VALUE        103
    #define _APS_NEXT_COMMAND_VALUE         40028
    #define _APS_NEXT_CONTROL_VALUE         1001
    #define _APS_NEXT_SYMED_VALUE           101
    #endif
    #endif

    //ShowDib2.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
    //
    SHOWDIB2 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
    END
    POPUP "&Edit"
    BEGIN
    MENUITEM "Cu&t	Ctrl+X", IDM_EDIT_CUT
    MENUITEM "&Copy	Ctrl+C", IDM_EDIT_COPY
    MENUITEM "&Delete	Delete", IDM_EDIT_DELETE
    END
    POPUP "&Show"
    BEGIN
    MENUITEM "&Actual Size", IDM_SHOW_NORMAL, CHECKED
    MENUITEM "&Center", IDM_SHOW_CENTER
    MENUITEM "&Stretch toWindow", IDM_SHOW_STRETCH
    MENUITEM "Stretch &Isotropically ", IDM_SHOW_ISOSTRETCH
    END
    END
    /////////////////////////////////////////////////////////////////////////////
    //
    // Accelerator
    //
    SHOWDIB2 ACCELERATORS
    BEGIN
    "^O", IDM_FILE_OPEN, ASCII, NOINVERT
    "^S", IDM_FILE_SAVE, ASCII, NOINVERT
    "^P", IDM_FILE_PRINT, ASCII, NOINVERT
    "^C", IDM_EDIT_COPY, ASCII, NOINVERT
    VK_DELETE, IDM_EDIT_DELETE, VIRTKEY, SHIFT, NOINVERT
    "^X", IDM_EDIT_CUT, ASCII, NOINVERT
    END
    #endif    // 中文(简体,中国) resources
    /////////////////////////////////////////////////////////////////////////////
    #ifndef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 3 resource.
    //
    /////////////////////////////////////////////////////////////////////////////
    #endif    // not APSTUDIO_INVOKED

    //DibFile.h和DibFile.c见ShowDib1程序

  • 相关阅读:
    appium 多线程还是多进程(转)
    清理不可用的模拟器
    ios-元素查看器安装
    Linux 一条命令杀死占用端口的所有进程
    appium 小程序自动化测试
    (转)MitmProxy+APPnium安装使用
    mysql死锁分析
    母线故障跳闸的处理方法(转载)
    电动葫芦使用注意事项(转载)
    三菱plc输出指示灯不亮怎么办(转载)
  • 原文地址:https://www.cnblogs.com/5iedu/p/4699013.html
Copyright © 2011-2022 走看看