Direct2D教程(九)渲染位图
?
概述
這篇的標(biāo)題更確切的說應(yīng)該叫位圖畫刷,這樣才好和前幾篇對(duì)應(yīng)起來。在Direct2D中,位圖的渲染也是通過畫刷來實(shí)現(xiàn)的。
Direct2D中并沒有直接操作位圖的接口,而是借助WIC(Windows Image Component)來完成的。今天我們來看看如何在Direct2D中加載并顯示位圖。這個(gè)方法可以用來渲染背景。基本步驟如下。
- 從文件創(chuàng)建WIC位圖
- 由WIC位圖創(chuàng)建D2D位圖
- 使用D2D繪制位圖
在開始之前,首先簡(jiǎn)要介紹一下WIC
什么是WIC?
WIC全稱是Windows Image Component,是一套擴(kuò)展的API,用來處理數(shù)字圖像,它是基于COM組件的。該API包含非常豐富的圖像處理函數(shù),比如
- 內(nèi)置對(duì)于標(biāo)準(zhǔn)web image格式的解碼支持
- 內(nèi)置對(duì)于標(biāo)準(zhǔn)metadata格式的支持
- 廣泛的像素格式支持
- 高色度支持,包含30位擴(kuò)展,30位及48位高精度像素格式
- 對(duì)于圖像解碼,像素格式及元數(shù)據(jù)格式的擴(kuò)展框架支持
WIC包含的組件及每個(gè)組件中的接口如下圖所示。
在這里,我們只要知道WIC能夠處理圖像即可,比如位圖操作。關(guān)于WIC的詳細(xì)信息,大家可以看看MSDN的介紹。
具體步驟
從文件創(chuàng)建WIC位圖
給定一個(gè)圖像文件,我們首先使用WIC函數(shù)將其讀入內(nèi)存,并創(chuàng)建一個(gè)WIC類型的位圖。
首先我們需要?jiǎng)?chuàng)建一個(gè)解碼器,因?yàn)閳D片是經(jīng)過編碼的,為了能顯示圖片,我們首先需要將其解碼,創(chuàng)建解碼器需要使用函數(shù)CreateDecoderFromFilename,該函數(shù)返回一個(gè)解碼器指針。稍后的操作都通過這個(gè)指針來完成,關(guān)于這個(gè)函數(shù)的詳細(xì)介紹,可以參考MSDN,這里不再贅述。
然后,利用創(chuàng)建好的解碼器來獲取圖片的幀,我么這里只要第一幀,因?yàn)閳D片只有一幀,但是對(duì)于視頻文件來說,就有許多幀了。代碼如下:在這里,uri即圖片文件名。
HRESULT LoadBitmapFromFile(ID2D1RenderTarget *pRenderTarget,IWICImagingFactory *pIWICFactory,PCWSTR uri,UINT destinationWidth,UINT destinationHeight,ID2D1Bitmap **ppBitmap) {HRESULT hr = S_OK;IWICBitmapDecoder *pDecoder = NULL;IWICBitmapFrameDecode *pSource = NULL;IWICStream *pStream = NULL;IWICFormatConverter *pConverter = NULL;IWICBitmapScaler *pScaler = NULL;hr = pIWICFactory->CreateDecoderFromFilename(uri,NULL,GENERIC_READ,WICDecodeMetadataCacheOnLoad,&pDecoder);if (SUCCEEDED(hr)){// Create the initial frame.hr = pDecoder->GetFrame(0, &pSource);}然后創(chuàng)建converter,負(fù)責(zé)對(duì)位圖進(jìn)行后續(xù)的格式轉(zhuǎn)換。
if (SUCCEEDED(hr)) {hr = pIWICFactory->CreateFormatConverter(&pConverter); }接下來則要判斷圖像是否被放大或者縮小了,比如一個(gè)圖片的原始尺寸是100 x 100,但是我們程序中要以 200 x 200的方式去顯示,那么相當(dāng)于將圖片放大了一倍,圖片的顯示尺寸通過參數(shù)來指定,而實(shí)際尺寸則是通過分析圖片文件得到。如果圖片有縮放,那么需要從新生成圖片的數(shù)據(jù)文件,如果沒有,那么直接進(jìn)行下一步即可。代碼如下:
// If a new width or height was specified, create an // IWICBitmapScaler and use it to resize the image. if (destinationWidth != 0 || destinationHeight != 0) {UINT originalWidth, originalHeight;hr = pSource->GetSize(&originalWidth, &originalHeight);if (SUCCEEDED(hr)){if (destinationWidth == 0){FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));}else if (destinationHeight == 0){FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));}hr = pIWICFactory->CreateBitmapScaler(&pScaler);if (SUCCEEDED(hr)){hr = pScaler->Initialize(pSource,destinationWidth,destinationHeight,WICBitmapInterpolationModeCubic);}if (SUCCEEDED(hr)){hr = pConverter->Initialize(pScaler,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,NULL,0.f,WICBitmapPaletteTypeMedianCut);}} }由WIC位圖創(chuàng)建D2D位圖
調(diào)用函數(shù)CreateBitmapFromWicBitmap可以由一個(gè)WIC位圖創(chuàng)建一個(gè)D2D位圖,代碼如下:
if (SUCCEEDED(hr)) {// Create a Direct2D bitmap from the WIC bitmap.hr = pRenderTarget->CreateBitmapFromWicBitmap(pConverter,NULL,ppBitmap); }上面這些代碼有個(gè)特點(diǎn),就是要時(shí)刻判斷前一次函數(shù)調(diào)用的返回值,只有前面的操作成功了,才進(jìn)行下一步操作。這是很好的編程習(xí)慣。
最后,需要做一些清理工作,由于WIC是基于COM的,所以,需要手動(dòng)釋放COM對(duì)象,代碼如下:
SAFE_RELEASE(pDecoder); SAFE_RELEASE(pSource); SAFE_RELEASE(pStream); SAFE_RELEASE(pConverter); SAFE_RELEASE(pScaler);SAFE_RELEASE是一個(gè)宏定義
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}使用D2D繪制位圖
這一步就很簡(jiǎn)單了,繪制位圖和繪制其他幾何圖形幾乎沒有區(qū)別。首先是將render target清空為指定顏色,也就是背景色,然后調(diào)用render target的接口DrawBitmap來繪制位圖,這個(gè)函數(shù)需要指定位圖的尺寸,所以之前還需要獲取位圖的大小。注意繪制代碼要放在BeginDraw和EndDraw之間。
void DrawBitmap() {CreateD2DResource(g_Hwnd) ;pRenderTarget->BeginDraw() ;// Clear background color to dark cyanpRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));D2D1_SIZE_F size = pBitmap->GetSize() ;D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;// Draw bitmappRenderTarget->DrawBitmap(pBitmap,D2D1::RectF(upperLeftCorner.x,upperLeftCorner.y,upperLeftCorner.x + size.width,upperLeftCorner.y + size.height)) ;HRESULT hr = pRenderTarget->EndDraw() ;if (FAILED(hr)){MessageBox(NULL, "Draw failed!", "Error", 0) ;return ;} }最后,來一張效果圖,這是微軟的游戲 4 Elements 2 的截圖,大家一同欣賞一下。這是我平生購(gòu)買的第一款游戲,值得紀(jì)念一下。
總結(jié)
以上是生活随笔為你收集整理的Direct2D教程(九)渲染位图的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#Redis集合set
- 下一篇: OpenCV异常问题(一)