Windows API рендеринг изображения из файла (для начинающих)

Я пытаюсь понять, как загрузить и визуализировать изображение из файла, используя Windows API, Direct2D и Visual C ++. Я более или менее пытался следовать статья MSDN по теме. Я новичок в C ++ (опыт работы в C) и Windows API.

Я написал 3 функции.

HRESULT imagefactorysetup(IWICImagingFactory * pImageFactory)
{
HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (LPVOID *) &pImageFactory);

return hr;
}

HRESULT imageload(LPCWSTR filename, IWICImagingFactory * pImageFactory, IWICBitmapFrameDecode * pFrame)
{
IWICBitmapDecoder * pDecoder = NULL;
HRESULT hr = pImageFactory->CreateDecoderFromFilename(filename, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder);

if (SUCCEEDED(hr))
hr = pDecoder->GetFrame(0, &pFrame);

//Format convert the frame to 32bppPBGRA
IWICFormatConverter * pFormatConverter = NULL;
if (SUCCEEDED(hr))
{
SafeRelease(&pFormatConverter);
hr = pImageFactory->CreateFormatConverter(&pFormatConverter);
}

if (SUCCEEDED(hr))
hr = pFormatConverter->Initialize(pFrame, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeCustom);

return hr;
}

HRESULT imagerender(HWND hWnd, IWICBitmapFrameDecode * pFrame, int x, int y)
{
//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 sz = D2D1::SizeU(MAINWINDOWWIDTH, MAINWINDOWHEIGHT); //Change size

ID2D1Factory * pD2DFactory;

HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory1), NULL, (LPVOID *) &pD2DFactory);

ID2D1RenderTarget * pRenderTarget;
//renderTargetProperties, D2D1::HwndRenderTargetProperties(hWnd, sz), &pRenderTarget);
hr = pD2DFactory->CreateHwndRenderTarget(&renderTargetProperties, D2D1::HwndRenderTargetProperties(hWnd, sz), &pRenderTarget);ID2D1Bitmap * pD2DBitmap = NULL;

pRenderTarget->CreateBitmapFromWicBitmap(pFrame, NULL, &pD2DBitmap);

D2D1_SIZE_F size = pD2DBitmap->GetSize();
D2D1_POINT_2F origin = D2D1::Point2F((float) x, (float) y);

if (pD2DBitmap)
pRenderTarget->DrawBitmap(pD2DBitmap, D2D1::RectF(origin.x, origin.y, origin.x + size.width, origin.y + size.height));

return hr;
}

Вопрос:

1) Следующая строка дает мне ошибку. Я попытался прочитать некоторые документы на MSDN, но не уверен, в чем проблема.

hr = pD2DFactory->CreateHwndRenderTarget(&renderTargetProperties, D2D1::HwndRenderTargetProperties(hWnd, sz), &pRenderTarget);

Ошибка:

IntelliSense: no instance of overloaded function "ID2D1Factory::CreateHwndRenderTarget" matches the argument list
argument types are: (D2D1_RENDER_TARGET_PROPERTIES *, D2D1_HWND_RENDER_TARGET_PROPERTIES, ID2D1RenderTarget **)
object type is: ID2D1Factory 68 18

2) В целом, существует ли более идиоматичный / эффективный способ решения проблемы рендеринга изображения из файла в окно, чем тот, который я пытался сделать? Мой предыдущий опыт программирования был строго на C.

1

Решение

Нет проблем. Вы можете использовать GDI + для загрузки любого изображения, которое Windows поддерживает изначально.
Затем вы можете использовать GDI, чтобы нарисовать его.

Вот краткий пример рисования (прозрачного) PNG на фоне диалога. Я построил его, используя MinGW32 и Code :: Blocks. Вам нужно будет связать msimg32 а также gdiplus библиотеки для использования AlphaBlend и класса Bitmap (и функции init / shutdown GDI +).

Точки, которые стоит упомянуть:

  • mLoadImage загрузит все, что Windows покажет в Windows Photo
    Просмотрщик (// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF и EMF) — использует
    Bitmap учебный класс, как найдено в Gdiplus.
  • Сообщение WM_ERASEBKGND приходит с wParam, содержащим контекст устройства
    что вы можете нарисовать прямо в — поэтому нет необходимости получать
    один от usig BeginPaint, как мы делаем в ответ на сообщение WM_PAINT.
  • Вы можете использовать BitBlt или StretchBlt для изображений, которые не содержат прозрачных областей.

main.cpp

#define WINVER 0x0500       // for AlphaBlend
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <gdiplus.h>
#include "resource.h"
using namespace Gdiplus;
HINSTANCE hInst;void setClientSize(HWND mHwnd, int width, int height)
{
RECT wndRect, clientRect, mRect;
int clientX, clientY, windowX, windowY, difX, difY;

GetWindowRect(mHwnd, &wndRect);
GetClientRect(mHwnd, &clientRect);
clientX = clientRect.right - clientRect.left;
clientY = clientRect.bottom - clientRect.top;

windowX = wndRect.right - wndRect.left;
windowY = wndRect.bottom - wndRect.top;

difX = windowX - clientX;
difY = windowY - clientY;

//    GetWindowRect(mHwnd, &mRect);
POINT topLeft = {wndRect.left, wndRect.top};
//  ScreenToClient(mParentHwnd, &topLeft);

SetWindowPos(mHwnd, HWND_TOP, topLeft.x, topLeft.y, width+difX, height+difY, SWP_NOZORDER);
}

HBITMAP mLoadImg(wchar_t *filename)
{
Bitmap mBitmap(filename,false);
HBITMAP result;
mBitmap.GetHBITMAP(0x00000000, &result);
return result;
}

void onPaint(HWND hwnd, HBITMAP bkg)
{
HDC memDC, hdc;
PAINTSTRUCT ps;
HBITMAP old;
RECT clientRect;
int width, height;

hdc = BeginPaint(hwnd, &ps);

GetClientRect(hwnd, &clientRect);
width = clientRect.right - clientRect.left;
height = clientRect.bottom - clientRect.top;

memDC = CreateCompatibleDC(NULL);
old = (HBITMAP)SelectObject(memDC, bkg);byte alpha = 255;
BLENDFUNCTION bf = {AC_SRC_OVER,0,alpha,AC_SRC_ALPHA};
AlphaBlend(hdc, 0,0,width,height, memDC, 0,0, width,height, bf);
// try the below instead of AlphaBlend - they each rely on the fact I've resized the
// client area to the same size as the image I'll draw on it.
//    BitBlt(hdc, 0,0, clientRect.right,clientRect.bottom, memDC, 0,0, SRCCOPY);

SelectObject(memDC, old);
DeleteDC(memDC);
EndPaint(hwnd, &ps);
}

BOOL CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HBITMAP mBkg;
switch(uMsg)
{
case WM_INITDIALOG:
{
mBkg = mLoadImg(L"wiki.png");
BITMAP bm;
GetObject(mBkg, sizeof(bm), &bm);
setClientSize(hwndDlg, bm.bmWidth, bm.bmHeight);
}
return TRUE;

case WM_ERASEBKGND:
{
RECT clientRect;
HBRUSH bkgBrush = CreateSolidBrush( RGB(255,0,0) );
GetClientRect(hwndDlg, &clientRect);
FillRect( (HDC)wParam, &clientRect, bkgBrush);
DeleteObject(bkgBrush);
}
return 1;

case WM_PAINT:
onPaint(hwndDlg, mBkg);
return 0;

case WM_CLOSE:
{
EndDialog(hwndDlg, 0);
}
return TRUE;

case WM_COMMAND:
{
switch(LOWORD(wParam))
{
}
}
return TRUE;
}
return FALSE;
}int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

hInst=hInstance;
InitCommonControls();
int retVal = DialogBox(hInst, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DlgMain);

GdiplusShutdown(gdiplusToken);

return retVal;
}

resource.h

#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif

#define DLG_MAIN                                100

resource.rc

// Generated by ResEdit 1.6.2
// Copyright (C) 2006-2014
// http://www.resedit.net

#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"//
// Dialog resources
//
DLG_MAIN DIALOG 0, 0, 186, 95
STYLE DS_3DLOOK | DS_CENTER | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_THICKFRAME | WS_SYSMENU
EXSTYLE WS_EX_WINDOWEDGE
CAPTION "Dialog"FONT 8, "Ms Shell Dlg"{
}

Wiki.png

введите описание изображения здесь

Результат
введите описание изображения здесь

6

Другие решения


По вопросам рекламы [email protected]