Linux应用开发:嵌入式Linux下矢量字体运用

简介: Linux应用开发:嵌入式Linux下矢量字体运用

一、freetype简介

      FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,可以非常方便我们开发字体显示相关的程序功能。它支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。关于freetype的详细信息可以参考freetype的官方网站:https://www.freetype.org/来获取更多相关的信息。


     CSDN下载地址: https://download.csdn.net/download/tech_pro/9873843

image.png

二、下载源码编译安装

2.1 编译freetype

image.png

image.png

image.png

2.2 部署编译环境和运行环境

image.png

2.3 windows电脑上的矢量字体存放目录

image.png

2.4 示例代码

1.#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <math.h>
#include <wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_STROKER_H
#define LCD_DEVICE "/dev/fb0"
int lcd_fd;
struct fb_var_screeninfo vinfo;//可变参数
struct fb_fix_screeninfo finfo; //固定参数
unsigned char *lcd_mem=NULL; //LCD首地址
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
/*定义一个结构体存放矢量字体的配置*/
struct FREE_TYPE_CONFIG
{
  FT_Library    library;
  FT_Face       face;
  FT_GlyphSlot  slot;
  FT_Vector     pen;                    /* untransformed origin  */
  FT_Error      error;
  FT_BBox  bbox;
  FT_Glyph  glyph;
};
struct FREE_TYPE_CONFIG FreeTypeConfig;
/*
函数功能: 封装画点函数
函数参数: u32 x,u32 y,u16 c
*/
void LCD_DrawPoint(u32 x,u32 y,u32 c)
{
   u32 *lcd_p=(u32*)(lcd_mem+vinfo.xres*vinfo.bits_per_pixel/8*y+x*vinfo.bits_per_pixel/8);
   *lcd_p=c;
}
/*
函数功能: 封装读点函数
函数参数: u32 x,u32 y,u16 c
*/
u32 LCD_ReadPoint(u32 x,u32 y)
{
   u32 *lcd_p=(u32*)(lcd_mem+vinfo.xres*vinfo.bits_per_pixel/8*y+x*vinfo.bits_per_pixel/8);
   return *lcd_p;
}
/*  LCD显示矢量字体的位图信息
 *    bitmap : 要显示的字体的矢量位图
 *    x : 显示的x坐标
 *    y : 显示的y坐标
 */
void LCD_DrawBitmap(FT_Bitmap* bitmap,FT_Int x,FT_Int y)
{
    FT_Int i,j,p,q;
    FT_Int x_max=x+bitmap->width;
    FT_Int y_max=y+bitmap->rows;
  /* 将位图信息循环打印到屏幕上 */
  for(i=x,p=0;i<x_max;i++,p++)
  {
    for(j=y,q=0;j<y_max;j++,q++)
    {
      if((i>x_max)||(j>y_max)||(i<0)||(j<0))continue;
      if(bitmap->buffer[q*bitmap->width+p]!=0)
      {
        LCD_DrawPoint(i, j,0xFF0033);
      }
      else
      {
        LCD_DrawPoint(i, j,0xFFFFFF);
      }
    }
  }
}
/*
函数功能: 初始化FreeType配置
*/
int InitConfig_FreeType(char *font_file)
{
  FT_Error      error;
  /*1. 初始化freetype库*/
  error=FT_Init_FreeType(&FreeTypeConfig.library);
  if(error)
  {
    printf("freetype字体库初始化失败.\n");
    return -1;
  }
  /*2. 打开加载的字体文件*/
  error=FT_New_Face(FreeTypeConfig.library,font_file,0,&FreeTypeConfig.face);
    if(error)
    {
    printf("矢量字体文件加载失败.\n");
    return -2;
  }
  return 0;
}
/*
函数功能: 释放FreeType配置
*/
void FreeType_Config(void)
{
  FT_Done_Face(FreeTypeConfig.face);
    FT_Done_FreeType(FreeTypeConfig.library);
}
/*
函数功能: 在LCD屏显示一串文本数据
函数参数:
  u32 x   坐标位置
  u32 y   坐标位置
  u32 size 字体大小
  wchar_t *text 显示的文本数据
*/
int LCD_DrawText(u32 x,u32 y,u32 size,wchar_t *text)
{
  FT_Error      error;
  int i = 0;
  int bbox_height_min = 10000;
  int bbox_height_max = 0;
  /*3. 设置字符的像素的大小为size*size*/
  error=FT_Set_Pixel_Sizes(FreeTypeConfig.face,size,0);
  if(error)
  {
    printf("字符的像素大小设置失败.\n");
    return -1;
  }
  /*4. 设置字体文件的轮廓的插槽*/
  FreeTypeConfig.slot=FreeTypeConfig.face->glyph;
  /* 设置坐标为原点坐标
   * 将LCD坐标转换成笛卡尔坐标
   * 单位是 1/64 Point
   */
  FreeTypeConfig.pen.x=x*64;
    FreeTypeConfig.pen.y=(vinfo.yres-size-y)*64;
  /*5. 循环的将文字显示出来*/
  for(i=0;i<wcslen(text);i++)
  {
    FT_Set_Transform(FreeTypeConfig.face,0,&FreeTypeConfig.pen);  //设置字体的起始坐标位置
    /*装载字符编码,填充face的glyph slot成员*/
    error=FT_Load_Char(FreeTypeConfig.face,text[i],FT_LOAD_RENDER);
    if(error)
    {
      printf("装载字符编码失败.\n");
      return -1;
    }
    /*通过glyph slot来获得glyph*/
    FT_Get_Glyph(FreeTypeConfig.slot,&FreeTypeConfig.glyph);
    /*通过glyph来获得cbox*/
    FT_Glyph_Get_CBox(FreeTypeConfig.glyph,FT_GLYPH_BBOX_TRUNCATE,&FreeTypeConfig.bbox);
    /*获得字体高度的最大值和最小值*/
    if(bbox_height_min>FreeTypeConfig.bbox.yMin)bbox_height_min=FreeTypeConfig.bbox.yMin;
    if(bbox_height_max<FreeTypeConfig.bbox.yMax)bbox_height_max=FreeTypeConfig.bbox.yMax;
    /*画点,把笛卡尔坐标转换成LCD坐标*/
    LCD_DrawBitmap(&FreeTypeConfig.slot->bitmap,
            FreeTypeConfig.slot->bitmap_left,
            vinfo.yres-FreeTypeConfig.slot->bitmap_top);
    if(FreeTypeConfig.slot->bitmap_left+size*2>vinfo.xres)
    {
      FreeTypeConfig.pen.x=0; //更新X坐标位置
      FreeTypeConfig.pen.y=(vinfo.yres-size-y-size)*64; //更新Y坐标位置
    }
    else
    {
      /* 更新原点坐标位置 */
      FreeTypeConfig.pen.x+=FreeTypeConfig.slot->advance.x;
      FreeTypeConfig.pen.y+=FreeTypeConfig.slot->advance.y;
    }
  }
  return 0;
}
int main(int argc,char **argv)
{ 
  if(argc!=2)
  {
    printf("./app <xxx.ttf 字体文件>\n");
    return 0;
  }
  /*1. 打开设备文件*/
  lcd_fd=open(LCD_DEVICE,O_RDWR);
  if(lcd_fd<0)
  {
    printf("%s open error.\n",LCD_DEVICE);
    return 0;
  }
  /*2. 获取可变参数*/
  ioctl(lcd_fd,FBIOGET_VSCREENINFO,&vinfo);
  printf("x=%d,y=%d,pixel=%d\n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel);
  /*3. 获取固定参数*/
  ioctl(lcd_fd,FBIOGET_FSCREENINFO,&finfo);
  printf("smem_len=%d\n",finfo.smem_len);
  printf("line_length=%d\n",finfo.line_length);
  /*4. 映射LCD地址*/
  lcd_mem=mmap(NULL,finfo.smem_len,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
  if(lcd_mem==NULL)
  {
    printf("映射LCD地址失败.\n");
    return -1;
  }
  memset(lcd_mem,0xFFFFFF,finfo.smem_len);
  /*5. 初始化配置FreeType*/
  InitConfig_FreeType(argv[1]);
  /*6. 在指定位置显示文本*/
  /*
  wcslen() 函数用于计算宽字符的个数,支持区分中文和英文字符,文本需要在UTF-8编码下。
  定义宽字符串示例:
  wchar_t *wp=L"1234567890中国"; //12
  printf("wcslen p:%d\n",wcslen(wp)); 返回值是12
  */
  LCD_DrawText(50,56*0,56,L"北京万邦易嵌科技有限公司");
  LCD_DrawText(150,56*1,56,L"www.wanbangee.com");
  LCD_DrawText(200,56*3,48,L"FreeType矢量字体");
  LCD_DrawText(150,56*5,80,L"Linux驱动开发");
  /*7. 释放FreeType配置*/
  FreeType_Config();
  close(lcd_fd);
  return 0;
}

2.5 编译源代码的Makefile示例

all:
  arm-linux-gcc video_app.c -I /home/wbyq/work/freetype-2.4.10/_install/include -I /home/wbyq/work/freetype-2.4.10/_install/include/freetype2 -o app -lfreetype -ljpeg
  cp app /home/wbyq/work/rootfs/code
  rm app -f

2.6 运行程序效果示例

image.png

image.png



目录
相关文章
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
703 1
|
JSON 机器人 Linux
推荐一款嵌入式Linux开源框架与封装-cpp-tbox
推荐一款嵌入式Linux开源框架与封装-cpp-tbox
872 3
|
XML 缓存 Linux
在Linux环境下解决Visual Studio Code字体显示异常和字体替换方法。
解决Linux下VS Code字体显示异常,需要对Linux字体渲染机制有所理解,并对VS Code的配置选项进行合理设置。替换字体时则要通过系统字体配置或VS Code设置来完成。通过上述方法,可以有效地解决字体显示问题,从而提升代码编辑的视觉体验。
2048 21
|
网络协议 算法 Linux
【嵌入式软件工程师面经】Linux网络编程Socket
【嵌入式软件工程师面经】Linux网络编程Socket
871 1
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
1079 15
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
930 13
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
1363 3
|
Ubuntu 算法 Linux
嵌入式Linux的学习误区
**嵌入式Linux学习误区摘要** 1. **过度聚焦桌面Linux** - 许多学习者误将大量时间用于精通桌面Linux系统(如RedHat、Fedora、Ubuntu),认为这是嵌入式Linux开发的基石。 - 实际上,桌面Linux仅作为开发工具和环境,目标不应是成为Linux服务器专家,而应专注于嵌入式开发工具和流程。 2. **盲目阅读Linux内核源码** - 初学者在不了解Linux基本知识时试图直接研读内核源码,这往往导致困惑和挫败感。 - 在具备一定嵌入式Linux开发经验后再有针对性地阅读源码,才能有效提升技能。
376 4
|
物联网 Linux 芯片
学习嵌入式是选择单片机还是Linux?
单片机通常指的是一种集成了处理器、存储器和各种外设接口的微控制器芯片,常见的有STC、51系列、AVR、ARM Cortex-M等。单片机具有低成本、低功耗、实时性强等特点,适用于对资源要求较低、功耗要求较低、实时性要求较高的嵌入式系统。学习单片机开发可以让您深入了解嵌入式系统的底层原理和硬件编程,对于对嵌入式系统底层开发感兴趣的人来说,是一个很好的选择。
631 4
|
消息中间件 安全 Java
【嵌入式软件工程师面经】Linux多进程与多线程
【嵌入式软件工程师面经】Linux多进程与多线程
535 1