FreeType和HarfBuzz入门示例

最近在了解字体渲染的一些东西,其中不可避免的需要到这两个库。现在写个入门示例记录一下。

一、FreeType和HarfBuzz介绍

1.1 FreeType

        FreeType 是一个开源的字体引擎,它提供了一套用于渲染字体的 API。FreeType 支持多种字体格式,包括 TrueType、Type 1、CFF、OpenType、SFNT、PCF、BDF、FNT 等。

        FreeType 下载地址:https://freetype.org/download.html

        FreeType 的主要功能包括:

  • 加载字体文件:FreeType 可以加载各种格式的字体文件,并提取其中的字形数据。
  • 渲染字形:FreeType 可以将字形数据渲染为位图,用于在屏幕或其他设备上显示。
  • 提取字体信息:FreeType 可以提取字体文件中的各种信息,如字体名称、作者、版权信息等。

        FreeType 是用 C 语言编写的,可以在多种操作系统和平台上运行,包括 Windows、macOS、Linux、iOS、Android 等。

        

1.2 HarfBuzz

        HarfBuzz 是一个开源的文本排版引擎,它主要用于处理 Unicode 文本的复杂脚本和字形。

        HarfBuzz 下载地址:https://github.com/harfbuzz/harfbuzz

        HarfBuzz 的主要功能包括:

  • 字形形状:HarfBuzz 可以将 Unicode 文本转换为字形索引和位置信息,这是在屏幕上显示文本的基础。
  • 文本方向:HarfBuzz 可以处理从左到右(LTR)和从右到左(RTL)的文本,以及垂直排版的文本。
  • 复杂脚本:HarfBuzz 支持全球各种语言的复杂脚本,包括阿拉伯语、印地语、泰语、藏语等。
  • OpenType 特性:HarfBuzz 支持 OpenType 字体的各种特性,如连字、变体、上标、下标等。

        HarfBuzz 是用 C 和 C++ 语言编写的,可以在多种操作系统和平台上运行,包括 Windows、macOS、Linux、iOS、Android 等。HarfBuzz 是许多开源和商业软件的核心组件,包括 Chrome、Firefox、Android、LibreOffice 等。

        

二、FreeType和HarfBuzz的使用

        环境:Windows, VSCode, CMake VS2022

        工程目录:

        CMakeLists.txt 配置:

cmake_minimum_required(VERSION 3.0.0)
project(font_demo VERSION 0.1.0 LANGUAGES C CXX)add_compile_options(/utf-8)add_executable(font_demo main.cpp)add_subdirectory(freetype)
add_subdirectory(harfbuzz)target_link_libraries(font_demo freetypeharfbuzz 
)if(CMAKE_BUILD_TYPE STREQUAL "Debug")add_definitions(-D_ITERATOR_DEBUG_LEVEL=0) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MD")
else()set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
endif()

main.cpp 代码:
 

// **************************************************************************
// 这个程序演示了如何使用 FreeType 和 HarfBuzz 将文本渲染到位图中。
// 该程序以字符串作为输入,并将每个字符的位图打印到控制台。
// 该程序基于以下示例:
//   
// Creation Date: 2024-01-21
// Created By: 又吹风了#include <iostream>
#include <vector>
#include <cstring>#include <ft2build.h>
#include FT_FREETYPE_H#include <hb.h>
#include <hb-ft.h>int main()
{// 要显示的文本std::wstring text =  L"Hi,你好";FT_Library library;FT_Face face;// 初始化 FreeType 库if (FT_Init_FreeType(&library)){std::cerr << "could not init freetype library\n";return 1;}// 从字体文件加载字体面if (FT_New_Face(library, "C:\\Windows\\Fonts\\msyh.ttc", 0, &face)){std::cerr << "could not open font\n";return 1;}// 设置字体面的像素大小FT_Set_Pixel_Sizes(face, 0, 30);// 为 harfbuzz 创建一个缓冲区hb_buffer_t *buf = hb_buffer_create();// 检查错误if (!buf){std::cerr << "could not create harfbuzz buffer\n";return 1;}// 设置缓冲区的方向为从右到左// harfbuzz 会根据‎自动调整文本方向,所以不需要设置// hb_buffer_set_direction(buf, HB_DIRECTION_RTL);// 将文本设置到缓冲区std::vector<uint32_t> utf32_text(text.begin(), text.end());hb_buffer_add_utf32(buf, utf32_text.data(), text.length(), 0, text.length());// 创建一个 harfbuzz 字体对象hb_font_t *hb_font = hb_ft_font_create(face, NULL);// 检查错误if (!hb_font){std::cerr << "could not create harfbuzz font\n";return 1;}// 检查文本的方向hb_direction_t direction = hb_buffer_get_direction(buf);// 对文本进行形状处理hb_shape(hb_font, buf, NULL, 0);// 从缓冲区获取字形信息和位置unsigned int len = hb_buffer_get_length(buf);hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buf, NULL);hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buf, NULL);// 存储每个字符的位图std::vector<std::pair<FT_Bitmap, unsigned char *>> bitmaps;// 加载文本的每个字符并存储其位图for (unsigned int i = 0; i < len; ++i){FT_UInt glyph_index;if (direction == HB_DIRECTION_RTL){// 如果文本的方向是从右到左,那么使用字形索引glyph_index = info[i].codepoint;}else{// 如果文本的方向是从左到右,那么使用字符码点glyph_index = FT_Get_Char_Index(face, info[i].codepoint);}if (glyph_index == 0){std::cerr << "Could not find glyph for codepoint=" << info[i].codepoint << "\n";continue;}if (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT)){std::cerr << "Could not load glyph,codepoint=" << info[i].codepoint << ",glyph=" << glyph_index << "'\n";return 1;}FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);FT_Bitmap bitmap_copy;unsigned char *buffer_copy;// 复制位图及其缓冲区        bitmap_copy = face->glyph->bitmap;buffer_copy = new unsigned char[bitmap_copy.rows * bitmap_copy.width];std::memcpy(buffer_copy, bitmap_copy.buffer, bitmap_copy.rows * bitmap_copy.width);bitmap_copy.buffer = buffer_copy;// 存储复制的位图及其缓冲区bitmaps.push_back(std::make_pair(bitmap_copy, buffer_copy));}int max_rows = 0;// 找到最大的行数for (const auto &pair : bitmaps)if (pair.first.rows > max_rows)max_rows = pair.first.rows;// 打印每个字符的位图for (int y = 0; y < max_rows; ++y){for (const auto &pair : bitmaps){for (int x = 0; x < pair.first.width; ++x){if (y < pair.first.rows && pair.first.buffer[y * pair.first.width + x])std::cout << "*";elsestd::cout << " ";}std::cout << "  "; // 字符之间的间距}std::cout << "\n";}// 释放位图的缓冲区for (auto &pair : bitmaps)delete[] pair.second;// 释放 harfbuzz 的缓冲区和字体hb_buffer_destroy(buf);hb_font_destroy(hb_font);// 释放 FreeType 的字体和库FT_Done_Face(face);FT_Done_FreeType(library);return 0;
}

显示效果:

注意:这是只是简单打印bitmap,没有考虑基线、行高、字距等排版问题。

阿拉伯语

.

.

.

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

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

相关文章

LLMs之Cheshire-Cat :Cheshire-Cat (Stregatto)的简介(构建自定义人工智能的框架)、安装、使用方法之详细攻略

LLMs之Cheshire-Cat &#xff1a;Cheshire-Cat (Stregatto)的简介(构建自定义人工智能的框架)、安装、使用方法之详细攻略 目录 Cheshire-Cat (Stregatto)的简介 1、文档和资源 2、为什么使用Cat Cheshire-Cat (Stregatto)的安装和使用方法 1、安装 2、最小插件示例 Che…

Centos使用Docker搭建自己的Gitlab(社区版和设置汉化、修改密码、设置SSH秘钥)

根据我的经验 部署Gitlab&#xff08;社区版&#xff09; 至少需要2核4g的服务器 带宽3~4M 1. 在自己电脑上安装终端&#xff1a;宝塔ssl终端 或者 FinalShell&#xff0c;根据喜好安装即可 http://www.hostbuf.com/t/988.html http://www.hostbuf.com/downloads/finalshell_w…

(力扣记录)739. 每日温度

数据结构&#xff1a;栈 时间复杂度&#xff1a;O(n) 空间复杂度&#xff1a;O(n) 代码实现&#xff1a; class Solution:def dailyTemperatures(self, temperatures: List[int]) -> List[int]:res [0] * len(temperatures)stack []for i in range(len(temperatures))…

数字媒体技术基础之:常见的 RGB 色彩空间

所谓“色彩空间” Color Space&#xff0c;是因为可以用 3 个及以上的相互独立的向量将所有色彩构成一个三维空间&#xff0c;以便进行色彩研究与计算。 色彩空间有时候也被称为“色彩模型”。然而它们还是各有侧重&#xff0c;色彩空间侧重于颜色的标识&#xff0c;色彩模型则…

el-upload中的before-upload不生效

我们先来看看官方对before-upload的定义 before-upload是在上传文件时触发&#xff0c;不是添加文件时触发&#xff0c;添加文件时触发 on-change。 所以如果我们要在添加文件时&#xff0c;对文件的大小和后缀等等进行判断&#xff0c;可以用 on-change 方法来实现。 checkSu…

go语言(十一)----面向对象继承

一、面向对象继承 写一个父类 package mainimport "fmt"type Human struct {name stringsex string }func (this *Human) Eat() {fmt.Println("Human.Eat()...") }func (this *Human) Walk() {fmt.Println("Human.Walk()...") }func main() {h…

P2P DMA发展全景分析解读

P2P DMA&#xff08;Peer-to-Peer Direct Memory Access&#xff09;技术是一种允许连接到PCIe总线上的不同设备之间直接进行数据交换的机制&#xff0c;无需通过CPU和系统内存中转。这一特性极大地提升了数据传输效率&#xff0c;减少了CPU负载&#xff0c;并在特定场景下优化…

Repository docker-ce-test is listed more than once in the configuration

这个消息表明&#xff0c;在你的 CentOS 系统的 YUM 软件源配置中&#xff0c;docker-ce-stable、docker-ce-stable-source 和 docker-ce-test 这几个仓库被列出了多次。这通常发生在 /etc/yum.repos.d/ 目录下的 YUM 配置文件中&#xff0c;相同的仓库被重复添加。 这种情况可…

VisualSVN Server实战

文章目录 一、实战概述二、实战步骤&#xff08;一&#xff09;下载VisualSVN Server&#xff08;二&#xff09;安装VisualSVN Server&#xff08;三&#xff09;使用VisualSVN Server1、新建仓库&#xff08;1&#xff09;新建Repository&#xff08;2&#xff09;选择仓库类…

go里面几个并发案例

1、用golang 写一个 消息队列&#xff0c;通过channel 多协程实现&#xff0c;一个写队列多个读队列 type MessageQueue struct {mu sync.Mutexqueue chan stringreaders []chan string }func NewMessageQueue() *MessageQueue {return &MessageQueue{queue: mak…

高速CAN总线 A C节点竞争总线时 电压分析(共ABC三个节点)

CAN 收发器放大图 ABC三节点框图如下图&#xff1a; 图① 简化过程同<<高速CAN总线 A节点发送 B节点接收 电压分析>> A C节点同时发送显性电平 如下图: 图② A C 节点同时发送显性电平, 则 4 个三极管全部导通, 假定三极管压降0.5V 则电路简化如下图.(导通分析参…

AI日报:扎克伯格瞄准AGI通用人工智能

文章目录 Meta瞄准通用人工智能领域Meta的目标Meta的产品 FAIR移动和装载H100扎克伯格对人工智能竞争对手的真实动机持怀疑态度Meta抛弃了元宇宙吗&#xff1f; Meta瞄准通用人工智能领域 Meta首席执行官马克扎克伯格&#xff08;Mark Zuckerberg&#xff09;在一份可能改变全…

抽象类和抽象方法

抽象方法&#xff1a;将共性的行为&#xff08;方法&#xff09;抽取到父类之后。由于每一个子类执行的内容是不一样&#xff0c;所以&#xff0c;在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。 抽象类&#xff1a;如果一个类中存在抽象方法&#xff0c;那么该类…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于混合博弈的配电网与多综合能源微网优化运行》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 这个标题涉及到配电网和多综合能源微网的优化运行&#xff0c;而优化的方法基于混合博弈理论。让我们逐步解读这个标题的关键部分&#xff1a; 基于混合…

mariadb数据库从入门到精通

mariadb数据库的安装以及安全初始化 mariadb数据库的安装以及安全初始化 mariadb数据库的安装以及安全初始化一、实验前提二、mariadb数据库的安装三、mariadb数据库安全初始化3.1 设定数据库基本的安全初始化3.2关闭对外开放端口 系列文章目录一、查看数据库二、进入库并且查看…

leetcode下一个更大的元素---1暴力---2单调栈

1.题目&#xff1a; nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。 给你两个 没有重复元素 的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#xff0c;其中nums1 是 nums2 的子集。 对于每个 0 < i < nums1.l…

【Element UI详细介绍】

Element UI详细介绍 1. Element UI1.1 VueElementUI安装1.2 开发示例 2. 特点3. 组件分类4. 开始使用5. 注意事项 1. Element UI Element UI 是一个基于 Vue 2.0 的桌面端组件库&#xff0c;主要用于构建快速、简洁的用户界面&#xff0c;Element UI 提供一套丰富的组件和工具…

Java进阶之旅第五天

Java进阶之旅第五天 不可变集合 应用场景 1.如果某个数据不能被修改,把它拷贝到不可变集合中是个很好的实践2.当集合对象被不可信的库调用时,不可变形式是安全的3.不可变集合不能修改,只能进行查询 获取方式 在List,Set,Map接口中,都存在静态的of方法,可以获取一个不可变的…

蓝桥杯、编程考级、NOC、全国青少年信息素养大赛—scratch列表考点

1、小小情报员&#xff08;202309scratch四级24题&#xff09; 1.准备工作 &#xff08;1&#xff09;选择背景 Colorful City&#xff1b; &#xff08;2&#xff09;保留角色小猫&#xff0c;选择角色Ballerina。 2.功能实现 &#xff08;1&#xff09;角色小猫初始位置…

leetcode-2788按分隔符拆分字符串

题目链接 2788. 按分隔符拆分字符串 - 力扣&#xff08;LeetCode&#xff09; 解题思路 class Solution:def splitWordsBySeparator(self, words: List[str], separator: str) -> List[str]:result []for i in words:for j in i.split(separator):if j:result.append(j)…