zoukankan      html  css  js  c++  java
  • 用VC6.0编写Win32程序加载位图(含工程源代码)

    一、实验原理

    具体原理,请参考《数字图像处理编程入门》.pdf,呵呵。主要讲的是位图和windows的调色板。考虑到大家估计也没空,我就精简一下,用户代码的形式列出来。如下:

    /************************************************************************/
    位图文件.bmp文件大体上分为四个部分:
    位图文件头BITMAPFILEHEADER
    位图信息头BITMAPINFOHEADER
    调色板Palette
    位图数据ImageData
    /************************************************************************/
    
    /************************************************************************/
    /* 
    WORD 无符号16位整数
    DWORD无符号32位整数                                                                     */
    /************************************************************************/
    
    //BITMAPFILEHEADER
    //结构长度固定,为14个字节
    typedef struct tagBITMFILEHEADER{ WORD bfType; //指定文件类型,必须是0x424D,及字符串“BM” DWORD bfSize;                 //指定文件大小,包括这14个字节 WORD bfReserved1;               //保留字,不予考虑 WORD bfReserved2; //同上 DWORD bfOffBits; //为从文件头到实际的位图数据的皮衣字节数,即位图文件前三个部分长度和 } BITMAPFILEHEADER; //BITMAPINFOHEADER
    //结构长度固定,为40个字节,其中LONG为32位整数
    typedef struct tagBITMAPINFOHEADER{ DWORD biSize; //指定结构长度,为40 LONG biWidth; //指定图像的宽度,单位是像素 LONG biHeight; //高度 WORD biPlanes; //必须为1,不考虑 WORD biBitCount; //指定表示颜色时要用到的位数,常用有1(黑白二色图),24(真彩色图) DWORD biCompression; //指定位图是否压缩,有效值为BI_RGB(不压缩),BI_RLE8等 DWORD biSizeImage; //实际的位图数据占用的字节数 LONG biXPelsPerMeter; //指定目标设备的水平分辨率,单位:每米的像素个数 LONG biYPelsPerMeter; //同上 DWORD biClrUser; //本图像实际用到的颜色数。如果该值为0(即真彩色),颜色数为2^bitBitCount DWORD biClrImportant; //图像中重要的颜色数,如果为0,认为所有颜色都是重要的 }BITMAPINFOHEADER; //Palette 调色板,真彩色图像不需要调色板。 //也称作Look up table
    //调色板实际上是一个数组(可以查看MSDN),共有biClrUsed个元素(若为0,则有2^bitBitCount个元素)。数组中每个元素的类型都是个 RGBQUAD结构,占4个字节。定义:
    typedef struct tagRGBQUAD{ BYTE rgbBlue; //该颜色的蓝色分量 BYTE rgbGreen; // BYTE rgbRed; // BYTE rgbReserved; //保留值 }RGBQUAD;

    二、上机指导

      打开VC++6.0,选择“新建”->“工程”->“win32 application”,然后输入名称,例如xxx,工作区间随意。在向导里面建议选择“一个简单的hello world程序”,点击“完成”。之所以选择简单的hello world 程序,是因为我们可以运行代码并且小范围修改代码,以此来观察win32程序是如何运行的。这里提示一点:

      win32程序并不像我们以往学习的C语言一样顺序执行,而是在winproc的消息处理函数里面循环,等待消息触发。大概是这个意思。

    三、工程源码

      代码我们只需要修改xxx.cpp(即和工程名称相同的那个cpp)即可。该文件完整代码如下,可直接覆盖你的cpp文件。要修改的就是181行的文件路径。

      1 // ImageTemplate.cpp : Defines the entry point for the application.
      2 //
      3 
      4 #include "stdafx.h"
      5 #include "resource.h"
      6 #include "stdio.h"
      7 
      8 #define MAX_LOADSTRING 100
      9 //自己加的宏
     10 #define WIDTHBYTES(i) ((i+31)/32*4)
     11 
     12 // Global Variables:
     13 HINSTANCE hInst;                                // current instance
     14 TCHAR szTitle[MAX_LOADSTRING];                                // The title bar text
     15 TCHAR szWindowClass[MAX_LOADSTRING];                                // The title bar text
     16 //自己的全局变量
     17 BITMAPFILEHEADER bf;
     18 BITMAPINFOHEADER bi;
     19 HPALETTE hPalette;
     20 HBITMAP hBitmap ;
     21 HGLOBAL hImgData;
     22 
     23 // Foward declarations of functions included in this code module:
     24 ATOM                MyRegisterClass(HINSTANCE hInstance);
     25 BOOL                InitInstance(HINSTANCE, int);
     26 LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
     27 LRESULT CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
     28 BOOL LoadBmpFile(HWND hWnd,char *BmpFileName);
     29 
     30 int APIENTRY WinMain(HINSTANCE hInstance,
     31                      HINSTANCE hPrevInstance,
     32                      LPSTR     lpCmdLine,
     33                      int       nCmdShow)
     34 {
     35      // TODO: Place code here.
     36     MSG msg;
     37     HACCEL hAccelTable;
     38 
     39     // Initialize global strings
     40     LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
     41     LoadString(hInstance, IDC_IMAGETEMPLATE, szWindowClass, MAX_LOADSTRING);
     42     MyRegisterClass(hInstance);
     43 
     44     // Perform application initialization:
     45     if (!InitInstance (hInstance, nCmdShow)) 
     46     {
     47         return FALSE;
     48     }
     49 
     50     hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_IMAGETEMPLATE);
     51 
     52     // Main message loop:
     53     while (GetMessage(&msg, NULL, 0, 0)) 
     54     {
     55         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
     56         {
     57             TranslateMessage(&msg);
     58             DispatchMessage(&msg);
     59         }
     60     }
     61 
     62     return msg.wParam;
     63 }
     64 
     65 
     66 
     67 //
     68 //  FUNCTION: MyRegisterClass()
     69 //
     70 //  PURPOSE: Registers the window class.
     71 //
     72 //  COMMENTS:
     73 //
     74 //    This function and its usage is only necessary if you want this code
     75 //    to be compatible with Win32 systems prior to the 'RegisterClassEx'
     76 //    function that was added to Windows 95. It is important to call this function
     77 //    so that the application will get 'well formed' small icons associated
     78 //    with it.
     79 //
     80 ATOM MyRegisterClass(HINSTANCE hInstance)
     81 {
     82     WNDCLASSEX wcex;
     83 
     84     wcex.cbSize = sizeof(WNDCLASSEX); 
     85 
     86     wcex.style            = CS_HREDRAW | CS_VREDRAW;
     87     wcex.lpfnWndProc    = (WNDPROC)WndProc;
     88     wcex.cbClsExtra        = 0;
     89     wcex.cbWndExtra        = 0;
     90     wcex.hInstance        = hInstance;
     91     wcex.hIcon            = LoadIcon(hInstance, (LPCTSTR)IDI_IMAGETEMPLATE);
     92     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
     93     wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
     94     wcex.lpszMenuName    = (LPCSTR)IDC_IMAGETEMPLATE;
     95     wcex.lpszClassName    = szWindowClass;
     96     wcex.hIconSm        = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
     97 
     98     return RegisterClassEx(&wcex);
     99 }
    100 
    101 //
    102 //   FUNCTION: InitInstance(HANDLE, int)
    103 //
    104 //   PURPOSE: Saves instance handle and creates main window
    105 //
    106 //   COMMENTS:
    107 //
    108 //        In this function, we save the instance handle in a global variable and
    109 //        create and display the main program window.
    110 //
    111 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    112 {
    113    HWND hWnd;
    114 
    115    hInst = hInstance; // Store instance handle in our global variable
    116 
    117    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
    118       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    119 
    120    if (!hWnd)
    121    {
    122       return FALSE;
    123    }
    124 
    125    ShowWindow(hWnd, nCmdShow);
    126    UpdateWindow(hWnd);
    127 
    128    return TRUE;
    129 }
    130 
    131 //
    132 //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
    133 //
    134 //  PURPOSE:  Processes messages for the main window.
    135 //
    136 //  WM_COMMAND    - process the application menu
    137 //  WM_PAINT    - Paint the main window
    138 //  WM_DESTROY    - post a quit message and return
    139 //
    140 //
    141 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    142 {
    143     int wmId, wmEvent;
    144     PAINTSTRUCT ps;
    145     HDC hdc;
    146      TCHAR szHello[MAX_LOADSTRING];
    147 //    LPSTR szHello = "Fucko";
    148     LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
    149     static HDC hMemDC;
    150 
    151     switch (message) 
    152     {
    153         case WM_COMMAND:
    154             wmId    = LOWORD(wParam); 
    155             wmEvent = HIWORD(wParam); 
    156             // Parse the menu selections:
    157             switch (wmId)
    158             {
    159                 case IDM_ABOUT:
    160                    DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
    161                    break;
    162                 case IDM_EXIT:
    163                    DestroyWindow(hWnd);
    164                    break;
    165                 default:
    166                    return DefWindowProc(hWnd, message, wParam, lParam);
    167             }
    168             break;
    169         case WM_PAINT:
    170             //    hdc = BeginPaint(hWnd, &ps);
    171             // TODO: Add any drawing code here...
    172 //    MessageBox(hWnd,"Error alloc memory","Error Message",MB_OK|MB_ICONEXCLAMATION);
    173 //
    174 //            RECT rt;
    175 //            GetClientRect(hWnd, &rt);
    176 //            DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
    177 //            EndPaint(hWnd, &ps);
    178 //            break;
    179 
    180             hdc = BeginPaint(hWnd,&ps);
    181              LoadBmpFile(hWnd,"e:\\xx.bmp");//这里的e:\\xx.bmp是你的位图路径
    182              if (hBitmap)
    183              {
    184                  hMemDC = CreateCompatibleDC(hdc);//建立一个内存设备上下文
    185                  if (hPalette)//有调色板
    186                  {
    187                      //将调色板选入屏幕设备上下文
    188                     SelectPalette(hdc,hPalette,FALSE);
    189                      //将调色板选入内存设备上下文
    190                     SelectPalette(hMemDC,hPalette,FALSE);
    191                      RealizePalette(hdc);
    192                  }
    193                  //将位图选入内存设备上下文
    194                 SelectObject(hMemDC,hBitmap);
    195                  //显示位图
    196                  BitBlt(hdc,0,0,bi.biWidth,bi.biHeight,hMemDC,0,0,SRCCOPY);
    197                  //释放内存设备上下文
    198                 DeleteDC(hMemDC);
    199              }
    200  
    201              //释放屏幕设备上下文
    202             EndPaint(hWnd,&ps);
    203              break;
    204 
    205 
    206         case WM_DESTROY:
    207             PostQuitMessage(0);
    208             break;
    209         default:
    210             return DefWindowProc(hWnd, message, wParam, lParam);
    211    }
    212    return 0;
    213 }
    214 
    215 // Mesage handler for about box.
    216 LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    217 {
    218     switch (message)
    219     {
    220         case WM_INITDIALOG:
    221                 return TRUE;
    222 
    223         case WM_COMMAND:
    224             if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
    225             {
    226                 EndDialog(hDlg, LOWORD(wParam));
    227                 return TRUE;
    228             }
    229             break;
    230     }
    231     return FALSE;
    232 }
    233 
    234 //自己加入的代码
    235 BOOL LoadBmpFile(HWND hWnd,char *BmpFileName)
    236 {
    237     HFILE hf;//
    238     //
    239     LPBITMAPINFOHEADER lpImgData;
    240     LOGPALETTE *pPal;//
    241     LPRGBQUAD lpRGB;
    242     HPALETTE hPrevPalette;
    243     HDC hDc;
    244     HLOCAL hPal;
    245     DWORD LineBytes;
    246     DWORD ImgSize;
    247     //
    248     DWORD NumColors;
    249     DWORD i;
    250 
    251     if((hf=_lopen(BmpFileName,OF_READ))==HFILE_ERROR)
    252     {
    253         MessageBox(hWnd,"File c:\\test.bmp not found!","Error Message",
    254             MB_OK|MB_ICONEXCLAMATION);
    255         return FALSE;
    256     }
    257     
    258     //将BITMAPFILEHEADER结构从文件中读出,写入bf中
    259     
    260     _lread(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));
    261 
    262     //
    263     _lread(hf,(LPSTR)&bi,sizeof(BITMAPINFOHEADER));
    264     
    265     //需要定义一个宏,因为每行字节数必须为4的倍数
    266     //#define WIDTHBYTES(i) ((i+31)/32*4)
    267     //调用WIDTHBYTES(bi.biWidth*bi.biBitCount)即可完成换算
    268 
    269     LineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount);
    270 
    271     
    272     //ImgSize为实际的图象数据占用的字节数
    273     ImgSize=(DWORD)LineBytes*bi.biHeight; 
    274 
    275     //NumColors为实际用到的颜色数,即调色板数组中的颜色个数
    276     if(bi.biClrUsed!=0) //如果bi.biClrUsed 不为零,即为实际用到的颜色数 
    277     NumColors=(DWORD)bi.biClrUsed; 
    278     else //否则,用到的颜色数为2biBitCount
    279     switch(bi.biBitCount){ 
    280         case 1: 
    281             NumColors=2; 
    282             break; 
    283         case 4: 
    284             NumColors=16; 
    285             break; 
    286          case 8: 
    287            NumColors=256; 
    288             break; 
    289         case 24: 
    290             NumColors=0; //对于真彩色图,没用到调色板 
    291             break; 
    292         default: //不处理其它的颜色数,认为出错。
    293         MessageBox(hWnd,"Invalid color numbers!","Error Message", MB_OK|MB_ICONEXCLAMATION);
    294         _lclose(hf);
    295         
    296         return FALSE; //关闭文件,返回FALSE
    297     }
    298 
    299     if(bf.bfOffBits!=(DWORD)(NumColors*sizeof(RGBQUAD)+
    300         sizeof(BITMAPFILEHEADER)+
    301         sizeof(BITMAPINFOHEADER)))
    302     {
    303         
    304         //计算出的偏移量与实际偏移量不符,一定是颜色数出错 
    305         MessageBox(hWnd,"Invalid color numbers!","Error Message",MB_OK|MB_ICONEXCLAMATION);
    306         _lclose(hf); 
    307         return FALSE; //关闭文件,返回FALSE 
    308     }
    309 
    310     //分配内存,大小为INFOHEADER和FILEHEADER结构长度+调色板+实际位图
    311     bf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+
    312         NumColors*sizeof(RGBQUAD)+ImgSize;
    313     
    314     if ((hImgData=GlobalAlloc(GHND,(DWORD)
    315         (sizeof(BITMAPINFOHEADER)+
    316         NumColors*sizeof(RGBQUAD)+
    317         ImgSize)))==NULL)
    318     {
    319         //分配内存错误
    320         MessageBox(hWnd,"Error alloc memory","Error Message",MB_OK|MB_ICONEXCLAMATION);
    321         _lclose(hf);
    322         return FALSE;
    323     }
    324 
    325     //指针lpImgData指向该内存区
    326     lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);
    327 
    328     //文件指针重新定位到BITMAPINFOHEADER开始处
    329     _llseek(hf,sizeof(BITMAPFILEHEADER),SEEK_SET);
    330 
    331     //将文件内容读入lpImgData
    332     _hread(hf,(char*)lpImgData,(long)sizeof(BITMAPINFOHEADER)
    333         +(long)NumColors*sizeof(RGBQUAD)+ImgSize);
    334 
    335     _lclose(hf);
    336     
    337     //使用了调色板
    338     if(NumColors!=0)
    339     {
    340         //为逻辑调色板分配局部内存,大小为逻辑调色板结构长度加
    341         //NumColors个PALETTENTRY
    342         
    343         hPal = LocalAlloc(LHND,sizeof(LOGPALETTE)+
    344             NumColors*sizeof(PALETTEENTRY));
    345         //指针pPal指向该内存区
    346         pPal = (LOGPALETTE*)LocalLock(hPal);
    347 
    348         //填写逻辑调色板结构的头
    349         pPal->palNumEntries = (WORD)NumColors;
    350         pPal->palVersion = 0x300;
    351         
    352         //lpRGB指向的是调色板开始的位置
    353         lpRGB = (LPRGBQUAD)((LPSTR)lpImgData+
    354             (DWORD)sizeof(BITMAPINFOHEADER));
    355         
    356         //填写每一项
    357         for(i=0;i<NumColors;i++){
    358             pPal->palPalEntry[i].peRed = lpRGB->rgbRed;
    359             pPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
    360             pPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
    361             pPal->palPalEntry[i].peFlags = (BYTE)0;
    362 
    363             lpRGB++;
    364         }
    365         
    366         //产生逻辑调色板,hPalette是一个全局变量
    367         hPalette = CreatePalette(pPal);
    368         
    369         //释放局部内存
    370         LocalUnlock(hPal);
    371         LocalFree(hPal);
    372     }
    373     
    374     //获得设备上下文句柄
    375     hDc = GetDC(hWnd);
    376 
    377     if (hPalette)
    378     {
    379         //将新的逻辑调色板选入DC,将旧的句柄保存在//hPrevPalette
    380         hPrevPalette = SelectPalette(hDc,hPalette,FALSE);
    381         RealizePalette(hDc);
    382     }
    383 
    384     //产生位图句柄
    385     hBitmap= CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpImgData,
    386         (LONG)CBM_INIT,
    387         (LPSTR)lpImgData+sizeof(BITMAPINFOHEADER)+NumColors*sizeof(RGBQUAD),
    388         (LPBITMAPINFO)lpImgData,DIB_RGB_COLORS);
    389 
    390     //将原来的调色板(如果有的话)选入设备上下文句柄
    391     if(hPalette&&hPrevPalette)
    392     {
    393         SelectPalette(hDc,hPrevPalette,FALSE);
    394         RealizePalette(hDc);
    395     }
    396     
    397     ReleaseDC(hWnd,hDc);
    398     GlobalUnlock(hImgData);//解锁内存区
    399     
    400     return TRUE;
    401 
    402 }
  • 相关阅读:
    php冒泡排序
    解决ubuntu下安装phpmyadmin访问不了的问题
    反省
    mysql主从复制
    ubuntu14.04 安装 bcm43142无线网卡
    mysql 批量更新和批量插入
    chromium 安装 pepper flash player
    js prototype新感悟
    读《乌合之众》
    马云---我的世界永不言败
  • 原文地址:https://www.cnblogs.com/muyun/p/2866767.html
Copyright © 2011-2022 走看看