当前位置: 首页 > news >正文

harfbuzz 的用法

hb-blob: HarfBuzz Manual

harfbuzz 的用法

HarfBuzz 整形 API 的核心是函数。此函数采用一种字体,即 包含一串 Unicode 代码点的缓冲区和 (可选)字体功能列表作为其输入。它取代了 缓冲区中的代码点,其中包含来自 字体,正确排序和定位,以及任何 应用的可选字体功能。hb_shape()

除了保存预整形输入(Unicode 构成输入字符串的代码点)和后整形 输出(字形和位置),HarfBuzz缓冲区有几个 影响成形的属性。最重要的是 文本流方向(例如,从左到右、从右到左、 从上到下或从下到上)、脚本标记和 语言标记。

对于输入字符串缓冲区,可以使用标志来表示何时 缓冲区表示段落的开头或结尾,到 指示是否以可见方式呈现 Unicode 代码点,以及修改群集合并 缓冲区的行为。对于整形输出缓冲区, 每个字形的单个 X 和 Y 偏移量和(逻辑尺寸)为 访问。HarfBuzz 还会标记字形,就好像在 该字形(例如,在换行或连字过程中) 将需要重新塑造案文。Default IgnorableadvancesUNSAFE_TO_BREAK

HarfBuzz还提供了比较以下内容的方法 缓冲区、联接缓冲区、规范化缓冲区内容和句柄 无效的代码点,以及确定状态 缓冲区(例如,输入代码点或输出字形)。缓冲区 管理生命周期,并对所有缓冲区进行引用计数。

虽然默认函数是 足以满足大多数用例,还提供了变体 允许您指定在缓冲区上使用哪些 HarfBuzz 的整形器。hb_shape()

HarfBuzz可以读取TrueType字体,TrueType集合,OpenType 字体和 OpenType 集合。提供查询函数 有关指标、Unicode 覆盖率、可用表和 功能和变体选择器。单个字形也可以是 查询指标、变体和字形名称。开放类型 支持可变字体,HarfBuzz 允许您设置 字体对象上的变体轴坐标。

HarfBuzz 提供胶水代码以与其他各种代码集成 库,包括FreeType,GObject和CoreText。支持 与Uniscribe和DirectWrite集成是实验性的 现在。

  1. 创建一个缓冲区并将文本放入其中。
#include <hb.h>
hb_buffer_t *buf;
buf = hb_buffer_create();
hb_buffer_add_utf8(buf, text, -1, 0, -1);
  1. 设置缓冲区的脚本、语言和方向。
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
  1. 从字体文件创建字体和字体。
hb_blob_t *blob = hb_blob_create_from_file(filename); 
/* or  hb_blob_create_from_file_or_fail() */
hb_face_t *face = hb_face_create(blob, 0);
hb_font_t *font = hb_font_create(face);
  1. 形状!
hb_shape(font, buf, NULL, 0);
  1. 获取字形和位置信息。
unsigned int glyph_count;
hb_glyph_info_t *glyph_info    = hb_buffer_get_glyph_infos(buf, &glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
  1. 遍历每个字形。
hb_position_t cursor_x = 0;
hb_position_t cursor_y = 0;
for (unsigned int i = 0; i < glyph_count; i++) 
{hb_codepoint_t glyphid  = glyph_info[i].codepoint;hb_position_t x_offset  = glyph_pos[i].x_offset;hb_position_t y_offset  = glyph_pos[i].y_offset;hb_position_t x_advance = glyph_pos[i].x_advance;hb_position_t y_advance = glyph_pos[i].y_advance;/* draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset); */cursor_x += x_advance;cursor_y += y_advance;
}
  1. 整理。
hb_buffer_destroy(buf);
hb_font_destroy(font);
hb_face_destroy(face);
hb_blob_destroy(blob);

HarfBuzz 中的数据类型概述

HarfBuzz 具有两种数据类型:非不透明、 按值传递类型和不透明的堆分配类型。这种 的分离在必须提供 API/ABI 兼容性(几乎)无限期。

*值类型:*不透明、按值传递 类型包括整数类型、枚举和小结构。暴露 公共 API 中的结构使得无法扩展 结构在未来。因此,公开结构保留用于 否则效率极低的情况。

在 HarfBuzz 中,几个结构,比如 和 ,都属于效率敏感型。 类别,并且是不透明的。hb_glyph_info_thb_glyph_position_t

对于未来扩展性可能为 包括必要的保留成员以保留空间 可能的未来成员。因此,为此类结构提供 和方法非常重要,允许 API 的用户 有效处理类型,而无需 调整他们的代码以适应未来的变化。equal()``hash()

HarfBuzz 提供的重要值类型包括结构 用于处理 Unicode 代码点、字形和字体标记 表和功能,以及许多 Unicode 和 开放类型属性。

一个可用的例子:

需要额外使用stb库,该库可以在github上找到对应的,只需要将stb_image_write 拷贝过来就可以了

//#include <iostream>
//#include <QApplication>
//#include <turboopenglwidget.h>
//
//int main(int argc, char **argv)
//{
//    QApplication app(argc, argv);
//    TurboOpenGLWidget tt;
//    tt.show();
//    return app.exec();
//}#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <hb.h>
#include <hb-ft.h>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"struct Pixel32
{uint8_t r, g, b, a;
};struct Image32
{size_t width;size_t height;Pixel32 *pixels;bool is_null() const{return pixels == nullptr;}
};void save_image(Image32 image, const char *filePath)
{int ret = stbi_write_png(filePath, image.width, image.height, 4, image.pixels, image.width * sizeof(Pixel32));if(!ret){fprintf(stderr, "could not save file\n");}
}Pixel32 mix_pixels(Pixel32 dst, Pixel32 src)
{uint8_t rev_src_a = 255 - src.a;Pixel32 result;result.r = ((uint16_t) src.r * (uint16_t)src.a + (uint16_t)dst.r * rev_src_a) >> 8;result.g = ((uint16_t) src.g * (uint16_t)src.a + (uint16_t)dst.g * rev_src_a) >> 8;result.b = ((uint16_t) src.b * (uint16_t)src.a + (uint16_t)dst.b * rev_src_a) >> 8;result.a = dst.a;return result;
}void slap_ftbitmap_onto_image32(Image32 dest,FT_Bitmap *src,Pixel32 color,int x, int y)
{assert(src->pixel_mode == FT_PIXEL_MODE_GRAY);assert(src->num_grays == 256);for(size_t row = 0; row < src->rows; ++row){if(row + y < dest.height){for(size_t col = 0; col < src->width; ++col){if(col + x < dest.width){color.a = src->buffer[row*src->pitch + col];dest.pixels[(row+y)*dest.width +col +x] =mix_pixels(dest.pixels[(row+y)*dest.width+col+x], color);}}}}
}void draw_glyph(Image32 surface, FT_Face face, hb_codepoint_t glyphId, double x, double y)
{// FT_UInt glyphIndex = FT_Get_Char_Index(face, glyphId);FT_Error error = FT_Load_Glyph(face, glyphId, FT_LOAD_DEFAULT);if(error){fprintf(stderr, "could not load glyph: %d", glyphId);return;}error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);if(error){fprintf(stderr, "could not render glyph: %d", glyphId);return;}const Pixel32 FONT_COLOR{200, 200, 200, 255};slap_ftbitmap_onto_image32(surface, &face->glyph->bitmap,FONT_COLOR,(int) floor(x) + face->glyph->bitmap_left,(int) floor(y) + face->glyph->bitmap_top);
}void destroy_or_whatever(void *userData)
{printf("destroy_or_whatever(%p)\n", userData);
}int main(int argc, char **argv)
{// 创建一个缓冲区并将文本放入其中。hb_buffer_t *buf = hb_buffer_create();hb_buffer_add_utf8(buf, u8"我是傻逼", -1, 0, -1);// 设置缓冲区的脚本、语言和方向。hb_buffer_set_direction(buf, HB_DIRECTION_LTR);hb_buffer_set_script(buf, HB_SCRIPT_HAN);hb_buffer_set_language(buf, hb_language_from_string("zh", -1));// 从字体文件创建字体和字体。FT_Library  ftLib;FT_Error error = FT_Init_FreeType(&ftLib);if(error){fprintf(stderr, "could not initialize Freetype\n");return -1;}FT_Face face;const char *fontPath = "E:\\QHarfbuzz3\\fonts\\NotoSerifSC-Regular.otf";size_t index = 0;error = FT_New_Face(ftLib, fontPath, index, &face);if(error){fprintf(stderr, "could not initialize load the font face %s\n", fontPath);return -1;}error = FT_Set_Char_Size(face, 0, 5000, 0, 0);if(error){fprintf(stderr, "could not set char size %s\n");return -1;}hb_font_t *font = hb_ft_font_create(face, destroy_or_whatever);// 形状!hb_shape(font, buf, NULL, 0);// 获取字形和位置信息。unsigned int glyph_count = 0;printf("glyph_count initial = %d\n", glyph_count);hb_glyph_info_t *glyph_info =hb_buffer_get_glyph_infos(buf, &glyph_count);printf("glyph_count infos = %d\n", glyph_count);hb_glyph_position_t *glyph_pos =hb_buffer_get_glyph_positions(buf, &glyph_count);printf("glyph_count position = %d\n", glyph_count);// 遍历每个字形。hb_position_t cursor_x = 0;hb_position_t cursor_y = 0;Image32 surface;surface.width = 1000;surface.height = 1000;surface.pixels = (Pixel32 *)malloc(sizeof(Pixel32) * surface.width * surface.height);for(int i = 0; i < surface.height; i++){for(int j = 0; j < surface.width; j++){surface.pixels[i*surface.width+j] = {30, 30, 30, 255};}}for (unsigned int i = 0; i < glyph_count; i++){hb_codepoint_t glyph_id  = glyph_info[i].codepoint;hb_position_t x_offset  = glyph_pos[i].x_offset / 64.0;hb_position_t y_offset  = glyph_pos[i].y_offset / 64.0;hb_position_t x_advance = glyph_pos[i].x_advance / 64.0;hb_position_t y_advance = glyph_pos[i].y_advance / 64.0;draw_glyph(surface, face, glyph_id, cursor_x + x_offset, cursor_y + y_offset);cursor_x += x_advance;cursor_y += y_advance;}save_image(surface, "out.png");hb_buffer_destroy(buf);hb_font_destroy(font);return 0;
}

相关文章:

harfbuzz 的用法

hb-blob&#xff1a; HarfBuzz Manual harfbuzz 的用法 HarfBuzz 整形 API 的核心是函数。此函数采用一种字体&#xff0c;即 包含一串 Unicode 代码点的缓冲区和 &#xff08;可选&#xff09;字体功能列表作为其输入。它取代了 缓冲区中的代码点&#xff0c;其中包含来自 字…...

JSP 在线学习管理系统myeclipse定制开发sqlserver数据库网页模式java编程jdbc

一、源码特点 JSP 在线学习管理系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为SQLServer2008&#x…...

Python学习笔记——PIL库(Pillow库)总结

一、图像数据的格式 ①jpg 支持高级别的压缩&#xff0c;利用部分损耗&#xff0c;使图片变小&#xff0c;方便网络传播。 ②png 无损压缩格式&#xff0c;比jpg略大&#xff0c;较好的保存图片画质&#xff0c;支持透明效果。 ③gif 动图效果&#xff0c;多帧图像组合到…...

C. Build Permutation【整数理论、构造、思维】

链接 理论基础 结论&#xff1a;在区间[n,2n]上&#xff0c;至少存在一个完全平方数。结论&#xff1a;在区间[n,2n]上&#xff0c;至少存在一个完全平方数。结论&#xff1a;在区间[n,2n]上&#xff0c;至少存在一个完全平方数。 构造⌈n⌉2构造\lceil \sqrt{n}\rceil^2构造⌈…...

关于ETL的两种架构(ETL架构和ELT架构)

ETL&#xff0c;是英文 Extract-Transform-Load 的缩写&#xff0c;用来描述将数据从来源端经过抽取&#xff08;extract&#xff09;、转换&#xff08;transform&#xff09;、加载&#xff08;load&#xff09;至目的端的过程。ETL一词较常用在数据仓库&#xff0c;但其对象…...

android系统目录

环境&#xff1a;android studio引入android系统源码android和ubuntu策略路由的差异android源码编译问题&#xff08;单编&#xff09;repo(android源码)命令使用和注意事项wifi&#xff1a;wifi的加密类型梳理android11 wifisetting 流程跟踪android wifi热点settingandroid n…...

【C/C++】中【typedef】用法大全

总结一下typedef用法&#xff0c;一共七种&#xff0c;分别是&#xff1a;为基本数据类型起别名、为结构体起别名、为指针类型起别名、为数组类型起别名、为枚举类型起别名、为模版函数起别名。 目录 一、为基本数据类型起别名 二、为结构体起别名 三、为指针类型起别名 四…...

超实用的公众号运营攻略分享,纯干货

很多小伙伴抱怨&#xff0c;公众号运营真的越来越难做了&#xff01; 每天会因为少得可怜的阅读量发愁&#xff0c;每天会因为纠结写什么选题发愁&#xff0c;每天更会因为公众号没有什么起色而感到无力。 现阶段公众号运营趋于饱和状态&#xff0c;公众号创建门槛低&#xf…...

编写NodeJs脚本实现接口请求

要编写运行脚本,需要先搭建开发环境 环境搭建 nodeJs脚本运行,当然需要先安装nodejs环境 官方地址在这里: nodejs官网 打开官网地址,可以看到下面一句话: Node.js is an open-source, cross-platform JavaScript runtime environment. 在打开的页面,可以直接下载最新的…...

【无人机】回波状态网络(ESN)在固定翼无人机非线性控制中的应用(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

YAML 文件简介

简介 我们在安装 kubernetes 集群的时候使用了一些 YAML 文件来创建相关的资源&#xff0c;但是对 YAML 文件还是非常陌生。所以我们先来简单看一看 YAML 文件是如何工作的&#xff0c;并使用 YAML 文件来定义一个 kubernetes pod&#xff0c;然后再来定义一个 kubernetes dep…...

Python四大主题之一【 Web】 编程框架

目前Python的网络编程框架已经多达几十个&#xff0c;逐个学习它们显然不现实。但这些框架在系统架构和运行环境中有很多共通之处&#xff0c;本文带领读者学习基于Python网络框架开发的常用知识,及目前的4种主流Python网络框架&#xff1a;Django、Tornado、Flask、Twisted。 …...

【C++】哈希表

1. unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 &#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最好的查询是&#xff0c;进行…...

深度学习入门(六十七)循环神经网络——注意力机制

深度学习入门&#xff08;六十七&#xff09;循环神经网络——注意力机制前言循环神经网络——注意力机制课件心理学注意力机制注意力机制是显式地考虑随意线索非参注意力池化层Nadaraya-Watson 核回归&#xff1a;总结教材&#xff08;注意力提示&#xff09;1 生物学中的注意…...

阿里云云通信风控系统的架构与实践

作者&#xff1a;铭杰 阿里云云通信创立于 2017 年&#xff0c;历经 5 年发展已经孵化出智能消息、智能语音、隐私号、号码百科等多个热门产品。目前&#xff0c;已成为了国内云通信市场的领头羊&#xff0c;在国际市场上服务范围也覆盖了 200 多个国家。随着业务的不断壮大&am…...

【性能测试】loadrunner(一)知识准备

【性能测试】loadrunner&#xff08;一&#xff09;知识准备 目录&#xff1a;导读 1.0. 前言 1.1 性能测试术语介绍 1.2 性能测试分类 1.3 HTTP我们需要知道的 1.4 Loadrunner 12.55安装 1.0. 前言 ​ 在性能测试中&#xff0c;牵扯到了许多比较杂的知识点&#xff0c;…...

【Vue3源码】第五章 ref的原理 实现ref

【Vue3源码】第五章 ref的原理 实现ref 上一章节我们实现了reactive 和 readonly 嵌套对象转换功能&#xff0c;以及shallowReadonly 和isProxy几个简单的API。 这一章我们开始实现 ref 及其它配套的isRef、unRef 和 proxyRefs 1、实现ref 接受一个内部值&#xff0c;返回一…...

[Flink]部署模式(看pdf上的放上面)

运行一个wordcountval dataStream: DataStream[String] environment.socketTextStream("hadoop1", 7777) //流式数据不能进行groupBy,流式数据要来一条处理一次.0表示第一个元素,1表示第二个元素 //keyBy(0)根据第一个元素进行分组 val out: DataStream[(String, In…...

Linux 查看 CPU 信息,机器型号,内存等信息

平时用的可能少&#xff0c;但需要记住&#xff0c;使用的命令&#xff0c;转载https://my.oschina.net/hunterli/blog/140783&#xff0c;以记录学习 系统 # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat /proc/…...

三维量子力学 量子力学(3)

动量ppp有三个分量&#xff0c;为pxp_xpx​等。它们分别满足与位置坐标的对易关系&#xff0c;比如px−iℏ∂∂xp_x-i\hbar\frac{\partial }{\partial x}px​−iℏ∂x∂​。可以用位置坐标梯度算符表示即p−iℏ∇\bm{p}-i\hbar\nablap−iℏ∇。位置矢量用r\bm{r}r表示。 在d3r…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...