Windows API从文件渲染图像(初学者)

时间:2014-08-07 05:47:38

标签: c++ winapi direct2d wic

我试图了解如何使用Windows API,Direct2D和Visual C ++从文件加载和呈现图像。我或多或少都试图在这个主题上关注an MSDN article。我是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 个答案:

答案 0 :(得分:7)

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

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

可能值得一提的要点是:

  • mLoadImage将加载Windows将在Windows Photo中显示的任何内容 Viewer(// BMP,GIF,JPEG,PNG,TIFF,Exif,WMF和EMF) - 它使用 在Gdiplus中找到的Bitmap
  • 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

enter image description here

<强>结果 enter image description here