如何用Python结合AWS Textract为PDF添加可搜索OCR隐形文本?
用AWS Textract生成可搜索PDF的Python实现方案
核心思路
利用AWS Textract的OCR结果(包含文本内容和坐标信息),通过PyMuPDF将文本以隐形模式插入PDF对应位置,实现可搜索功能。隐形文本不会显示在页面上,但能被PDF阅读器识别并支持搜索,无需严格匹配原字体样式。
关键步骤与代码实现
1. 获取AWS Textract OCR结果
调用Textract的analyze_document接口,按页面整理LINE/WORD类型的识别结果,包含文本内容和几何坐标。
import boto3 import fitz # PyMuPDF def fetch_textract_ocr(pdf_file_path): textract_client = boto3.client('textract') with open(pdf_file_path, 'rb') as pdf_file: response = textract_client.analyze_document( Document={'Bytes': pdf_file.read()}, FeatureTypes=['TEXT'] # 仅提取文本相关信息 ) # 按页面索引(0开始)整理结果 page_ocr_data = {} for block in response['Blocks']: if block['BlockType'] == 'PAGE': page_idx = block['Page'] - 1 # 转换为PyMuPDF的0索引 page_ocr_data[page_idx] = [] elif block['BlockType'] in ['LINE', 'WORD']: page_idx = block['Page'] - 1 if page_idx in page_ocr_data: page_ocr_data[page_idx].append(block) return page_ocr_data
2. 坐标转换与隐形文本插入
Textract采用左上角原点的相对坐标(0-1),而PyMuPDF采用左下角原点的绝对坐标,需先完成坐标转换,再插入隐形文本。
def inject_invisible_searchable_text(input_pdf, output_pdf, ocr_results): pdf_doc = fitz.open(input_pdf) for page_idx in range(len(pdf_doc)): page = pdf_doc[page_idx] page_rect = page.rect page_width = page_rect.width page_height = page_rect.height current_page_blocks = ocr_results.get(page_idx, []) if not current_page_blocks: continue # 判断页面是否已有可搜索文本,纯图片页才需要添加(可根据需求调整) has_existing_text = bool(page.get_text().strip()) if not has_existing_text: for block in current_page_blocks: # 跳过无几何信息的块 if 'Geometry' not in block: continue # 优先使用Polygon计算精确文本区域,替代BoundingBox polygon = block['Geometry']['Polygon'] # 转换Polygon坐标到PyMuPDF坐标系 converted_points = [ (p['X'] * page_width, page_height - p['Y'] * page_height) for p in polygon ] # 生成文本对应的Rect区域 x_coords = [p[0] for p in converted_points] y_coords = [p[1] for p in converted_points] text_rect = fitz.Rect( min(x_coords), min(y_coords), max(x_coords), max(y_coords) ) # 插入隐形文本:使用TEXT_INVISIBLE标志,无需匹配原字体 text_content = block['Text'] # 字体大小设为文本区域高度的90%,确保文本完全容纳 font_size = text_rect.height * 0.9 page.insertTextbox( text_rect, text_content, fontsize=font_size, fontname="helv", # 通用无衬线字体 text_flags=fitz.TEXT_INVISIBLE, align=fitz.TEXT_ALIGN_LEFT ) pdf_doc.save(output_pdf) pdf_doc.close()
3. 主流程调用
if __name__ == "__main__": input_path = "source.pdf" output_path = "searchable_output.pdf" ocr_data = fetch_textract_ocr(input_path) inject_invisible_searchable_text(input_path, output_path, ocr_data)
针对你的问题的优化建议
- 字体与对齐问题:由于插入的是隐形文本,无需匹配原字体样式。通过文本区域高度自动计算字体大小,左对齐即可满足搜索需求,用户完全看不到文本,样式不影响使用。
- 多类型PDF适配:
- 纯图片PDF:直接插入隐形文本即可。
- 纯可搜索PDF:可通过
page.get_text()判断,选择跳过或补充缺失文本(如扫描件嵌入的文本不全时)。 - 混合PDF:结合
page.get_image_info()判断页面是否包含图片,针对性补充隐形文本。
- 精度提升:优先使用Textract返回的
Polygon坐标生成文本区域,比BoundingBox更贴合实际文本位置,避免空白区域的无效文本插入。
注意事项
- 确保AWS账号拥有Textract的调用权限,并配置好本地AWS凭证。
- 对于大文件,可考虑分页处理,避免内存占用过高。
- 若需要处理多语言文本,可在Textract调用时指定
LanguageCode参数,提高识别准确率。
内容的提问来源于stack exchange,提问作者REJ
相关产品推荐
相关产品推荐

