本章主要內容如下: 1)多行顯示 2)居中顯示 在上章3.數位相框-通過freetype庫實現矢量顯示里,我們使用矢量坐標時,該坐標僅僅在原點位置處,所以文字有可能會超出坐標,如下圖所示: 既然超出了坐標,會不會被下一行的文字覆蓋掉? 答:對於幾行同樣大的文字而言,不會的. 以 24*24的韋字為例 ...
本章主要內容如下:
- 1)多行顯示
- 2)居中顯示
在上章3.數位相框-通過freetype庫實現矢量顯示里,我們使用矢量坐標時,該坐標僅僅在原點位置處,所以文字有可能會超出坐標,如下圖所示:
既然超出了坐標,會不會被下一行的文字覆蓋掉?
答:對於幾行同樣大的文字而言,不會的.
以 24*24的韋字為例,讓它顯示在(0,40)處,所以文字的y範圍在17~40,如下圖所示,發現該文字超過了原點,而上方數據又會空出來一段,就不會覆蓋到上一行數據.
對於幾行規格大小不同的文字,則有可能會被覆蓋.以20*20的韋字為例,如下圖,可以發現空出的數據比24*24的少1行,若上一行的規格很大時(超出原點很大一部分), 那麼這個20*20的韋字,就會覆蓋掉上一行文字底部的數據.
1.從左顯示多行24*24文字
內容如下:
定義一個兩個標誌變數line_box_ymax和line_box_ymin.
通過FT_Glyph_Get_CBox()測量字形圖像,獲取一行文字的yMax,Min最大值,最小值.
顯示第一行時:
pen.x = 0* 64; pen.y = ( fb_var.yres-24 ) * 64; // fb_var.yres:LCD總高度, 原點為(0,24)
顯示第2~n行時:
pen.x = 0* 64; pen.y-= (line_box_ymax - line_box_ymin )* 64; //在上行的pen.y基礎上,減去上行的邊框高
代碼如下:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <string.h> #include <linux/fb.h> #include <math.h> #include<wchar.h> #include <ft2build.h> #include FT_FREETYPE_H #include FT_GLYPH_H unsigned char *fbmem; unsigned char *hzkmem; struct fb_var_screeninfo fb_var; struct fb_fix_screeninfo fb_fix; unsigned int screensize; #define FONTDATAMAX 4096 /*rgb565*/ void pixel_show(int x,int y, unsigned int color) { unsigned int red,green,blue; switch(fb_var.bits_per_pixel) //rgb 像素 { case 32: { unsigned int *addr=(unsigned int *)fbmem+(fb_var.xres*y+x); *addr=color; break; } case 24: { unsigned int *addr=(unsigned int *)fbmem+(fb_var.xres*y+x); *addr=color; break; } case 16: //將RGB888 轉為RGB565 { unsigned short *addr=(unsigned short *)fbmem+(fb_var.xres*y+x); red = (color >> 16) & 0xff; green = (color >> 8) & 0xff; blue = (color >> 0) & 0xff; color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); *addr = color; break; } case 8: { unsigned char *addr=(unsigned char *)fbmem+(fb_var.xres*y+x); *addr = (unsigned char)color; break; } default: { printf("can't surport %dbpp \n",fb_var.bits_per_pixel); break; } } } void draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y) { FT_Int i, j, p, q; FT_Int x_max = x + bitmap->width; //x:當前X位置, bitmap->width:該字寬度 FT_Int y_max = y + bitmap->rows; for ( i = x, p = 0; i < x_max; i++, p++ ) //i:lcd的x軸 { for ( j = y, q = 0; j < y_max; j++, q++ ) //j:lcd的y軸 { if ( i < 0 || j < 0 || i >= fb_var.xres || j >= fb_var.yres ) continue;
pixel_show( i, j, bitmap->buffer[q * bitmap->width + p]); } } } unsigned int line_box_ymax=0; unsigned int line_box_ymin=30000; void lcd_vector_show(char *argv,wchar_t *str[],unsigned int lines) { FT_Glyph glyph; FT_BBox acbox; FT_Library library; FT_Face face; FT_GlyphSlot slot; FT_Vector pen; /* untransformed origin */ unsigned char error; unsigned int line_nums=0; unsigned char n,font_size;
error = FT_Init_FreeType( &library ); /* initialize library */ if(error) { printf("FT_Init_FreeType ERROR\n"); return ; } error = FT_New_Face( library, argv, 0, &face ); /* create face object */ if(error) { printf("FT_New_Face ERROR\n"); return ; } slot = face->glyph; error = FT_Set_Pixel_Sizes( face, 0,24); /* set character size */ for(line_nums=0;line_nums<lines;line_nums++) { /*設置筆記落下位置*/ /*顯示坐標(從LCD左上方顯示3 行) *x=0 *y=fb_var.yres-24 (減24,是因為笛卡爾坐標以左下方開始計算坐標值的) */ if(line_nums==0) { pen.x = 0* 64; pen.y = ( fb_var.yres-24 ) * 64; } else { pen.x = 0* 64; pen.y-= (line_box_ymax - line_box_ymin )* 64; //在上行的Y值上減去邊框高 /*清空標誌位,因為上一行的ymin永遠當前行小*/ line_box_ymax=0; line_box_ymin=30000; } for ( n = 0; n < wcslen(str[line_nums]); n++ ) { FT_Set_Transform( face, 0, &pen ); error = FT_Load_Char( face,str[line_nums][n], FT_LOAD_RENDER ); if ( error ) { printf("FT_Load_Char ERROR\n"); continue; } FT_Get_Glyph( face->glyph, &glyph ); //獲取字形圖像 的信息 FT_Glyph_Get_CBox( glyph,FT_GLYPH_BBOX_TRUNCATE,&acbox ); //獲取此行文字的box if(acbox.yMax>acbox.yMin) { if(line_box_ymax<acbox.yMax) line_box_ymax=acbox.yMax; if(line_box_ymin>acbox.yMin) line_box_ymin=acbox.yMin; } draw_bitmap( &slot->bitmap, slot->bitmap_left, fb_var.yres- slot->bitmap_top ); pen.x += slot->advance.x; } } FT_Done_Face( face ); FT_Done_FreeType( library ); } int main(int argc,char **argv) { int fd_fb,fd_hzk; struct stat hzk_start; //HZK16文件信息 wchar_t *chinese_str[]={L"韋東山gh",L"abc 中國chinese",L"哈哈哈哈wqe"}; if ( argc != 2 ) { printf ("usage: %s font_file \n", argv[0] ); return 0; } fd_fb=open("/dev/fb0", O_RDWR); if(fd_fb<0) { printf("can't open /dev/fb0 \n"); return 0; } if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&fb_var)<0) { printf("can't get var \n"); return 0; } if(ioctl(fd_fb,FBIOGET_FSCREENINFO,&fb_fix)<0) { printf("can't get fix \n"); return 0; } screensize=fb_var.xres*fb_var.yres*(fb_var.bits_per_pixel/8); //顯存大小 fbmem =(unsigned char *)mmap(NULL,screensize, PROT_READ|PROT_WRITE,MAP_SHARED, fd_fb, 0); //映射fb0 if(!fbmem) { printf("can't map /dev/fb0 \n"); return 0; } memset(fbmem, 0, screensize); //清屏黑色 /*顯示3 行 矢量文字*/ lcd_vector_show(argv[1], chinese_str,3); munmap(fbmem,screensize); return 0; }
2.居中顯示
參考第11頁:https://wenku.baidu.com/view/060a0b44f12d2af90342e63a.html?from=search
1)首先定義一個用來存儲一行文字的字形圖像數組
#define MAX_GLYPHS 100 //最多存儲一行100個字 TGlyph glyphs[MAX_GLYPHS]; /* glyphs table */
2)首先以坐標(0,0)為基值,獲取每個文字的字形圖像和坐標值,存到glyphs[]里
/*初始化庫,獲取face,設置字體*/ error = FT_Init_FreeType( &library ); /* initialize library */ if(error) { //... ...} error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */ if(error) {//... ...} FT_Set_Pixel_Sizes(face, 24, 0); ... ...
int num_glyphs = 0; PGlyph glyph = glyphs; // Pglyph在庫里被定義為Tglyph *, glyph指向glyphs int pen_x = 0; int pen_y = 0; for (n = 0; n < wcslen(wstr); n++) // wstr: wchar_t類型的文字數組 { glyph->index = FT_Get_Char_Index( face, wstr[n]); //存儲每個文字的索引值 glyph->pos.x = pen_x; //記錄每個文字的坐標值,後面會用來設置字形圖像的位置信息 glyph->pos.y = pen_y; error=FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT); //通過索引值,找到face(字體文件)里的字形圖像,並放到face->glyph字元槽里. if ( error ) continue; FT_Get_Glyph(face->glyph, &glyph->image );//然後存儲每個文字的字形圖像 if ( error ) continue; FT_Glyph_Transform(glyph->image, 0, &glyph->pos ); //使用FT_Glyph_Transform(),使glyph->image包含位置信息 pen_x += face->glyph->advance.x; // 以1/64像素點為單位 glyph++; } num_glyphs= glyph- glyphs; //獲取轉換成功的文字個數
3)通過glyphs[]存的一行字形圖像,計算出邊界框
FT_BBox bbox; bbox.xMin = bbox.yMin = 32000; bbox.xMax = bbox.yMax = -32000; /*判斷一行文字的邊界框範圍*/ for ( n = 0; n < num_glyphs; n++ ) { FT_BBox glyph_bbox; FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox ); // FT_GLYPH_BBOX_TRUNCATE:獲取的坐標信息以像素坐標為單位 if (glyph_bbox.xMin < bbox.xMin) bbox.xMin = glyph_bbox.xMin; if (glyph_bbox.yMin < bbox.yMin) bbox.yMin = glyph_bbox.yMin; if (glyph_bbox.xMax > bbox.xMax) bbox.xMax = glyph_bbox.xMax; if (glyph_bbox.yMax > bbox.yMax) bbox.yMax = glyph_bbox.yMax; }
4)通過邊界框,找到居中顯示的坐標信息
int line_box_width; int line_box_height; line_box_width = bbox.xMax - bbox.xMin; //一行文字的寬度 line_box_height = bbox.yMax - bbox.yMin; //一行文字的高度 pen.x = (var.xres - line_box_width)/2 * 64; // var.xres:LCD總寬度 pen.y = (var.yres - line_box_height)/2 * 64;
5)通過坐標信息,將glyphs[]存的一行字形圖像顯示出來
for (n = 0; n < num_glyphs; n++) { //再次使用FT_Glyph_Transform(),更新glyphs[n].image里的坐標值 FT_Glyph_Transform(glyphs[n].image, 0, &pen); error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, 0,1); //轉化為點陣圖,1:轉換後並摧毀glyphs[n].image的內容 if( !error ) { FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image; draw_bitmap(&glyphs[n].image->bitmap, bit->left, var.yres - bit->top); //列印點陣圖 FT_Done_Glyph(glyphs[n].image ); //註銷一個Glyph } }