[原创]SOUI GDI+渲染引擎下的字体特效,抛砖引玉
由于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+所以默认支持多行,但是请根据多行来设置对应的高宽,否则显示肯定错误。
头文件:
1 /*! 2 * \file SEffectStatic.h 3 * \date 2016/02/15 19:51 4 * 5 * \author koangel 6 * Contact: jackliu100@gmail.com 7 * blog: http://www.cnblogs.com/koangel/ 8 * 9 * \brief GDI渲染模式下专用静态特效渲染库 10 * 11 * \note GDI+渲染模式下专用,如果在SKIA模式下,直接切换为标准SSTAIC模式渲染 12 * 效果使用GDI编写,暂不支持SKIA 13 * 部分效果使用TextDesigner库编写。 14 * CodeProject: http://www.codeproject.com/Articles/42529/Outline-Text 15 * TextDesigner版权归原作者所有。 16 */ 17 #pragma once 18 #include <gdiplus.h> 19 20 #pragma comment(lib,"gdiplus.lib") 21 22 class SEffectStatic : public SStatic 23 { 24 SOUI_CLASS_NAME(SStatic, L"eff_text") 25 public: 26 SEffectStatic(); 27 virtual ~SEffectStatic(); 28 /** 29 * SStatic::SDrawText 30 * @brief 绘制文本 31 * @param IRenderTarget *pRT -- 绘制设备句柄 32 * @param LPCTSTR pszBuf -- 文本内容字符串 33 * @param int cchText -- 字符串长度 34 * @param LPRECT pRect -- 指向矩形结构RECT的指针 35 * @param UINT uFormat -- 正文的绘制选项 36 * 37 * Describe 对DrawText封装 38 */ 39 virtual void DrawText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); 40 41 protected: 42 43 void DrawMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); 44 void DrawShadowMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); 45 46 // 渲染带阴影的字体 47 void DrawShadowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); 48 void DrawStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); 49 void DrawDoubleStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); 50 void DrawGowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat); 51 52 void initGDIFont(IRenderTarget *pRT,Gdiplus::Font& gf); 53 54 LOGFONT* GetGDIFont(IRenderTarget *pRT); 55 Gdiplus::StringFormat* toFormat(UINT uFormat); 56 57 int m_nEffectDrawMode; /**< 渲染模式 */ 58 COLORREF m_nEffectColor; /**< 效果颜色 */ 59 COLORREF m_nEffectColor2; /**< 效果颜色 */ 60 WORD m_StrokeSize; /**< 描边大小 */ 61 62 SOUI_ATTRS_BEGIN() 63 ATTR_INT(L"drawMode", m_nEffectDrawMode, FALSE) 64 ATTR_COLOR(L"effectColor", m_nEffectColor, FALSE) 65 ATTR_COLOR(L"effectColor2", m_nEffectColor2, FALSE) 66 ATTR_INT(L"strokeSize", m_StrokeSize, FALSE) 67 SOUI_ATTRS_END() 68 };
实现文件:
1 /*! 2 * \file SEffectStatic.cpp 3 * \date 2016/02/16 13:00 4 * 5 * \author koangel 6 * Contact: jackliu100@gmail.com 7 * 8 * \brief 渲染对应的静态文本,多行文本渲染可能存在问题 9 * 10 * TODO: blog http://www.cnblogs.com/koangel/ 11 * 12 * \note 13 */ 14 #include "stdafx.h" 15 #include "SEffectStatic.h" 16 enum DRAW_EFFECT_MODE 17 { 18 DRAW_TEXT_NORMAL = 0, // 默认渲染 19 DRAW_TEXT_STROKE, // 渲染 描边 20 DRAW_TEXT_SHADOW, // 渲染 阴影 21 DRAW_TEXT_GROW, // 渲染 外发光效果 22 DRAW_TEXT_DBSTROKE, // 渲染 双描边 23 }; 24 25 #define GR(rgb) ((BYTE)(rgb)) 26 #define GG(rgb) ((BYTE)(((WORD)(rgb)) >> 8)) 27 #define GB(rgb) ((BYTE)((rgb)>>16)) 28 29 // 默认调用之前的构造函数 30 SEffectStatic::SEffectStatic() : SStatic(), 31 m_nEffectColor(0xFFFFFF), 32 m_nEffectColor2(0xFF0080), 33 m_nEffectDrawMode(0), 34 m_StrokeSize(1) 35 { 36 } 37 38 39 SEffectStatic::~SEffectStatic() 40 { 41 42 } 43 44 void SEffectStatic::DrawText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat) 45 { 46 if (!m_bMultiLines) 47 { 48 switch (m_nEffectDrawMode) 49 { 50 case DRAW_TEXT_NORMAL: 51 __super::DrawText(pRT, pszBuf, cchText, pRect, uFormat); 52 break; 53 case DRAW_TEXT_STROKE: 54 DrawStrokeText(pRT, pszBuf, cchText, pRect, uFormat); 55 break; 56 case DRAW_TEXT_SHADOW: 57 DrawShadowText(pRT, pszBuf, cchText, pRect, uFormat); 58 break; 59 case DRAW_TEXT_GROW: 60 DrawGowText(pRT, pszBuf, cchText, pRect, uFormat); 61 break; 62 case DRAW_TEXT_DBSTROKE: 63 DrawDoubleStrokeText(pRT, pszBuf, cchText, pRect, uFormat); 64 break; 65 } 66 } 67 else 68 { 69 switch (m_nEffectDrawMode) 70 { 71 case DRAW_TEXT_NORMAL: 72 { 73 if (uFormat&(DT_VCENTER | DT_BOTTOM) && !(uFormat & DT_CALCRECT)) 74 { 75 //static 多行控件支持垂直居中及底对齐 76 CRect rcText = *pRect; 77 DrawMultiLine(pRT, pszBuf, cchText, &rcText, uFormat | DT_CALCRECT); 78 CSize szTxt = rcText.Size(); 79 rcText = *pRect; 80 switch (GetStyle().GetTextAlign()&(DT_VCENTER | DT_BOTTOM)) 81 { 82 case DT_VCENTER: 83 rcText.DeflateRect(0, (rcText.Height() - szTxt.cy) / 2); 84 break; 85 case DT_BOTTOM: 86 rcText.DeflateRect(0, (rcText.Height() - szTxt.cy)); 87 break; 88 } 89 DrawMultiLine(pRT, pszBuf, cchText, &rcText, uFormat); 90 } 91 else 92 { 93 DrawMultiLine(pRT, pszBuf, cchText, pRect, uFormat); 94 } 95 break; 96 } 97 case DRAW_TEXT_STROKE: 98 DrawStrokeText(pRT, pszBuf, cchText, pRect, uFormat); 99 break; 100 case DRAW_TEXT_SHADOW: 101 DrawShadowMultiLine(pRT, pszBuf, cchText, pRect, uFormat); 102 break; 103 case DRAW_TEXT_GROW: 104 DrawGowText(pRT, pszBuf, cchText, pRect, uFormat); 105 break; 106 case DRAW_TEXT_DBSTROKE: 107 DrawDoubleStrokeText(pRT, pszBuf, cchText, pRect, uFormat); 108 break; 109 } 110 } 111 } 112 113 void SEffectStatic::DrawMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat) 114 { 115 SIZE szChar; 116 int i = 0, nLine = 1; 117 if (cchText == -1) cchText = _tcslen(pszBuf); 118 LPCTSTR p1 = pszBuf; 119 POINT pt = { pRect->left,pRect->top }; 120 pRT->MeasureText(_T("A"), 1, &szChar); 121 int nLineHei = szChar.cy; 122 int nRight = pRect->right; 123 pRect->right = pRect->left; 124 while (i<cchText) 125 { 126 LPTSTR p2 = CharNext(p1); 127 if (*p1 == _T('\\') && p2 && *p2 == _T('n')) 128 { 129 pt.y += nLineHei + m_nLineInter; 130 pt.x = pRect->left; 131 nLine++; 132 i += p2 - p1; 133 p1 = CharNext(p2); 134 i += p1 - p2; 135 continue; 136 } 137 pRT->MeasureText(p1, p2 - p1, &szChar); 138 if (pt.x + szChar.cx > nRight) 139 { 140 pt.y += nLineHei + m_nLineInter; 141 pt.x = pRect->left; 142 nLine++; 143 continue; 144 } 145 if (!(uFormat & DT_CALCRECT)) 146 { 147 pRT->TextOut(pt.x, pt.y, p1, p2 - p1); 148 } 149 pt.x += szChar.cx; 150 if (pt.x > pRect->right && uFormat & DT_CALCRECT) pRect->right = pt.x; 151 i += p2 - p1; 152 p1 = p2; 153 } 154 if (uFormat & DT_CALCRECT) 155 { 156 pRect->bottom = pt.y + nLineHei; 157 } 158 } 159 160 void SEffectStatic::DrawShadowMultiLine(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat) 161 { 162 COLORREF textColor = this->m_style.GetTextColor(0); 163 164 Gdiplus::StringFormat *strFmt = toFormat(uFormat); 165 166 Gdiplus::Graphics gs(pRT->GetDC()); 167 Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); 168 169 gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); 170 gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); 171 gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); 172 173 Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); 174 175 Gdiplus::FontFamily ffamliy; 176 gf.GetFamily(&ffamliy); 177 178 Gdiplus::SolidBrush br1(Gdiplus::Color(255, GR(textColor), GG(textColor), GB(textColor))); 179 180 TextDesigner::OutlineText outtext; 181 outtext.EnableShadow(true); 182 outtext.TextNoOutline(br1); 183 outtext.Shadow(Gdiplus::Color(128, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)), 2, Gdiplus::Point(1,2)); 184 outtext.DrawString(&gs, &ffamliy, (Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize(), pszBuf, rectF, strFmt); 185 } 186 187 void SEffectStatic::DrawShadowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat) 188 { 189 COLORREF textColor = this->m_style.GetTextColor(0); 190 191 Gdiplus::StringFormat *strFmt = toFormat(uFormat); 192 Gdiplus::Graphics gs(pRT->GetDC()); 193 Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); 194 195 gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); 196 gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); 197 gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); 198 199 Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); 200 201 Gdiplus::FontFamily ffamliy; 202 gf.GetFamily(&ffamliy); 203 204 Gdiplus::SolidBrush br1(Gdiplus::Color(255, GR(textColor), GG(textColor), GB(textColor))); 205 206 TextDesigner::OutlineText outtext; 207 outtext.EnableShadow(true); 208 outtext.TextNoOutline(br1); 209 outtext.Shadow(Gdiplus::Color(128, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)), 2, Gdiplus::Point(1,2)); 210 outtext.DrawString(&gs, &ffamliy,(Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize() , pszBuf, rectF, strFmt); 211 } 212 213 void SEffectStatic::DrawStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat) 214 { 215 COLORREF textColor = this->m_style.GetTextColor(0); 216 Gdiplus::Graphics gs(pRT->GetDC()); 217 Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); 218 Gdiplus::StringFormat *strFmt = toFormat(uFormat); 219 220 gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); 221 gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); 222 gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); 223 224 Gdiplus::RectF rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); 225 226 Gdiplus::SolidBrush br1(Gdiplus::Color(255,GR(textColor), GG(textColor), GB(textColor))); 227 Gdiplus::SolidBrush br2(Gdiplus::Color(250,GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor))); 228 229 int nOffsetX[8] = { 1,1,1,0,-1,-1,-1,0 }; 230 int nOffsetY[8] = { -1,0,1,1,1,0,-1,-1 }; 231 232 for (int i = 0; i < 8;i++) 233 { 234 Gdiplus::RectF lRecf(rectF); 235 lRecf.Offset(nOffsetX[i], nOffsetY[i]); 236 gs.DrawString(pszBuf, cchText, &gf, lRecf, strFmt, &br2); 237 } 238 239 gs.DrawString(pszBuf, cchText, &gf, rectF, toFormat(uFormat), &br1); 240 } 241 242 void SEffectStatic::DrawDoubleStrokeText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat) 243 { 244 COLORREF textColor = this->m_style.GetTextColor(0); 245 Gdiplus::StringFormat *strFmt = toFormat(uFormat); 246 Gdiplus::Graphics gs(pRT->GetDC()); 247 Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); 248 249 gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); 250 gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); 251 gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); 252 253 Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); 254 255 Gdiplus::FontFamily ffamliy; 256 gf.GetFamily(&ffamliy); 257 258 Gdiplus::SolidBrush br1(Gdiplus::Color(255, GR(textColor), GG(textColor), GB(textColor))); 259 260 TextDesigner::OutlineText outtext; 261 outtext.EnableShadow(false); 262 outtext.TextDblOutline(br1, Gdiplus::Color(255, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)), 263 Gdiplus::Color(255, GR(m_nEffectColor2), GG(m_nEffectColor2), GB(m_nEffectColor2)), 3,3); 264 outtext.DrawString(&gs, &ffamliy, (Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize(), pszBuf, rectF, strFmt); 265 } 266 267 void SEffectStatic::DrawGowText(IRenderTarget *pRT, LPCTSTR pszBuf, int cchText, LPRECT pRect, UINT uFormat) 268 { 269 COLORREF textColor = this->m_style.GetTextColor(0); 270 Gdiplus::StringFormat *strFmt = toFormat(uFormat); 271 Gdiplus::Graphics gs(pRT->GetDC()); 272 Gdiplus::Font gf(pRT->GetDC(), GetGDIFont(pRT)); 273 274 gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); 275 gs.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); 276 gs.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality); 277 278 Gdiplus::Rect rectF(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); 279 280 Gdiplus::FontFamily ffamliy; 281 gf.GetFamily(&ffamliy); 282 283 Gdiplus::SolidBrush br1(Gdiplus::Color(255, GR(textColor), GG(textColor), GB(textColor))); 284 285 TextDesigner::OutlineText outtext; 286 outtext.EnableShadow(false); 287 outtext.TextGlow(br1,Gdiplus::Color(64, GR(m_nEffectColor), GG(m_nEffectColor), GB(m_nEffectColor)),6); 288 outtext.DrawString(&gs, &ffamliy, (Gdiplus::FontStyle) gf.GetStyle(), gf.GetSize(), pszBuf, rectF, strFmt); 289 } 290 291 LOGFONT* SEffectStatic::GetGDIFont(IRenderTarget *pRT) 292 { 293 SOUI::IFontPtr pFont = m_style.GetTextFont(0); 294 SOUI::IFontPtr pDFont = (SOUI::IFontPtr)pRT->GetCurrentObject(OT_FONT); 295 LOGFONT * logFont = NULL; 296 if (pFont == NULL) 297 logFont = (LOGFONT*)pDFont->LogFont(); 298 else 299 logFont = (LOGFONT*)pFont->LogFont(); 300 301 return logFont; 302 } 303 304 Gdiplus::StringFormat* SEffectStatic::toFormat(UINT uFormat) 305 { 306 Gdiplus::StringFormat *strFmt = Gdiplus::StringFormat::GenericTypographic()->Clone(); 307 308 if (uFormat&(DT_VCENTER | DT_BOTTOM)) 309 { 310 strFmt->SetAlignment(Gdiplus::StringAlignmentCenter); 311 strFmt->SetLineAlignment(Gdiplus::StringAlignmentCenter); 312 } 313 else 314 { 315 strFmt->SetAlignment(Gdiplus::StringAlignmentNear); 316 strFmt->SetLineAlignment(Gdiplus::StringAlignmentNear); 317 } 318 319 return strFmt; 320 }
以上代码抛砖引玉,希望各位发扬光大,多写一些组件库噢。