1

我试图了解如何使用 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 语言。

4

1 回答 1

7

没问题。您可以使用 GDI+ 加载 Windows 本机支持的任何图像。然后,您可以使用 GDI 来绘制它。

这是一个将(透明)PNG 绘制到对话框背景的简短示例。我使用 MinGW32 和 Code::Blocks 构建了它。您需要链接msimg32gdiplus库以使用 AlphaBlend 和 Bitmap 类(以及初始化/关闭 GDI+ 的函数)。

可能值得一提的是:

  • mLoadImage 将加载窗口将在 Windows 照片查看器(// BMP、GIF、JPEG、PNG、TIFF、Exif、WMF 和 EMF)中显示的任何内容 - 它使用Gdiplus 中的Bitmap 类。
  • WM_ERASEBKGND 消息与 wParam 一起提供了一个设备上下文,您可以直接将其绘制到 - 这就是为什么不需要通过使用 BeginPaint 来获取一个,就像我们在响应 WM_PAINT 消息时所做的那样。
  • 对于不包含透明区域的图像,您可以使用 BitBlt 或 StretchBlt。

主文件

#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;
}

资源.h

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

#define DLG_MAIN                                100

资源.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"
{
}

维基.png

在此处输入图像描述

结果 在此处输入图像描述

于 2014-08-07T07:46:16.607 回答