标签:
本例主要是对比D2D和GDI在绘制文字、线条的区别,以及D2D与GDI+在绘制图片时的区别。
D2D是基于COM组件开发的,使用前的CoInitialize(NULL)是必须的;另外,GDI+的初始化GdiplusStartup()也别忘了。
废话少说,完整代码如下:
// D2DDemo.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "D2DDemo.h" #include <D2D1.h> #include <DWrite.h> #pragma comment(lib, "D2D1") #pragma comment(lib, "DWrite") #include <atlbase.h> #include <atlcom.h> #include <wincodec.h> #pragma comment(lib, "windowscodecs") #include <GdiPlus.h> #pragma comment(lib, "GdiPlus") using namespace Gdiplus; #define MAX_LOADSTRING 100 // 全局变量: HINSTANCE hInst; // 当前实例 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); BOOL InitD2DResource(); BOOL InitDeviceResource(HWND hWnd); void D2DDraw(); BOOL OnCreate(HWND hWnd); HRESULT LoadBitmapFromFile( ID2D1RenderTarget *pRenderTarget, IWICImagingFactory *pIWICFactory, PCWSTR uri, UINT destinationWidth, UINT destinationHeight, ID2D1Bitmap **ppBitmap ); //这里来定义全局变量 CComPtr<ID2D1Factory> g_pD2d1Factory; CComPtr<IDWriteFactory> g_pDWriteFactory; CComPtr<IDWriteTextFormat> g_pDWriteFormat; CComPtr<ID2D1HwndRenderTarget> g_pD2D1HwndRender; CComPtr<ID2D1GdiInteropRenderTarget> g_pD2DGdiRender; CComPtr<IWICImagingFactory> g_pWicImageFactory; CComPtr<ID2D1Bitmap> g_pBkImage; LOGFONT g_logFont; HFONT g_hTextFont = NULL; #define FREE_COM_PTR(x) { if (x) { x->Release(); x = NULL; } } int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); HRESULT hr = CoInitialize(NULL); ULONG_PTR ptr; GdiplusStartupInput input; GdiplusStartup(&ptr, &input, NULL); // TODO: 在此放置代码。 MSG msg; HACCEL hAccelTable; memset(&g_logFont, 0, sizeof(LOGFONT)); g_logFont.lfHeight = 40; g_logFont.lfWidth = 0; g_logFont.lfWeight = FW_NORMAL; g_logFont.lfCharSet = DEFAULT_CHARSET; g_logFont.lfOutPrecision = OUT_DEFAULT_PRECIS; g_logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; g_logFont.lfQuality = DEFAULT_QUALITY; g_logFont.lfPitchAndFamily = DEFAULT_PITCH|FF_SWISS; wcscpy(g_logFont.lfFaceName, L"微软雅黑"); g_hTextFont = CreateFontIndirect(&g_logFont); // 初始化全局字符串 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_D2DDEMO, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D2DDEMO)); // 主消息循环: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } if ( g_hTextFont ) { DeleteObject(g_hTextFont); g_hTextFont = NULL; } GdiplusShutdown(ptr); CoUninitialize(); return (int) msg.wParam; } // // 函数: MyRegisterClass() // // 目的: 注册窗口类。 // // 注释: // // 仅当希望 // 此代码与添加到 Windows 95 中的“RegisterClassEx” // 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要, // 这样应用程序就可以获得关联的 // “格式正确的”小图标。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_D2DDEMO)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_D2DDEMO); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // 函数: InitInstance(HINSTANCE, int) // // 目的: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_CREATE: OnCreate(hWnd); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... D2DDraw(); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_SIZE: { if ( g_pD2D1HwndRender ) { int nWidth = LOWORD(lParam); int nHeight= HIWORD(lParam); D2D1_SIZE_U sz = D2D1::SizeU(nWidth, nHeight); g_pD2D1HwndRender->Resize(sz); } } case WM_ERASEBKGND: return TRUE; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } BOOL InitD2DResource() { BOOL bRet = FALSE; ID2D1Factory* pD2dFactory = NULL; IDWriteFactory* pDwriteFactory = NULL; IDWriteTextFormat* pDwriteTextFormat = NULL; IWICImagingFactory* pWicImgFactory = NULL; try { HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2dFactory); if ( FAILED(hr) ) throw L"D2D1CreateFactory error!"; hr = CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (LPVOID*)&pWicImgFactory ); if ( FAILED(hr) ) throw L"CoCreateInstance error!"; hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDwriteFactory)); if ( FAILED(hr) ) throw L"DWriteCreateFactory error!"; hr = pDwriteFactory->CreateTextFormat(L"微软雅黑", NULL, DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 30.0f, L"chs", &pDwriteTextFormat); if ( FAILED(hr) ) throw L"CreateTextFormat error!"; //水平居中 pDwriteTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); //垂直居中 pDwriteTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); bRet = TRUE; } catch(WCHAR* pMsg) { MessageBox(NULL, pMsg, L"InitD2DResource出错:", IDOK); } catch(...) { } if ( bRet ) { g_pD2d1Factory = pD2dFactory; g_pDWriteFactory = pDwriteFactory; g_pDWriteFormat = pDwriteTextFormat; g_pWicImageFactory = pWicImgFactory; } else { FREE_COM_PTR(pD2dFactory); FREE_COM_PTR(pDwriteFactory); FREE_COM_PTR(pDwriteTextFormat); FREE_COM_PTR(pWicImgFactory); } return bRet; } BOOL InitDeviceResource(HWND hWnd) { if ( g_pD2d1Factory == NULL ) return FALSE; RECT rc; GetClientRect(hWnd, &rc); D2D1_SIZE_U sz = D2D1::SizeU(rc.right-rc.left, rc.bottom-rc.top); D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(); rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE; HRESULT hr = g_pD2d1Factory->CreateHwndRenderTarget( rtProps, D2D1::HwndRenderTargetProperties(hWnd, sz), &g_pD2D1HwndRender); if ( FAILED(hr) ) return FALSE; hr = g_pD2D1HwndRender->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&g_pD2DGdiRender); return SUCCEEDED(hr); } void D2DDraw() {//D2D GDI混合绘图 if ( g_pD2D1HwndRender == NULL ) return ; g_pD2D1HwndRender->BeginDraw(); //D2D绘制 g_pD2D1HwndRender->Clear(D2D1::ColorF(RGB(255,255,255), 1.0)); //绘制背景位图 if ( g_pBkImage ) { D2D1_RECT_F desRc = D2D1::RectF(420.0f, 0.0f, 720.0f, 200.0f); g_pD2D1HwndRender->DrawBitmap(g_pBkImage, &desRc); } const WCHAR* pText = L"Hello world!!! by D2D"; D2D1_RECT_F rc = D2D1::RectF(0,0,400,100); CComPtr<ID2D1SolidColorBrush> pTextBrush; g_pD2D1HwndRender->CreateSolidColorBrush(D2D1::ColorF(RGB(155,0,255), 2.0), &pTextBrush); CComPtr<ID2D1SolidColorBrush> pLineBrush; g_pD2D1HwndRender->CreateSolidColorBrush(D2D1::ColorF(RGB(0,0,255), 1.0), &pLineBrush); g_pD2D1HwndRender->DrawLine(D2D1::Point2F(0.0f, 0.0f), D2D1::Point2F(400.0F, 100.0F), pLineBrush, 1.0); g_pD2D1HwndRender->DrawText(pText, wcslen(pText), g_pDWriteFormat, rc, pTextBrush); //GDI绘制 if ( g_pD2DGdiRender == NULL ) { g_pD2D1HwndRender->EndDraw(); return ; } HDC hDC = NULL; HRESULT hr = g_pD2DGdiRender->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &hDC); if ( SUCCEEDED(hr) ) { { Graphics g(hDC); Image image(L"1.jpg"); g.DrawImage(&image, 420, 220, 300, 200); } //绘制文字 HFONT hOldFont = (HFONT)SelectObject(hDC, g_hTextFont); SetTextColor(hDC, RGB(255,0,155)); SetBkMode(hDC, TRANSPARENT); RECT rcText = {0,100,400,200}; pText = L"Hello world!!! by GDI"; DrawText(hDC, pText, wcslen(pText), &rcText, DT_CENTER|DT_VCENTER|DT_SINGLELINE); SelectObject(hDC, hOldFont); //绘制线条 HPEN hPen = CreatePen(PS_SOLID, 2, RGB(255,0,0)); HPEN hOldPen = (HPEN)SelectObject(hDC, hPen); POINT pt; MoveToEx(hDC, 0, 100, &pt); LineTo(hDC, 400, 200); SelectObject(hDC, hOldPen); DeleteObject(hPen); g_pD2DGdiRender->ReleaseDC(NULL); } g_pD2D1HwndRender->EndDraw(); } BOOL OnCreate( HWND hWnd ) { if ( !InitD2DResource() ) goto __error; if ( !InitDeviceResource(hWnd) ) goto __error; ID2D1Bitmap* pBitmap = NULL; HRESULT hr = LoadBitmapFromFile(g_pD2D1HwndRender, g_pWicImageFactory, L"1.jpg", 0, 500, &pBitmap); if ( SUCCEEDED(hr) ) { g_pBkImage = pBitmap; } goto __successed; __error: PostQuitMessage(0); return FALSE; __successed: return TRUE; } HRESULT LoadBitmapFromFile( ID2D1RenderTarget *pRenderTarget, IWICImagingFactory *pIWICFactory, PCWSTR uri, UINT destinationWidth, UINT destinationHeight, ID2D1Bitmap **ppBitmap ) { HRESULT hr = S_OK; CComPtr<IWICBitmapDecoder> pDecoder = NULL; CComPtr<IWICBitmapFrameDecode> pSource = NULL; CComPtr<IWICStream> pStream = NULL; CComPtr<IWICFormatConverter> pConverter = NULL; CComPtr<IWICBitmapScaler> pScaler = NULL; hr = pIWICFactory->CreateDecoderFromFilename( uri, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder ); if ( FAILED(hr) ) return hr; // Create the initial frame. hr = pDecoder->GetFrame(0, &pSource); if ( FAILED(hr) ) return hr; hr = pIWICFactory->CreateFormatConverter(&pConverter); if ( FAILED(hr) ) return hr; // If a new width or height was specified, create an // IWICBitmapScaler and use it to resize the image. if (destinationWidth == 0 && destinationHeight == 0) return S_FALSE; UINT originalWidth, originalHeight; hr = pSource->GetSize(&originalWidth, &originalHeight); if ( FAILED(hr) ) return 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 ( FAILED(hr) ) return hr; hr = pScaler->Initialize( pSource, destinationWidth, destinationHeight, WICBitmapInterpolationModeCubic ); if ( FAILED(hr) ) return hr; hr = pConverter->Initialize( pScaler, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut ); if ( FAILED(hr) ) return hr; // Create a Direct2D bitmap from the WIC bitmap. hr = pRenderTarget->CreateBitmapFromWicBitmap( pConverter, NULL, ppBitmap ); return hr; }基于COM的对象在使用完之后都应该调用Release(),当引用计数为0时,将删除这个对象。这里为了使用方便,用到了COM里的智能指针CComPtr,析构时会自动调用对象的Release方法,可以查看ATL源码。
运行图如下:
对比效果可以明显发现,D2D绘制文字、线条(实际上调用的是DirectWrite)效果好于GDI,GDI的锯齿太明显了。在绘图方面,感觉D2D和GDI+的绘制效果差不多。但是,GDI+的性能大家都知道那叫一个渣,而且不支持硬件加速。
标签:
原文地址:http://blog.csdn.net/mfcing/article/details/43411979