用QT开发图像显示的小程序,需要一些标注工具,由于用的是opengl渲染,所以就在内存中进行绘制,然后纹理贴图贴出去,发现Qt绘制的效果太差,且速度一般,于是就想着用direct2d来绘制需要的纹理图像。
下图是QT直接在QImage对象上绘制的效果,其中QImage长和宽分别为:564 - 466。在打开反走样的设置下,线段和椭圆中的锯齿非常明显,字体绘制的也非常丑陋。
QT绘制代码:
void YGLayerScreen::UpdateQImage(){
if (m_QImage.isNull())
return;
QFont m_Font;
m_Font.setPixelSize(36);
m_Font.setStyleStrategy(QFont::PreferAntialias);
QPainter painter;
if (!painter.begin(&m_QImage))
return;
painter.setPen(QPen(Qt::red, 1));
painter.setFont(m_Font);
painter.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
painter.drawEllipse(QPoint(m_TextureCol/2, m_TextureRow/2),100,200);
painter.drawLine(10, 10, m_TextureCol / 2, 30);
painter.drawText(QPoint(50, 50), QString::fromLocal8Bit("你好123TEXTtext"));
painter.end();
}
QT中Direct2D的配置(非常简单),添加头文件和对应的Lib文件即可,如下:
#include
#include
#include
#include
#include
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "Dwrite.lib")
#pragma comment(lib, "windowscodecs.lib")
在窗口中随机绘制100个圆形和一个字符串和椭圆,代码如下:
void QtOpenGL::TestDirect2D()
{
/* 统计运行时间 */
LARGE_INTEGER start_counter, end_counter, counters, nFreq;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&start_counter);
/* 离屏渲染图像的宽高 */
UINT uiWidth = 512;// 1920;
UINT uiHeight = 512;// 1080;
/* IWIC 相关变量 */
IWICBitmap *pBitmap = NULL;
IWICImagingFactory* pImageFactory = NULL;
/* IDWrite 相关变量 */
IDWriteTextFormat *pTextFormat = NULL;
IDWriteFactory* pDWriterFactory = NULL; /* use the DrawText method */
static const WCHAR msc_fontName[] = L"Verdana";
static const FLOAT msc_fontSize = 50;
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
(LPVOID*)&pImageFactory
);
if (SUCCEEDED(hr)) {
//WICPixelFormatGUID formatGUID = GUID_WICPixelFormat32bppBGRA;
hr = pImageFactory->CreateBitmap(uiWidth, uiHeight,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnLoad, &pBitmap);
if (SUCCEEDED(hr)) {
int a = 0;
}
}
/* */
hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED,
__uuidof(pDWriterFactory),
reinterpret_cast(&pDWriterFactory)
);
// Create a DirectWrite text format object.
hr = pDWriterFactory->CreateTextFormat(msc_fontName, NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
msc_fontSize,
L"", //locale
&pTextFormat
);
pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
ID2D1Factory *m_pD2DFactory = NULL;
//ID2D1DCRenderTarget *m_pRenderTarget = NULL;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
if (SUCCEEDED(hr))
{
// Create a DC render target.
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_PREMULTIPLIED),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT
);
ID2D1RenderTarget* m_Target = NULL;
hr = m_pD2DFactory->CreateWicBitmapRenderTarget(pBitmap, &props, &m_Target);
D2D1_SIZE_F rtSize = m_Target->GetSize();
// Draw a grid background.
int width = static_cast(rtSize.width);
int height = static_cast(rtSize.height);
ID2D1SolidColorBrush* pBlackBrush = NULL;
hr = m_Target->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Red),//颜色
&pBlackBrush//接收画刷
);
static const WCHAR sc_txt[] = L"你好!Direct 2D!";
if (SUCCEEDED(hr))
{
m_Target->BeginDraw();
m_Target->Clear(D2D1::ColorF(0.26f, 0.56f, 0.87f));
m_Target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(150, 55), 50, 30), pBlackBrush);
m_Target->DrawTextW(
sc_txt,
ARRAYSIZE(sc_txt) - 1,
pTextFormat,
D2D1::RectF(0, 0, uiWidth/2, uiHeight/2),
pBlackBrush);
for (int i = 0; i < 100; ++i)
{
FLOAT left = rand() % width;
FLOAT top = rand() % height;
FLOAT radius = rand() % 200;
pBlackBrush->SetColor(D2D1::ColorF(rand() % 100 / 100.f, rand() % 100 / 100.f, rand() % 100 / 100.f, 100));
//CD2DEllipse ellipse(CD2DRectF(left, top, left + radius, top + radius));
//CD2DSolidColorBrush brush(pRenderTarget, D2D1::ColorF(rand() % 100 / 100.f, rand() % 100 / 100.f, rand() % 100 / 100.f, 100));
m_Target->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(left, top), radius, radius), pBlackBrush);
//pRenderTarget->FillEllipse(ellipse, &brush);
}
m_Target->EndDraw();
}
IWICBitmapLock *pLock = NULL;
WICRect rcLock = { 0, 0, uiWidth, uiHeight };
hr = pBitmap->Lock(&rcLock, WICBitmapLockWrite, &pLock);
if (SUCCEEDED(hr))
{
UINT cbBufferSize = 0;
UINT cbStride = 0;
BYTE *pv = NULL;
hr = pLock->GetStride(&cbStride);
if (SUCCEEDED(hr))
{
hr = pLock->GetDataPointer(&cbBufferSize, &pv);
FILE* pFile = fopen("bmp512.raw", "wb+");
fwrite(pv, 1, cbBufferSize, pFile);
fclose(pFile);
}
// Clear the image data
//ZeroMemory(pv, cbBufferSize);
// Release the bitmap lock.
pLock->Release();
}
}
if (pBitmap) {
pBitmap->Release();
}
if (pImageFactory) {
pImageFactory->Release();
}
QueryPerformanceCounter(&end_counter);
counters.QuadPart = end_counter.QuadPart - start_counter.QuadPart;
LONGLONG fps = nFreq.QuadPart / counters.QuadPart;
LONGLONG elapsed = counters.QuadPart * 1000 / nFreq.QuadPart;
qDebug() << "FPS :" << fps << "ms";
qDebug() << "TIMES :" << elapsed << "ms";
start_counter = end_counter;
}
绘制效果如下:
由于绘制的内容不同,暂时没对性能进行测试。