由於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 }
以上代碼拋磚引玉,希望各位發揚光大,多寫一些組件庫噢。