Conmajia

Stop stealing sheep!

导航

< 20253 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

一种简单的文字描边方法

 

© 版权所有 conmajia 2012

在色彩丰富的图片上显示文字的时候由于背景色变化的关系文字往往不能清晰呈现就像很多早期电影使用纯白色字幕在蓝天白云的画面下常常看不清楚字幕这时候就需要文字描边这种能够突出显示文字的效果了就像这样

动画截图 by Wong Shao Voon

怎样实现这样的效果呢下面我粗略介绍下目前常见的几种方法最后介绍我构思的一种简单而实用的实现方法

一般方法

第一种思路文字即图片

  1. TextBlock 转换为WriteableBitmap
  2. WriteableBitmap 的Pixels 进行循环,判断每一个像素点的值最终达到描边的效果

参考Silverlight字体描边

这种思路将文字转为图片根据判断图片上每个像素点效率低下最终效果简单如下图所示

第二种思路像素着色器

该方法基本思路为假定只会对TextBlock应用像素着色器那么TextBlock是一个矩形文字所在像素的 alpha分量必定大于0,否则必定是透明像素判断如果当前像素的上右任意一个像素不透明则说明本像素需要被描边否则就输出文字颜色由于需要知道相邻像素所以还需要传入TextBlockActualWidthActualHeight 这样 当前位置的 x+ 1/width 就是相邻像素的坐标就可以用tex2D函数来提取它的颜色值还需要输入描边的颜色还有文字的颜色

参考SILVERLIGHT像素着色器编写简明指南 附送文字描边效果

仍然是一个大炮打蚊子的思路将文字进行逐像素的处理和思路1唯一的区别在于使用了像素着色器让把部分工作交给GPU来完成看起来很高效很快速但是如果禁用了硬件加速就变成和1一样了下面是该方法的效果截图

第三种思路GDI+路径绘图

这种方法不再是逐像素处理了其基本思路是将文字字符串添加到GDI+的绘图路径中GraphicsPath然后再DrawPath()利用不同的笔刷这种方法可以出非常华丽的描边效果就像这样

这是扩展性最好的方法由于利用了GDI+的高级特性所以可以利用不同的笔刷如纹理渐变以及多次绘图等方法做出非常精美的描边阴影效果唯一的遗憾就是代码量较大比前面2种要少很多了

参考文章C# 水印图片+文字描边+发光文字看示图及Demo

关于该方法的高级效果设计参考Outline Text一文Code ProjectBest C++/MFC article of Sep 2009比赛获奖文章

 

简易方法

看了前面几种设计思路后你有没有一头雾水的感觉或者眼花缭乱的感觉难道我们只有这样实现吗需要描边文字就一定要

其实完全没有必要曾经我在山寨Safari介绍过一种简单的通过重复绘制文字实现高光效果的方法

如下图所示当底层文字和顶层文字相差1px就会呈现出不同的阴影/高光效果如果把这个思路拓展下把上右四个方向的偏差结合到一起就会像下图最后显示的效果一样得到了描边文字的效果

接下来在GDI+里面实现它 

复制代码
 1     // Code by Conmajia
 2     // txtPoint是绘制文字的定位点
 3     txtPoint.Offset(-1, 0);  // 绘制左背景文字
 4     e.Graphics.DrawString(this.Text, this.Font, backBrush, txtPoint);
 5     txtPoint.Offset(2, 0);  // 绘制右背景文字
 6     e.Graphics.DrawString(this.Text, this.Font, backBrush, txtPoint);
 7     txtPoint.Offset(-1, -1);  // 绘制下背景文字
 8     e.Graphics.DrawString(this.Text, this.Font, backBrush, txtPoint);
 9     txtPoint.Offset(0, 2);  // 绘制上背景文字
10     e.Graphics.DrawString(this.Text, this.Font, backBrush, txtPoint);
11     txtPoint.Offset(0, -1);  // 定位点归位
12 
13     // 绘制前景文字
14     e.Graphics.DrawString(this.Text, this.Font, foreBrush, txtPoint);
复制代码

 

下面请欣赏效果

 

结语

遇到问题不一定需要完全跟着问题走就像这次需要描边但谁说的非得要边呢你要的只是效果而不是过程所以要跳出问题表象的禁锢就能获得更加宽广的视野

© 版权所有 conmajia 2012

全文完

 

posted on2012-05-27   Conmajia  阅读(4626)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示