简单双层PDF制作
简单双层PDF制作
用途
将扫描版PDF通过百度OCR识别后,生成包含原始图像和可搜索文本的双层PDF文档。
优势
- 相比ABBYY FineReader OCR Editor,百度OCR在中文识别准确率方面表现更优
- 提供每月1000次免费调用额度,适合小规模使用免费
用法
百度OCR控制台:https://console.bce.baidu.com/ai-engine/ocr/overview/index
将获得的参数填入常量,根据图片分辨率指定OUTDPI
参数。
代码
import base64
import requests
import fitz # PyMuPDF
from aip import AipOcr # 百度官方 Python SDK
OUTDPI = 260
# ———— 1. 配置百度 OCR 凭证 ————
APP_ID = 'APP_ID '
API_KEY = 'API_KEY '
SECRET_KEY = 'SECRET_KEY '
# 使用 SDK 获取 access_token
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
# SDK 内部也可直接调用 client.get_access_token(),此处演示手动获取:
auth_url = 'https://aip.baidubce.com/oauth/2.0/token'
auth_params = {
'grant_type': 'client_credentials',
'client_id': API_KEY,
'client_secret': SECRET_KEY
}
auth_resp = requests.get(auth_url, params=auth_params)
auth_resp.raise_for_status()
access_token = auth_resp.json()['access_token']
# ———— 2. 打开源 PDF 和准备输出 PDF ————
src_path = '有机化学结构与功能 第八版戴立信 席振峰_401.pdf'
out_path = 'output_searchable.pdf'
doc = fitz.open(src_path)
out_doc = fitz.open() # 新建一个空 PDF
# ———— 检查和准备中文字体 ————
def get_chinese_font():
"""获取可用的中文字体"""
# 优先级顺序的中文字体列表
font_candidates = [
"china-s", # PyMuPDF 内置简体中文字体
"china-t", # PyMuPDF 内置繁体中文字体
"cjk", # CJK 字体
"china-ss", # 简体中文宋体
"china-ts", # 繁体中文宋体
]
# 创建临时页面测试字体
test_doc = fitz.open()
test_page = test_doc.new_page()
for font in font_candidates:
try:
test_page.insert_text((10, 50), "测试中文", fontname=font, fontsize=12)
test_doc.close()
print(f"使用中文字体: {font}")
return font, None
except:
continue
test_doc.close()
print("警告:未找到合适的中文字体,可能出现乱码")
return None, None
chinese_font, font_file_path = get_chinese_font()
# ———— 3. 通用文字识别(标准含位置版)接口地址 ————
ocr_url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/general' # :contentReference[oaicite:0]{index=0}
for page_index in range(len(doc)):
# if page_index<=250:
# continue
page = doc.load_page(page_index)
# 获取页面尺寸
rect = page.rect
max_width = 2000
# PyMuPDF中,像素 = 尺寸(点) * DPI / 72
# 所以 DPI = 像素 * 72 / 尺寸(点)
max_dpi = int(max_width * 72 / rect.height)
# 使用计算出的DPI值,但不低于150dpi以保证质量
dpi = min(300, max(0, max_dpi))
pix = page.get_pixmap(dpi=dpi)
# 首先尝试PNG格式
img_bytes = pix.tobytes(output="png")
with open("tmp.png", "wb") as f:
f.write(img_bytes)
# 如果图像大小超过K8M,尝试JPEG格式并调整质量
max_size = 8 * 1024 * 1024 # 8MB
if len(img_bytes) > max_size:
# 尝试JPEG格式,从高质量开始逐步降低
for quality in [95, 85, 75, 65, 55, 45, 35]:
img_bytes = pix.tobytes(output="jpeg", jpg_quality=quality)
if len(img_bytes) <= max_size:
break
img_b64 = base64.b64encode(img_bytes).decode()
print(len(img_b64),max_size)
# 调用通用文字识别(标准含位置版)
params = {
'image': img_b64,
# 可选增强识别:
# 'language_type': 'CHN_ENG',
# 'detect_direction': 'true',
# 'vertexes_location': 'true',
# 'probability': 'true'
}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
resp = requests.post(
f"{ocr_url}?access_token={access_token}",
data=params,
headers=headers
)
resp.raise_for_status()
result = resp.json()
# 在新文档中创建同等大小的页面
rect = page.rect
pix_write = page.get_pixmap(dpi=OUTDPI)
new_page = out_doc.new_page(width=rect.width, height=rect.height)
new_page.insert_image(rect, stream=pix_write.tobytes())
img_width = pix.width
img_height = pix.height
# PDF页面尺寸(点)
pdf_width = rect.width
pdf_height = rect.height
# 缩放比例:PDF坐标 = 图片坐标 * 缩放比例
scale_x = pdf_width / img_width
scale_y = pdf_height / img_height
print(f"页面 {page_index + 1}: 图片尺寸({img_width}x{img_height}), PDF尺寸({pdf_width:.1f}x{pdf_height:.1f}), 缩放比例({scale_x:.3f}, {scale_y:.3f})")
# 统计文字处理情况
total_words = len(result.get('words_result', []))
print(f"页面 {page_index + 1}: 检测到 {total_words} 个文字块")
for item in result.get('words_result', []):
txt = item['words']
loc = item['location']
left, top, w, h = loc['left'], loc['top'], loc['width'], loc['height']
# 1. 将图片坐标转换为PDF坐标(考虑缩放)
left_pdf = left * scale_x
top_pdf = top * scale_y
w_pdf = w * scale_x
h_pdf = h * scale_y
y_pdf = (top_pdf + h_pdf)
if chinese_font:
new_page.insert_text(
(left_pdf, y_pdf),
txt,
fontname=chinese_font,
fontsize=max(6, h_pdf * 0.8), # 字体大小稍小于文字框高度,避免过大
render_mode=3, # 填充+描边
overlay=True
)
elif font_file_path:
new_page.insert_text(
(left_pdf, y_pdf),
txt,
fontfile=font_file_path,
fontsize=max(6, h_pdf * 0.8),
render_mode=3,
overlay=True
)
else:
print(f"警告:使用默认字体,可能出现乱码: {txt[:10]}...")
new_page.insert_text(
(left_pdf, y_pdf),
txt,
fontsize=max(6, h_pdf * 0.8),
render_mode=3,
overlay=True
)
# break
try:
if page_index % 10 == 0:
out_doc.save(out_path, garbage=4, deflate=True)
except Exception as e:
print(f"保存失败:{e}",page_index)
out_doc.save(out_path, garbage=4, deflate=True)
print(f"已生成可搜索的双层 PDF:{out_path}")
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果