日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【Visual C++】游戏开发笔记十四 游戏画面绘图(四) 华丽的CImage类

發布時間:2025/6/15 c/c++ 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Visual C++】游戏开发笔记十四 游戏画面绘图(四) 华丽的CImage类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本系列文章由zhmxy555編寫,轉載請注明出處。

http://qianmo.blog.51cto.com/5127279/875711

作者:毛星云 郵箱: happylifemxy@qq.com 歡迎郵件交流編程心得

?

我們知道,Visual C++中的CBitmap類的功能簡直太弱小了,這曾經讓Visual C++在圖像處理方面的功能比較尷尬。之前筆記里面,我們采用的CBitmap配合GDI進行透明圖像的處理有些晦澀繁瑣,而且受到圖像素材的限制,可以說是有些落后,不是太實用。

為了解決這個問題,這節筆記我們將系統的學習MFC和ATL中新增一個圖像處理的類,它就是華麗而強大的CImage類。

由于本節筆記是對CImage類的一個非常系統近乎完全的介紹,我盡量讓它涵蓋到了CImage類的所有的屬性和類成員,所以

篇幅也許比以往的筆記內容都長,里面的不少內容是用到的時候才需要掌握或者查閱的,并不用強行記憶。

一,概念講解部分

1.CImage類的定位和概述

首先,我們簡單介紹一下CImage類的定位。

CImage是MFC和ATL共享的新類,它提供了增強的位圖支持,包括加載、保存和轉換JPEG,BMP,GIF,PNG圖像格式的能力。可以說是微軟意識到了CBitmap的不足,然后推出了一個CBitmap的增強版。使用CImage類,需在代碼頭部加入包含atlp_w_picpath.h文件,即添加代碼#include "atlp_w_picpath.h"。

由于CImage擁有功能強大的類成員函數的支持,它便具有了下列四個比較出彩的特性:

1、AlphaBlend支持像素級的顏色混合,從而實現透明和半透明的效果。

2、PlgBlt能使一個矩形區域的位圖映射到一個平行四邊形區域中,而且還可能使用位屏蔽操作。

3、TransparentBlt在目標區域中產生透明圖像

4、MaskBlt在目標區域中產生源位圖與屏蔽位圖合成的效果。

2.以CImage類做媒,讓CBitmap類也能處理豐富的圖片格式

解決的思路比較明朗,我們采用CImage類的Load函數加載圖片,之后用Detch取得HBITMAP的句柄,然后再將此句柄附加給CBitmap的對象就行了。

這樣就實現了讓CBitmap類也可以操作JPG/JPEG/GIF/PNG格式的圖片。

具體代碼如下:

  • #include?"atlp_w_picpath.h"?
  • CImage?p_w_picpath;???????????????//定義一個CBitmap類 ?
  • p_w_picpath.Load(“filename”);?//filename為要加載的文件地址 ?
  • HBITMAP?hBitmap=p_w_picpath.Detach();?//返回被分離的圖片的句柄 ?
  • CBitmap?bmp;?????????????????????//?定義一個bitmap ?
  • bmp.Attach(hBitmap);????????//進行句柄的附加?
  • 然后就可以用CBitmap進行余下的操作了。

    3.CImage額外的一些性質

    CImage類對于DIB(device-independent bitmap)設備無關位圖文件和非DIB都可以處理。我們可以通過Create函數或者CImage::Load來處理DIB部分,用Attach函數來將非DIB部分附加到一個CImage對象上。

    對于以下函數,只支持DIB部分的位圖文件,他們是:

    GetBitsGetColorTable,GetMaxColorTableEntries,GetPitch,GetPixelAddress,IsIndexed,SetColorTable。

    我們可以通過CImage類中的IsDIBSection()函數來幫助我們判斷一個位圖文件是否為DIB部分,其定義如下:

  • bool?IsDIBSection(?)?const?throw(?);??//如果返回值為true,則該文件為DIB;返回flase則不是DIB文件?
  • 我們需要注意的是,CImage不能被選到一個新的CDC( class of device-context設備描述表的類),CImage會為圖像創建自己的HDC(設備描述表DC的句柄)。因為一個HBITMAP只能被選入到一個HDC中一次,也就是說這個與CImage相關的HBITMAP不能被選到一個其他的HDC中。

    如果需要一個CDC,我們可以從CImage中獲取HDC,然后使用CDC::FromHandle函數。

    4.CImage兼容性的說明

    在CImage中,有如下兼容性的要求:

    只支持Windows NT4.0以上系統的成員函數:PlgBlt,MaskBlt,AlphaBlend。

    只支持Windows 2000,98以上系統的成員函數:TransparentBlt,Draw

    其實由于目前都是Windows XP以上的操作系統,這個知識點了解一下就行。

    5.CImage類用于貼圖的一般的使用方法

    使用方法不唯一,最常用的方法如下,該方法大致分為三部分:

    <1> 在源文件中添加CImage類的包含文件

    #include "atlp_w_picpath.h"

    <2> 定義一個CImage類對象,然后調用CImage::Load方法裝載一個外部圖像文件。Load方法有如下兩種重載:

  • HRESULT?Load( ?
  • ???LPCTSTR?pszFileName????//包含加載文件名的字符串指針 ?
  • )?throw(?); ?
  • ?
  • ?
  • HRESULT?Load( ?
  • ???IStream*?pStream???//指向包含加載文件名的流的指針 ?
  • )?throw();?
  • <3> 調用CImage::Draw方法繪制圖像

    下面重點介紹一下Draw方法。

    CImage::Draw 將一個位圖文件從源設備描述表復制到當前設備描述表

    該函數有如下六種重載:

  • BOOL?Draw( ?
  • ???HDC?hDestDC,?????????//目標設備環境DC的句柄 ?
  • ???int?xDest,???????????//目的矩形的左上角X坐標(邏輯單位) ?
  • ???int?yDest,???????????//目的矩形的左上角Y坐標(邏輯單位) ?
  • ???int?nDestWidth,?????//目標矩形的寬度(就是設定貼過去的圖片的寬度) ?
  • ???int?nDestHeight,????//目標矩形的高度(就是設定鐵鍋的圖片的高度) ?
  • ???int?xSrc,????????????//源矩形的左上角X坐標 ?
  • ???int?ySrc,????????????//源矩形的左上角Y坐標 ?
  • ???int?nSrcWidth,??????//源矩形的寬度 ?
  • ???int?nSrcHeight??????//源矩形的高度 ?
  • )?const?throw(?); ?
  • ?
  • ?
  • BOOL?Draw( ?
  • ???HDC?hDestDC,???????//目標環境DC的句柄 ?
  • ???const?RECT&?rectDest,????????//一個RECT結構的引用,用來確定目標圖像。 ?
  • ???const?RECT&?rectSrc?????????//一個RECT結構體的引用,用來確定源圖像 ?
  • )?const?throw(?); ?
  • ?
  • ?
  • BOOL?Draw( ?
  • ???HDC?hDestDC,?????????//目標環境DC的句柄 ?
  • ???int?xDest,????????//目標矩形的左上角X坐標 ?
  • ???int?yDest?????????//目標矩形的左上角Y坐標 ?
  • )?const?throw(?);????????// ?
  • BOOL?Draw( ?
  • ???HDC?hDestDC,????????//目標環境DC的句柄 ?
  • ???const?POINT&?pointDest?????????//一個POINT結構體,用來確定目的矩形的左上角坐標 ?
  • )?const?throw(?); ?
  • ?
  • ?
  • BOOL?Draw( ?
  • ???HDC?hDestDC,????????//目標環境DC的句柄 ?
  • ???int?xDest,????????//目標矩形的左上角X坐標 ?
  • ???int?yDest,????????//目標矩形的左上角Y坐標 ?
  • ???int?nDestWidth,????????//目標矩形的寬度 ?
  • ???int?nDestHeight?????????//目標矩形的寬度 ?
  • )?const?throw(?); ?
  • ?
  • ?
  • BOOL?Draw( ?
  • ???HDC?hDestDC,????????//目標環境DC的句柄 ?
  • ???const?RECT&?rectDest?????????//一個RECT結構的引用,用來確定目標圖像。 ?
  • )?const?throw(?);?
  • 在上面的Draw函數的各種重載中,對于沒有指定源矩形的版本,則整個源圖像就是默認的源矩形。對于沒有指定目的矩形尺寸的,則源圖片的尺寸就是默認的目的矩形尺寸。

    需要注意的是,Draw方法綜合了StretchBlt、TransparentBlt和AlphaBlend函數的功能。。通常情況下,Draw()函數作用和StretchBlt()函數一致。但是當我們的圖像中存在透明的顏色和alpha通道的時候,Draw()函數作用和TransparentBlt()或者AlphaBlend()函數一致。所以,在一般情況下,我們都盡量調用Draw方法來繪制圖像.

    6.對CImage所有類成員的介紹

    我將CImage類的所有類函數按功能分為了四大類,可以更方面的了解各函數的定位和作用,也方便大家查閱:

    <1>功能為創建與連接,釋放的函數


    Attach 附加一個HBITMAP到CImage對象,位圖類型DIB與否都可以

    Create 創建一個DIB部分的位圖,并將其附加到之前創建的CImage對象

    CreateEX 創建一個DIB部分的位圖(擁有額外的參數),并將其附加到之前 創建的CImage對象

    Destroy 從CImage類上分離該位圖并進行刪除

    Detach 從CImage類里分離該位圖

    ReleaseDC 釋放設備描述表中的數據

    ReleaseGDIPlus 釋放GDI+使用的源

    <2>功能為輸入與輸出的函數

    GetExporterFilterString 返回系統支持的輸入文件格式類型及其描述

    GetImporterFilterString 返回系統支持的輸出文件格式類型及其描述

    LoadFromResource 從指定的源處加載一個圖像資源

    Load 從指定文件處加載一個圖像資源

    IsIndexed 判斷一個位圖顏色映射到了一個索引調色盤

    IsNull 判斷一個源位圖是否被當前載入

    Save 以指定的類型來保存圖像

    <3>關于位圖類型與參數的函數


    GetBits 返回一個指向該位圖實際像素值指針

    GetBPP 返回該位圖每個像素的位

    GetColorTable 返回顏色表中RGB值的范圍條目

    GetDC 返回目前被選擇的設備描述表

    GetExporterFilterString 返回系統支持的輸入文件格式類型及其描述

    GetImporterFilterString 返回系統支持的輸出文件格式類型及其描述

    GetHeight 返回當前圖像的像素高度

    GetMaxColorTableEntries 返回顏色表條目中的最大值

    GetPitch 返回當前圖片的間距(單位為字節),用來決定像素格式的

    GetTransparentColor 返回顏色表中透明色的位置

    GetWidth 返回當前圖片的寬度(單位為像素)

    <4>功能為圖形繪制與位圖塊傳輸相關的函數

    AlphaBlend 顯示一個半透明或者透明像素的位圖

    BitBlt 從源設備描述表復制一個位圖文件到當前設備描述表

    Draw 從源矩形復制一個位圖到目的矩形,該函數伸縮或者拉伸位圖來適應目標矩 形的尺寸,如果有必要,會處理Alpha值和透明顏色。

    MaskBlt 用指定的掩碼和光柵操作來結合顏色數據和目的位圖

    PlgBlt 執行一個從源設備描述表的矩形到目標設備描述表的平行 四邊形的塊狀位圖轉換

    SetColorTabel 在DIB的顏色表中設定一系列條目的RGB顏色的值

    SetPixelIndexed 設置在指定坐標處的像素(使用索調色板的索引值)。

    SetPixelRGB 設置在指定坐標處的像素(使用RGB值)

    SetPixel 在指定坐標處設置像素的顏色

    SetTransparentColor 設置將被視為透明色的顏色的索引值(只能選取調色板中的 一種顏色)

    StretchBlt 從源矩形復制一個位圖到目的矩形,如果有必要,該函數會 伸縮或者拉伸位圖來適應目標矩形的尺寸,

    TransparentBlt 從源設備描述表中復制一個帶有透明色的位圖到當前設備 描述表
    ?

    二,實例運用部分

    運用CImage完成透明貼圖的一個完整實例

    介紹了這么多了,下面我們依然用一個實例來鞏固本節筆記的知識。

    我們知道,CImage支持透明PNG的貼圖,下面我們就運用透明PNG的貼圖,來代替之前的掩碼操作貼圖。

    <第一步>

    準備兩張素材圖,一張背景圖,一張需要進行透明操作的人物圖。

    這次的選材就很廣了,沒有之前透明操作需要自己一定的美工功底或者美工童鞋支持的諸多限制了。

    我選的兩張圖片素材如下:

    背景圖 bg.bmp 640x444

    人物圖 onion.bmp 130x130(呵呵,可愛的洋蔥頭~~)

    <第二步>

    將人物圖 onion.bmp用photoshop等圖像處理軟件進行摳圖操作,除去紅黃相間的背景圖,并將背景圖用透明圖層代替,再將圖片大小調節成85x113,用png格式輸出,效果如下:

    處理好的人物圖 onion.png 85x113

    <第三步>

    將bg.bmp以及onion.png放到工程目錄下,并在源文件寫入代碼并運行。


    該代碼和筆記六中代碼的思路基本相同,只不過,將筆記六中使用掩碼操作進行透明化處理的方式換成了png透明貼圖的方式,更加的直觀和易懂易用。

    詳細注釋的源代碼如下

  • #include?"stdafx.h"?? ?
  • #include?"atlp_w_picpath.h"?
  • //全局變量聲明?? ?
  • HINSTANCE?hInst;?? ?
  • HBITMAP?bg;????????//聲明一個位圖對象,用于存儲背景圖?? ?
  • HDC??mdc;????????//聲明一個內存DC"mdc",用來暫存位圖 ?
  • //全局函數聲明?? ?
  • ATOM?????MyRegisterClass(HINSTANCE?hInstance);?? ?
  • BOOL?????InitInstance(HINSTANCE,?int);?? ?
  • LRESULT?CALLBACK????WndProc(HWND,?UINT,?WPARAM,?LPARAM);?? ?
  • void?????MyPaint(HDC?hdc);?? ?
  • ****Winmain函數,程序入口點函數**************************************?? ?
  • int?APIENTRY?WinMain(HINSTANCE?hInstance,?? ?
  • ?????????????????????HINSTANCE?hPrevInstance,?? ?
  • ?????????????????????LPSTR?????lpCmdLine,?? ?
  • ?????????????????????int???????nCmdShow)?? ?
  • {?? ?
  • MSG?msg;?? ?
  • MyRegisterClass(hInstance);?? ?
  • if?(!InitInstance?(hInstance,?nCmdShow))??? ?
  • {?? ?
  • return?FALSE;?? ?
  • }?? ?
  • //消息循環?? ?
  • while?(GetMessage(&msg,?NULL,?0,?0))??? ?
  • {?? ?
  • TranslateMessage(&msg);?? ?
  • DispatchMessage(&msg);?? ?
  • }?? ?
  • return?msg.wParam;?? ?
  • }?? ?
  • //****設計一個窗口類,類似填空題,使用窗口結構體*************************?? ?
  • ATOM?MyRegisterClass(HINSTANCE?hInstance)?? ?
  • {?? ?
  • WNDCLASSEX?wcex;?? ?
  • wcex.cbSize?=?sizeof(WNDCLASSEX);??? ?
  • wcex.style???=?CS_HREDRAW?|?CS_VREDRAW;?? ?
  • wcex.lpfnWndProc????=?(WNDPROC)WndProc;?? ?
  • wcex.cbClsExtra??=?0;?? ?
  • wcex.cbWndExtra??=?0;?? ?
  • wcex.hInstance???=?hInstance;?? ?
  • wcex.hIcon???=?LoadIcon(NULL,IDI_APPLICATION);?? ?
  • wcex.hCursor?????=?NULL;?? ?
  • wcex.hCursor?????=?LoadCursor(NULL,?IDC_ARROW);?? ?
  • wcex.hbrBackground??=?(HBRUSH)(COLOR_WINDOW+1);?? ?
  • wcex.lpszMenuName???=?NULL;?? ?
  • wcex.lpszClassName??=?"canvas";?? ?
  • wcex.hIconSm?????=?NULL;?? ?
  • return?RegisterClassEx(&wcex);?? ?
  • }?? ?
  • //****初始化函數*************************************?? ?
  • //?1.建立與窗口DC兼容的內存DC?? ?
  • //?2.從文件加載背景圖及透明的洋蔥頭? ?
  • BOOL?InitInstance(HINSTANCE?hInstance,?int?nCmdShow)?? ?
  • {?? ?
  • HWND?hWnd;?? ?
  • HDC?hdc;?? ?
  • hInst?=?hInstance;?? ?
  • hWnd?=?CreateWindow("canvas",?"淺墨的繪圖窗口"?,?WS_OVERLAPPEDWINDOW,?? ?
  • CW_USEDEFAULT,?0,?CW_USEDEFAULT,?0,?NULL,?NULL,?hInstance,?NULL);?? ?
  • if?(!hWnd)?? ?
  • {?? ?
  • return?FALSE;?? ?
  • }?? ?
  • MoveWindow(hWnd,10,10,600,444,true);?? ?
  • ShowWindow(hWnd,?nCmdShow);?? ?
  • UpdateWindow(hWnd);?? ?
  • hdc?=?GetDC(hWnd);?????????????????????//獲得窗口DC?? ?
  • mdc?=?CreateCompatibleDC(hdc);???????????//創建與窗口兼容的內存DC(mdc)?? ?
  • bg?=?(HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,600,444,LR_LOADFROMFILE);?? ?
  • ? ?
  • MyPaint(hdc);?? ?
  • ReleaseDC(hWnd,hdc);?? ?
  • return?TRUE;?? ?
  • }?? ?
  • //****自定義繪圖函數*********************************?? ?
  • //透明貼圖?? ?
  • void?MyPaint(HDC?hdc)?? ?
  • {?? ?
  • SelectObject(mdc,bg);?? ?
  • BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);????//先將背景圖貼到顯示窗口中?? ?
  • CImage?p_w_picpath;??????//定義一個CImage對象,用于透明貼圖 ?
  • CString?str;??????//定義一個CString對象,用于存放文件名字符串 ?
  • str="onion.png";??????????????//將字符串賦值為文件名 ?
  • p_w_picpath.Load(str);????????????????????//在p_w_picpath中載入圖像文件 ?
  • p_w_picpath.Draw(hdc,120,180,85,113,0,0,85,113);????//調用Draw進行透明貼圖 ?
  • //或者為p_w_picpath.TransparentBlt(hdc,?120,?180,?85,?113,CLR_INVALID?);//調用TransparentBlt進行透明貼圖 ?
  • p_w_picpath.Destroy(); ?
  • }?? ?
  • //****消息處理函數**********************************?? ?
  • LRESULT?CALLBACK?WndProc(HWND?hWnd,?UINT?message,?WPARAM?wParam,?LPARAM?lParam)?? ?
  • {?? ?
  • PAINTSTRUCT?ps;?? ?
  • HDC?hdc;?? ?
  • switch?(message)?? ?
  • {?? ?
  • case?WM_PAINT:???//窗口重繪消息?? ?
  • hdc?=?BeginPaint(hWnd,?&ps);?? ?
  • MyPaint(hdc);?? ?
  • EndPaint(hWnd,?&ps);?? ?
  • break;?? ?
  • case?WM_DESTROY:?????//窗口結束消息?? ?
  • DeleteDC(mdc);?? ?
  • DeleteObject(bg);?? ?
  • PostQuitMessage(0);?? ?
  • break;?? ?
  • default:?????//其他消息?? ?
  • return?DefWindowProc(hWnd,?message,?wParam,?lParam);?? ?
  • ???}?? ?
  • ???return?0;?? ?
  • }???
  • 最后得到的效果圖如下:

    我們可以改變CImage::Draw函數的參數值,讓“洋蔥頭”出現在地圖不同的地方。

    通過這個實例可以發現,用CImage類進行透明貼圖,實在是方便多了。

    本節筆記到這里就結束了,由于近期在做一個純flash的網站,更新速度和評論的回復都不像往常那么及時,希望大家能夠體諒。

    本節筆記的源代碼請點擊這里下載: 【Visual C++】Code_Note_14

    感謝一直支持【Visual C++】游戲開發筆記系列專欄的朋友們,也請大家繼續關注我的專欄,我一有時間就會把自己的學習心得,覺得比較好的知識點寫出來和大家一起分享。

    精通游戲開發的路還很長很長,非常希望能和大家一起交流,共同學習,共同進步。

    大家看過后覺得值得一看的話,可以頂一下這篇文章,你們的支持是我繼續寫下去的動力~

    如果文章中有什么疏漏的地方,也請大家指正。也希望大家可以多留言來和我探討編程相關的問題。

    最后,謝謝你們一直的支持~~~

    ?????????????????????????????????????????????? ——————————淺墨于2012年4月3日


    The end.

    ?

    轉載于:https://blog.51cto.com/qianmo/875711

    總結

    以上是生活随笔為你收集整理的【Visual C++】游戏开发笔记十四 游戏画面绘图(四) 华丽的CImage类的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。