chun2495 发表于 2017-6-6 14:43:35

给大家介绍一种做界面的去锯齿方法

本帖最后由 chun2495 于 2017-6-6 14:49 编辑

我们在做嵌入式界面时,有两种方案可供选择 :1是用商业化的gui,比如emwin。2是自己做界面。
下面主要介绍方法2。

先贴张图,对比下锯齿的效果


我找过很多软件,想能否生成抗锯齿的字体,都没找到。想着以后自己用QT写一个抗锯齿字体的提取软件,这是后话。
在photoshop中,我们输入的文字默认都是抗锯齿的,我想很多人都想过用图片的方式将每个字母的抗锯齿图片保存下来,然后放入flash或内存中,调用显示。
这样最是简单,但是也很暴力,因为工作量太大,为了适应不同的背景,工作量也是倍数增加,后期的维护也是很悲催的。
我介绍的方法是将所有的字母写在一个背景图片中,然后程序上调用显示。具体做法如下:
1, photoshop中,先将背景颜色设置好


2, 键入需要的ascii字符(我这里用了标准ascii和欧文集iso88591)


3, 保存为 .bmp格式,然后打开彩色取模(我用的是Img2Lcd)软件,生成.h 数据,保存在内存中。或者生成.bin文件,保存在外部存储器中。


4, 调用字库显示一个字符函数如下:
void Char_UbuntuMono_FrontGround_8_17(int x, int y, unsigned char c)
{//8*32 = 256 wide
//17*5 = 85high
    unsigned int i, j, factor;
   
    if(c < 128)    c = c - ' ';
    else         c = c - 96;
   
    factor = c/32;
   
    for(i = 0;i < 17; i++){
      for(j = 0; j < 8; j++){
         frambuf = UbuntuMono_FrontGround_8_17<<8|
                                          UbuntuMono_FrontGround_8_17;
      }
    }
}
显示字符串函数如下:
void String_UbuntuMono_FrontGround_8_17(int x,int y, unsigned char *str)
{
    unsigned char *p = str;
    while (*p != 0){
      Char_UbuntuMono_FrontGround_8_17(x, y, *p);
      y = y + 8;
      p++;
    }
}

最后贴张抗锯齿界面图


往期帖子 :
液晶多级菜单实现加强版https://www.amobbs.com/thread-5599589-1-1.html
嵌入式全键盘拼音输入法分享https://www.amobbs.com/thread-5668320-1-1.html
ucgui下制作漂亮按键 https://www.amobbs.com/thread-5551143-1-1.html

chen849928055 发表于 2017-6-6 14:47:50

本帖最后由 chen849928055 于 2017-6-6 14:58 编辑

沙发 沙发,好幸福,再也不用这种方式显示了,以前做这图片做想哭啊

tomy 发表于 2017-6-6 14:55:11

{:2_37:}长姿势了。谢谢分享。

chen849928055 发表于 2017-6-6 15:06:08

12 3 4 5 ,是你之前gui帖子里那种方法做的button吗?

lg05128018 发表于 2017-6-6 15:13:51

兄弟,来我们这里来做HMI软件吧?》

chun2495 发表于 2017-6-6 15:26:01

chen849928055 发表于 2017-6-6 15:06
12 3 4 5 ,是你之前gui帖子里那种方法做的button吗?

对。   

chun2495 发表于 2017-6-6 15:28:09

lg05128018 发表于 2017-6-6 15:13
兄弟,来我们这里来做HMI软件吧?》

hmi不赚钱哦。。。

creep 发表于 2017-6-6 15:41:40

感谢分享。不同的背景是不是要取多次,比如你的图片里面的状态栏(黑色背景)和下面的设置内容(蓝色背景),

chun2495 发表于 2017-6-6 16:20:49

creep 发表于 2017-6-6 15:41
感谢分享。不同的背景是不是要取多次,比如你的图片里面的状态栏(黑色背景)和下面的设置内容(蓝色背景) ...

对,一般界面也没几种颜色。

isakura 发表于 2017-6-6 16:23:48

这个效果好

但是想知道怎么控制字体大小呢

isakura 发表于 2017-6-6 16:26:42

chen849928055 发表于 2017-6-6 14:47
沙发 沙发,好幸福,再也不用这种方式显示了,以前做这图片做想哭啊

我现在也是这种方式{:biggrin:}

不过有美工,本人不会PS

chun2495 发表于 2017-6-6 16:26:48

isakura 发表于 2017-6-6 16:23
这个效果好

但是想知道怎么控制字体大小呢

再做一套

dgtg 发表于 2017-6-6 16:34:35

请教一下,如何处理半角的字符啊?

chen849928055 发表于 2017-6-6 16:48:42

isakura 发表于 2017-6-6 16:26
我现在也是这种方式

不过有美工,本人不会PS

你的图片也存在spi flash的吧,你用的什么MCU

redroof 发表于 2017-6-6 16:59:07

creep 发表于 2017-6-6 15:41
感谢分享。不同的背景是不是要取多次,比如你的图片里面的状态栏(黑色背景)和下面的设置内容(蓝色背景) ...

更节约的方法是图片资源只使用黑底白字,带上抗锯齿之后保存BMP,这样你得到的实际上是带alpha通道的位图。在输出的时候不管背景上是什么,你对每个点做动态叠加就行了,总是可以在底图上生成正确的抗锯齿的文字。
对每个点,输出值=alpha*文本色+(255-alpha)*原来背景色
为了减少乘法,alpha=0的时候不写输出即可(输出就是原来的背景色)

canspider 发表于 2017-6-6 17:01:43

redroof 发表于 2017-6-6 16:59
更节约的方法是图片资源只使用黑底白字,带上抗锯齿之后保存BMP,这样你得到的实际上是带alpha通道的位图 ...

纯色背景可以这样

chun2495 发表于 2017-6-6 17:17:47

redroof 发表于 2017-6-6 16:59
更节约的方法是图片资源只使用黑底白字,带上抗锯齿之后保存BMP,这样你得到的实际上是带alpha通道的位图 ...

阿莫里果然高手如云,这个理论上是可行的,下来我试试效果。

chun2495 发表于 2017-6-6 17:19:04

canspider 发表于 2017-6-6 17:01
纯色背景可以这样

非纯色背景能否读取当前背景点,以此做背景和字符做阿拉法运算?

chun2495 发表于 2017-6-6 17:22:44

dgtg 发表于 2017-6-6 16:34
请教一下,如何处理半角的字符啊?

目前只支持ascii字符,汉字库太庞大了,有兴趣的可以试试。

jssd 发表于 2017-6-6 17:24:22

好想法。之前一直在想HGE2D游戏引擎的字体是怎么得来的,也是这样的一个图片,看完这贴,豁然开朗{:victory:}。谢谢楼主分享

redroof 发表于 2017-6-6 17:27:32

canspider 发表于 2017-6-6 17:01
纯色背景可以这样

不需要纯色背景。对任意颜色的背景这样都是正确的半透明算法。

chun2495 发表于 2017-6-6 17:28:12

jssd 发表于 2017-6-6 17:24
好想法。之前一直在想HGE2D游戏引擎的字体是怎么得来的,也是这样的一个图片,看完这贴,豁然开朗{:victory ...

你这一说,我也想起以前的文曲星像素游戏都是这样一副整图。

redroof 发表于 2017-6-6 17:30:22

chun2495 发表于 2017-6-6 17:19
非纯色背景能否读取当前背景点,以此做背景和字符做阿拉法运算?

毫无疑问当然可以。
只要你能读背景图,不管背景图是什么样,都可以用这个算法来叠加任意前景色的带半透明通道的字体。
而且只要预先做好一个黑底白字的带抗锯齿的文字图当作半透明通道就行了。

canspider 发表于 2017-6-6 17:30:27

redroof 发表于 2017-6-6 17:27
不需要纯色背景。对任意颜色的背景这样都是正确的半透明算法。

半透明是对的,对于抗锯齿不是这样

redroof 发表于 2017-6-6 17:31:51

canspider 发表于 2017-6-6 17:30
半透明是对的,对于抗锯齿不是这样

你的黑白文字图就是Photoshop用抗锯齿算法生成的啊!

chun2495 发表于 2017-6-6 17:38:46

redroof 发表于 2017-6-6 17:27
不需要纯色背景。对任意颜色的背景这样都是正确的半透明算法。

嗯 试了下,的确是这样 ,看来以后在非纯色背景上也可以显示非锯齿文字了,终于搞明白了抗锯齿字体的算法原理,谢谢大神!

canspider 发表于 2017-6-6 17:43:59

redroof 发表于 2017-6-6 17:31
你的黑白文字图就是Photoshop用抗锯齿算法生成的啊!

看了下26楼的测试结果
你说的这个方法果然可行
我之前认为抗锯齿需要综合计算领接几个像素点
如果领接几个点颜色不一样会有差别

chun2495 发表于 2017-6-6 17:55:06

canspider 发表于 2017-6-6 17:43
看了下26楼的测试结果
你说的这个方法果然可行
我之前认为抗锯齿需要综合计算领接几个像素点


我这个测试结果就是针对这种情况的
三个彩色点包围的像素点是我要测试的像素。在photoshop里背景是一个图层 文字是一个图层。
1, 在纯色背景下,我将测试像素点的值记录下来。如图一右上显示。
2, 将被测像素点周围背景颜色进行改变,之后再取被测像素颜色值,如图2右上所示。
结论:周围的颜色并不影响当前点的颜色值。

redroof 发表于 2017-6-6 17:55:19

canspider 发表于 2017-6-6 17:43
看了下26楼的测试结果
你说的这个方法果然可行
我之前认为抗锯齿需要综合计算领接几个像素点


哪有那么复杂。
抗锯齿的半透明其实只考虑字体数据本身。最终就等于在内部生成了一个半透明叠加图层。

isakura 发表于 2017-6-6 18:00:23

chen849928055 发表于 2017-6-6 16:48
你的图片也存在spi flash的吧,你用的什么MCU

TW8823,51内核

canspider 发表于 2017-6-6 18:25:55

redroof 发表于 2017-6-6 17:55
哪有那么复杂。
抗锯齿的半透明其实只考虑字体数据本身。最终就等于在内部生成了一个半透明叠加图层。
...

看了测试确实如此
又学到了一招

chen849928055 发表于 2017-6-7 10:50:14

isakura 发表于 2017-6-6 18:00
TW8823,51内核

你这片子专用的,可直接驱动lcd,好用吧.介绍下

huangqi412 发表于 2017-6-7 11:15:12

应该用空白背景取字模,后期去读回屏幕点叠加背景吧。预置背景取字模,不同背景不得累死啊。

isakura 发表于 2017-6-7 12:27:38

chen849928055 发表于 2017-6-7 10:50
你这片子专用的,可直接驱动lcd,好用吧.介绍下

可以直接驱屏的。。。LVDS或者RGB都可以

主要是视频切换功能的(CVBS RGB VGA那些),用来主要做UI的话就有点浪费的

isakura 发表于 2017-6-7 12:31:31

huangqi412 发表于 2017-6-7 11:15
应该用空白背景取字模,后期去读回屏幕点叠加背景吧。预置背景取字模,不同背景不得累死啊。 ...

个人觉得不太可行:
1、取模软件取得就是一整张的图片色值,应该没有透明选项吧;除非你自己显示的时候直接把底色数值用想要的替换掉;

2、抗锯齿应该是结合底色生成的模糊的过渡色,所以看起来圆滑,直接叠加的话可能不适用

huangqi412 发表于 2017-6-7 12:53:25

isakura 发表于 2017-6-7 12:31
个人觉得不太可行:
1、取模软件取得就是一整张的图片色值,应该没有透明选项吧;除非你自己显示的时候直 ...

PS我记得是有空白背景的,背景空白,也就是没背景色,如果抗锯齿了取到的RGB应该是图形边沿淡化的彩色,字体图形本来的RGB是纯色,变化了多少应该能能算出透明度的,应该是能用透明度系数临时和背景色混色出来的。
比如字体是纯红色,抗锯齿后边沿变化了不是纯红色了,淡化掉了,取字模后字体中间还是纯红色,边沿是淡红色,再远地方是无色,这个淡红色相对红色是有透明度百分比/变化百分比的。应该是能跟新的背景色混色的。

huangqi412 发表于 2017-6-7 12:55:39

再或者,每个字体图片有两张表, 第一张是取字模RGB色彩, 第二张是每个像素的混色百分比。   显示用图片RGB色彩+ 混色百分比去混背景色。

huangqi412 发表于 2017-6-7 12:56:46

这个应该是能软件提取出来的。指定字体纯色RGB值, 读图片所有像素,跟纯色对比,生成两张表。

peterlzj 发表于 2017-6-7 12:58:10

学习了,有空我也试试

redroof 发表于 2017-6-7 13:01:50

isakura 发表于 2017-6-7 12:31
个人觉得不太可行:
1、取模软件取得就是一整张的图片色值,应该没有透明选项吧;除非你自己显示的时候直 ...

看我上面说的。只用黑白两色来取模就行了。想要的文本色是你输岀的时候合成的

fengyunyu 发表于 2017-6-7 13:05:09

受益良多,赞!

huangqi412 发表于 2017-6-7 13:07:25

isakura 发表于 2017-6-7 12:31
个人觉得不太可行:
1、取模软件取得就是一整张的图片色值,应该没有透明选项吧;除非你自己显示的时候直 ...

打开PS ,新建了一个70*40像素的图片   放大800%敲入带拐弯的字符再拼合图层将字体转为位图   用取色器取色看了下(纯色的黑色是0,0,0,   边沿是非0)    看起来应该是这个样子







huangqi412 发表于 2017-6-7 13:09:22

上图明显可以看出,边沿不同位置淡黑色的深度不同,也就是边沿每个像素混色比例不同      

huangqi412 发表于 2017-6-7 13:12:35

从上面的分析,不止背景色可以临时叠加,字体颜色也可以临时指定的(当然也可以在生成字模的取模软件里做字体颜色替换),不管你用什么颜色生成字体。
楼主干脆写个 可以从图片生成无背景色的字模的软件给大家吧。

redroof 发表于 2017-6-7 13:15:29

huangqi412 发表于 2017-6-7 13:09
上图明显可以看出,边沿不同位置淡黑色的深度不同,也就是边沿每个像素混色比例不同       ...

是啊,所以我上面说了正确的实现方法:用黑底白字来取模,你取到的就是这个混色比例。
然后输岀的时候用文本色和混色比例加上你读回的背景色做运算,才能算岀每个点应当输岀的真实颜色

huangqi412 发表于 2017-6-7 13:18:07

redroof 发表于 2017-6-7 13:15
是啊,所以我上面说了正确的实现方法:用黑底白字来取模,你取到的就是这个混色比例。
然后输岀的时候用 ...

嗯 对的。字体颜色 背景颜色都可以临时指定。接下来就是字体缩放了。

peterlzj 发表于 2017-6-9 09:19:39

方法是好,可惜储存量就要大很多,如果仅仅存黑色一个像素一个bit就可以代表,要存多种颜色就要一个像素16个bit或24个bit了

huangqi412 发表于 2017-6-9 09:25:35

peterlzj 发表于 2017-6-9 09:19
方法是好,可惜储存量就要大很多,如果仅仅存黑色一个像素一个bit就可以代表,要存多种颜色就要一个像素16 ...

发明用一个BIT表示一个彩色像素点的黑科技任务就交给你了。

redroof 发表于 2017-6-9 09:38:12

peterlzj 发表于 2017-6-9 09:19
方法是好,可惜储存量就要大很多,如果仅仅存黑色一个像素一个bit就可以代表,要存多种颜色就要一个像素16 ...

8bit足够了。
你只需要记录半透明信息。
文本色可以在输出的时候指定,背景色是从显存里实时读取的。

waymcu 发表于 2017-6-9 09:54:50

好方法,学习学习!

chun2495 发表于 2017-6-9 10:33:11

peterlzj 发表于 2017-6-9 09:19
方法是好,可惜储存量就要大很多,如果仅仅存黑色一个像素一个bit就可以代表,要存多种颜色就要一个像素16 ...

做成灰阶最省资源了,一个字节表示一个像素值。

tarchen 发表于 2017-6-9 15:59:39

受益匪浅,赞!

hwh1328 发表于 2017-6-9 16:39:14

谢谢分享!效果看起来很好。

zstein 发表于 2017-6-9 18:31:58

谢谢分享。

shower.xu 发表于 2017-6-9 20:26:58

redroof 发表于 2017-6-9 09:38
8bit足够了。
你只需要记录半透明信息。
文本色可以在输出的时候指定,背景色是从显存里实时读取的。 ...

黑底白字保存为bmp后每个像素是RGBA一共32bit的是吧,只需要A的8bit就可以了,是这样理解么?

redroof 发表于 2017-6-9 21:44:38

shower.xu 发表于 2017-6-9 20:26
黑底白字保存为bmp后每个像素是RGBA一共32bit的是吧,只需要A的8bit就可以了,是这样理解么? ...

正常是24位bmp,每个点随便取rgb哪个分量都行。三个分量是一样的。
如果你可以存8位灰度的bmp,就省了2/3的大小
Bmp要是存为rgba,我反而不知道是什么结果了

vjcmain 发表于 2017-6-9 22:59:33

楼主做超声的?

shower.xu 发表于 2017-6-10 00:31:24

redroof 发表于 2017-6-9 21:44
正常是24位bmp,每个点随便取rgb哪个分量都行。三个分量是一样的。
如果你可以存8位灰度的bmp,就省了2/3的 ...

谢谢明白了

litop 发表于 2017-6-10 09:25:43

漂亮的字模界面

bg6agf 发表于 2017-6-10 22:53:28

光是看到方法就已经很让人茅塞顿开了。

nengcai0313 发表于 2017-6-12 09:11:24

这是用了网页中的CSS控制显示小图标的远离啊。

chun2495 发表于 2017-6-12 09:28:05

vjcmain 发表于 2017-6-9 22:59
楼主做超声的?

√      

chun2495 发表于 2017-6-12 09:30:42

bg6agf 发表于 2017-6-10 22:53
光是看到方法就已经很让人茅塞顿开了。

我也是最近才想出来结果抛砖引玉 15楼才是大神

larry.xu 发表于 2017-6-12 09:37:01

不错,以后用这种方法就可以抗锯齿。

chen849928055 发表于 2017-6-12 14:59:25

redroof 发表于 2017-6-6 17:30
毫无疑问当然可以。
只要你能读背景图,不管背景图是什么样,都可以用这个算法来叠加任意前景色的带半透 ...

我做好一个黑底白字的带抗锯齿的文字图,显示字符时,LCD_DrawPoint(u16 x, u16 y, u16 color)描点函数这里的color不知道怎么处理了,按道理应该是数组里是什么颜色的点,这里应该描什么颜色的点.搞到这里没思路了?

redroof 发表于 2017-6-12 15:45:03

chen849928055 发表于 2017-6-12 14:59
我做好一个黑底白字的带抗锯齿的文字图,显示字符时,LCD_DrawPoint(u16 x, u16 y, u16 color)描点函数这里 ...

在我的理解里面,描点函数是最底层的函数。只负责原样向显存写一个点。它被“写半透明图”函数调用。
写半透明图是核心函数,参数包括半透明图片,前景色,位置。
对需要写入的半透明图片里面的每个点,先读显存,读到的是这个点的背景色
然后从半透明图片里面获取当前点的数据,8位无符号数据,作为alpha
这个点的混合结果是,按RGB每个分量8位数据:
输出颜色=(alpha*前景色+(255-alpha)*背景色)/256

chen849928055 发表于 2017-6-12 16:17:32

redroof 发表于 2017-6-12 15:45
在我的理解里面,描点函数是最底层的函数。只负责原样向显存写一个点。它被“写半透明图”函数调用。
写 ...

前景色是指的什么颜色,假如一个蓝色背景,上面一个红色的20,20的实际颜色就是前景色吗?你说的我能理解个大概,你说的这个半透明函数,你能稍微用c来描述下不

redroof 发表于 2017-6-12 18:26:28

chen849928055 发表于 2017-6-12 16:17
前景色是指的什么颜色,假如一个蓝色背景,上面一个红色的20,20的实际颜色就是前景色吗?你说的我能理解个大 ...

比如你要写白色的文本,那么前景色就是白色。你要写红色的文本,前景色就是红色。
因为你的字库只存储了半透明度,其它啥也没存,也不需要存,所以你可以在输出的时候临时改变前景色。
叠加算法就是我上面写的那个表达式,我写的就是C语法,所有语言的加减乘除不都是那样嘛https://www.amobbs.com/static/image/smiley/default/titter.gif
如果你做乘法很慢,想优化一点,那么透明度255的直接输出前景色,透明度0的不输出任何东西(也就是背景色),透明度是其它值的才需要计算颜色混合。

jxyctwt 发表于 2017-6-12 20:30:02

茅塞顿开

chen849928055 发表于 2017-6-13 08:49:51

redroof 发表于 2017-6-12 18:26
比如你要写白色的文本,那么前景色就是白色。你要写红色的文本,前景色就是红色。
因为你的字库只存储了 ...

明白了,自己试试!多谢!

modbus 发表于 2017-6-13 09:24:18

huangqi412 发表于 2017-6-7 13:18
嗯 对的。字体颜色 背景颜色都可以临时指定。接下来就是字体缩放了。

点阵字体缩放太难看了,想缩放还是得研究矢量字体

redroof 发表于 2017-6-13 09:47:13

modbus 发表于 2017-6-13 09:24
点阵字体缩放太难看了,想缩放还是得研究矢量字体

点阵字体根本就不能缩放。
矢量字体的处理算法又非常复杂,而且小字号的情况下效果也不好。
经典的宋体其实在小字号的时候是用的内嵌的点阵字体,大于某个号码以后才变成真正的矢量字体。

chun2495 发表于 2017-6-13 10:14:08

redroof 发表于 2017-6-13 09:47
点阵字体根本就不能缩放。
矢量字体的处理算法又非常复杂,而且小字号的情况下效果也不好。
经典的宋体其 ...

32*32所放到16*16有没有研究过? 1:2缩放会失真不,如果不行,那岂不是每一种大小都要来存储一遍。

redroof 发表于 2017-6-13 10:31:12

chun2495 发表于 2017-6-13 10:14
32*32所放到16*16有没有研究过? 1:2缩放会失真不,如果不行,那岂不是每一种大小都要来存储一遍。 ...

小字号下面效果最好的是宋体。
那么宋体的小字号为什么效果还能很锐利呢?因为每种字号都是人工优化过的点阵字体!!
多的我就不用说了。


dory_m 发表于 2017-6-13 12:51:05

学习,谢谢!!!

OneRain 发表于 2017-6-13 14:28:30

确实不错啊!!!!一起制作字体一个一个来,搞死人,这个方法确实好啊!!!!{:titter:}{:titter:}{:titter:}

小小苹果 发表于 2017-7-11 15:01:59

这个方法确实不错!
页: [1]
查看完整版本: 给大家介绍一种做界面的去锯齿方法