使用Borb修改PDF字体触发Rectangle宽度非负AssertionError
问题:使用Borb修改指定字体文本时触发断言错误
AssertionError: A Rectangle must have a non-negative width 问题背景
尝试参考#581-filtering-by-font示例,结合SimpleFindReplace修改PDF中指定字体(VFMBOX+HelveticaNeueLTStd-Roman)的文本字体,触发了断言错误。已确认文档中存在该目标字体,当前环境:
- Borb版本:2.1.25
- Python版本:3.11
相关代码
#!chapter_005/src/snippet_017.py import typing from borb.pdf import Document from borb.pdf import PDF from borb.toolkit import FontNameFilter from borb.toolkit import SimpleTextExtraction from borb.toolkit import SimpleFindReplace def main(): # 创建FontNameFilter l0: FontNameFilter = FontNameFilter("VFMBOX+HelveticaNeueLTStd-Roman") # 过滤后的文本传递给SimpleTextExtraction l1: SimpleTextExtraction = SimpleTextExtraction() l0.add_listener(l1) # 读取文档 doc: typing.Optional[Document] = None with open("C:\Data\PDFFontChange\PD-1239-G_RevA_PR.pdf", "rb") as in_file_handle: doc = PDF.loads(in_file_handle, [l0]) # 确认文档读取成功 assert doc is not None templist = (l1.get_text()[0]).splitlines() # print(templist) i = 0 for x in templist : print(i, ' : ', x) i += 1 doc = SimpleFindReplace.sub(x, x, doc, repl_font="Helvetica") # 保存修改后的文档 with open("output2.pdf", "wb") as pdf_file_handle: PDF.dumps(pdf_file_handle, doc) if __name__ == "__main__": main()
错误回溯
0 : At the heart of your pump or dispenser, Traceback (most recent call last): File "c:\Python\Glenn_Begin\PDF_Workings\BORB_PDF_FontNameAlterTrajan.py", line 43, in <module> main() File "c:\Python\Glenn_Begin\PDF_Workings\BORB_PDF_FontNameAlterTrajan.py", line 36, in main doc = SimpleFindReplace.sub(x, x, doc, repl_font="Helvetica") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\toolkit\text\simple_find_replace.py", line 72, in sub ] = RegularExpressionTextExtraction.get_matches_for_pdf(pattern, doc) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\toolkit\text\regular_expression_text_extraction.py", line 375, in get_matches_for_pdf CanvasStreamProcessor(page, Canvas(), []).read(page_source, [cse]) File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\pdf\canvas\canvas_stream_processor.py", line 277, in read raise e File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\pdf\canvas\canvas_stream_processor.py", line 271, in read operator.invoke(self, operands, event_listeners) File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\pdf\canvas\operator\text\show_text_with_glyph_positioning.py", line 84, in invoke l._event_occurred(tri) File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\toolkit\text\regular_expression_text_extraction.py", line 326, in _event_occurred self._render_text(event) File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\toolkit\text\regular_expression_text_extraction.py", line 338, in _render_text for e in text_render_info.split_on_glyphs(): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\pdf\canvas\event\chunk_of_text_render_event.py", line 177, in split_on_glyphs e._baseline_bounding_box = Rectangle( ^^^^^^^^^^ File "C:\Python\Glenn_Begin\.venv\Lib\site-packages\borb\pdf\canvas\geometry\rectangle.py", line 30, in __init__ assert width >= 0, "A Rectangle must have a non-negative width." ^^^^^^^^^^ AssertionError: A Rectangle must have a non-negative width.
分析与解决方向
- 错误根源:该断言错误通常是因为PDF中存在宽度为负的文本片段(比如反向排版文字),导致
split_on_glyphs方法创建Rectangle时触发断言校验。 - 现有代码问题:循环中逐行调用
SimpleFindReplace.sub会重复扫描整个文档,且直接用提取的整行文本作为匹配模式,容易命中包含异常排版的文本片段。 - 修复建议:
- 升级Borb到最新版本:后续版本可能修复了这类边界情况的处理逻辑。
- 避免重复替换:一次性处理所有目标字体文本,而非循环逐行调用
sub,减少异常触发概率。 - 自定义Listener处理:直接在文本渲染阶段针对目标字体替换,绕过
SimpleFindReplace的全局匹配逻辑。
优化代码示例:
from borb.pdf import Document, PDF from borb.pdf.canvas.event.chunk_of_text_render_event import ChunkOfTextRenderEvent from borb.pdf.canvas.font.simple_font.font_type_1 import FontType1 from borb.toolkit import FontNameFilter class FontReplacementListener(FontNameFilter): def __init__(self, target_font_name: str, replacement_font: FontType1): super().__init__(target_font_name) self._replacement_font = replacement_font def _event_occurred(self, event: ChunkOfTextRenderEvent): # 替换目标字体 event._font = self._replacement_font super()._event_occurred(event) def main(): # 初始化替换字体 replacement_font = FontType1("Helvetica") # 创建自定义Listener listener = FontReplacementListener("VFMBOX+HelveticaNeueLTStd-Roman", replacement_font) # 读取并处理文档 doc = None with open("C:\Data\PDFFontChange\PD-1239-G_RevA_PR.pdf", "rb") as in_file_handle: doc = PDF.loads(in_file_handle, [listener]) # 保存结果 with open("output.pdf", "wb") as pdf_file_handle: PDF.dumps(pdf_file_handle, doc) if __name__ == "__main__": main()
内容的提问来源于stack exchange,提问作者user28348887
相关产品推荐
相关产品推荐

