使用linux fb进行界面显示时,遇到文字(英文、中文、其他语言、符号等),需要先将这些字符转换成图像,再进行显示。freetype是一个比较通用的转换工具。
这里先给出一个简单的使用示例:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include FT_FREETYPE_H
/*****************************************************************************
*
* Macro definition
*
*****************************************************************************/
#define FU_IMAGE_MARGIN (2)
/*****************************************************************************
*
* Structure/Class Definition
*
*****************************************************************************/
/*****************************************************************************
*
* Data definition
*
*****************************************************************************/
static FT_Library library;
static FT_Face face;
static FT_GlyphSlot slot;
static FT_Matrix matrix; /* transformation matrix */
static FT_Vector pen; /* untransformed origin */
// 每英寸像素个数,根据480*800屏幕计算得到235
static uint32_t pixel_per_inch;
static uint32_t canvas_max_width;
static uint32_t canvas_max_height;
static uint8_t **canvas_buf;
//
static pthread_mutex_t text_trans_mutext;
/*****************************************************************************
*
* Function Entity
*
*****************************************************************************/
static void DrawBitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y)
{
FT_Int i;
FT_Int j;
FT_Int p;
FT_Int q;
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
//
q = (FT_Int)0 - (FT_Int)(bitmap->width);
for (j = y; j < y_max; j ++) {
q += bitmap->width;
for (i = x, p = 0; i < x_max; i ++, p ++) {
if (i < 0 || j < 0 || i >= canvas_max_width || j >= canvas_max_height) {
continue;
}
canvas_buf[j][i] |= bitmap->buffer[q + p];
}
}
}
static void GetBitmap(int image_width, int image_height, uint8_t *image, int *real_width, int *real_height) {
int x;
int y;
int none_zero_x_start = canvas_max_width;
int none_zero_x_end = 0;
int none_zero_y_start = canvas_max_height;
int none_zero_y_end = 0;
uint8_t *line;
//
*real_width = 0;
*real_height = 0;
/*
// 得到字符点阵的顶部y坐标
for (y = 0; y < canvas_max_height; ++ y) {
for (x = 0; x < canvas_max_width; ++ x) {
if (canvas_buf[y][x] != 0) {
none_zero_y_start = y;
break;
}
}
if (x < canvas_max_height) break;
}
//printf("none_zero_y_start = %d\n\r", none_zero_y_start);
// 得到字符点阵的底部y坐标
for (y = canvas_max_height - 1; y >= 0; -- y) {
for (x = 0; x < canvas_max_width; ++ x) {
if (canvas_buf[y][x] != 0) {
none_zero_y_end = y;
break;
}
}
if (x < canvas_max_height) break;
}
//printf("none_zero_y_end = %d\n\r", none_zero_y_end);
// 得到字符点阵的左边x坐标
for (x = 0; x < canvas_max_width; ++ x) {
for (y = 0; y < canvas_max_height; ++ y) {
if (canvas_buf[y][x] != 0) {
none_zero_x_start = x;
break;
}
}
if (y < canvas_max_height) break;
}
//printf("none_zero_x_start = %d\n\r", none_zero_x_start);
// 得到字符点阵的右边x坐标
for (x = canvas_max_width - 1; x >= 0 ; -- x) {
for (y = 0; y < canvas_max_height; ++ y) {
if (canvas_buf[y][x] != 0) {
none_zero_x_end = x;
break;
}
}
if (y < canvas_max_height) break;
}
//printf("none_zero_x_end = %d\n\r", none_zero_x_end);
*/
for (x = 0; x < canvas_max_width; ++ x) {
for (y = 0; y < canvas_max_height; ++ y) {
if (canvas_buf[y][x] != 0) {
if (none_zero_x_start > x) none_zero_x_start = x;
if (none_zero_x_end < x) none_zero_x_end = x;
if (none_zero_y_start > y) none_zero_y_start = y;
if (none_zero_y_end < y) none_zero_y_end = y;
}
}
}
//
(*real_width) = none_zero_x_end - none_zero_x_start + 1 + (FU_IMAGE_MARGIN << 1);
if ((*real_width) > image_width) (*real_width) = image_width;
*real_height = none_zero_y_end - none_zero_y_start + 1 + (FU_IMAGE_MARGIN << 1);
if (*real_height > image_height) *real_height = image_height;
//printf("real_height = %d, real_width = %d\n\r", *real_height, *real_width);
//
for (y = 0; y < *real_height && y < image_height; ++ y) {
line = image + (y + FU_IMAGE_MARGIN) * (*real_width);
//printf("image = %p, line = %p, y = %d\n\r", line, image, y);
for (x = 0; x < *real_width && x < (*real_width); ++ x) {
line[x + FU_IMAGE_MARGIN] = canvas_buf[y + none_zero_y_start][x + none_zero_x_start];
}
}
}
/*
static void show_image(void)
{
int i, j;
for (i = 0; i < canvas_max_height; i++)
{
printf("%d:", i);
for (j = 0; j < canvas_max_width; j++)
putchar(canvas_buf[i][j] == 0 ? '.'
: canvas_buf[i][j] < 128 ? '+'
: '*');
putchar('\n');
}
}
*/
int FreetypeInit(const char *font_file, uint32_t ppi, uint32_t max_width, uint32_t max_height) {
int err;
int i;
// initialize library
err = FT_Init_FreeType(&library);
if (err) {
printf("Init library failed\n\r");
return -1;
}
// create face object
err = FT_New_Face(library, font_file, 0, &face);
if (err == FT_Err_Unknown_File_Format) {
printf("the font is not supported\n\r");
return -1;
} else if (err) {
printf("the font file can't open\n\r");
return -1;
}
//
pixel_per_inch = ppi;
canvas_max_width = max_width;
canvas_max_height = max_height;
canvas_buf = (uint8_t **)malloc(max_height * sizeof(uint8_t *));
if (NULL == canvas_buf) {
printf("malloc canvas buf fail\n\r");
FreetypeExit();
return -1;
}
memset(canvas_buf, 0, max_height * sizeof(uint8_t *));
for (i = 0; i < max_height; ++ i) {
canvas_buf[i] = (uint8_t *)malloc(max_width);
if (NULL == canvas_buf[i]) {
printf("malloc canvas buf fail\n\r");
FreetypeExit();
return -1;
}
}
//
pthread_mutex_init(&text_trans_mutext, NULL);
return 0;
}
void FreetypeExit(void) {
int i;
FT_Done_Face(face);
FT_Done_FreeType(library);
if (canvas_buf) {
for (i = 0; i < canvas_max_height; ++ i) {
if (canvas_buf[i]) {
free(canvas_buf[i]);
canvas_buf[i] = 0;
}
}
free(canvas_buf);
canvas_buf = NULL;
}
pthread_mutex_destroy(&text_trans_mutext);
}
// 文字转换完成的点阵信息,连续的存储在缓存区域里,由返回的宽、高信息,说明如何从缓存区域读取点阵数据
// 返回的点阵信息,按如下存储,image[height][width]
//
// 0 - *real_width
//
// |
//
// * real_height
//
int GetCharacterStringBitmap(const wchar_t *char_str, int font_size, int image_width, int image_height,
uint8_t *image, int *real_width, int * real_height) {
int i;
//double angle = 0;
int rtn;
//
rtn = 0;
pthread_mutex_lock(&text_trans_mutext);
// set character size
//rtn = FT_Set_Char_Size(face, font_size * 64, 0, pixel_per_inch, 0);
rtn = FT_Set_Char_Size(face, font_size << 6, 0, pixel_per_inch, 0);
if (rtn != 0) {
printf("FT_Set_Char_Size error\n");
goto ERR_OUT;
}
// cmap selection
//FT_Select_Charmap(face, FT_ENCODING_GB2312);
//
for (i = 0; i < canvas_max_height; ++ i) {
memset(canvas_buf[i], 0, canvas_max_width);
}
//
slot = face->glyph;
// set up matrix
/*
matrix.xx = (cos(angle) * 0x10000L);
matrix.xy = (-sin(angle) * 0x10000L);
matrix.yx = (sin(angle) * 0x10000L);
matrix.yy = (cos(angle) * 0x10000L);
*/
/*
*/
matrix.xx = (FT_Fixed)(0x10000L);//(cos(angle) * 0x10000L);
matrix.xy = (FT_Fixed)(0L);//(-sin(angle) * 0x10000L);
matrix.yx = (FT_Fixed)(0L);//(sin(angle) * 0x10000L);
matrix.yy = (FT_Fixed)(0x10000L);//(cos(angle) * 0x10000L);
//
//pen.x = 0 * 64;
//pen.y = (canvas_max_height / 2) * 64;
pen.x = 0;//0 * 64;
pen.y = canvas_max_height << 5;//(canvas_max_height / 2) * 64;
for (i = 0; char_str[i] != '\0'; ++ i) {
FT_Set_Transform(face, &matrix, &pen);
rtn = FT_Load_Char(face, char_str[i], FT_LOAD_RENDER);
if (rtn != 0) {
printf("FT_load_char error, i = %d\n", i);
goto ERR_OUT;
}
DrawBitmap(&slot->bitmap,
slot->bitmap_left,
canvas_max_height - slot->bitmap_top);
// increment pen position
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
//show_image();
GetBitmap(image_width, image_height, image, real_width, real_height);
rtn = 0;
ERR_OUT:
pthread_mutex_unlock(&text_trans_mutext);
return rtn;
}
下面这个例子,是利用前面封装的函数,实现多行文字转换成图像。里面调用的函数,都在本博客的tslib、freetype相关文章中给出过:
#include
#include
#include
#include
#include
#include
#include
#include
/*****************************************************************************
*
* Macro definition
*
*****************************************************************************/
#define GR_MAX_TEXT_LINE (8)
// position
#define GB_UI_ALIGN_VERTICAL_MASK (0x0f)
#define GB_UI_ALIGN_VERTICAL_TOP (1 << 0)
#define GB_UI_ALIGN_VERTICAL_BOTTOM (1 << 1)
#define GB_UI_ALIGN_VERTICAL_CENTER (GB_UI_ALIGN_VERTICAL_TOP | GB_UI_ALIGN_VERTICAL_BOTTOM)
#define GB_UI_ALIGN_HORIZONTAL_MASK (0xf0)
#define GB_UI_ALIGN_HORIZONTAL_LEFT (1 << 4)
#define GB_UI_ALIGN_HORIZONTAL_RIGHT (1 << 5)
#define GB_UI_ALIGN_HORIZONTAL_CENTER (GB_UI_ALIGN_HORIZONTAL_LEFT | GB_UI_ALIGN_HORIZONTAL_RIGHT)
/*****************************************************************************
*
* Structure/Class Definition
*
*****************************************************************************/
/*****************************************************************************
*
* Data definition
*
*****************************************************************************/
/*****************************************************************************
*
* Function Entity
*
*****************************************************************************/
//
int GuiText2Image(const wchar_t *char_str, int font_size, uint32_t row_spacing, uint32_t text_align, int width,
uint8_t **text_image, int32_t *text_image_width, int32_t *text_image_height) {
wchar_t *char_tmp;
wchar_t *char_buf[GR_MAX_TEXT_LINE];
uint8_t *image_buf[GR_MAX_TEXT_LINE];
int image_width[GR_MAX_TEXT_LINE];
int image_height[GR_MAX_TEXT_LINE];
uint8_t *image_line;
int i;
int j;
int l;
int line;
int line_num;
int pre_zero_num;
int suf_zero_num;
int max_width;
int final_height;
int wchar_len;
int rtn;
rtn = -1;
wchar_len = wcslen(char_str);
//
memset(char_buf, 0, GR_MAX_TEXT_LINE * sizeof(wchar_t *));
memset(image_buf, 0, GR_MAX_TEXT_LINE * sizeof(uint8_t *));
// 申请缓存区
for (i = 0; i < GR_MAX_TEXT_LINE; ++ i) {
//
char_buf[i] = (wchar_t *)malloc((wchar_len + 4) * sizeof(wchar_t));
if (char_buf[i] == NULL) {
goto ERR_OUT;
}
memset(char_buf[i], 0, (wchar_len + 4) * sizeof(wchar_t));
//
image_buf[i] = (uint8_t *)malloc(width * width);
if (image_buf[i] == NULL) {
goto ERR_OUT;
}
memset(image_buf[i], 0, width * width);
}
//
*text_image = (uint8_t *)malloc(width * width);
if (NULL == *text_image) {
goto ERR_OUT;
}
// 根据换行,拆分成多个字符串,每行一个字符串
for (char_tmp = (wchar_t *)char_str, line_num = 0; *char_tmp != '\0' && line_num < GR_MAX_TEXT_LINE; ++ line_num) {
// 跳过前面的换行符
while (*char_tmp == '\n' || *char_tmp == '\r') {
char_tmp ++;
}
for (i = 0; *char_tmp != '\n' && *char_tmp != '\r' && *char_tmp != '\0'; ++ i, ++ char_tmp) {
char_buf[line_num][i] = *char_tmp;
}
char_buf[line_num][i] = '\0';
}
if (0 == line_num) {
goto ERR_OUT;
}
// 每行转换成位图
for (i = 0, max_width = 0, final_height = 0; i < line_num; ++ i) {
rtn = GetCharacterStringBitmap(char_buf[i], font_size, width, width,
image_buf[i], &(image_width[i]), &(image_height[i]));
if (image_width[i] > max_width) {
max_width = image_width[i];
}
final_height += image_height[i];
}
// 加上行距
final_height += ((line_num - 1) * row_spacing);
// 按对齐方式,合并每行的位图
// 高度,每行的高度相加
// 宽度,找到最宽的。然后按对齐方式,拷贝每行的位图到最终buf
for (line = 0, l = 0; line < line_num; ++ line) {
switch (text_align & GB_UI_ALIGN_HORIZONTAL_MASK)
{
case GB_UI_ALIGN_HORIZONTAL_LEFT:
pre_zero_num = 0;
suf_zero_num = max_width - image_width[line];
break;
case GB_UI_ALIGN_HORIZONTAL_RIGHT:
pre_zero_num = max_width - image_width[line];
suf_zero_num = 0;
break;
case GB_UI_ALIGN_HORIZONTAL_CENTER:
pre_zero_num = (max_width - image_width[line]) / 2;
suf_zero_num = max_width - image_width[line] - pre_zero_num;
break;
default:
pre_zero_num = 0;
suf_zero_num = max_width - image_width[line];
break;
}
// 开始拷贝数据
for (j = 0; j < image_height[line]; ++ j) {
image_line = image_buf[line] + image_width[line] * j;
// 根据分析结果,补每行前面的0
for (i = 0; i < pre_zero_num; ++ i) {
(*text_image)[l ++] = 0;
}
// 拷贝数据
for (i = 0; i < image_width[line]; ++ i) {
(*text_image)[l ++] = image_line[i];
}
// 根据分析结果,补每行后面的0
for (i = 0; i < suf_zero_num; ++ i) {
(*text_image)[l ++] = 0;
}
}
// 每2行间增加行距,最后一行下面不增加行距
if ((line + 1) < line_num) {
for (j = 0; j < (int)row_spacing; ++ j) {
for (i = 0; i < max_width; ++ i) {
(*text_image)[l ++] = 0;
}
}
}
}
*text_image_width = max_width;
*text_image_height = final_height;
rtn = 0;
ERR_OUT:
for (i = 0; i < GR_MAX_TEXT_LINE; i ++) {
if (char_buf[i]) {
free(char_buf[i]);
}
if(image_buf[i]) {
free(image_buf[i]);
}
}
return rtn;
}