如何在 PDF 中正确渲染古吉拉特语(Gujarati)文本

发布时间 - 2026-01-22 00:00:00    点击率:

使用 pymupdf(fitz)向 pdf 插入古吉拉特语等复杂脚本文字时,若直接调用 `insert_text()` 且未正确配置字体与渲染方式,易出现字符错位、连字断裂(如“રવ્ નિદર”而非“રવિન્દ્ર”),根本原因是 `insert_text()` 不支持 opentype 特性(如 gsub/gpos 表),无法处理印度系文字的上下文连字与元音附标定位。

要可靠渲染古吉拉特语(以及泰米尔语、印地语、孟加拉语等印度系文字),必须避免 page.insert_text(),而应改用 page.insert_htmlbox() —— 这是 PyMuPDF 内置的轻量级 HTML 渲染引擎,底层基于 MuPDF 的 HTML/CSS 解析器,原生支持 Unicode、双向文本(BIDI)、OpenType 字体特性(包括连字、元音位置调整、辅音簇组合),能准确还原复杂脚本的视觉呈现。

✅ 正确做法:使用 insert_htmlbox()

insert_htmlbox() 接收 HTML 字符串和一个矩形区域(rect),自动选择系统或嵌入字体,并启用完整文本整形(shaping)。以下是适配您原始场景的修复版代码:

import fitz
from googletrans import Translator

def add_gujarati_text_to_pdf(pdf_path, output_path, text_to_add):
    # 打开现有 PDF(注意:insert_htmlbox 可用于已有文档)
    doc = fitz.open(pdf_path)

    # 定义插入区域:x0, y0, x1, y1(左上→右下)
    # 示例:在第3页(索引2)的 (175, 215) 附近放置一个宽150高40的文本框
    rect = fitz.Rect(175, 215, 325, 255)  # 宽度=150, 高度=40

    for page_num in range(doc.page_count):
        if page_num == 2:  # 第三页(0-indexed)
            page = doc[page_num]

            # 构建带内联样式的 HTML(确保字体可读且支持 Gujarati)
            html = f'''
            {text_to_add}
            '''

            # 关键:使用 inser

t_htmlbox 替代 insert_text page.insert_htmlbox(rect, html) break # 启用字体子集化(减小体积,保留所需字符) doc.subset_fonts() # 保存并压缩 doc.save(output_path, garbage=3, deflate=True) doc.close() # 使用示例 if __name__ == "__main__": input_pdf_path = "input.pdf" output_pdf_path = "output_with_gujarati.pdf" translator = Translator() result = translator.translate('Ravindra Nakrani', src='en', dest='gu') gujarati_name = result.text # 如:રવિન્દ્ર નાકરાણી print("Translated:", gujarati_name) add_gujarati_text_to_pdf(input_pdf_path, output_pdf_path, gujarati_name)

⚠️ 关键注意事项

  • 字体选择:insert_htmlbox() 会自动查找系统中已安装的支持古吉拉特语的字体(如 Noto Sans Gujarati、Shruti、Lohit Gujarati)。若目标环境无合适字体,需提前将 .ttf 文件嵌入 PDF(通过 doc.embed_font()),并在 HTML 中指定 font-family。
  • 坐标与尺寸:insert_htmlbox() 使用 Rect(x0,y0,x1,y1),不是 (x,y) 点坐标;务必预留足够高度(≥ fontsize × 1.4)以容纳上下标与连字。
  • HTML 是必需的封装层:即使只插纯文本,也必须包裹在 或 中,并声明 font-family 和 font-size,否则可能回退到不支持的默认字体。
  • 不支持 fontfile= 参数:insert_htmlbox() 不接受 fontfile=,字体由 CSS 控制;如需强制使用特定字体文件,请先调用 doc.embed_font("path/to/NotoSansGujarati-Regular.ttf"),再在 HTML 中引用其 PostScript 名(可通过 fitz.Font(fontfile=...) 获取)。
  • 性能提示:insert_htmlbox() 比 insert_text() 略慢,但对单次插入完全可忽略;批量插入时建议复用 doc 实例,避免重复解析。
  • ✅ 验证是否成功

    生成 PDF 后,用 Adobe Acrobat 或最新版 Chrome 打开,检查:

    • “રવિન્દ્ર” 是否显示为连贯字符(િ 正确附着在 ર 下方,ન્ 正确形成辅音簇);
    • 无乱码、空格异常或字符分离现象;
    • 文本可被 PDF 阅读器正确复制粘贴为 Unicode 字符串。

    通过 insert_htmlbox(),PyMuPDF 能真正实现多语言、多脚本的高质量 PDF 文本注入——这是处理印度系文字、阿拉伯文、希伯来文等复杂书写系统的推荐标准方案。


# css  # html  # go  # adobe  # ai  # pdf  # 多语言  # google  # chrome  # 封装  # 字符串  # 古吉拉特  # 印度  # 不支持  # 这是  # 阿拉伯文  # 泰米尔  # 孟加拉  # 已有  # 并在  # 所需 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?  Laravel如何创建自定义Facades?(详细步骤)  如何在建站主机中优化服务器配置?  在线教育网站制作平台,山西立德教育官网?  Google浏览器为什么这么卡 Google浏览器提速优化设置步骤【方法】  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  JavaScript如何操作视频_媒体API怎么控制播放  如何快速生成橙子建站落地页链接?  如何在IIS7中新建站点?详细步骤解析  轻松掌握MySQL函数中的last_insert_id()  Laravel API资源类怎么用_Laravel API Resource数据转换  谷歌Google入口永久地址_Google搜索引擎官网首页永久入口  Laravel如何配置任务调度?(Cron Job示例)  邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?  重庆市网站制作公司,重庆招聘网站哪个好?  使用Dockerfile构建java web环境  如何在 Pandas 中基于一列条件计算另一列的分组均值  JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)  edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】  高防服务器如何保障网站安全无虞?  uc浏览器二维码扫描入口_uc浏览器扫码功能使用地址  大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?  HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】  Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  javascript中闭包概念与用法深入理解  昵图网官网入口 昵图网素材平台官方入口  Gemini怎么用新功能实时问答_Gemini实时问答使用【步骤】  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  Laravel如何使用查询构建器?(Query Builder高级用法)  Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】  Laravel模型关联查询教程_Laravel Eloquent一对多关联写法  Python3.6正式版新特性预览  如何在景安服务器上快速搭建个人网站?  Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】  Laravel怎么实现模型属性转换Casting_Laravel自动将JSON字段转为数组【技巧】  Android利用动画实现背景逐渐变暗  高端云建站费用究竟需要多少预算?  详解jQuery停止动画——stop()方法的使用  Laravel Octane如何提升性能_使用Laravel Octane加速你的应用  Laravel如何创建自定义中间件?(Middleware代码示例)  Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程  Android使用GridView实现日历的简单功能  Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】  新三国志曹操传主线渭水交兵攻略  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  如何用JavaScript实现文本编辑器_光标和选区怎么处理  如何用免费手机建站系统零基础打造专业网站?  Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程