MFC 用 Direct2D 显示图像到 Picture Control 中

    2016年第一天,新年快乐!!!

    由于一直跟视频这块打交道,对于图像编解码和显示等方面都有所研究。最近遇到一个性能要求比较高的应用,原本的GDI绘图导致到线程负荷比较重,造成整个系统不稳定,因而生了要用Direct2D来取代的念头。经过一番研究后发现,Direct2D原来是这么的简单方便,而效率也比GDI有了显著的提升。废话不多说,下面还是直接上代码吧。

    本人一开始是在网上搜的一份代码,后来改了很多才将代码调好,并修复了一些内存泄露的bug,所以如有雷同绝非偶然,但不雷同之处便是其中要紧之处。

    主要的代码都封装成了BaseFactory类,其代码如下:

    BaseFactory.h

// 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
//
#pragma once

// 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 7 or later.
#define WINVER 0x0700       // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT        // Allow use of features specific to Windows 7 or later.
#define _WIN32_WINNT 0x0700 // Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef UNICODE
#define UNICODE
#endif

// Exclude rarely-used items from Windows headers.
#include <d2d1.h>
//#include <d2d1helper.h>


/******************************************************************
*                                                                 *
*  Macros                                                         *
*                                                                 *
******************************************************************/
template<class Interface>
inline void SafeRelease(
	Interface **ppInterfaceToRelease
	)
{
	if (*ppInterfaceToRelease != NULL)
	{
		(*ppInterfaceToRelease)->Release();

		(*ppInterfaceToRelease) = NULL;
	}
}

#ifndef Assert
#if defined( DEBUG ) || defined( _DEBUG )
#define Assert(b) do {if (!(b)) {OutputDebugStringA("Assert: " #b "\n");}} while(0)
#else
#define Assert(b)
#endif //DEBUG || _DEBUG
#endif

#ifndef HINST_THISCOMPONENT
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
#endif

class BaseFactory
{
public:
	BaseFactory(void);
	~BaseFactory(void);
	bool Initialize(HWND hwnd,int width,int height);
private:
	// Initialize device-dependent resources.
	HRESULT CreateDeviceResources();

	// Release device-dependent resource.
	
public:
	//绘图
	void OnRender(char *data);
	void DiscardDeviceResources();
	//图片信息
	int imgwidth;
	int imgheight;
	D2D1_RECT_U imgrect;
	char *imgdata;

private:
	RECT rc;
	HWND m_hwnd;
	ID2D1Factory* m_pDirect2dFactory;
	ID2D1HwndRenderTarget* m_pRenderTarget;

	ID2D1Bitmap* m_pBitmap;
};
    BaseFactory.cpp
#include "stdafx.h"
#include "BaseFactory.h"

BaseFactory::BaseFactory(void)
{
}

bool BaseFactory::Initialize(HWND hwnd, int width, int height)
{
	imgheight = height;
	imgwidth = width;
	m_hwnd = hwnd;
	m_pRenderTarget = nullptr;
	m_pBitmap = nullptr;
	CreateDeviceResources();
	return true;
}

BaseFactory::~BaseFactory(void)
{
}

HRESULT BaseFactory::CreateDeviceResources()
{
	D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory);
	HRESULT hr = S_OK;

	if (!m_pRenderTarget)
	{
		GetClientRect(m_hwnd, &rc);

		D2D1_SIZE_U size = D2D1::SizeU
			(
			rc.right-rc.left,
			rc.bottom-rc.top
			);
		// Create a Direct2D render target.
		hr = m_pDirect2dFactory->CreateHwndRenderTarget(
			D2D1::RenderTargetProperties(),
			D2D1::HwndRenderTargetProperties(m_hwnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY),//第三个参数设置不等待垂直同步,默认垂直同步时最高刷新频率为显卡刷新频率,一般60FPS
			&m_pRenderTarget
			);
		//创建位图
		D2D1_SIZE_U imgsize= D2D1::SizeU(imgwidth, imgheight);
		D2D1_PIXEL_FORMAT pixelFormat =  //位图像素格式描述
		{
			DXGI_FORMAT_B8G8R8A8_UNORM, //该参数设置图像数据区的像素格式,现为RGBA,可根据需要改为别的格式,只是后面的数据拷贝要做相应的调整
			D2D1_ALPHA_MODE_IGNORE
		};
		D2D1_BITMAP_PROPERTIES prop =  //位图具体信息描述
		{
			pixelFormat,
			imgsize.width,
			imgsize.height
		};
		long pitch = imgsize.width*4;
		imgdata = new char[imgsize.width * imgsize.height * 4];
		memset(imgdata, 0, imgsize.width * imgsize.height * 4);
		m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);//设置图像为抗锯齿模式
		m_pRenderTarget->CreateBitmap(imgsize, imgdata, pitch, &prop, &m_pBitmap);
		
		imgrect.left = 0;
		imgrect.right = imgwidth;
		imgrect.top = 0;
		imgrect.bottom = imgheight;
	}
	return hr;
}

void BaseFactory::DiscardDeviceResources()
{
	delete[] imgdata;
	SafeRelease(&m_pRenderTarget);
	m_pDirect2dFactory->Release();
	m_pBitmap->Release();
}

void BaseFactory::OnRender(char *data)//绘制图形到指定控件中
{
	m_pRenderTarget->BeginDraw();//跟显示刷新频率有关系
	m_pBitmap->CopyFromMemory(&imgrect, data, imgwidth * 4);
	m_pRenderTarget->DrawBitmap(m_pBitmap, D2D1::RectF(0, 0, rc.right - rc.left, rc.bottom - rc.top));//该矩形大小会受到"更改文本、应用和其他项目的大小:xxx%"的影响
	m_pRenderTarget->EndDraw();
}
    将两个文件添加到工程,在需要的时候将 BaseFactory.h 包含进去即可。对了,由于用到了Diretc2D,所以需要将d2d1.lib给链接上去。

    完成了上面的工作,在需要用到的地方加上下面代码即可,代码中调用了OpenCV库来读取并解码图片,所以给Direct2D的只是指向图像RGBA数据区的指针而已,假设不想如此,也可自作修改。

char *filename = "1.jpg";//图像路径  
IplImage* img = cvLoadImage(filename);
BaseFactory* m_BaseFactory = new BaseFactory();//创建Direct2D工厂对象
HWND m_hWnd = GetDlgItem(IDC_STATIC_SHOW)->GetSafeHwnd();//IDC_STATIC_SHOW为Picture Control的ID
m_BaseFactory->Initialize(m_hWnd, img->width, img->height);//初始化

//将rgb转为rgba
char *data = new char[img->width*img->height * 4];
for (size_t row = 0; row < img->height; row++)
	for (size_t col = 0; col < img->width; col++)
	{
		int point = col * 3 + row*img->width * 3;
		int pointrbga = col * 4 + row*img->width * 4;
		data[pointrbga + 0] = img->imageData[point + 0];
		data[pointrbga + 1] = img->imageData[point + 1];
		data[pointrbga + 2] = img->imageData[point + 2];
	}

int i = 480;
long time = clock();

while (i--)
{
	//将图像绘制到控件中
	m_BaseFactory->OnRender(data);
}
printf("D2D花费时间%dms\n", clock() - time);
printf("刷新频率%lf张/s\n", 480 / (double(clock() - time) / 1000));
//释放对象,回收内存
if (m_BaseFactory != NULL)
{
	m_BaseFactory->DiscardDeviceResources();
	delete m_BaseFactory;
	m_BaseFactory = NULL;
}
cvReleaseImage(&img);
delete[]data;


你可能感兴趣的:(C++,mfc,picture,2d,control,Direct)