廢話不多說(shuō),先上成果圖。
目前完成了基本的簡(jiǎn)析功能,還差圖片,表情以及動(dòng)畫(huà)的部分,以及后期優(yōu)化工作,最最后的代碼整理。- -。
接下來(lái)就分享下整個(gè)實(shí)現(xiàn):
1.繪制采用freetype庫(kù)實(shí)現(xiàn),支持加粗,斜體,漸變(這個(gè)自己算下就可以了)以及描邊,其中描邊估計(jì)是最麻煩的,其它都很簡(jiǎn)單,網(wǎng)上也有很多實(shí)現(xiàn)方式,這里我就主要說(shuō)說(shuō)描邊了,
描邊方式也很多,但是大多效果都不太好,所以最后還是決定用freetype api來(lái)實(shí)現(xiàn)而不用自己去處理,整個(gè)實(shí)現(xiàn)可以參考:
http://blog.sina.com.cn/s/blog_69a2aeff0100ol7e.html
1 bool Font::border(Word& word, unsigned int color1, unsigned int color2, unsigned int border)
2 {
3 if (!ok())
4 {
5 return false;
6 }
7
8 FT_Face face = m_size->face;
9
10 FT_UInt index = FT_Get_Char_Index(face, FT_ULong(word.m_code));
11 if (!index)
12 {
13 return false;
14 }
15
16 if (FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP))
17 {
18 return false;
19 }
20
21 FT_Glyph glyph;
22 if (FT_Get_Glyph(face->glyph, &glyph))
23 {
24 return false;
25 }
26
27 FT_Stroker stroker;
28 if (FT_Stroker_New(s_library, &stroker))
29 {
30 return false;
31 }
32
33 FT_Stroker_Set(stroker, (int)(border * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
34
35 if (FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1))
36 {
37 return false;
38 }
39
40 FT_Outline *outline = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
41
42 FT_BBox bbox;
43 FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_GRIDFIT, &bbox);
44
45 int width = (bbox.xMax - bbox.xMin) >> 6;
46 int rows = (bbox.yMax - bbox.yMin) >> 6;
47
48 FT_Bitmap *bitmap = &face->glyph->bitmap;
49
50 word.m_width = width;
51 word.m_height = rows;
52 word.m_drawX = face->glyph->metrics.horiBearingX >> 6;
53 word.m_drawY = face->glyph->metrics.horiBearingY >> 6;
54 word.m_advanceX = face->glyph->metrics.horiAdvance >> 6;
55 word.m_buffer = new unsigned char[word.m_width * word.m_height * 4];
56 memset(word.m_buffer, 0, word.m_width * word.m_height * 4);
57
58 unsigned char* buffer = word.m_buffer;
59
60 FT_Raster_Params params;
61 FT_Bitmap bmp;
62
63 bmp.buffer = new unsigned char[width * rows];
64 memset(bmp.buffer, 0, width * rows);
65 bmp.width = width;
66 bmp.rows = rows;
67 bmp.pitch = width;
68 bmp.pixel_mode = FT_PIXEL_MODE_GRAY;
69 bmp.num_grays = 256;
70
71 memset(¶ms, 0, sizeof (params));
72 params.source = outline;
73 params.target = &bmp;
74 params.flags = FT_RASTER_FLAG_AA;
75 FT_Outline_Translate(outline,-bbox.xMin,-bbox.yMin);
76 FT_Outline_Render(s_library, outline, ¶ms);
77 unsigned char* buffer1 = bmp.buffer;
78
79 FT_BBox bbox_in;
80 FT_Glyph glyph_fg;
81 FT_Get_Glyph(face->glyph, &glyph_fg);
82 FT_Glyph_Get_CBox(glyph_fg, FT_GLYPH_BBOX_GRIDFIT,&bbox_in);
83
84 bmp.buffer = new unsigned char[width * rows];
85 memset(bmp.buffer, 0, width * rows);
86 bmp.width = width;
87 bmp.rows = rows;
88 bmp.pitch = width;
89 bmp.pixel_mode = FT_PIXEL_MODE_GRAY;
90 bmp.num_grays = 256;
91 outline = &reinterpret_cast<FT_OutlineGlyph>(glyph_fg)->outline;
92 memset(¶ms, 0, sizeof (params));
93 params.source = outline;
94 params.target = &bmp;
95 params.flags = FT_RASTER_FLAG_AA;
96 FT_Outline_Translate(outline,-bbox.xMin,-bbox.yMin);
97 FT_Outline_Render(s_library, outline, ¶ms);
98 unsigned char* buffer2 = bmp.buffer;
99
100 int pitch = width;
101 for (int yy = 0; yy < rows; ++yy)
102 {
103 for (int xx = 0; xx < width; ++xx)
104 {
105 int si = yy * word.m_width * 4 + xx * 4;
106 int alpha1 = buffer1[yy * pitch + xx];
107
108 unsigned char sr = (color1 & 0xFF0000) >> 16,
109 sg = (color1 & 0xFF00 ) >> 8,
110 sb = (color1 & 0xFF );
111
112 unsigned char dr = (color2 & 0xFF0000) >> 16,
113 dg = (color2 & 0xFF00 ) >> 8,
114 db = (color2 & 0xFF );
115
116 if (alpha1)
117 {
118 buffer[si + 0] = dr;
119 buffer[si + 1] = dg;
120 buffer[si + 2] = db;
121 buffer[si + 3] = alpha1;
122 }
123
124 int alpha2 = buffer2[yy * pitch + xx];
125 if (alpha2)
126 {
127 buffer[si + 0] = dr + ( sr - dr) * alpha2 / 255.0f;
128 buffer[si + 1] = dg + ( sg - dg) * alpha2 / 255.0f;
129 buffer[si + 2] = db + ( sb - db) * alpha2 / 255.0f;
130 buffer[si + 3] = min(255, alpha1 + alpha2);
131 }
132 }
133 }
134
135 delete [] buffer1;
136 delete [] buffer2;
137
138 FT_Stroker_Done(stroker);
139
140 return true;
141 }
2.字體緩存,緩存可以參考 FTC_Manager 緩存子系統(tǒng),可以參看 ft_cache.h 的說(shuō)明。
3.布局,目前我的布局方案:
IElement 接口:用于獲取每個(gè)元素的大小,以及保存元素的位置信息,后面可以用于處理 Hittest。
ElementCollection :具體說(shuō)來(lái)就是一行,由多個(gè) Element 組成,繪制前線設(shè)置x,y值,然后調(diào)用本身layout函數(shù)來(lái)布局,最后父節(jié)點(diǎn)可以獲取高度和寬度用于計(jì)算。
RowCollection :由多個(gè)ElementCollection構(gòu)成,主要用于緩存所有結(jié)點(diǎn)信息,提供layout接口后計(jì)算出整個(gè)布局的包圍盒,然后生成紋理在繪制。
RichDoc : 內(nèi)部有一個(gè) RowCollection,主要用于將字符串轉(zhuǎn)換成IElement,并處理?yè)Q行等。
TextElement :文本元素,如果是漢字就一個(gè)字對(duì)應(yīng)一個(gè)TextElement,單詞則由多個(gè)構(gòu)成,這樣方便布局。
后期可能還有 ImageElement 等等。
補(bǔ)充:ElementCollection 中元素,即通常的一行,如果未滿行而剩余空間又小于一個(gè)固定值,我這里大概設(shè)置的30,那么就應(yīng)該吧這30的空隙填充到每個(gè)元素之間,這樣布局出來(lái)的效果行尾基本都是對(duì)齊的,如果空隙太大就不應(yīng)該插入。
4.字符串簡(jiǎn)析
這個(gè)看自己的愛(ài)好,可以自由發(fā)揮,這里貼出效果圖的布局文本。
#{effect="border" color1="ffffff"}#{effect="border" color1="ff0000"}英文原文:Developer Hacks His Microwave Into The Microwave Of The Future#{}
普通的#{effect="italic" color1="ff00ff" value="25"}家用微波爐#{}可以說(shuō)是非常不智能的產(chǎn)品,買回來(lái)不僅時(shí)間需要人工設(shè)定,使用過(guò)程中,我們也很少會(huì)根據(jù)事物的不同,選擇對(duì)應(yīng)的設(shè)置,只要能熱食物就行。
所以,當(dāng)我看到開(kāi)發(fā)者 Nathan Broadbent 跟他的微波爐說(shuō)話,語(yǔ)音控制微波爐,并且能夠自動(dòng)設(shè)置時(shí)間,甚至,你只需要掃描一下產(chǎn)品的條形碼,微波爐便能自動(dòng)識(shí)別對(duì)應(yīng)的模式以及分鐘數(shù)時(shí),我感覺(jué)我快要窒息了。
這款微波爐被命名為 #{effect="border" color1="00ff00"}"Raspberry Picrowave"#{},顧名思義,是一臺(tái)同樹(shù)莓派相連的微波爐設(shè)備。
經(jīng)過(guò)調(diào)試之后,這款微波爐具備以下功能:
#{effect="gradient" color1="220022" color2="ff0000"}通過(guò)網(wǎng)絡(luò),自動(dòng)調(diào)節(jié)時(shí)間。#{}
#{effect="gradient" color1="220022" color2="ff0000"}通過(guò)將對(duì)應(yīng)食物的數(shù)據(jù)錄入自建的在線數(shù)據(jù)庫(kù),只需掃描條形碼,微波爐便會(huì)自動(dòng)開(kāi)始運(yùn)作。#{}
#{effect="gradient" color1="220022" color2="ff0000"}可自定義聲效。#{}
你可以使用手機(jī)或者 #{effect="bold" color1="00ffff"}iPad#{} 來(lái)控制微波爐。適用場(chǎng)景包括:你可以提前放置食物,然后通過(guò)手機(jī)等設(shè)備來(lái)操控微波爐,或者你也可以用這項(xiàng)功能嚇嚇你的小伙伴。
當(dāng)食物熱好之后,它還能發(fā)推!
讓微波爐更加智能化,本該是大型的微波爐廠商自己該做的事情,但市面上一直沒(méi)有智能和人性化的微波爐出現(xiàn),直到今天,我們?nèi)诵枰斯ぴO(shè)置時(shí)間

. 好的是,相信這款 Raspberry Picrowave 的出現(xiàn),可能會(huì)推動(dòng)微波爐智能化的進(jìn)程,將物聯(lián)網(wǎng)的生活往前又推進(jìn)了一步,不過(guò)這款微波爐只是極客們自己的玩具,并沒(méi)有量產(chǎn),普及到普通消費(fèi)者的家中還需要一段時(shí)間。#{}
PS:附帶一張真機(jī)測(cè)試圖,沒(méi)想象中感覺(jué)好。
PS:造成失真是猶豫界面被拉伸導(dǎo)致,所以如果不拉升,效果還是一樣的。