[原创]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 }

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

posted @ 2016-02-16 14:16  koangel  阅读(3523)  评论(0编辑  收藏  举报