libharu 中文乱码因默认不支持 utf-8,须先调用 hpdf_useutfencoding() 再加载中文字体;表格错位因无原生 api,需手动计算坐标与基线;内存暴涨因未复用字体及未及时释放;错误易被忽略因无异常机制,须设回调并检查返回值。

libharu 生成 PDF 时中文乱码或文字不显示
根本原因是 libharu 默认只支持 Latin-1 字符集,不内置中文字体,直接传入 UTF-8 中文字符串会跳过渲染或显示为空白。
必须显式加载 TrueType 字体(如 simsun.ttc、NotoSansCJKsc-Regular.otf),并用 HPDF_UseUTFEncoding() 切换编码模式:
HPDF_Doc doc = HPDF_New(NULL, NULL); HPDF_UseUTFEncoding(doc); // 必须在加载字体前调用 HPDF_Font font = HPDF_LoadTTFontFromFile(doc, "simsun.ttc", HPDF_TRUE); HPDF_Page page = HPDF_AddPage(doc); HPDF_Page_SetFontAndSize(page, font, 12);
常见坑:
-
HPDF_UseUTFEncoding()必须在任何字体加载前调用,否则无效 - Windows 下路径用反斜杠需转义(
"C:\fonts\simsun.ttc")或改用正斜杠 - 字体文件必须可读且含完整 CJK 字形;仅含英文的
arial.ttf无法显示中文 - macOS/Linux 用户注意字体路径权限,避免
HPDF_INVALID_FONT错误
用 libharu 绘制表格时行列对齐错乱
libharu 没有原生表格 API,靠手动计算 HPDF_Page_MoveTo() 和 HPDF_Page_LineTo() 画线 + HPDF_Page_TextOut() 填内容,稍有偏差就会错位。
关键控制点:
- 所有坐标以页面左下角为原点(0, 0),Y 向上增长,别和 GUI 坐标系混淆
- 文本垂直对齐依赖
HPDF_Page_TextOut()的 Y 值 —— 它定位的是基线(baseline),不是顶部;若想居中,需减去字体高度的约 0.8 倍 - 列宽必须统一用
HPDF_Font_GetTextWidth()测量实际字宽,不能按字符数估算(中文/英文宽度不同) - 画线前务必调用
HPDF_Page_Stroke(),否则线条不出现
示例:绘制两列等宽表头
float x1 = 50, x2 = 300, y = 750; HPDF_Page_MoveTo(page, x1, y); HPDF_Page_LineTo(page, x2, y); HPDF_Page_MoveTo(page, x1, y - 20); HPDF_Page_LineTo(page, x2, y - 20); HPDF_Page_Stroke(page); HPDF_Page_TextOut(page, x1 + 5, y - 15, "序号"); // y-15 是基线位置 HPDF_Page_TextOut(page, x1 + 100, y - 15, "姓名");
导出大量数据时内存暴涨或崩溃
libharu 的 HPDF_Doc 对象会缓存全部绘图指令和字体资源,逐行写入不释放中间对象极易 OOM。尤其在循环中反复调用 HPDF_AddPage() 或未复用 HPDF_Font 时更明显。
实操缓解方式:
- 复用同一个
HPDF_Font对象,不要每页都HPDF_LoadTTFontFromFile() - 单页内容超过 50 行建议分页,避免单页过大;用
HPDF_Page_GetHeight()动态判断剩余空间 - 导出完成立即调用
HPDF_Free(),它会释放所有关联内存 —— 忘记这步是内存泄漏主因 - 调试时加
HPDF_SetPagesConfiguration(doc, 10)限制初始页槽,提前暴露分配问题
libharu 在 C++ 中处理异常与错误码
libharu 是纯 C 库,不抛 C++ 异常,所有错误通过返回码和回调函数传递。默认错误处理是静默失败,容易掩盖问题。
必须主动设置错误回调并检查关键函数返回值:
- 注册回调:用
HPDF_SetErrorHandler(doc, error_handler),其中error_handler是自定义函数,接收HPDF_STATUS和HPDF_UINT错误码 - 关键函数如
HPDF_LoadTTFontFromFile()、HPDF_SaveToFile()返回HPDF_OK才算成功,否则要查HPDF_GetError() - 常见错误码:
HPDF_INVALID_FONT(字体加载失败)、HPDF_PAGE_OUT_OF_RANGE(页索引越界)、HPDF_FILE_IO_ERROR(写磁盘失败) - C++ RAII 封装时,在析构函数里确保
HPDF_Free()被调用,防止资源残留
导出 PDF 不是“调个函数就完事”,字体路径、坐标系理解、内存生命周期、错误反馈链,每个环节断掉都会让文档空白或程序崩掉。最常被跳过的其实是错误回调注册和 HPDF_UseUTFEncoding() 的调用顺序 —— 这俩不落实,中文导出大概率无声无息地失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











