// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved // Modify the following defines if you have to target a platform prior to the ones specified below. // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef WINVER // Allow use of features specific to Windows XP or later. #define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. #endif #ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. #define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. #endif #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include #include #include #include #include #include "WICViewerD2D.h" template inline void SafeRelease(T *&p) { if (NULL != p) { p->Release(); p = NULL; } } /****************************************************************** * Application entrypoint * ******************************************************************/ int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR pszCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(pszCmdLine); UNREFERENCED_PARAMETER(nCmdShow); HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); if (SUCCEEDED(hr)) { { DemoApp app; hr = app.Initialize(hInstance); if (SUCCEEDED(hr)) { BOOL fRet; MSG msg; // Main message loop: while ((fRet = GetMessage(&msg, NULL, 0, 0)) != 0) { if (fRet == -1) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } } } CoUninitialize(); } return 0; } /****************************************************************** * Initialize member data * ******************************************************************/ DemoApp::DemoApp() : m_pD2DBitmap(NULL), m_pConvertedSourceBitmap(NULL), m_pIWICFactory(NULL), m_pD2DFactory(NULL), m_pRT(NULL) { } /****************************************************************** * Tear down resources * ******************************************************************/ DemoApp::~DemoApp() { SafeRelease(m_pD2DBitmap); SafeRelease(m_pConvertedSourceBitmap); SafeRelease(m_pIWICFactory); SafeRelease(m_pD2DFactory); SafeRelease(m_pRT); } /****************************************************************** * Create application window and resources * ******************************************************************/ HRESULT DemoApp::Initialize(HINSTANCE hInstance) { HRESULT hr = S_OK; // Create WIC factory hr = CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pIWICFactory) ); if (SUCCEEDED(hr)) { // Create D2D factory hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory); } if (SUCCEEDED(hr)) { WNDCLASSEX wcex; // Register window class wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = DemoApp::s_WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(LONG_PTR); wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = NULL; wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); wcex.lpszClassName = L"WICViewerD2D"; wcex.hIconSm = NULL; m_hInst = hInstance; hr = RegisterClassEx(&wcex) ? S_OK : E_FAIL; } if (SUCCEEDED(hr)) { // Create window HWND hWnd = CreateWindow( L"WICViewerD2D", L"WIC Viewer D2D Sample", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, this ); hr = hWnd ? S_OK : E_FAIL; } return hr; } /****************************************************************** * Load an image file and create an D2DBitmap * ******************************************************************/ HRESULT DemoApp::CreateD2DBitmapFromFile(HWND hWnd) { HRESULT hr = S_OK; WCHAR szFileName[MAX_PATH]; // Step 1: Create the open dialog box and locate the image file if (LocateImageFile(hWnd, szFileName, ARRAYSIZE(szFileName))) { // Step 2: Decode the source image // Create a decoder IWICBitmapDecoder *pDecoder = NULL; hr = m_pIWICFactory->CreateDecoderFromFilename( szFileName, // Image to be decoded NULL, // Do not prefer a particular vendor GENERIC_READ, // Desired read access to the file WICDecodeMetadataCacheOnDemand, // Cache metadata when needed &pDecoder // Pointer to the decoder ); // Retrieve the first frame of the image from the decoder IWICBitmapFrameDecode *pFrame = NULL; if (SUCCEEDED(hr)) { hr = pDecoder->GetFrame(0, &pFrame); } //Step 3: Format convert the frame to 32bppPBGRA if (SUCCEEDED(hr)) { SafeRelease(m_pConvertedSourceBitmap); hr = m_pIWICFactory->CreateFormatConverter(&m_pConvertedSourceBitmap); } if (SUCCEEDED(hr)) { hr = m_pConvertedSourceBitmap->Initialize( pFrame, // Input bitmap to convert GUID_WICPixelFormat32bppPBGRA, // Destination pixel format WICBitmapDitherTypeNone, // Specified dither pattern NULL, // Specify a particular palette 0.f, // Alpha threshold WICBitmapPaletteTypeCustom // Palette translation type ); } //Step 4: Create render target and D2D bitmap from IWICBitmapSource if (SUCCEEDED(hr)) { hr = CreateDeviceResources(hWnd); } if (SUCCEEDED(hr)) { // Need to release the previous D2DBitmap if there is one SafeRelease(m_pD2DBitmap); hr = m_pRT->CreateBitmapFromWicBitmap(m_pConvertedSourceBitmap, NULL, &m_pD2DBitmap); } SafeRelease(pDecoder); SafeRelease(pFrame); } return hr; } /****************************************************************** * Creates an open file dialog box and locate the image to decode. * ******************************************************************/ BOOL DemoApp::LocateImageFile(HWND hWnd, LPWSTR pszFileName, DWORD cchFileName) { pszFileName[0] = L'\0'; OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hWnd; ofn.lpstrFilter = L"All Image Files\0" L"*.bmp;*.dib;*.wdp;*.mdp;*.hdp;*.gif;*.png;*.jpg;*.jpeg;*.tif;*.ico\0" L"Windows Bitmap\0" L"*.bmp;*.dib\0" L"High Definition Photo\0" L"*.wdp;*.mdp;*.hdp\0" L"Graphics Interchange Format\0" L"*.gif\0" L"Portable Network Graphics\0" L"*.png\0" L"JPEG File Interchange Format\0" L"*.jpg;*.jpeg\0" L"Tiff File\0" L"*.tif\0" L"Icon\0" L"*.ico\0" L"All Files\0" L"*.*\0" L"\0"; ofn.lpstrFile = pszFileName; ofn.nMaxFile = cchFileName; ofn.lpstrTitle = L"Open Image"; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; // Display the Open dialog box. return GetOpenFileName(&ofn); } /****************************************************************** * This method creates resources which are bound to a particular * * D2D device. It's all centralized here, in case the resources * * need to be recreated in the event of D2D device loss * * (e.g. display change, remoting, removal of video card, etc). * ******************************************************************/ HRESULT DemoApp::CreateDeviceResources(HWND hWnd) { HRESULT hr = S_OK; if (!m_pRT) { RECT rc; hr = GetClientRect(hWnd, &rc) ? S_OK : E_FAIL; if (SUCCEEDED(hr)) { // Create a D2D render target properties D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties = D2D1::RenderTargetProperties(); // Set the DPI to be the default system DPI to allow direct mapping // between image pixels and desktop pixels in different system DPI settings renderTargetProperties.dpiX = DEFAULT_DPI; renderTargetProperties.dpiY = DEFAULT_DPI; // Create a D2D render target D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); hr = m_pD2DFactory->CreateHwndRenderTarget( renderTargetProperties, D2D1::HwndRenderTargetProperties(hWnd, size), &m_pRT ); } } return hr; } /****************************************************************** * Regsitered Window message handler * ******************************************************************/ LRESULT CALLBACK DemoApp::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DemoApp *pThis; LRESULT lRet = 0; if (uMsg == WM_NCCREATE) { LPCREATESTRUCT pcs = reinterpret_cast (lParam); pThis = reinterpret_cast (pcs->lpCreateParams); SetWindowLongPtr(hWnd, GWLP_USERDATA, PtrToUlong(pThis)); lRet = DefWindowProc(hWnd, uMsg, wParam, lParam); } else { pThis = reinterpret_cast (GetWindowLongPtr(hWnd, GWLP_USERDATA)); if (pThis) { lRet = pThis->WndProc(hWnd, uMsg, wParam, lParam); } else { lRet = DefWindowProc(hWnd, uMsg, wParam, lParam); } } return lRet; } /****************************************************************** * Internal Window message handler * ******************************************************************/ LRESULT DemoApp::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: { // Parse the menu selections: switch (LOWORD(wParam)) { case IDM_FILE: { if (SUCCEEDED(CreateD2DBitmapFromFile(hWnd))) { InvalidateRect(hWnd, NULL, TRUE); } else { MessageBox(hWnd, L"Failed to load image, select a new one.", L"Application Error", MB_ICONEXCLAMATION | MB_OK); } break; } case IDM_EXIT: { PostMessage(hWnd, WM_CLOSE, 0, 0); break; } } break; } case WM_SIZE: { D2D1_SIZE_U size = D2D1::SizeU(LOWORD(lParam), HIWORD(lParam)); if (m_pRT) { // If we couldn't resize, release the device and we'll recreate it // during the next render pass. if (FAILED(m_pRT->Resize(size))) { SafeRelease(m_pRT); SafeRelease(m_pD2DBitmap); } } break; } case WM_PAINT: { return OnPaint(hWnd); } case WM_DESTROY: { PostQuitMessage(0); return 0; } default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } /****************************************************************** * Rendering routine using D2D * ******************************************************************/ LRESULT DemoApp::OnPaint(HWND hWnd) { HRESULT hr = S_OK; PAINTSTRUCT ps; if (BeginPaint(hWnd, &ps)) { // Create render target if not yet created hr = CreateDeviceResources(hWnd); if (SUCCEEDED(hr) && !(m_pRT->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED)) { m_pRT->BeginDraw(); m_pRT->SetTransform(D2D1::Matrix3x2F::Identity()); // Clear the background m_pRT->Clear(D2D1::ColorF(D2D1::ColorF::White)); D2D1_SIZE_F rtSize = m_pRT->GetSize(); // Create a rectangle same size of current window D2D1_RECT_F rectangle = D2D1::RectF(0.0f, 0.0f, rtSize.width, rtSize.height); // D2DBitmap may have been released due to device loss. // If so, re-create it from the source bitmap if (m_pConvertedSourceBitmap && !m_pD2DBitmap) { m_pRT->CreateBitmapFromWicBitmap(m_pConvertedSourceBitmap, NULL, &m_pD2DBitmap); } // Draws an image and scales it to the current window size if (m_pD2DBitmap) { m_pRT->DrawBitmap(m_pD2DBitmap, rectangle); } hr = m_pRT->EndDraw(); // In case of device loss, discard D2D render target and D2DBitmap // They will be re-create in the next rendering pass if (hr == D2DERR_RECREATE_TARGET) { SafeRelease(m_pD2DBitmap); SafeRelease(m_pRT); // Force a re-render hr = InvalidateRect(hWnd, NULL, TRUE)? S_OK : E_FAIL; } } EndPaint(hWnd, &ps); } return SUCCEEDED(hr) ? 0 : 1; }