利用freetype生成显示数据的简单示例

使用linux fb进行界面显示时,遇到文字(英文、中文、其他语言、符号等),需要先将这些字符转换成图像,再进行显示。freetype是一个比较通用的转换工具。

这里先给出一个简单的使用示例:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <pthread.h>

#include <ft2build.h>
#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <time.h> 
#include <sys/time.h>
#include <sys/sysinfo.h>



/*****************************************************************************
 *
 * 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;
}

Freetype是一个开源的字体渲染库,可以用于生成位图表。位图表是指将字体信息渲染成位图的表格,可以用于显示特定字体的文本或图像。 使用Freetype生成位图表的过程大致分为以下几步: 1. 首先,需要加载字体文件。这可以通过提供字体文件的路径以及指定字体的大小和其他参数来实现。Freetype将字体文件加载到内存中,以供后续的操作使用。 2. 加载字体文件后,需要创建一个字体对象。字体对象是对字体文件的封装,包含了字体的属性和字符集等信息。可以根据需要创建一个或多个字体对象。 3. 接下来,可以选择一个字符,例如"A"或"字"作为待渲染的字符。可以使用Freetype提供的接口获取字符对应的轮廓信息,也就是字符的笔画路径。 4. 获得字符的轮廓信息后,可以设置位图的大小和像素格式等参数。然后,使用Freetype提供的接口将字符的轮廓信息转换为位图,即进行字体渲染。 5. 最后,可以保存生成的位图表,或将其用于显示文本或图像。可以根据实际需求选择合适的保存或显示方式。 总而言之,使用Freetype生成位图表可以通过加载字体文件、创建字体对象、获取字符轮廓信息、进行字体渲染以及保存或显示位图等步骤来实现。这是一种常见的字体渲染方式,可以用于各种需要显示特定字体文本或图像的应用程序中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值