C++系列——Direct2D图片处理
01 前言
图片处理工具多如牛毛了,自不必说。主要是应对需要批量处理
的场景,所以不如手搓。已经试过直接用C#
封装好的库System.Drawing
,挺好的,就是过了一段时间感觉这速度有点受不了。于是转用C++
,结合GDI+
又手搓了一个。因为部分代码与C#版本类似(C#底层用的还是GDI),很快也搞好了。
嗯~~ 这下舒服了。随着效率的提高,我以为可以快乐的摸鱼了。省下来的时间里,突然想到——有没有可能利用上GPU
的性能再提高一下?于是与Direct2D
偶遇了,有人说这玩意比GDI+
更快,还可以利用GPU的优势。什么?总以为这玩意就是做游戏开发的,这辈子可能都接触不到的……
于是,新的活又来了——继续搓。
因为需求只是想简单的做图片处理,比如复制图片,然后加点文字、形状等等,然后保存输出。但是似乎这么玩的人比较少(或者可能是用Direct2D
的人比较少),资料比较少。没办法只能结合官方的文档慢慢踩坑了。
第一步,我只想简单地从磁盘读取一个PNG图片,然后再画一个矩形,然后再另存为一张图。就这么一个简单的需求,不需要显示到窗口什么的,就单纯的图片处理,都没找到一个比较完整可用的例子(我菜我承认 )。
由于半桶水的水平,摸索了大半天才搞出来一个例子,供学习参考。
02 正文
开发环境:
Windows 11 64 bit
Microsoft Visual Studio Community 2022
C++ 14
VS编辑器,怎么创建项目不用多说了。
就直接写在主文件中。代码如下:
// ImgTool.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <windows.h>
#include <d2d1.h>
#include <d2d1_1.h>
#include <wincodec.h>
//表示链接XXXX.lib这个库。
//和在工程设置里写上链入wpcap.lib的效果一样(两种方式等价,或说一个隐式一个显式调用)
//不过这种方法写的 程序别人在使用你的代码的时候就不用再设置工程settings了。
//告诉连接器连接的时候要找XXX.lib,这样你就不用在linker的lib设置里指定这个lib了。
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "windowscodecs.lib")
using namespace std;
/// <summary>
/// 释放 COM 接口指针
/// https://learn.microsoft.com/zh-cn/windows/win32/medfound/saferelease
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ppT"></param>
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
/// <summary>
/// 导入图片,转换成direct2d的图像对象:ID2D1Bitmap
/// </summary>
/// <param name="pRenderTarget"></param>
/// <param name="pIWICFactory"></param>
/// <param name="resourceName"></param>
/// <param name="ppBitmap"></param>
/// <returns></returns>
HRESULT LoadResourceBitmap(
ID2D1RenderTarget* pRenderTarget,
IWICImagingFactory* pIWICFactory,
PCWSTR resourceName,
ID2D1Bitmap** ppBitmap
)
{
IWICBitmapDecoder* pDecoder = NULL;
IWICBitmapFrameDecode* pSource = NULL;
IWICFormatConverter* pConverter = NULL;
//直接从文件,比fromStream方便一点,不需要处理那么多步
HRESULT hr = pIWICFactory->CreateDecoderFromFilename(
resourceName, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder
);
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
else {
std::cout << "pDecoder->GetFrame fail..." << std::endl