Windows 2D 绘图 (GDI, GDI+, Direct2D)
Windows 2D 繪圖
- GDI
- GDI 函數(shù)
- GDI+
- GDI 和 GDI+ 的區(qū)別
- GDI+ 新特性
- Direct2D
- 視覺效果
- demo
GDI
GDI 是 Graphics Device Interface 的縮寫,含義是圖形設(shè)備接口,它的主要任務(wù)是負責(zé)系統(tǒng)與繪圖程序之間的信息交換,處理所有 Windows 程序的圖形輸出。
在 Windows 操作系統(tǒng)下,絕大多數(shù)具備圖形界面的應(yīng)用程序都離不開 GDI,我們利用 GDI 所提供的眾多 API 就可以方便的在屏幕、打印機及其它輸出設(shè)備上輸出圖形、文本等操作。
GDI 具有如下特點:
- 不允許程序直接訪問物理顯示硬件,通過稱為“設(shè)備環(huán)境”的抽象接口間接訪問顯示硬件
- 程序需要與顯示硬件(顯示器、打印機等) 進行通訊時,必須首先獲得與特定窗口相關(guān)聯(lián)的設(shè)備環(huán)境
- 用戶無需關(guān)心具體的物理設(shè)備類型
- Windows 參考設(shè)備環(huán)境的數(shù)據(jù)結(jié)構(gòu)完成數(shù)據(jù)的輸出
GDI 函數(shù)
GDI 函數(shù)大致可分類為:
- 設(shè)備上下文函數(shù)(如 GetDC、CreateDC、DeleteDC)
- 畫線函數(shù)(如 LineTo、Polyline、Arc)
- 填充畫圖函數(shù)(如 Ellipse、FillRect、Pie)
- 畫圖屬性函數(shù)(如 SetBkColor、SetBkMode、SetTextColor)
- 文本、字體函數(shù)(如 TextOut、GetFontData)
- 位圖函數(shù)(如 SetPixel、BitBlt、StretchBlt)
- 坐標函數(shù)(如 DPtoLP、LPtoDP、ScreenToClient、ClientToScreen)
- 映射函數(shù)(如 SetMapMode、SetWindowExtEx、SetViewportExtEx)
- 元文件函數(shù)(如 PlayMetaFile、SetWinMetaFileBits)
- 區(qū)域函數(shù)(如 FillRgn、FrameRgn、InvertRgn)
- 路徑函數(shù)(如 BeginPath、EndPath、StrokeAndFillPath)
- 裁剪函數(shù)(如 SelectClipRgn、SelectClipPath)
GDI+
GDI+ 是 GDI 的后續(xù)版本,最早于 2000 年隨 Windows 2000 一起推出,后來又被包裝進 .NET 框架的托管類庫中,成為 .NET 中窗體繪圖的主要工具。
GDI+ 主要提供了以下三類服務(wù):
- 二維矢量圖形:GDI+ 提供了存儲圖形基元自身信息的類(或結(jié)構(gòu)體)、存儲圖形基元繪制方式信息的類以及實際進行繪制的類;
- 圖像處理:大多數(shù)圖片都難以劃定為直線和曲線的集合,無法使用二維矢量圖形方式進行處理。因此,GDI+ 為我們提供了 Bitmap、Image 等類。它們可用于顯示、操作和保存 BMP、JPG、GIF 等圖像。
- 文字顯示:GDI+ 支持使用各種字體、字號和樣式來顯示文本。
GDI 接口是基于函數(shù)的,而 GDI+ 是基于 C++ OO 的編程接口,因此使用起來比 GDI 要方便。因為 GDI+ 實際上是 GDI 的封裝和擴展,所以執(zhí)行效率一般要低于 GDI。
GDI 和 GDI+ 的區(qū)別
GDI 的核心是設(shè)備上下文,GDI 函數(shù)都依賴于設(shè)備上下文句柄,其編程方式是基于句柄的;GDI+ 無需時刻依賴于句柄或設(shè)備上下文,用戶只需創(chuàng)建一個 Graphics 對象,就可以用面向?qū)ο蟮姆绞秸{(diào)用其成員函數(shù)進行圖形操作,編程方式是基于對象的。
GDI 在使用設(shè)備上下文繪制線條之前,必須先調(diào)用 SelectObject 以使鋼筆對象和設(shè)備上下文關(guān)聯(lián)。其后,在設(shè)備上下文中繪制的所有線條均使用該鋼筆,直到選擇另一支不同的鋼筆為止。GDI 中有當(dāng)前位置的概念,所以在使用 GDI 繪制線條前應(yīng)該先使用MoveTo 移動當(dāng)前位置,再使用 LineTo 畫線。
CPen pen(PS_SOLID, 1, RGB(255, 0, 0));dc.SelectObject(pen.GetSafeHandle());dc.MoveTo(0, 0);dc.LineTo(100, 100);在 GDI+ 中,只需將 Pen 對象直接作為參數(shù)傳遞給 Graphics 類的 DrawLine 等方法即可,而不必使 Pen 對象與 Graphics 對象關(guān)聯(lián)。且 GDI+ 中則沒有當(dāng)前位置的概念,畫線函數(shù)中可以直接指定起點和終點。
Pen myPen(Color::Red);graphics.DrawLine(&myPen, 0, 0, rect.right, 0);GDI+ 新特性
- 改進了顏色管理
GDI+ 不僅提供了更多可供選擇使用的顏色,使其支持 Alpha 通道合成運算,而且還保持了與其他顏色的兼容性。 - 繪圖支持反鋸齒
通過設(shè)置 GDI+ 對象的相關(guān)屬性,GDI+ 可以與相關(guān)的顯示驅(qū)動程序搭配完成圖形繪制時的反鋸齒功能,使得繪制的圖形更加平滑、美觀,而整個過程是由 GDI+ 對象自動計算完成的。 - 提供漸變畫刷
GDI+ 拓展了 GDI 的功能,提供線性漸變和路徑漸變畫刷來填充圖形、路徑和區(qū)域,甚至也可用來繪制直線、曲線等。 - 獨立的路徑對象
GDI+ 使用 Graphics 對象來進行繪圖操作,并將路徑操作從 Graphics 對象分離出來,提供一個 Graphics 類供用戶使用,用戶不必擔(dān)心對象會受到 Graphics 對象操作的影響,從而可以使用同一個操作對象進行多次的路徑繪制操作。 - 樣條曲線
GDI+ 封裝了繪制基數(shù)樣條曲線和貝塞爾樣條曲線的方法。 - 變形和矩陣運算
GDI+ 提供了功能強大的 Matrix 類來實現(xiàn)矩陣的旋轉(zhuǎn),錯切、平移、比例等變換操作,以便產(chǎn)生復(fù)雜的新圖形。 - 多圖片格式的支持
GDI+ 改進了圖形處理能力,通過 GDI+,用戶能夠訪問多種格式的圖片文件,轉(zhuǎn)換文件格式等,還能進行圖像重新著色、色彩修正、消除走樣等圖像處理。
Direct2D
Direct2D 是一個基于 Direct3D 的 2D 圖形 API,可以利用硬件加速特性來提供高性能、高質(zhì)量的 2D 渲染。而且十分方便的是,Direct2D 與 GDI,GDI+ 和 D3D 都是可以交互的。一項技術(shù)總是有其受眾面,看看微軟怎么說的:
- 大型企業(yè)級本機應(yīng)用程序開發(fā)人員。
- 創(chuàng)建供下游開發(fā)人員使用的控件工具包和庫的開發(fā)人員。
- 需要對二維圖形進行服務(wù)器端呈現(xiàn)的開發(fā)人員。
- 使用 Direct3D 圖形,并且需要在菜單、用戶界面 (UI) 元素和抬頭顯示器 (HUD) 中使用高性能的簡單二維和文本呈現(xiàn)的開發(fā)人員。
在 Direct2D 架構(gòu)的右下方,有一個軟件光柵化(software rasterizer),假如顯卡不支持硬件加速,那么 Direct2D 可以使用軟件方式渲染,即便是這樣,其效果還是要優(yōu)于 GDI。
視覺效果
使用 Direct2D 渲染出來的效果要比 GDI 要好的多。因為 Direct2D 使用基于圖元的反鋸齒效果(這樣會使線條更加的平滑),而且在渲染二維圖元的時候,完全支持透明和 Alpha 混合。以下是對比的照片:
顯然,右邊的 Direct2D 的線條效果要好于左邊的 GDI。
demo
- GDI
正弦曲線 - GDI+
漸變色,Alpha混合 - D2D
螺旋路徑動畫
GDI 繪圖代碼:
void CChildView::_drawWithGDI( CPaintDC& dc ) {CRect rect;GetClientRect(&rect);// 繪制 titledc.TextOut(10, 10, _T("GDI"), 3);//邏輯坐標與設(shè)備坐標變換dc.SetMapMode(MM_ANISOTROPIC);dc.SetWindowOrg(0, 0);dc.SetWindowExt(rect.right, rect.bottom);dc.SetViewportOrg(0, rect.bottom / 2);dc.SetViewportExt(rect.right, - rect.bottom);//創(chuàng)建繪制 x 軸的 pen 并將其選入設(shè)備上下文CPen penx(PS_SOLID, 1, RGB(0, 0, 255));HGDIOBJ oldObject = dc.SelectObject(penx.GetSafeHandle());//繪制 x 軸dc.MoveTo(0, 0);dc.LineTo(rect.right, 0);//創(chuàng)建繪制正旋曲線的 pen 并將其選入設(shè)備上下文CPen pen(PS_SOLID, 1, RGB(255, 0, 0));dc.SelectObject(pen.GetSafeHandle());//繪制正弦曲線dc.MoveTo(0, 0);for (int i = 0; i < rect.right; i++)dc.LineTo(i, (int)(100 * sin(2 *(i / (rect.right / 5.0)) * M_PI)));//恢復(fù)原先的 pendc.SelectObject(oldObject);// 恢復(fù)邏輯坐標與設(shè)備坐標變換dc.SetViewportOrg(0, 0);dc.SetViewportExt(rect.right, rect.bottom); }GDI+ 繪圖代碼:
void CChildView::_drawWithGDIPlus( CPaintDC& dc ) {using namespace Gdiplus;CRect rect;GetClientRect(&rect);Graphics graphics(dc);//創(chuàng)建漸變畫刷LinearGradientBrush lgb(Point(0, 0), Point(rect.right, rect.bottom), Color::Blue, Color::Purple);graphics.FillRectangle(&lgb, 0, 0, rect.right, rect.bottom);//創(chuàng)建ColorMatrixColorMatrix ClrMatrix ={1.0f, 0.0f, 0.0f, 0.0f, 0.0f,0.0f, 1.0f, 0.0f, 0.0f, 0.0f,0.0f, 0.0f, 1.0f, 0.0f, 0.0f,0.0f, 0.0f, 0.0f, 0.5f, 0.0f,0.0f, 0.0f, 0.0f, 0.0f, 1.0f};//將 ColorMatrix 賦給 ImageAttributesImageAttributes ImgAttr;ImgAttr.SetColorMatrix(&ClrMatrix, ColorMatrixFlagsDefault,ColorAdjustTypeBitmap);FontFamily fontFamily1(_T("Calibri"));Font font1(&fontFamily1, 12, FontStyleRegular, UnitPoint);//Alpha 混合graphics.DrawString(_T("LENA"), 4, &font1, PointF(140.0f, 140.0f), &SolidBrush(Color::White));TCHAR szImgPath[MAX_PATH] = {0};//確保程序所在目錄下存在 lena.png (res 文件夾下有)PathHelper::makeFullPathWithModuleDir(szImgPath, MAX_PATH, _T("lena.png"));Image img(szImgPath);graphics.DrawImage(&img, RectF(60, 140, 200, 200), 0, 0, (REAL)img.GetWidth(), (REAL)img.GetHeight(), UnitPixel, &ImgAttr);// 繪制 titlegraphics.DrawString(_T("GDI+"), 4, &font1, PointF(10.0f, 10.0f), &SolidBrush(Color::White)); }Direct2D 繪制代碼(部分):
HRESULT D2DImpl::render(HWND hwnd) {using namespace D2D1;HRESULT hr;hr = createDeviceResources(hwnd);RETURN_IF_FAILED(hr);int wndState = m_pRenderTarget->CheckWindowState();RETURN_IF_TRUE(wndState & D2D1_WINDOW_STATE_OCCLUDED, E_FAIL);D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();// Prepare to draw.m_pRenderTarget->BeginDraw();// Reset to identity transformm_pRenderTarget->SetTransform(Matrix3x2F::Identity());m_pRenderTarget->Clear(ColorF(ColorF::Black));TCHAR szTitle[] = _T("Direct2D");m_pRenderTarget->DrawText(szTitle,_tcslen(szTitle),m_pTextFormat,D2D1::RectF(10, 10, rtSize.width, rtSize.height),m_pTextBrush);//center the pathfloat minWidthHeightScale = min(rtSize.width, rtSize.height) / 512;Matrix3x2F scale = Matrix3x2F::Scale(minWidthHeightScale, minWidthHeightScale);Matrix3x2F translation = Matrix3x2F::Translation(rtSize.width / 2, rtSize.height / 2);m_pRenderTarget->SetTransform(scale * translation);//draw the path in redm_pRenderTarget->DrawGeometry(m_pPathGeometry, m_pRedBrush);static float float_time = 0.0f;float length = m_animation.GetValue(float_time);D2D1_POINT_2F point;D2D1_POINT_2F tangent;// Ask the geometry to give us the point that corresponds with the length at the current time.hr = m_pPathGeometry->ComputePointAtLength(length, NULL, &point, &tangent);// Reorient the triangle so that it follows the direction of the path.D2D1_MATRIX_3X2_F triangleMatrix = Matrix3x2F(tangent.x, tangent.y,-tangent.y, tangent.x,point.x, point.y );m_pRenderTarget->SetTransform(triangleMatrix * scale * translation);// Draw the yellow triangle.m_pRenderTarget->FillGeometry(m_pObjectGeometry, m_pYellowBrush);// Commit the drawing operations.hr = m_pRenderTarget->EndDraw();if (hr == D2DERR_RECREATE_TARGET) {hr = S_OK;discardDeviceResources();}// When we reach the end of the animation, loop back to the beginning.if (float_time >= m_animation.GetDuration())float_time = 0.0f;elsefloat_time += (float)(m_dwmTiming.rateCompose.uiDenominator) / (m_dwmTiming.rateCompose.uiNumerator);InvalidateRect(hwnd, NULL, FALSE);return hr; }
– EOF –
總結(jié)
以上是生活随笔為你收集整理的Windows 2D 绘图 (GDI, GDI+, Direct2D)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 动画七、动画的PropertyValue
- 下一篇: 【人工智能】发展简史 | 复习笔记