嵌入式应用-详解移植并使用freetype显示文字

news2024/11/15 17:41:47

目录

前言 

1. freetype和相关概念简介

2.freetype显示文字流程和主要函数

2.1 包含头文件及API头文件:ft2build.h

2.2 初始化: FT_InitFreetype

2.3 加载(打开)字体Face: FT_New_Face

2.4 设置字体大小:FT_Set_Char_Size或FT_Set_Pixel_Size

2.4.5 (可选)选择charmap: FT_Select_Charmap

2.5 得到位图FT_Load_Char

2.6 显示单个文字


前言 

学过单片机的朋友都会用点阵来显示一个字符,无非就是把点阵里的值取出来一个个在屏幕上显示,修改字符大小需重新定义点阵,或者经过运算,freetype是一个矢量字体引擎,可以显示ttf字体文件中的字符。点阵和矢量字体并无优劣,点阵在资源少,显示字符少的情况下更加适合,矢量字体在资源多,显示字符多,显示要求变化大的情况下更加好。

移植freetype详见Linux安装zlib、libpng、freetype给交叉编译工具链使用

1. freetype和相关概念简介

freetype

一个免费的、可移植的字体引擎开源库,提供统一的接口来访问多种字体格式文字。
官网:The FreeType Project

矢量字体(Vector font)

矢量字体又叫Outline font,即轮廓字体。

矢量字体显示有3步:
1)确定关键点;2)使用数学曲线(贝塞尔曲线)连接关键点;3)填充闭合曲线内部空间。

字体的关键点

以字母“A”为例,它的关键点如下图黄色点所示:

然后用数学曲线(如贝塞尔曲线),将这些关键点连接起来:

填充封闭闭合区间,就显示出字母“A”。如下图所示:

字符编码

在计算机里一切都是用数字来表示,字符编码本质上就是解决一个字符用什么数字来表示的问题。比如字符 A,用 0x41 来表示它。我们常见的ASCII码有128个字符,用一个字节,8位表示。

ANSI编码

ANSI不是一种特定的编码

ANSI 是 ASCII 的扩展,向下包含 ASCII。对于 ASCII 字符仍以一个字节来表示,对于非 ASCII 字符则使用 两个字节来表示。并没有固定的 ASNI 编码,它跟“本地化”(locale)密切相关。比如在中国大陆地区, ANSI 的默认编码是 GB2312;在港澳台地区默认编码是 BIG5。以数值“ 0xd0d6”为例,对于 GB2312 编码它表示“中”;对于 BIG5 编码它表示“ 笢”。所以对于 ANSI 编码的 TXT 文件,如果你打开它发现乱码,那么还得再次细分它的具体编码。

UNICODE字符集

在 ANSI 标准中,很多种文字都有自己的编码标准,汉字简体字有 GB2312、繁体字有 BIG5,这难免同一个数值对应不同字符。比如数值“ 0xd0d6”,对于GB2312 编码它表示“中”;对于 BIG5 编码它表示“ 笢”。这造成了使用 ANSI 编码保存的文件,不适合跨地区交流。

UNICODE 字符集(也可以叫编码,实际上叫字符集更加合适)就是解决这类问题:对于地球上任意一个字符,都给它一个唯一的数值。

UNICODE 仍然向下兼容 ASCII,但是对于其他字符会有对应的数值,比如对于“中”、“ 笢”,它们的数值分别是: 0x4e2d、 0x7b22UNICODE 中的数值范围是 0x0000 至 0x10FFFF。

UTF-8编码

Unicode 统一了所有字符的编码,是一个 Character Set,也就是字符集,字符集只是给所有的字符一个唯一编号,但是却没有规定如何存储,一个编号为 65 的字符,只需要一个字节就可以存下,但是编号 40657 的字符需要两个字节的空间才可以装下,而更靠后的字符可能会需要三个甚至四个字节的空间。

这时,用什么规则存储 Unicode 字符就成了关键,我们可以规定,一个字符使用四个字节存储,也就是 32 位,这样就能涵盖现有 Unicode 包含的所有字符,这种编码方式叫做 UTF-32(UTF 是 UCS Transformation Format 的缩写)。UTF-32 的规则虽然简单,但是缺陷也很明显,假设使用 UTF-32 和 ASCII 分别对一个只有西文字母的文档编码,前者需要花费的空间是后者的四倍(ASCII 每个字符只需要一个字节存储)。

在存储和网络传输中,通常使用更为节省空间的变长编码方式 UTF-8,UTF-8 代表 8 位一组表示 Unicode 字符的格式,使用 1 - 4 个字节来表示字符。

wchar_t

char型的常见编码方式是ASCII,ASCII编码是一种基于8位二进制数的字符编码算法,能表示256种可能的字符。

wchar_t的出现,是出于程序兼容多语言的需求,因为在很多语言中,字符的数量远远大于256。因此wchar_t出现了,wchar_t全称是wide character type,也就是宽字符。

wchar_t *a=“哈”

哈字的UNICODE值就被保存在a指向的地址了。

我们编写 C 程序时,输入的字符本身(如上面的哈字)可以使用 ANSI 编码,或是 UTF-8 编码;在编译程序时,可以使用以下的选项告诉编译器:

-finput-charset=GB2312
-finput-charset=UTF-8

如果不指定“ -finput-charset”, GCC 就会默认 C 程序的编码方式为 UTF-8,即使你是以 ANSI 格式保存,也会被当作 UTF-8 来对待。对于编译出来的可执行程序,可以指定它里面的字符是以什么方式编码,可以使用以下的选项编译器:

-fexec-charset=GB2312
-fexec-charset=UTF-8

2.freetype显示文字流程和主要函数

2.1 包含头文件及API头文件:ft2build.h

#include <ft2build.h>
#include FT_FREETYPE_H // 基础的FreeType 2 API
#include FT_GLYPH_H // 管理Glyph Images

2.2 初始化: FT_InitFreetype

初始化FreeType库

FT_Library    library;
error = FT_Init_FreeType( &library );              /* initialize library */

2.3 加载(打开)字体Face: FT_New_Face

face描述了一个给定(印刷)字体和样式

FT_Face       face;   
error = FT_New_Face( library, 字体文件路径, 0, &face ); /* create face object */

2.4 设置字体大小:FT_Set_Char_Size或FT_Set_Pixel_Size

FT_Set_Char_Size:设置字符尺寸(nominal size in points,1pt=0.376mm);

这个函数是设置物理上的大小,freetype会根据设备分辨率调整像素,一般不怎么用这个

FT_Set_Pixel_Size:设置字符尺寸(nominal size (in pixels),单位是像素点);

这个函数是设置像素大小,一半用这个比较多。

2.4.5 (可选)选择charmap: FT_Select_Charmap

一个字体可能可以支持不同的编码,支持哪些编码的信息会被放在字体文件的charmaps中。face对象创建时,默认从字体文件中查找Unicode charmap,也就是如果使用Unicode就不需要指定charmap了。如果想要改变,可以调用该函数。

当前charmap可以通过face->charmap来访问。

我们这里不需要设置。

2.5 得到位图FT_Load_Char

FT_Load_Char(face, charcode, FT_LOAD_RENDER),可以直接得到glyph对应的bitmap。

wchar_t *chinese_str = L"哈";
error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER );

可以看到,传入的是2.3中定义的FT_Face  face;。生成一个字符的点阵位图时,位图保存在哪里?

FT_Face结构体内部有一个结构体成员, FT_GlyphSlot      glyph

FT_GlyphSlot结构体内部有一个成员,FT_Bitmap         bitmap;

生成第2个字符位图时,也会保存在这,会覆盖第1个字符的位图。 

我们往往自己定义一个FT_GlyphSlot结构体slot,在加载字体后就将face->glyph传给他。

FT_GlyphSlot  slot;

slot = face->glyph;

这些结构体都是指针,所以其实就是赋值了地址face->glyph->bitmap发生了变化,slot->bitmap也会变化。

FT_Bitmap 结构体:

  typedef struct  FT_Bitmap_
  {
    int             rows;
    int             width;
    int             pitch;
    unsigned char*  buffer;
    short           num_grays;
    char            pixel_mode;
    char            palette_mode;
    void*           palette;

  } FT_Bitmap

重要的成员是rows、width,buffer,含义如下图,其他成员作用可以自己搜一下。 

由于位图中每一个像素用一个字节来表示,为8位灰度图。

参考:

嵌入式Linux入门-Framebuffer应用编程在Linux系统下画个点

 到这应该就知道怎么在屏幕上显示了吧。

2.6 显示单个文字

draw_bitmap( 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;

	//printf("x = %d, y = %d\n", x, y);

	for ( j = y, q = 0; j < y_max; j++, q++ )
	{
		for ( i = x, p = 0; i < x_max; i++, p++ )
		{
			if ( i < 0      || j < 0       ||
				i >= var.xres || j >= var.yres )
			continue;

			//image[j][i] |= bitmap->buffer[q * bitmap->width + p];
			lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);
		}
	}
}

参数里的x,y是在显示的位置的坐标。

下面函数为在lcd上画一个点的函数。

lcd_put_pixel(int x, int y, unsigned int color)

显示一行文字你可以用位图,一个个显示字,但是并不完美,更好的方式可以参考【硬核】韦东山:使用freetype显示一行文字 - 知乎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sqrt函数模拟实现的两种方法

起因:在leetcode刷题时&#xff0c;有一道题目考察了有关sqrt的原理的题目&#xff0c;当时就去查了网上的文章&#xff0c;结果发现&#xff0c;一开始的时候看的很懵&#xff0c;最后也是搞定了两种方法&#xff0c;今天我就以最简单的方式写下这两种方式的思路讲解&#xff…

Python批量获取高校基本信息

文章目录前言一、需求二、分析三、处理四、运行效果前言 为了更好的掌握数据处理的能力&#xff0c;因而开启Python网络爬虫系列小项目文章。 小项目小需求驱动&#xff0c;每篇文章会使用两种以上的方式&#xff08;Xpath、Bs4、PyQuery、正则等&#xff09;获取想要的数据。…

T31快启图像效果优化

T31快启图像效果优化 liwen01 20220821 (一)基础方法及概念 参考文档 《Ingenic_Zeratul_T31_快起效果调试说明_20200927_CN》 (1)起始EV参数 IPC 每次启动都是冷启动&#xff0c;画面有一个暗变亮的过程&#xff0c;称作为AE收敛过程(自动曝光收敛过程)。 为了加快AE收…

LeetCode50天刷题计划第二季(Day 23 — 重排链表(16.20- 17.00)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、题目重排链表示例提示二、思路三、代码前言 链表基础题加一 一、题目 重排链表 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff…

基于粒子群优化算法的时间调制非线性频偏FDA(Matlab代码实现)

&#x1f389;&#x1f389;&#x1f389;&#x1f389;欢迎您的到来&#x1f60a;&#x1f60a;&#x1f60a; &#x1f96c;博客主页&#xff1a;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 &#x1f4dd;床头铭&#xff1a;将来的我一定会感谢…

ARM64下构建 UEFI 模块

构建Application工程目录 mkdir edk2/ShellPkg/Application/ShellHello 目录内容如下: 编写 ShellHello.c /* edk2/ShellPkg/Application/ShellHello/ShellHello.c*/ #include <Uefi.h> #include <Library/UefiLib.h> #include <Library/DebugLib.h> #i…

上手之Python之异常

什么是异常 当检测到一个错误时&#xff0c;Python解释器就无法继续执行了&#xff0c;反而出现了一些错误的提示&#xff0c;这就是所谓的“异常”, 也就是我们常说的BUG bug单词的诞生 早期计算机采用大量继电器工作&#xff0c;马克二型计算机就是这样的。 1945年9月9日&…

【JVM技术专题】 深入学习JIT编译器实现机制「 原理篇」

前提概要 解释器 Java程序最初是通过解释器(Interpreter)进行解释执行的&#xff0c;当虚拟机发现某个方法或代码块的运行特别频繁的时候&#xff0c;就会把这些代码认定为“热点代码”&#xff08;hotspot code&#xff09;。正因为如此&#xff0c;我们的hotspot的虚拟机就是…

将matlab数据导入到Python中使用

相信不少小伙伴都遇到过和我一样的问题&#xff0c;就是在尝试使用scipy.io.loadmat将matlab类型的数据导入python中的时候遇到如下错误提示。 import scipy as sc# 设定需要导入的matlab数据目录 path_TE00 r"D:\Window自带文件夹\桌面\PIC Design\Lumerical\Tutorials…

Apollo GraphQL

一、Apollo GraphQL介绍 Apollo 是一个开源的 GraphQL 开发平台&#xff0c; 提供了符合 GraphQL 规范的服务端和客户端实现。使用 Apollo 可以帮助我们更方便快捷的开发使用 GraphQL。 ● 官网&#xff1a;https://www.apollographql.com/ ● GitHub 相关开源仓库&#xff1a…

Vite+Vue+Electron环境搭建

因为electron可以直接加载html文件&#xff0c;也可以直接加载url链接&#xff0c;所以&#xff0c;我们可以在调试过程中使用url地址&#xff0c;来动态显示我们的改变过程。 electron简单来说就是对html的一种封装&#xff0c;所以我们先来搭建vue的开发环境&#xff0c;这里…

LQ0135 左孩子右兄弟【DFS+二叉树】

题目来源&#xff1a;蓝桥杯2021初赛 C A组H题 题目描述 对于一棵多叉树&#xff0c;我们可以通过“左孩子右兄弟” 表示法&#xff0c;将其转化成一棵二叉树。 如果我们认为每个结点的子结点是无序的&#xff0c;那么得到的二叉树可能不唯一。 换句话说&#xff0c;每个结点可…

并发编程之ForkJoin框架

什么是 Fork/Join 框架 Fork/Join 是从 java7 开始提供的并行执行任务的框架&#xff0c;是一个把大任务分割成若干个小任务&#xff0c;最终汇总每个小任务的结果&#xff0c;得到大任务结果的框架. 如下图&#xff1a; Fork/Join 的特性 ForJoinPool 不是为了替代 Execu…

毕业仅1年,干Python赚了50W!网友:不是吹的

前言 惊讶 ​Py现状&#xff1a;Python职位月薪5W起&#xff1f; 其他程序员&#xff1a;心态塌了&#xff01; 秒杀各行业薪资榜单&#xff0c;拿下编程语言排行榜的Python&#xff0c;工资真的如网上说的开挂了吗&#xff1f;有人在网上发现这样的一条评论信息&#xff1a…

公众号网课查题接口题库

公众号网课查题接口题库 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&#xf…

Navicat 现已支持 OceanBase 企业版

近期&#xff0c;PremiumSoft CyberTech Limited 公司发布了 Navicat 16.1.3 版本&#xff0c;正式支持蚂蚁集团旗下的 OceanBase 企业版&#xff08;MySQL 兼容模式&#xff09;。此次合作旨在帮助用户通过 Navcicat 进行 OceanBase 企业版的数据库开发及管理&#xff0c;更大…

说说 Redis 事务

Redis 事务简介# Redis 只是提供了简单的事务功能。其本质是一组命令的集合&#xff0c;事务支持一次执行多个命令&#xff0c;在事务执行过程中&#xff0c;会顺序执行队列中的命令&#xff0c;其他客户端提交的命令请求不会插入到本事务执行命令序列中。命令的执行过程是顺序…

MPLS综合实验

目录 实验要求 划分IP地址 首先对MPLSVPN骨干网络进行配置 首先配置IP地址 启动IGP协议 激活MPLS和LDP VRF空间的创建 将接口划入到VRF空间中 R1和R5通过静态路由在CE和PE上配置 建立MP-BGP 对站点R1和R5进行配置 首先把IP给配置好 在VRF空间中发布路由信息 对站点…

2000-2020上市公司全要素生产率LP方法含原始数据和Stata代码

1、时间&#xff1a;2000-2020年 2、指标包括&#xff1a;stkcd、year、证券代码、固定资产净额、营业总收入、营业收入、营业成本、销售费用、管理费用、财务费用、支付给职工以及为职工支付的现金、员工人数、折旧摊销、行业代码、上市日期、AB股交叉码、退市日期、年末是否…

windows下用Java跑通spark官方文档的quick-start

这里写自定义目录标题前置环境官方示例三个小坑maven文件引用不明确未传递master url前置环境 见上一篇&#xff1a;https://blog.csdn.net/shuzip/article/details/115606522 官方示例 https://spark.apache.org/docs/3.1.1/quick-start.html /* SimpleApp.java */ import…