广东白云手机网站建设沈阳网络运营推广
2026/4/6 9:34:59 网站建设 项目流程
广东白云手机网站建设,沈阳网络运营推广,python 网站开发神器,黄骅贴吧招聘临时工一、hb-blob1#xff09;定义blob 是一个抽象概念#xff0c;是对一段二进制数据的封装#xff0c;一般用来承载字体数据#xff0c;在HarfBuzz中用 hb_blob_t 结构体表示。2#xff09;hb_blob_createhb_blob_t 的构造方法#xff0c;签名如下#xff1a;表示从一段二进…一、hb-blob1定义blob 是一个抽象概念是对一段二进制数据的封装一般用来承载字体数据在HarfBuzz中用 hb_blob_t 结构体表示。2hb_blob_createhb_blob_t 的构造方法签名如下表示从一段二进制数据u8序列中创建hb_blob_t *hb_blob_create (const​ ​char​ *data,unsigned​ ​int​ length,hb_memory_mode_t​ mode,void​ *user_data,hb_destroy_func_t​ destroy);​data​原始二进制数据比如字体文件内容​length​二进制长度​mode​内存管理策略即如何管理二进制数据一般使用 HB_MEMORY_MODE_DUPLICATE 最安全类型如下模式 含义 优缺点HB_MEMORY_MODE_DUPLICATE 复制模式HarfBuzz会将传入的数据完整复制一份到私有内存 优点是不受传入的 data 生命周期影响缺点是多一次内存分配HB_MEMORY_MODE_READONLY 只读模式HarfBuzz会直接使用传入的数据数据不会被修改 优点是无额外性能开销缺点是外部需要保证在 hb_blob_t 及其衍生的所有对象如 hb_face_t被销毁之前始终保持有效且内容不变HB_MEMORY_MODE_WRITABLE 可写模式HarfBuzz会直接使用传入的指针同时修改这块内存数据 优点同READONLY缺点同READONLY同时还可能修改数据HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE 写时复制HarfBuzz会直接使用传入的指针在需要修改这块内存时才复制一份到私有内存 优点同READONLY缺点同READONLY同时还可能修改数据​user_data​可以通过 user_data 携带一些上下文​destroy​blob释放时的回调使用示例// 准备字体文件let ctFont UIFont.systemFont(ofSize: 18) as CTFontlet url CTFontCopyAttribute(ctFont, kCTFontURLAttribute) as! URLguard let fontData try? Data(contentsOf: url) else {return}// 创建 HarfBuzz Blob 和 Face// withUnsafeBytes 确保指针在 hb_blob_create 调用期间是有效的。// HB_MEMORY_MODE_DUPLICATE 告诉 HarfBuzz 复制数据这是在 Swift 中管理内存最安全的方式。let blob fontData.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) - OpaquePointer? inlet charPtr ptr.baseAddress?.assumingMemoryBound(to: CChar.self)return hb_blob_create(charPtr, UInt32(fontData.count), HB_MEMORY_MODE_DUPLICATE, nil, nil)}3hb_blob_create_from_filehb_blob_t 的构造方法签名如下表示从文件路径创建hb_blob_t *hb_blob_create_from_file (const char ​*file_name);​file_name​文件绝对路径注意非文件名使用示例let ctFont UIFont.systemFont(ofSize: 18) as CTFontlet url CTFontCopyAttribute(ctFont, kCTFontURLAttribute) as! URLlet blob url.path.withCString { ptr inhb_blob_create_from_file(ptr)}查看 hb_blob_create_from_file 函数实现会通过 mmap 的方式来映射字体文件可以共享系统的字体内存缓存相比自己读取二进制数据来创建blob来说这种方式会少一次IO且内存占用也可能更小复用系统内存缓存。二、hb-face1定义face 表示一个单独的字体它会解析blob中的二进制字体数据通过face可以访问字体中的各种table如GSUB、GPOS、cmap表等在HarfBuzz中用 hb_face_t 结构体表示。2hb_face_createhb_face_t的构造方法签名如下表示从一段字体二进制数据中构造facehb_face_t *hb_face_create (hb_blob_t​ ​*blob,unsigned int index);blob字体数据index有的字体文件是一个字体集合ttcindex表示使用第几个字体数据来创建face对于单字体文件ttf来说index传0即可关于字体更多知识可以参考一文读懂字体文件3hb_face_referencehb_face_t的引用计数 1hb_face_t *hb_face_reference (hb_face_t​ ​*face);3hb_face_destroyhb_face_t的引用计数 -1注意不是直接销毁对象在HarfBuzz中所有对象类型都提供了特定的生命周期管理APIcreate、reference、destroy对象采用引用计数方式管理生命周期当引用计数为0时才会释放内存。voidhb_face_destroy (hb_face_t​ ​*face);在实际使用时需要注意调用顺序需要保证所有从face创建出的对象销毁之后再调用hb_face_destroy。4hb_face_get_upem获取字体的upem。unsigned inthb_face_get_upem (const ​hb_face_t​ ​*face);upem 即 unitsPerEm在字体文件中一般存储在 head 表中字体的upem通常很大一般是1000或2048其单位并不是像素值而是 em unitunitsPerEm value2048/ 表示 2048 units 1 em 设计的字高比如当字体在屏幕上以 16px 渲染时1 em 16px其他数值可按比例换算。5hb_face_reference_table从字体中获取原始的table数据这个函数返回的是table数据的引用而不是拷贝所以这个函数几乎没有性能开销如果对应 tag 的table不存在会返回一个空的blob可以通过 hb_blob_get_length 来检查获取是否成功。hb_blob_t *hb_face_reference_table (const ​hb_face_t​ ​*face,hb_tag_t​ tag);使用示例// 构造tag这里是获取head表let headTag head.withCString { ptr inhb_tag_from_string(ptr, -1)}let headBlob hb_face_reference_table(face, headTag);// 检查是否成功if (hb_blob_get_length(headBlob) 0) {// 获取原始数据指针并解析var length: UInt32 0let ptr hb_blob_get_data(headBlob, length);// ... 在这里执行自定义解析 ...}// 必须销毁返回的 blobhb_blob_destroy(headBlob);6hb_face_collect_unicodes获取字体文件支持的所有Unicode这个函数会遍历cmap表收集cmap中定义的所有code point。voidhb_face_collect_unicodes (hb_face_t​ ​*face,hb_set_t​ ​*out);可以用收集好的结果来判断字体文件是否支持某个字符这在做字体回退时非常有用。使用示例let set hb_set_create()hb_face_collect_unicodes(face, set)var cp: UInt32 0while hb_set_next(set, cp) 1 {print(code point: , cp)}hb_set_destroy(set)三、hb-font1定义font 表示字体实例可以在face的基础上设置字号、缩放等feature来创建一个font在HarfBuzz中用 hb_font_t 结构体表示。2hb_font_create hb_font_reference hb_font_destroyhb_font_t 的创建、引用、销毁函数整体同face对象一样采用引用计数的方式管理生命周期。3hb_font_get_glyph_advance_for_direction获取一个字形在指定方向上的默认前进量advancevoidhb_font_get_glyph_advance_for_direction(hb_font_t​ *font,hb_codepoint_t​ glyph,hb_direction_t​ direction,hb_position_t​ *x,hb_position_t​ *y);font指定字体glyph目标字形direction指定方向HB_DIRECTION_LTR/HB_DIRECTION_LTR/HB_DIRECTION_TTB/HB_DIRECTION_BTTx返回值advance.xy返回值advance.y这个函数会从 hmtx横向或vmtx纵向表中读取advance。一般情况下我们不需要直接使用这个函数这个函数是直接查表返回静态的默认前进量但实际塑形时一般还涉及kerning等调整所以一般常用hb_shape()的返回值hb_shape()返回的是包含字形上下文调整如kerning等的结果。使用示例let glyph_A: hb_codepoint_t 65var x_adv: hb_position_t 0var y_adv: hb_position_t 0// 1. 获取 A 在水平方向上的前进位移hb_font_get_glyph_advance_for_direction(font,glyph_A,HB_DIRECTION_LTR, // 水平方向x_adv,y_adv)4hb_font_set_ptem hb_font_get_ptem设置和获取字体大小point sizeptem 即 points per Em也就是 iOS 中的 point sizevoidhb_font_set_ptem (hb_font_t​ ​*font,float ptem);这个函数是 hb_font_set_scale() 简易封装在HarfBuzz内部字体大小不是用 points 来存储的而是用一个称为 scale 的 26.6 的整数格式来存储的。使用示例// 设置字体大小为 18 pthb_font_set_ptem(myFont, 18.0f);// 等价于// 手动计算 scaleint32_t scale (int32_t)(18.0f * 64); // scale 1152// 手动设置 scalehb_font_set_scale(myFont, scale, scale);Q什么是 26.6 整数格式26.6 格式是一种定点数Fixed-Point Number表示法用于将浮点数转换成整数存储和运算在 HarfBuzz 中这个格式用于 hb_position_t 类型int32_t用来表示所有的坐标和度量值如字形位置、前进量等。26.6 表示将一个 32 位整数划分为高26位用于存储整数部分一个有符号的 25 位整数 1 个符号位 低6位用于存储小数部分。换算规则2^6 64从「浮点数」转为「26.6 格式」hb_position_t (float_value * 64)从「26.6 格式」转回「浮点数」float_value hb_position_t / 64.0那为什么不直接用整数呢因为文本布局需要极高的精度如果只用整数那任何小于1的误差都会被忽略在一行文本中累计下来误差就很大了。那为什么不直接用浮点数呢因为整数比浮点数的运算快且浮点数在不同平台上存储和计算产生的误差还确定。因此为了兼顾性能和精确将浮点数「放大」成整数参与计算。5hb_font_get_glyph用于查询指定 unicode 在字体中的有效字形glyph这在做字体回退时非常有用。hb_bool_thb_font_get_glyph (hb_font_t​ ​*font,hb_codepoint_t​ unicode,hb_codepoint_t​ variation_selector,hb_codepoint_t​ ​*glyph);返回值 hb_bool_ttrue 表示成功glyph 被设置有效字形false 表示失败即字体不支持该 unicodefont字体unicode待查询 unicodevariation_selector变体选择符的code point比如在 CJK 中日韩表意文字中一个汉字可能有不同的字形如下图一个字体可能包含这些所有的变体那我们可以通过 variation_selector 指定要查询哪个变体如果只想获取默认字形那该参数可传 0在这里插入图片描述glyph返回值用于存储 unicode 对应字形当然还有与之对应的批量查询的函数hb_font_get_nominal_glyphs四、hb-buffer1定义buffer 在HarfBuzz中表示输入输出的缓冲区用 hb_buffer_t 结构体表示一般用于存储塑形函数的输入和塑形结束的输出。2hb_buffer_create hb_buffer_reference hb_buffer_destroyhb_buffer_t 的创建、引用、销毁函数整体同face对象一样采用引用计数的方式管理生命周期。3hb_buffer_add_utf8 hb_buffer_add_utf16 hb_buffer_add_utf32将字符串添加到buffer使用哪个函数取决于字符串编码方式。voidhb_buffer_add_utf8 (hb_buffer_t​ *buffer,const​ ​char​ *text,int​ text_length,unsigned​ ​int​ item_offset,int​ item_length);buffer目标buffertext文本text_length文本长度传 -1 会自动查找到字符串末尾的 \0item_offset偏移量0 表示从头开始item_length添加长度-1 表示全部长度使用示例let buffer hb_buffer_create()let text Hello World!let cText text.cString(using: .utf8)!hb_buffer_add_utf8(buffer, cText, -1, 0, -1)4hb_buffer_guess_segment_properties猜测并设置buffer的塑形属性script、language、direction等。voidhb_buffer_guess_segment_properties (hb_buffer_t​ ​*buffer);这个函数一般取第一个字符的属性作为整体buffer的属性所以如果要使用这个函数来猜测属性的话需要保证字符串已经被提前分段。当然也可以手动调用hb_buffer_set_script、hb_buffer_set_language 等来手动设置。五、hb-shapehb_shape是HarfBuzz的核心塑形函数签名如下voidhb_shape (hb_font_t​ *font,hb_buffer_t​ *buffer,const​ ​hb_feature_t​ *features,unsigned​ ​int​ num_features);font用于塑形的字体实例需要提前设置好字体大小等属性buffer既是输入待塑形的字符串会通过buffer传入也是输出塑形完成后塑形结果会通过buffer返回featuresfeature数组用于启用或禁用字体中的某些特性不需要的话可以传nilnum_features上一参数features数组的数量hb_shape 会执行一系列复杂操作比如字符到字形映射查询cmap表将字符转换为字形字形替换查询 GSUB 表进行连字替换、上下文替换等字形定位查询 GPOS 表微调每个字形的位置比如kerning标记定位草书连接等详细的塑形操作可以参考HarfBuzz核心概念。下面重点介绍塑形结果可以通过 hb_buffer_get_glyph_infos 和 hb_buffer_get_glyph_positions 从buffer中获取塑形结果。hb_buffer_get_glyph_infos 签名如下// hb_buffer_get_glyph_infoshb_glyph_info_t *hb_buffer_get_glyph_infos (hb_buffer_t​ ​*buffer,unsigned int ​*length);typedef struct {hb_codepoint_t codepoint;uint32_t cluster;} hb_glyph_info_t;hb_buffer_get_glyph_infos 返回一个 hb_glyph_info_t 数组用于获取字形信息hb_glyph_info_t 中有两个重要参数codepointglyphID注意这里不是 unicode 码点cluster映射回原始字符串的字节索引这里需要展开介绍下cluster在连字 (多对一)情况下比如 f 和 i (假设在索引 0 和 1) 被塑形为一个 fi 字形。这个 fi 字形的 cluster 值会是 0即它所代表的第一个字符的索引拆分 (一对多)情况下在某些语言中一个字符可能被拆分为两个字形这两个字形都会有相同的 cluster 值都指向那个原始字符高亮与光标当我们需要高亮显示原始文本的第 3 到第 5 个字符时就是通过 cluster 值来查找所有 cluster 在 3 和 5 之间的字形然后绘制它们的选区hb_buffer_get_glyph_positions 的签名如下hb_glyph_position_t *hb_buffer_get_glyph_positions (hb_buffer_t​ ​*buffer,unsigned int ​*length);typedef struct {hb_position_t x_advance;hb_position_t y_advance;hb_position_t x_offset;hb_position_t y_offset;} hb_glyph_position_t;hb_buffer_get_glyph_positions 返回一个 hb_glyph_position_t 的数组用于获取字形的位置信息hb_glyph_position_t 参数有x_advance / y_advancex / y 方向的前进量前进量指的是绘制完一个字形后光标应该移动多远继续绘制下一个字形对于横向排版而言y_advance 一般是0需要注意的是 advance 值中已经包含了 kernig 的计算结果x_offset / y_offsetx / y 方向的绘制偏移对于带重音符的字符如 é 来说塑形时可能拆分成 e ´重音符 ´ 塑形结果往往会带 offset以保证绘制在 e 的上方position主要在排版/绘制时使用以绘制为例通常用法如下// (x, y) 是“笔尖”或“光标”位置var current_x: Double 0.0var current_y: Double 0.0// 获取塑形结果var glyphCount: UInt32 0let infos hb_buffer_get_glyph_infos(buffer, glyphCount)let positions hb_buffer_get_glyph_positions(buffer, glyphCount)// 遍历所有输出的字形for i in 0..Int(glyphCount) {let info infos[i]let pos positions[i]// 1. 计算这个字形的绘制位置 (Draw Position)// 当前光标位置 本字形的偏移let draw_x current_x (Double(pos.x_offset) / 64.0)let draw_y current_y (Double(pos.y_offset) / 64.0)// 2. 在该位置绘制字形// (info.codepoint 就是字形 ID)drawGlyph(glyphID: info.codepoint, x: draw_x, y: draw_y)// 3. 将光标移动到下一个字形的起点// 当前光标位置 本字形的前进位移current_x (Double(pos.x_advance) / 64.0)current_y (Double(pos.y_advance) / 64.0)}六、完整示例下面我们以 Swift 中调用 HarfBuzz 塑形一段文本为例func shapeTextExample() {// 1. 准备字体let ctFont UIFont.systemFont(ofSize: 18) as CTFontlet url CTFontCopyAttribute(ctFont, kCTFontURLAttribute) as! URL// 2. 从字体文件路径创建bloblet blob url.path.withCString { ptr inhb_blob_create_from_file(ptr)}guard let face hb_face_create(blob, 0) else { // 0 是字体索引 (TTC/OTF collections)print(无法创建 HarfBuzz face。)hb_blob_destroy(blob) // 即使失败也要清理return}// Blob 已经被 face 引用现在可以安全销毁hb_blob_destroy(blob)// --- 3. 创建 HarfBuzz 字体对象 ---guard let font hb_font_create(face) else {print(无法创建 HarfBuzz font。)hb_face_destroy(face)return}// 告诉 HarfBuzz 使用其内置的 OpenType 函数来获取字形等信息// 这对于 OpenType 字体.otf, .ttf是必需的hb_ot_font_set_funcs(font)hb_font_set_synthetic_slant(font, 1.0)// 设置字体大小 (例如 100pt)。// HarfBuzz 内部使用 26.6 整数坐标系即 1 单位 1/64 像素。let points: Int32 100let scale points * 64hb_font_set_scale(font, scale, scale)// --- 4. 创建 HarfBuzz 缓冲区 ---guard let buffer hb_buffer_create() else {print(无法创建 HarfBuzz buffer。)hb_font_destroy(font)hb_face_destroy(face)return}// --- 5. 添加文本到缓冲区 ---let text Hello World!let cText text.cString(using: .utf8)!// hb_buffer_add_utf8:// - buffer: 缓冲区// - cText: UTF-8 字符串指针// - -1: 字符串长度 (传 -1 表示自动计算直到 null 终止符)// - 0: item_offset (从字符串开头)// - -1: item_length (处理整个字符串)hb_buffer_add_utf8(buffer, cText, -1, 0, -1)// 猜测文本属性 (语言、文字方向、脚本)// 这对于阿拉伯语 (RTL - 从右到左) 至关重要hb_buffer_guess_segment_properties(buffer)// --- 6. 执行塑形 (Shape!) ---// 使用 nil 特征 (features)表示使用字体的默认 OpenType 特征hb_shape(font, buffer, nil, 0)// --- 7. 获取塑形结果 ---var glyphCount: UInt32 0// 获取字形信息 (glyph_info)let glyphInfoPtr hb_buffer_get_glyph_infos(buffer, glyphCount)// 获取字形位置 (glyph_position)let glyphPosPtr hb_buffer_get_glyph_positions(buffer, glyphCount)guard glyphCount 0, let glyphInfo glyphInfoPtr, let glyphPos glyphPosPtr else {print(塑形失败或没有返回字形。)// 清理hb_buffer_destroy(buffer)hb_font_destroy(font)hb_face_destroy(face)return}print(\n--- 塑形结果 for \(text) (\(glyphCount) glyphs) ---)// --- 8. 遍历并打印结果 ---// cluster 字段将字形映射回原始 UTF-8 字符串中的字节索引。// 这对于高亮显示、光标定位等非常重要。var currentX: Int32 0var currentY: Int32 0// 注意阿拉伯语是从右到左 (RTL) 的。// hb_buffer_get_direction(buffer) 会返回 HB_DIRECTION_RTL。// HarfBuzz 会自动处理布局所以我们只需按顺序迭代字形。for i in 0..Int(glyphCount) {let info glyphInfo[i]let pos glyphPos[i]let glyphID info.codepoint // 这是字形 ID (不是 Unicode 码点!)let cluster info.cluster // 映射回原始字符串的字节索引let x_adv pos.x_advance // X 轴前进let y_adv pos.y_advance // Y 轴前进let x_off pos.x_offset // X 轴偏移 (绘制位置)let y_off pos.y_offset // Y 轴偏移 (绘制位置)print(Glyph[\(i)]: ID\(glyphID))print( Cluster (string index): \(cluster))print( Advance: (x\(Double(x_adv) / 64.0), y\(Double(y_adv) / 64.0)) pt) // 除以 64 转回 ptprint( Offset: (x\(Double(x_off) / 64.0), y\(Double(y_off) / 64.0)) pt)print( Cursor pos before draw: (x\(Double((currentX x_off)) / 64.0), y\(Double((currentY y_off)) / 64.0)) pt)// 累加光标位置currentX x_advcurrentY y_adv}print(------------------------------------------)print(Total Advance: (x\(currentX / 64), y\(currentY / 64)) pt)// --- 9. 清理所有 HarfBuzz 对象 ---// 按照创建的相反顺序销毁hb_buffer_destroy(buffer)hb_font_destroy(font)hb_face_destroy(face)print(✅ 塑形和清理完成。)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询