由于SOUI是一种双渲染引擎的DUI库,默认在SKIA渲染引擎下是支持特效字体的,具体请参考DEMO中的源码。

但是使用GDI+渲染时是没有这些特效的,着实比较苦恼,此代抛砖引玉,细节实现 请自己再去封装,此处只封装了STATIC控件。

部分效果使用了库:TextDesigner

CodeProject: http://www.codeproject.com/Articles/42529/Outline-Text

此代码有一个小BUG,在使用SOUI布局时,POS必须4个参数都指定,类似如此:pos="15,20,-15,@25"

有兴趣的朋友可以自己实现一下。

先看下预览效果

我只实现了部分效果,由于效果组合太多,所以这里暂时把我常用的先贴出来。

参数说明:

drawMode: 1为描边 2阴影 3外发光 4双描边,具体特效请自己设置颜色和渲染效果

EffectColor: 特效的颜色数值

EffectColor2: 使用双效果时的第二个数值颜色

底层使用GDI+所以默认支持多行,但是请根据多行来设置对应的高宽,否则显示肯定错误。

头文件:

 /*!
* \file SEffectStatic.h
* \date 2016/02/15 19:51
*
* \author koangel
* Contact: jackliu100@gmail.com
* blog: http://www.cnblogs.com/koangel/
*
* \brief GDI渲染模式下专用静态特效渲染库
*
* \note GDI+渲染模式下专用,如果在SKIA模式下,直接切换为标准SSTAIC模式渲染
* 效果使用GDI编写,暂不支持SKIA
* 部分效果使用TextDesigner库编写。
* CodeProject: http://www.codeproject.com/Articles/42529/Outline-Text
* TextDesigner版权归原作者所有。
*/
#pragma once
#include <gdiplus.h> #pragma comment(lib,"gdiplus.lib") class SEffectStatic : public SStatic
{
SOUI_CLASS_NAME(SStatic, L"eff_text")
public:
SEffectStatic();
virtual ~SEffectStatic();
/**
* SStatic::SDrawText
* @brief 绘制文本
* @param IRenderTarget *pRT -- 绘制设备句柄
* @param LPCTSTR pszBuf -- 文本内容字符串
* @param int cchText -- 字符串长度
* @param LPRECT pRect -- 指向矩形结构RECT的指针
* @param UINT uFormat -- 正文的绘制选项
*
* Describe 对DrawText封装
*/
virtual void DrawText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); protected: void DrawMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat);
void DrawShadowMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); // 渲染带阴影的字体
void DrawShadowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat);
void DrawStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat);
void DrawDoubleStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat);
void DrawGowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); void initGDIFont(IRenderTarget *pRT,Gdiplus::Font& gf); LOGFONT* GetGDIFont(IRenderTarget *pRT);
Gdiplus::StringFormat* toFormat(UINT uFormat); int m_nEffectDrawMode; /**< 渲染模式 */
COLORREF m_nEffectColor; /**< 效果颜色 */
COLORREF m_nEffectColor2; /**< 效果颜色 */
WORD m_StrokeSize; /**< 描边大小 */ SOUI_ATTRS_BEGIN()
ATTR_INT(L"drawMode", m_nEffectDrawMode, FALSE)
ATTR_COLOR(L"effectColor", m_nEffectColor, FALSE)
ATTR_COLOR(L"effectColor2", m_nEffectColor2, FALSE)
ATTR_INT(L"strokeSize", m_StrokeSize, FALSE)
SOUI_ATTRS_END()
};

实现文件:

 /*!
* \file SEffectStatic.cpp
* \date 2016/02/16 13:00
*
* \author koangel
* Contact: jackliu100@gmail.com
*
* \brief 渲染对应的静态文本,多行文本渲染可能存在问题
*
* TODO: blog http://www.cnblogs.com/koangel/
*
* \note
*/
#include "stdafx.h"
#include "SEffectStatic.h"
enum DRAW_EFFECT_MODE
{
DRAW_TEXT_NORMAL = , // 默认渲染
DRAW_TEXT_STROKE, // 渲染 描边
DRAW_TEXT_SHADOW, // 渲染 阴影
DRAW_TEXT_GROW, // 渲染 外发光效果
DRAW_TEXT_DBSTROKE, // 渲染 双描边
}; #define GR(rgb) ((BYTE)(rgb))
#define GG(rgb) ((BYTE)(((WORD)(rgb)) >> 8))
#define GB(rgb) ((BYTE)((rgb)>>16)) // 默认调用之前的构造函数
SEffectStatic::SEffectStatic() : SStatic(),
m_nEffectColor(0xFFFFFF),
m_nEffectColor2(0xFF0080),
m_nEffectDrawMode(),
m_StrokeSize()
{
} SEffectStatic::~SEffectStatic()
{ } void SEffectStatic::DrawText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat)
{
if (!m_bMultiLines)
{
switch (m_nEffectDrawMode)
{
case DRAW_TEXT_NORMAL:
__super::DrawText(pRT, pszBuf, cchText, pRect, uFormat);
break;
case DRAW_TEXT_STROKE:
DrawStrokeText(pRT, pszBuf, cchText, pRect, uFormat);
break;
case DRAW_TEXT_SHADOW:
DrawShadowText(pRT, pszBuf, cchText, pRect, uFormat);
break;
case DRAW_TEXT_GROW:
DrawGowText(pRT, pszBuf, cchText, pRect, uFormat);
break;
case DRAW_TEXT_DBSTROKE:
DrawDoubleStrokeText(pRT, pszBuf, cchText, pRect, uFormat);
break;
}
}
else
{
switch (m_nEffectDrawMode)
{
case DRAW_TEXT_NORMAL:
{
if (uFormat&(DT_VCENTER | DT_BOTTOM) && !(uFormat & DT_CALCRECT))
{
//static 多行控件支持垂直居中及底对齐
CRect rcText = *pRect;
DrawMultiLine(pRT, pszBuf, cchText, &rcText, uFormat | DT_CALCRECT);
CSize szTxt = rcText.Size();
rcText = *pRect;
switch (GetStyle().GetTextAlign()&(DT_VCENTER | DT_BOTTOM))
{
case DT_VCENTER:
rcText.DeflateRect(, (rcText.Height() - szTxt.cy) / );
break;
case DT_BOTTOM:
rcText.DeflateRect(, (rcText.Height() - szTxt.cy));
break;
}
DrawMultiLine(pRT, pszBuf, cchText, &rcText, uFormat);
}
else
{
DrawMultiLine(pRT, pszBuf, cchText, pRect, uFormat);
}
break;
}
case DRAW_TEXT_STROKE:
DrawStrokeText(pRT, pszBuf, cchText, pRect, uFormat);
break;
case DRAW_TEXT_SHADOW:
DrawShadowMultiLine(pRT, pszBuf, cchText, pRect, uFormat);
break;
case DRAW_TEXT_GROW:
DrawGowText(pRT, pszBuf, cchText, pRect, uFormat);
break;
case DRAW_TEXT_DBSTROKE:
DrawDoubleStrokeText(pRT, pszBuf, cchText, pRect, uFormat);
break;
}
}
} void SEffectStatic::DrawMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat)
{
SIZE szChar;
int i = , nLine = ;
if (cchText == -) cchText = _tcslen(pszBuf);
LPCTSTR p1 = pszBuf;
POINT pt = { pRect->left,pRect->top };
pRT->MeasureText(_T("A"), , &szChar);
int nLineHei = szChar.cy;
int nRight = pRect->right;
pRect->right = pRect->left;
while (i<cchText)
{
LPTSTR p2 = CharNext(p1);
if (*p1 == _T('\\') && p2 && *p2 == _T('n'))
{
pt.y += nLineHei + m_nLineInter;
pt.x = pRect->left;
nLine++;
i += p2 - p1;
p1 = CharNext(p2);
i += p1 - p2;
continue;
}
pRT->MeasureText(p1, p2 - p1, &szChar);
if (pt.x + szChar.cx > nRight)
{
pt.y += nLineHei + m_nLineInter;
pt.x = pRect->left;
nLine++;
continue;
}
if (!(uFormat & DT_CALCRECT))
{
pRT->TextOut(pt.x, pt.y, p1, p2 - p1);
}
pt.x += szChar.cx;
if (pt.x > pRect->right && uFormat & DT_CALCRECT) pRect->right = pt.x;
i += p2 - p1;
p1 = p2;
}
if (uFormat & DT_CALCRECT)
{
pRect->bottom = pt.y + nLineHei;
}
} void SEffectStatic::DrawShadowMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat)
{
COLORREF textColor = this->m_style.GetTextColor(); Gdiplus::StringFormat *strFmt = toFormat(uFormat); Gdiplus::Graphics gs(pRT->GetDC());
Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit);
gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); Gdiplus::FontFamily ffamliy;
gf.GetFamily(&ffamliy); Gdiplus::SolidBrush br1(Gdiplus::Color(, GR(textColor), GG(textColor), GB(textColor))); TextDesigner::OutlineText outtext;
outtext.EnableShadow(true);
outtext.TextNoOutline(br1);
outtext.Shadow(Gdiplus::Color(, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)), , Gdiplus::Point(,));
outtext.DrawString(&gs, &ffamliy, (Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize(), pszBuf, rectF, strFmt);
} void SEffectStatic::DrawShadowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat)
{
COLORREF textColor = this->m_style.GetTextColor(); Gdiplus::StringFormat *strFmt = toFormat(uFormat);
Gdiplus::Graphics gs(pRT->GetDC());
Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit);
gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); Gdiplus::FontFamily ffamliy;
gf.GetFamily(&ffamliy); Gdiplus::SolidBrush br1(Gdiplus::Color(, GR(textColor), GG(textColor), GB(textColor))); TextDesigner::OutlineText outtext;
outtext.EnableShadow(true);
outtext.TextNoOutline(br1);
outtext.Shadow(Gdiplus::Color(, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)), , Gdiplus::Point(,));
outtext.DrawString(&gs, &ffamliy,(Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize() , pszBuf, rectF, strFmt);
} void SEffectStatic::DrawStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat)
{
COLORREF textColor = this->m_style.GetTextColor();
Gdiplus::Graphics gs(pRT->GetDC());
Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT));
Gdiplus::StringFormat *strFmt = toFormat(uFormat); gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit);
gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); Gdiplus::RectF rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); Gdiplus::SolidBrush br1(Gdiplus::Color(,GR(textColor), GG(textColor), GB(textColor)));
Gdiplus::SolidBrush br2(Gdiplus::Color(,GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor))); int nOffsetX[] = { ,,,,-,-,-, };
int nOffsetY[] = { -,,,,,,-,- }; for (int i = ; i < ;i++)
{
Gdiplus::RectF lRecf(rectF);
lRecf.Offset(nOffsetX[i], nOffsetY[i]);
gs.DrawString(pszBuf, cchText, &gf, lRecf, strFmt, &br2);
} gs.DrawString(pszBuf, cchText, &gf, rectF, toFormat(uFormat), &br1);
} void SEffectStatic::DrawDoubleStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat)
{
COLORREF textColor = this->m_style.GetTextColor();
Gdiplus::StringFormat *strFmt = toFormat(uFormat);
Gdiplus::Graphics gs(pRT->GetDC());
Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit);
gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); Gdiplus::FontFamily ffamliy;
gf.GetFamily(&ffamliy); Gdiplus::SolidBrush br1(Gdiplus::Color(, GR(textColor), GG(textColor), GB(textColor))); TextDesigner::OutlineText outtext;
outtext.EnableShadow(false);
outtext.TextDblOutline(br1, Gdiplus::Color(, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)),
Gdiplus::Color(, GR(m_nEffectColor2), GG(m_nEffectColor2), GB(m_nEffectColor2)), ,);
outtext.DrawString(&gs, &ffamliy, (Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize(), pszBuf, rectF, strFmt);
} void SEffectStatic::DrawGowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat)
{
COLORREF textColor = this->m_style.GetTextColor();
Gdiplus::StringFormat *strFmt = toFormat(uFormat);
Gdiplus::Graphics gs(pRT->GetDC());
Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit);
gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); Gdiplus::FontFamily ffamliy;
gf.GetFamily(&ffamliy); Gdiplus::SolidBrush br1(Gdiplus::Color(, GR(textColor), GG(textColor), GB(textColor))); TextDesigner::OutlineText outtext;
outtext.EnableShadow(false);
outtext.TextGlow(br1,Gdiplus::Color(, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)),);
outtext.DrawString(&gs, &ffamliy, (Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize(), pszBuf, rectF, strFmt);
} LOGFONT* SEffectStatic::GetGDIFont(IRenderTarget *pRT)
{
SOUI::IFontPtr pFont = m_style.GetTextFont();
SOUI::IFontPtr pDFont = (SOUI::IFontPtr)pRT->GetCurrentObject(OT_FONT);
LOGFONT * logFont = NULL;
if (pFont == NULL)
logFont = (LOGFONT*)pDFont->LogFont();
else
logFont = (LOGFONT*)pFont->LogFont(); return logFont;
} Gdiplus::StringFormat* SEffectStatic::toFormat(UINT uFormat)
{
Gdiplus::StringFormat *strFmt = Gdiplus::StringFormat::GenericTypographic()->Clone(); if (uFormat&(DT_VCENTER | DT_BOTTOM))
{
strFmt->SetAlignment(Gdiplus::StringAlignmentCenter);
strFmt->SetLineAlignment(Gdiplus::StringAlignmentCenter);
}
else
{
strFmt->SetAlignment(Gdiplus::StringAlignmentNear);
strFmt->SetLineAlignment(Gdiplus::StringAlignmentNear);
} return strFmt;
}

以上代码抛砖引玉,希望各位发扬光大,多写一些组件库噢。

[原创]SOUI GDI+渲染引擎下的字体特效,抛砖引玉的更多相关文章

  1. Fedora 24 Linux 环境下实现 Infinality 字体渲染增强及 Java 字体渲染改善的方法(修订)

    Fedora 24 Linux 桌面环境默认字体渲染引擎 freetype 及字体配置工具 fontconfig 采用的是未经优化的编译及设置,字体渲染效果比较差.而某些 Linux 发行版的桌面字体 ...

  2. 【原创】smarty引擎下的导航按钮高亮实现

    <?php$_nvaarr = array( array('name'=>'首页','url'=>'company.php?id='), array('name'=>'公司介绍 ...

  3. 剖析虚幻渲染体系(14)- 延展篇:现代渲染引擎演变史Part 1(萌芽期)

    目录 14.1 本篇概述 14.1.1 游戏引擎简介 14.1.2 游戏引擎模块 14.1.3 游戏引擎列表 14.1.3.1 Unreal Engine 14.1.3.2 Unity 14.1.3. ...

  4. [比较老的文章]三维渲染引擎 OGRE 与 OSG 的比较综述

    1 .引言随着计算机可视化.虚拟现实技术的飞速发展,人们对实时真实感渲染以及场景复杂度提出了更高的要求.传统的直接使用底层图形接口如OpenGL.DirectX开发图形应用的模式越来越暴露出开发复杂性 ...

  5. How Javascript works (Javascript工作原理) (十一) 渲染引擎及性能优化小技巧

    个人总结:读完这篇文章需要20分钟,这篇文章主要讲解了浏览器中引擎的渲染机制. DOMtree       ----|   |---->  RenderTree CSSOMtree  ----| ...

  6. JavaScript 工作原理之十一-渲染引擎及性能优化小技巧

    原文请查阅这里,略有删减,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland. 本系列持续更新中,Github 地址请查阅这里. 这是 JavaScript 工作原理的第十一章. 迄 ...

  7. 浏览器渲染引擎,提高css渲染速度。

    一.渲染引擎渲染引擎的职责是……渲染,也就是把请求的内容显示到浏览器屏幕上.默认情况下渲染引擎可以显示HTML,XML文档以及图片. 通过插件(浏览器扩展)它可以显示其它类型文档. 二.各种渲染引擎我 ...

  8. Outlook HTML渲染引擎

    OutLook始终不离不弃 是不是很讨厌为Email代码兼容Outlook? 太遗憾了!虽然光都有尽头,但Outlook始终存在. 为了应付Email的怪癖,我们花了很多时间测试,确保我们搞定了所有O ...

  9. linux服务器下添加字体

    版权声明:本文为楼主原创文章,未经楼主允许不得转载,如要转载请注明来源. 引言:这两天在开发一个动态生成海报的东西(图片拼接,图片水印),开发在windows下没有问题,图片和文字都能正常的生成出来. ...

随机推荐

  1. GOF23设计模式之享元模式(flyweight)

    一.享元模式概述 内存属于稀缺资源,不要随便浪费.如果有很多个完全相同或相似的对象,可以通过享元模式,节省内存. 享元模式核心: (1)享元模式可以共享的.方式高效的支持大量细粒度对象的重用: (2) ...

  2. 原 win10 msys2 vs2015 ffmpeg3.2.2 编译

    01 环境 win10x64企业版.vs2015update3企业版.git(git version 2.10.0.windows.1). 02 下载ffmpeg代码 git clone https: ...

  3. Java-Runoob-高级教程: Java 多线程编程

    ylbtech-Java-Runoob-高级教程: Java 多线程编程 1.返回顶部 1. Java 多线程编程 Java 给多线程编程提供了内置的支持. 一条线程指的是进程中一个单一顺序的控制流, ...

  4. Java-API-POI:POI 笔记

    ylbtech-Java-API-POI:POI 笔记 1. 笔记一返回顶部 1. 1,POI对JDK版本支持及XLSX (2017-04-01 13:51:39)对JDK6的支持,最后版本是POI- ...

  5. [转]加密经验集 => C#

    下载地址 代码摘自 C#高级编程(第7版) 第579页 不对称加密

  6. Web应用层协议---HTTP

    处于协议栈顶层的应用层协议定义了运行在不同端系统的应用程序进程如何相互传递报文.定义内容如下: 1.交换的报文类型.请求报文和响应报文. 2.各种报文类型的语法,如报文中的各个字段及这这些字段是如何描 ...

  7. 优化笔记:pfyhparopenfundinfotest_D_20140916.gz

    性能瓶颈在函数的乱用.原代码黄色部分. 12分钟->35秒 ------------------------------------------------------------------- ...

  8. 【转】C#父类与子类的静态成员变量、实例成员变量、构造函数的执行顺序

    原文地址:http://www.xuebuyuan.com/1092603.html Win7+VS2010测试的结果如下: ①子类静态成员变量②子类静态构造函数③子类实例成员变量④父类静态成员变量⑤ ...

  9. xargs的i参数

    xargs与find经常结合来进行文件操作,平时删日志的时候只是习惯的去删除,比如 # find . -type f -name "*.log" | xargs rm -rf * ...

  10. python变量、引用、拷贝之间的关系

    Python中一切皆为对象,不管是集合变量还是数值型or字符串型的变量都是一个引用,都指向对应内存空间中的对象. 简而言之: 变量直接赋值:新变量本身及其内部的元素都与原变量指向相同的内存空间,并且值 ...