文章目錄
1 Framebuffer應(yīng)用開(kāi)發(fā)
1.1 LCD Framebuffer操作原理
1.2.1 open系統(tǒng)調(diào)用
1.2.2 ioctl系統(tǒng)調(diào)用
1.2.3 mmap系統(tǒng)調(diào)用
1.3 在LCD上描點(diǎn)操作
1.3.1 在LCD上顯示點(diǎn)陣?yán)碚摶A(chǔ)
1.3.2 獲取fb_var_screeninfo結(jié)構(gòu)體
1.3.3 根據(jù)fb_var_screeninfo計(jì)算變量
1.3.4 使用mmap系統(tǒng)調(diào)用,映射內(nèi)存
1.3.5 描點(diǎn)函數(shù)編寫(xiě)
1.4 在LCD上使用點(diǎn)陣寫(xiě)字
1.4.1 在LCD上顯示英文字母
1.4.2 在LCD上顯示漢字
1.5 搭建freetype相關(guān)環(huán)境
1.5.1 交叉編譯freetype,并安裝
1.5.2 freetype庫(kù),頭文件移植至開(kāi)發(fā)板
1.6 使用freetype
1.5.1 矢量字體引入
1.5.2 Freetype理論介紹
1.5.2 在LCD上顯示一個(gè)矢量字體
1.5.3 在LCD上令矢量字體旋轉(zhuǎn)某個(gè)角度
1 Framebuffer應(yīng)用開(kāi)發(fā)
1.1 LCD Framebuffer操作原理
? LCD Framebuffer 就是一塊顯存,在嵌入式系統(tǒng)中,顯存是被包含在內(nèi)存中。LCD Framebuffer里的若干字節(jié)(根據(jù)驅(qū)動(dòng)程序?qū)CD控制器的配置而定)表示LCD屏幕中的一個(gè)像素點(diǎn),一一對(duì)應(yīng)整個(gè)LCD屏幕。舉個(gè)例子,LCD屏幕是800*600的分辨率,即LCD屏幕存在480000個(gè)像素點(diǎn),若每個(gè)像素點(diǎn)4個(gè)字節(jié)表示,那么LCD Framebuffer顯存大小為480000 *4=960000字節(jié),即1.92MB。因此我們的內(nèi)存將會(huì)分割至少1.92MB的空間用作顯存。具體地址在哪里,這個(gè)就是又驅(qū)動(dòng)程序去定,應(yīng)用程序只需直接使用即可,硬件相關(guān)操作已由驅(qū)動(dòng)程序封裝好。
? 如上圖,我們只需要往Framebuffer中填入不同的值,驅(qū)動(dòng)程序和硬件控制器就會(huì)把這些數(shù)據(jù)傳輸?shù)綄?duì)應(yīng)LCD屏幕上的像素點(diǎn),從而顯示不同的顏色。由此可知,我們應(yīng)用程序只需要針對(duì)Framebuffer操作即可,其他交給驅(qū)動(dòng)程序和硬件。
1.2 Framebuffer API接口
1.2.1 open系統(tǒng)調(diào)用
頭文件:#include ,#include ,#include
函數(shù)原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
函數(shù)說(shuō)明:
pathname 表示打開(kāi)文件的路徑;
Flags表示打開(kāi)文件的方式,常用的有以下6種,
①:O_RDWR表示可讀可寫(xiě)方式打開(kāi);
②:O_RDONLY表示只讀方式打開(kāi);
③:O_WRONLY表示只寫(xiě)方式打開(kāi);
④:O_APPEND 表示如果這個(gè)文件中本來(lái)是有內(nèi)容的,則新寫(xiě)入的內(nèi)容會(huì)接續(xù)到原來(lái)內(nèi)容的后面;
⑤:O_TRUNC表示如果這個(gè)文件中本來(lái)是有內(nèi)容的,則原來(lái)的內(nèi)容會(huì)被丟棄,截?cái)啵?/p>
⑥:O_CREAT表示當(dāng)前打開(kāi)文件不存在,我們創(chuàng)建它并打開(kāi)它,通常與O_EXCL結(jié)合使用,當(dāng)沒(méi)有文件時(shí)創(chuàng)建文件,有這個(gè)文件時(shí)會(huì)報(bào)錯(cuò)提醒我們;
Mode表示創(chuàng)建文件的權(quán)限,只有在flags中使用了O_CREAT時(shí)才有效,否則忽略。
返回值:打開(kāi)成功返回文件描述符,失敗將返回-1。
1.2.2 ioctl系統(tǒng)調(diào)用
頭文件:#include
函數(shù)原型:
int ioctl(int fd, unsigned long request, …);
函數(shù)說(shuō)明:
fd 表示文件描述符;
request表示與驅(qū)動(dòng)程序交互的命令,用不同的命令控制驅(qū)動(dòng)程序輸出我們需要的數(shù)據(jù);
… 表示可變參數(shù)arg,根據(jù)request命令,設(shè)備驅(qū)動(dòng)程序返回輸出的數(shù)據(jù)。
返回值:打開(kāi)成功返回文件描述符,失敗將返回-1。
1.2.3 mmap系統(tǒng)調(diào)用
頭文件:#include
函數(shù)原型:
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
函數(shù)說(shuō)明:
addr表示指定映射的內(nèi)存起始地址,通常設(shè)為 NULL表示讓系統(tǒng)自動(dòng)選定地址,并在成功映射后返回該地址;
length表示將文件中多大的內(nèi)容映射到內(nèi)存中;
prot 表示映射區(qū)域的保護(hù)方式,可以為以下4種方式的組合
①PROT_EXEC 映射區(qū)域可被執(zhí)行
②PROT_READ 映射區(qū)域可被讀寫(xiě)
③PROT_WRITE 映射區(qū)域可被寫(xiě)入
④PROT_NONE 映射區(qū)域不能存取
Flags 表示影響映射區(qū)域的不同特性,常用的有以下兩種
①M(fèi)AP_SHARED 表示對(duì)映射區(qū)域?qū)懭氲臄?shù)據(jù)會(huì)復(fù)制回文件內(nèi),原來(lái)的文件會(huì)改變。
②MAP_PRIVATE 表示對(duì)映射區(qū)域的操作會(huì)產(chǎn)生一個(gè)映射文件的復(fù)制,對(duì)此區(qū)域的任何修改都不會(huì)寫(xiě)回原來(lái)的文件內(nèi)容中。
返回值:若成功映射,將返回指向映射的區(qū)域的指針,失敗將返回-1。
1.3 在LCD上描點(diǎn)操作
1.3.1 在LCD上顯示點(diǎn)陣?yán)碚摶A(chǔ)
? 如上圖,當(dāng)我們需要顯示一個(gè)字母‘A’時(shí),是通過(guò)判斷點(diǎn)陣的每一個(gè)位數(shù)值狀態(tài),來(lái)填充顏色,達(dá)到顯示字符效果。其中‘1’表示一種顏色,‘0’表示填充另一種顏色。上圖的是8*16的點(diǎn)陣,我們也可以用其他不同大小點(diǎn)陣,只要有這個(gè)點(diǎn)陣,我們就可以在LCD上面描點(diǎn),達(dá)到顯示字符的效果。
1.3.2 獲取fb_var_screeninfo結(jié)構(gòu)體
? 在用點(diǎn)陣顯示字符之前,我們需要先從設(shè)備fb0中獲取相關(guān)的LCD信息,下圖截取我們將用到的fb_info結(jié)構(gòu)體部分內(nèi)容。
? 通過(guò)系統(tǒng)調(diào)用ioctl,獲取xres(x方向總像素點(diǎn)),yres(y方向總像素點(diǎn)),bits_per_pixel(每個(gè)像素點(diǎn)占據(jù)的位數(shù)),根據(jù)獲取的三個(gè)資源,外加點(diǎn)陣,根據(jù)這四個(gè)資源,我們就可以顯示一個(gè)字符。
程序文件:show_ascii.c
4718 fd_fb = open("/dev/fb0", O_RDWR); 4719 if (fd_fb < 0) 4720 { 4721 printf("can't open /dev/fb0n"); 4722 return -1; 4723 } 4724 if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) 4725 { 4726 printf("can't get varn"); 4727 return -1; 4728 }
? 先打開(kāi)LCD設(shè)備(fb0),獲得文件描述符,再通過(guò)ioctl獲取fb_var_screeninfo信息并保存在var變量,后續(xù)只需訪問(wèn)var這個(gè)結(jié)構(gòu)體,就可以獲得xres(x方向總像素點(diǎn)),yres(y方向總像素點(diǎn)),bits_per_pixel(每個(gè)像素點(diǎn)占據(jù)的位數(shù))這三個(gè)關(guān)于fb0的資源。
1.3.3 根據(jù)fb_var_screeninfo計(jì)算變量
fb_var_screeninfo已保存在var結(jié)構(gòu)體變量中,接著來(lái)訪問(wèn)var結(jié)構(gòu)體變量即可
根據(jù)xres與bits_per_pixel算出每行像素點(diǎn)所占據(jù)的字節(jié)數(shù)
程序文件:show_ascii.c
4730 line_width = var.xres * var.bits_per_pixel / 8;
根據(jù)bits_per_pixel算出每個(gè)像素點(diǎn)所占據(jù)的字節(jié)數(shù)
程序文件:show_ascii.c
4731 pixel_width = var.bits_per_pixel / 8;
根據(jù)xres,yres,bits_per_pixel算出全部像素點(diǎn)所占據(jù)的字節(jié)總和
程序文件:show_ascii.c
4732 screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
1.3.4 使用mmap系統(tǒng)調(diào)用,映射內(nèi)存
程序文件:show_ascii.c
4733 fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); 4734 if (fbmem == (unsigned char *)-1) 4735 { 4736 printf("can't mmapn"); 4737 return -1; 4738 } 4739 4740 /* 清屏: 全部設(shè)為黑色 */ 4741 memset(fbmem, 0, screen_size);
? 調(diào)用mmap將顯存映射在內(nèi)存中,以可讀可寫(xiě)(PROT_READ | PROT_WRITE)及內(nèi)存回寫(xiě)(MAP_SHARED)的方式映射,從而獲得一個(gè)指向映射在內(nèi)存空間的首地址fbmem,后續(xù)操作就是在這個(gè)首地址的基礎(chǔ)上計(jì)算各種不同的偏移量,填充顏色值。
1.3.5 描點(diǎn)函數(shù)編寫(xiě)
程序文件:show_ascii.c
4641 void lcd_put_pixel(int x, int y, unsigned int color)
描點(diǎn)函數(shù)有3個(gè)參數(shù),x坐標(biāo),y坐標(biāo),像素點(diǎn)顏色值。
程序文件:show_ascii.c
4643 unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width; 4644 unsigned short *pen_16; 4645 unsigned int *pen_32; 4646 4647 unsigned int red, green, blue; 4648 4649 pen_16 = (unsigned short *)pen_8; 4650 pen_32 = (unsigned int *)pen_8;
? 在此處函數(shù)參數(shù)x與y表示的是像素點(diǎn)的坐標(biāo),而單個(gè)像素點(diǎn)所占據(jù)的顯存大小可能會(huì)有不同的情況出現(xiàn),如1字節(jié)表示一個(gè)像素點(diǎn),2字節(jié)表示一個(gè)像素點(diǎn),4字節(jié)表示一個(gè)像素點(diǎn)等,為了更多的兼容不同的情況,因此申請(qǐng)3個(gè)指針,pen_8指向的是占據(jù)1個(gè)字節(jié)的像素點(diǎn)空間, pen_16指向的是占據(jù)2個(gè)字節(jié)的像素點(diǎn)空間,pen_32指向的是占據(jù)4個(gè)字節(jié)的像素點(diǎn)空間。
fbmem是系統(tǒng)調(diào)用mmap返回的顯存首地址,根據(jù)fbmem計(jì)算填充顏色的內(nèi)存空間。
當(dāng)像素點(diǎn)占據(jù)1個(gè)字節(jié)空間時(shí)
對(duì)應(yīng)描點(diǎn)地址= fbmem+Y * 一行所占據(jù)的字節(jié)數(shù) + x * 每個(gè)像素點(diǎn)所占據(jù)的字節(jié)數(shù)
程序文件:show_ascii.c
4652 switch (var.bits_per_pixel) 4653 { 4654 case 8: 4655 { 4656 *pen_8 = color; 4657 break; 4658 } 4659 case 16: 4660 { 4661 /* 565 */ 4662 red = (color >> 16) & 0xff; 4663 green = (color >> 8) & 0xff; 4664 blue = (color >> 0) & 0xff; 4665 color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); 4666 *pen_16 = color; 4667 break; 4668 } 4669 case 32: 4670 { 4671 *pen_32 = color; 4672 break; 4673 } 4674 default: 4675 { 4676 printf("can't surport %dbppn", var.bits_per_pixel); 4677 break; 4678 } 4679 } 4680 }
? 根據(jù)設(shè)備fb0實(shí)際的bits_per_pixel值,選擇對(duì)應(yīng)的pen(pen_8,pen_16,pen_32其中一個(gè)),最后把color顏色變量傳入選擇的pen中。
1.4 在LCD上使用點(diǎn)陣寫(xiě)字
1.4.1 在LCD上顯示英文字母
①找出英文字母在點(diǎn)陣數(shù)組中的地址,c所代表的是一個(gè)英文字母(ASCII值)。
程序文件:show_ascii.c
4693 unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
②根據(jù)獲得的英文字母點(diǎn)陣,每一位依次判斷,描點(diǎn),‘1’表示白色,‘0’表示黑色。
? 根據(jù)上圖,我們分析下如何利用點(diǎn)陣在LCD上顯示一個(gè)英文字母,因?yàn)橛惺校允紫纫幸粋€(gè)循環(huán)16次的大循環(huán),然后每一行里有8位,那么在每一個(gè)大循環(huán)里也需要一個(gè)循環(huán)8次的小循環(huán),小循環(huán)里的判斷單行的描點(diǎn)情況,如果是1,就填充白色,如果是0就填充黑色,如此一來(lái),就可以顯示出黑色底,白色輪廓的英文字母。
程序文件:show_ascii.c
4697 for (i = 0; i < 16; i++) 4698 { 4699 byte = dots[i]; 4700 for (b = 7; b >= 0; b--) 4701 { 4702 if (byte & (1<
③調(diào)用我們編寫(xiě)的lcd_put_ascii函數(shù)
程序文件:show_ascii.c
4743 lcd_put_ascii(var.xres/2, var.yres/2, 'A'); /*在屏幕中間顯示8*16的字母A*/
④編譯c文件show_ascii.c
編譯命令:arm-linux-gnueabihf-gcc -o show_ascii show_ascii.c
⑤將編譯出來(lái)的show_ascii傳輸?shù)介_(kāi)發(fā)板,并進(jìn)入show_ascii的目錄下
執(zhí)行命令:./show_ascii
如果實(shí)驗(yàn)成功,我們將看到屏幕中間會(huì)顯示出一個(gè)白色的字母‘A’。
1.4.2 在LCD上顯示漢字
? 與顯示英文字母有點(diǎn)不同,因?yàn)闈h字的點(diǎn)陣我們是需要通過(guò)漢字庫(kù)提取出來(lái),并沒(méi)有直接提供點(diǎn)陣數(shù)組,因此我們程序開(kāi)頭需要打開(kāi)漢字庫(kù)文件(HZK16),然后再找到相應(yīng)的位置,提取出漢字的點(diǎn)陣,最后再按顯示英文字母一樣顯示它,不過(guò)這個(gè)漢字是16*16的。
① 打開(kāi)漢字庫(kù)文件
程序文件:show_font.c
4760 fd_hzk16 = open("HZK16", O_RDONLY);
② 獲取漢字庫(kù)文件的屬性,存在hzk_stat結(jié)構(gòu)體變量中
程序文件:show_font.c
4793 if(fstat(fd_hzk16, &hzk_stat))
此處主要是用知道該文件的大小,因?yàn)楹竺鎚map時(shí)需要知道映射的文件大小。
③使用mmap系統(tǒng)調(diào)用
程序文件:show_font.c
4798 hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
hzkmem與fbmem類似,也是一個(gè)指向映射內(nèi)存的指針,但是它是指向漢字庫(kù),方便
后續(xù)計(jì)算漢字點(diǎn)陣偏移位置用。
④使用漢字庫(kù),調(diào)出點(diǎn)陣顯示漢字
? HZK16 字庫(kù)是符合GB2312標(biāo)準(zhǔn)的16×16點(diǎn)陣字庫(kù)HZK16的編碼,每個(gè)字需要32個(gè)字節(jié)的點(diǎn)陣來(lái)表示,例如我們將要顯示的‘中’字,編碼是D6D0,難道就是2個(gè)字節(jié)表示嗎?不是說(shuō)32字節(jié)嗎?D6D0編碼是一個(gè)類似于索引碼,D6是區(qū)碼,D0是位碼,先要找到D6-A1才是真正區(qū),在D6-A1區(qū)里找到D0-A1的真正位置,這才是‘中’字點(diǎn)陣的起始位置(減去A1是為了兼容ascii),每一個(gè)區(qū)有94個(gè)漢字。
程序文件:show_font.c
4734 unsigned int area = str[0] - 0xA1; 4735 unsigned int where = str[1] - 0xA1; 4736 unsigned char *dots = hzkmem + (area * 94 + where)*32;
? 上圖是漢字點(diǎn)陣排布的示意圖,總共有十六行,因此需要一個(gè)循環(huán)16次的大循環(huán),考慮到一行有兩個(gè)字節(jié),我們大循環(huán)中加入一個(gè)循環(huán)2次的循環(huán)用于區(qū)分是哪個(gè)字節(jié),最后判斷當(dāng)前字節(jié)的每一位,如果為 ‘1’描白色,如果為‘0’描黑色
程序文件:show_font.c
4740 for (i = 0; i < 16; i++) 4741 for (j = 0; j < 2; j++) 4742 { 4743 byte = dots[i*2 + j]; 4744 for (b = 7; b >=0; b--) 4745 { 4746 if (byte & (1<
⑤調(diào)用我們編寫(xiě)的lcd_put_chinese函數(shù)
程序文件:show_font.c
4810 printf("chinese code: %02x %02xn", str[0], str[1]); 4811 lcd_put_chinese(var.xres/2 + 8, var.yres/2, str);
⑥編譯c文件show_font.c
編譯命令:arm-linux-gnueabihf-gcc -o show_font show_font.c
注:使用此命令HZK16文件必須與show_font.C在同一目錄下。
⑦將編譯出來(lái)的show_font傳輸?shù)介_(kāi)發(fā)板,并進(jìn)入show_font的目錄下
執(zhí)行命令:./show_font
如果實(shí)驗(yàn)成功,我們將看到屏幕中間會(huì)顯示出一個(gè)白色的字母‘A’與漢字‘中’,同時(shí)在串口打印信息中看到‘中’對(duì)應(yīng)的編碼。
chinese code: d6 d0
1.5 搭建freetype相關(guān)環(huán)境
1.5.1 交叉編譯freetype,并安裝
①解壓freetype源文件
tar xjf freetype-2.4.10.tar.bz2
②進(jìn)入解壓后的freetype-2.4.10目錄
cd freetype-2.4.10
③配置freetype-2.4.10
./configure --host=arm-linux-gnueabihf --prefix=/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/
④建個(gè)目錄,避免后面安裝出錯(cuò)提示缺少這個(gè)internal目錄
mkdir /home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/freetype2/freetype/internal -p
④編譯
make
⑤安裝
make install
⑥移動(dòng)freetype頭文件,避免以后編譯總是需要指定頭文件路徑
mv /home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/freetype2/freetype /home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/
1.5.2 freetype庫(kù),頭文件移植至開(kāi)發(fā)板
? 由于100ask開(kāi)發(fā)板已經(jīng)有freetype相關(guān)的庫(kù)和頭文件,因此不需要移植,如果開(kāi)發(fā)板沒(méi)有freetype庫(kù)和頭文件就需要按以下方法移植
/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/* 復(fù)制到開(kāi)發(fā)板的頭文件目錄中
/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib/so 復(fù)制到開(kāi)發(fā)板的庫(kù)文件目錄中
注:鏈接文件需要保持它的鏈接屬性(即加-d選項(xiàng))。
1.6 使用freetype
1.5.1 矢量字體引入
? 點(diǎn)陣顯示英文字母,漢字時(shí),大小固定,如果放大會(huì)有鋸齒出現(xiàn),為了解決這個(gè)問(wèn)題,引用矢量字體。
矢量字體形成分三步,若干的關(guān)鍵點(diǎn),數(shù)學(xué)曲線(貝塞爾曲線),填充顏色組合而成。
①假設(shè)A字母的關(guān)鍵點(diǎn)如圖中的黃色圈圈,確定關(guān)鍵點(diǎn)。
②用數(shù)學(xué)曲線將關(guān)鍵點(diǎn)都連接起來(lái),成為封閉的曲線。
③最后把封閉空間填滿顏色,就顯示出一個(gè)A字母。
? 如果需要放大或者縮小字體,關(guān)鍵點(diǎn)的相對(duì)位置是不變的,跟進(jìn)放大比例放大或縮小,但是相對(duì)位置不變,好像分?jǐn)?shù)中的1/2 和 2/4,比例是不變的,但是值卻大了,類似這個(gè)味道。
1.5.2 Freetype理論介紹
? 開(kāi)源的Freetype字體引擎庫(kù)它提供統(tǒng)一的接口來(lái)訪問(wèn)多種字體格式文件,從而實(shí)現(xiàn)矢量字體顯示。我們只需要移植這個(gè)字體引擎,調(diào)用對(duì)應(yīng)的API接口,提供字體關(guān)鍵點(diǎn),就可以讓freetype庫(kù)幫我們實(shí)現(xiàn)閉合曲線,填充顏色,達(dá)到顯示矢量字體的目的。
關(guān)鍵點(diǎn)(glyph)存在字體文件中,Windows使用的字體文件在FONTS目錄下,擴(kuò)展名為T(mén)TF的都是矢量字庫(kù),本次使用實(shí)驗(yàn)使用的是新宋字體simsun.ttc。
字體文件結(jié)構(gòu)如上圖
? Charmaps表示字符映射表,字體文件可能支持哪一些編碼,GBK,UNICODE,BIG5還是別的編碼,如果字體文件支持該編碼,跟進(jìn)編碼,通過(guò)charmap,找到對(duì)應(yīng)的glyph,一般而言都支持UNICODE碼。
有了以上基礎(chǔ),我們想象一個(gè)文字的顯示過(guò)程
①給定一個(gè)文字嗎‘A’(0x41),‘中’(GBK,UNICODE ,BIG5)可以確定它的編碼值;
②跟進(jìn)編碼值,從枝頭文件中通過(guò)charmap找到對(duì)應(yīng)的關(guān)鍵點(diǎn)(glyph);
③設(shè)置字體大;
④用某些函數(shù)把關(guān)鍵點(diǎn)(glyph)縮放為我們?cè)O(shè)置的字體大小;
⑤轉(zhuǎn)換為位圖點(diǎn)陣
⑥在LCD上顯示出來(lái)
? 如上圖,參照step1,step2,step3里的內(nèi)容,可以學(xué)習(xí)如何使用freetype庫(kù),大致總結(jié)下,為如下步驟。
①初始化:FT_InitFreetype
②加載(打開(kāi))字體Face:FT_New_Face
③設(shè)置字體大小:FT_Set_Char_Sizes 或 FT_Set_Pixel_Sizes
④選擇charmap:FT_Select_Charmap
⑤根據(jù)編碼值charcode找到glyph : glyph_index = FT_Get_Char_Index(face,charcode)
⑥根據(jù)glyph_index取出glyph:FT_Load_Glyph(face,glyph_index)
⑦轉(zhuǎn)為位圖:FT_Render_Glyph
⑧移動(dòng)或旋轉(zhuǎn):FT_Set_Transform
1.5.2 在LCD上顯示一個(gè)矢量字體
我們可以參考上圖位置的c程序,編寫(xiě)程序。
①初始化freetype庫(kù)
程序文件:freetype_show_font.c
4872 error = FT_Init_FreeType( &library ); /* initialize library */
②用freetype庫(kù)中的FT_New_Face函數(shù)創(chuàng)建一個(gè)face字體文件對(duì)象,保存在&face中
程序文件:freetype_show_font.c
4875 error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
③提取face對(duì)象中的glyph,即關(guān)鍵點(diǎn)集
程序文件:freetype_show_font.c
4877 slot = face->glyph;
④設(shè)置像素點(diǎn)大小,24*24
程序文件:freetype_show_font.c
4879 FT_Set_Pixel_Sizes(face, 24, 0);
⑤確定坐標(biāo)
? 目前我們前面所用的都是LCD的坐標(biāo)系對(duì)應(yīng)的x與y坐標(biāo),然后在freetype上卻是使用的笛卡爾坐標(biāo)系,因此我們還需要轉(zhuǎn)換x與y坐標(biāo)。
我們將要顯示的是‘繁’字,根據(jù)上圖可知,先計(jì)算在lcd坐標(biāo)系的情況下‘繁’字
的左下角的x坐標(biāo)與y坐標(biāo),因?yàn)樵诘芽栕鴺?biāo)中左下角為字符的原點(diǎn),‘A’是的左上角為整個(gè)屏幕的中心點(diǎn),即(xres/2,yres/2)。
lcd_x = var.xres/2 + 8 + 16;lcd_y = var.yres/2 + 16
則笛卡爾座標(biāo)系:x = lcd_x = var.xres/2 + 8 + 16 ; y = var.yres - lcd_y = var.yres/2 – 16
單位是1/64像素,所以需要乘以64
程序文件:freetype_show_font.c
4888 pen.x = (var.xres/2 + 8 + 16) * 64; 4889 pen.y = (var.yres/2 - 16) * 64; 4890 4891 /* set transformation */ 4892 FT_Set_Transform( face, 0, &pen);
⑥找到glyph的位置,然后取出,并轉(zhuǎn)換為位圖
4895 error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER ); 4896 if (error) 4897 { 4898 printf("FT_Load_Char errorn"); 4899 return -1; 4900 }
FT_Load_Char函數(shù)調(diào)用替代了上圖這3步。
最后把轉(zhuǎn)換出來(lái)的位圖打印出來(lái),也是參考example1.c編寫(xiě)
程序文件:freetype_show_font.c
4902 draw_bitmap( &slot->bitmap, 4903 slot->bitmap_left, 4904 var.yres - slot->bitmap_top);
程序文件:example1.c
修改上圖3處位置
Width寬度:因?yàn)樵贚CD上顯示,寬度自然就是x方向的像素點(diǎn)數(shù),var.xres;
Height高度:因?yàn)樵贚CD上顯示,高度自然就是y方向的像素點(diǎn)數(shù),var.yres;
用點(diǎn)陣實(shí)驗(yàn)中的的描點(diǎn)函數(shù)lcd_put_pixel替代image數(shù)組
lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);
⑥編譯C程序文件freetype_show_font.c
編譯命令:arm-linux-gnueabihf-gcc -finput-charset=GBK -fexec-charset=GBK -o freetype_show_font freetype_show_font.c -lfreetype -lm
⑦將編譯好的freetype_show_font的文件與simsun.ttc字體文件拷貝至開(kāi)發(fā)板,simsun.ttc字體文件放在freetype_show_font執(zhí)行文件的上一層目錄下,執(zhí)行以下命令。
執(zhí)行命令:./freetype_show_font …/simsun.ttc
如果實(shí)驗(yàn)成功,我們將看到屏幕中間會(huì)比之前實(shí)驗(yàn)多出一個(gè)藍(lán)色的‘繁’字。
1.5.3 在LCD上令矢量字體旋轉(zhuǎn)某個(gè)角度
在實(shí)現(xiàn)顯示一個(gè)矢量字體后,我們可以添加讓該字旋轉(zhuǎn)某個(gè)角度的功能。
我們根據(jù)輸入的第二個(gè)參數(shù),判斷其旋轉(zhuǎn)角度,主要代碼還是參照example1.c
根據(jù)上圖,增加旋轉(zhuǎn)角度功能,旋轉(zhuǎn)的角度由執(zhí)行命令的第二個(gè)參數(shù)指定。
程序文件:freetype_show_font_angle.c
/* use 25 degrees */ 4894 angle = ( 1.0 * strtoul(argv[2], NULL, 0) / 360 ) * 3.14159 * 2; 4895 /* set up matrix */ 4896 matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); 4897 matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L ); 4898 matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L ); 4899 matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); 4900 4901 /* set transformation */ 4902 FT_Set_Transform( face, &matrix, &pen);
最后編譯,在開(kāi)發(fā)板上運(yùn)行
編譯命令如下:
編譯命令:arm-linux-gnueabihf-gcc -finput-charset=GBK -fexec-charset=GBK -o freetype_show_font_angle freetype_show_font_angle.c -lfreetype -lm
編譯出的文件名為freetype_show_font_angle,將文件拷貝至開(kāi)發(fā)板
在含有該文件的目錄下執(zhí)行以下命令,以下命令正確執(zhí)行前提是執(zhí)行文件freetype_show_font在此目錄,而且字體文件simsun.ttc,在上一級(jí)目錄:
執(zhí)行命令:./freetype_show_font_angle …/simsun.ttc 90
如果實(shí)驗(yàn)成功,我們將看到屏幕中間的藍(lán)色‘繁’字,旋轉(zhuǎn)了90度。
審核編輯黃昊宇
-
lcd
+關(guān)注
關(guān)注
34文章
4425瀏覽量
167425 -
Linux
+關(guān)注
關(guān)注
87文章
11296瀏覽量
209361 -
Display
+關(guān)注
關(guān)注
1文章
53瀏覽量
24722
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論