用 PaddleOCR 生成双层 pdf

06.13更新:

  • 更新至PP-OCRv6。(韩语、西里尔/希腊字母尚不支持,仍默认使用v5)

05.09更新:

  • 新增reocr脚本,只处理pdf的特定页面

  • 修复了竖排文本的问题

04.28更新:

  • 经测试,更大的服务器默认模型的边际收益已经很小了,所以改成默认使用小模型。

  • 使用字符集更大的默认字体,以避免 pdf 字体出错。

  • 修复了pdf生成中的一些问题。


写在前面:

  • 本脚本适合希望调用 N 卡加速 OCR 识别的用户。如果只能在 CPU 上运行,使用 C 语言编程而且集成化的 Umi-OCR 可能是更好的选择;如果要在 A 卡或 I 卡运行,请自行探索;由于 CUDA 配置受显卡型号影响较大,无法打包发布,需要按下面的方法自行配置。

  • 目前存在的问题:

    • 本项目生成的双层 pdf 旨在方便搜索,没有进行版面处理(例如多栏、表格、页眉页脚等等),因此复制出来的结果很可能是混乱的;
    • 中英文混排时,英文的空格识别有时候有问题,经常几个单词连在一起。这好像是Paddle OCR的问题,暂时无法解决。
    • 受模型限制,无法处理中文和英语、日语外小语种的混排文档。
  • 顺带一提,按现在的发展势头,ai消灭扫描版书籍估计也就是这一两年的事情了。也许需要考虑一下折腾双层 pdf 还值不值得。

特别鸣谢

双层 pdf 的生成参考了 hiroi-sora/Umi-OCR 的实现。

配置环境

首先安装 python。我这里在 python 3.10 下测试通过,理论上 3.10 ~ 3.12 应该都可以。

在任一文件夹下创建虚拟环境:


python3.10 -m venv .venv

激活虚拟环境(以 Windows 为例):


.venv\Scripts\activate

安装 PaddlePaddle GPU 版。我这里在 3.2.0 下测试通过。先运行 nvidia-smi 测试支持的 cuda 版本,如果低于 12.9 则需要将 cu129 改为 cu126 或 cu118。50 系显卡可能需要参考该文档:飞桨框架安装 - PaddleOCR 文档


python -m pip install paddlepaddle-gpu==3.2.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu129/

安装 Paddle OCR 和 pymupdf。


pip install paddleocr pymupdf

将本文附带的脚本放置到文件夹下,激活虚拟环境后就可以这样运行:


python paddle_pdf.py [参数]

命令行参数

必需参数

  • 输入的 PDF 文件路径

可选参数

  • -o, --output:输出的 PDF 文件路径

    • 默认为同一路径下 {输入文件基本名}_ocr.pdf
  • –lang:指定 OCR 识别语言

参数值 对应的 PaddleOCR 模型 主要支持语言
dft(默认) 见下 中文、英文、日文
ko korean_PP-OCRv5_mobile_rec 韩文、英文
ltn 见下 英文等拉丁语言
cyr eslav_PP-OCRv5_mobile_rec 俄文等斯拉夫语言、英文
gk el_PP-OCRv5_mobile_rec 希腊文、英文

(注意:dft 和 ltn 目前只有内嵌字体区别,不在意这个可以直接忽略)

  • –model:语言为 dft 和 ltn 时可以指定模型大小,可选参数包括 s 和 m,分别使用 PP-OCRv6_small_rec 和 PP-OCRv6_medium_rec。后者识别效果更好,性能需要也相应更高(不过对于现代电脑应该都不是问题),可按需设置。

使用示例

基本用法


python paddle_pdf.py input.pdf

将生成 input_ocr.pdf 文件,使用默认模型(中/英/日)

指定输出文件名


python paddle_pdf.py input.pdf -o output.pdf

使用指定模型


# 处理韩文文档

python paddle_pdf.py korean_doc.pdf --lang ko

# 处理俄文文档

python paddle_pdf.py russian_doc.pdf --lang cyr

# 使用 medium 模型

python paddle_pdf.py english_doc.pdf --model m

paddle_reocr.py 脚本用于重新识别pdf中特定的页面。此脚本会逐页渲染为图片再识别,性能上自然有劣势,只建议需要识别少量页面时使用。


python paddle_reocr.py input.pdf -p "3,5,7,9-11"

附带了一个remove_text.py脚本,可以删除双层 pdf 中的所有文字,并移除内嵌字体:


python remove_text.py "文件.pdf" "结果.pdf"

该脚本也会删除所有的文字内容,请谨慎使用。

效果测试

对生僻字的支持还可以,但太奇怪的还是不支持。

拼音的识别效果不错。

英文和其他拉丁语系混合文本识别效果:

脚本下载见此处:

paddle_pdf.7z (78.8 KB)

I plan to get a hard copy of Oxford Learner’s Thesaurus. This is the perfect model i was looking. I got a CUDA support GPU. I have a quick question. How many time CUDA accelerates compare to CPU?

Of course, this depends on the hardware level of the CPU and GPU. According to info from Paddle OCR (source: 使用教程 - PaddleOCR 文档), generally GPUs will be 3x~8x faster than CPUs.

However, if one wishes to create a textual dictionary, OCR models of this scale may not be sufficient (e.g., PaddleOCR doesn’t seem to support IPA). A larger model PaddleOCR-VL may be a better choice.

I tested with the page images obtained from the internet:

And this is the result with PaddleOCR-VL — In my opinion, it is already quite satisfactory:

## ways of cooking

[the image, omitted]

grill (BrE) / broil (AmE)

## bake verb See also the entry for COOK

take • fry • roast • grill • broil • toast • barbecue

these are all words for ways of cooking food.

## ATTERNS AND COLLOCATIONS

to fry/ roast/ grill/ broil/ barbecue chicken

to fry/ grill/ barbecue a steak

to fry/ grill/ barbecue sausages

to bake/ fry/ grill/ broil fish

to fry/ grill bacon

to bake/ fry/ roast potatoes

to bake/ fry/ toast bread

to roast/ toast nuts

ake [T, I] to cook food, especially bread, cakes and potatoes, in an oven without extra fat or liquid; to be cooked in this way: baked potatoes ◇ I'm baking a birthday cake for Alex. ◇ I'm baking Alex a cake. ◼ Bake is not used about cooking meat; use roast instead. See also baking → COOKING

y [T, I] to cook sth in hot fat or oil; to be cooked in this way: fried fish/eggs ◇ I woke up to the smell of bacon frying.

past [T, I] to cook meat without liquid in an oven or over fire; to cook vegetables in oil or fat in an oven; to cook nuts or beans in order to dry them and turn them brown; to be cooked in any of these ways: You should boil the potatoes for a little before you roast them. The smell of roasting meat came from the kitchen. The past participle of roast is usually roasted, except when it is used before noun, when roast is usually used: roast beef/chicken/potatoes/parsnips However, roasted beef/chicken/potatoes/parsnips However, roasted is used to describe nuts and beans: roasted chestnuts/coffee beans/peanuts

ill [T] to cook food under or over a very strong heat: Grill he sausages for ten minutes, turning occasionally. At night we used to grill steaks over charcoal in the open air. Food can be grilled in an oven under the grill (BrE) or broiler (AmE), or outdoors over a fire; however, it is even more frequent to talk about barbecuing food that is booked outdoors.

broil [T] (AmE) to cook meat or fish under direct heat: We ate broiled chicken with vegetables. In British English use grill for this.



toast [T, I] to make sth, especially bread, turn brown by heating it in a toaster or close to heat; to turn brown in this way: a toasted sandwich ◇ Place under a hot grill until the nuts have toasted.

barbecue /'bɑːbɪkjʊː; AmE 'bɑːrb-/ [T] to cook food on a barbecue (= a metal frame on or over an open fire outdoors): barbecued chicken

## ban noun

## ban · sanction · boycott · embargo · prohibition · moratorium · veto · taboo

These are all words for a rule, order or custom which does not allow people to do sth or for the act of stopping sth from being done.

## PATTERNS AND COLLOCATIONS

a ban/sanctions/a boycott/an embargo/a prohibition/a veto/a moratorium/a taboo on sb/sth

a ban/sanctions/a boycott/an embargo/a prohibition/a veto/a taboo against sb/sth

a total ban/boycott/embargo/prohibition/moratorium

(an) international ban/sanctions/boycott/embargo/moratorium

(a) trade ban / sanctions / boycott / embargo

(an) economic sanctions/ boycott/ embargo

to impose a ban/sanctions/a boycott/an embargo/a prohibition/a moratorium/a veto

to call for/introduce a ban/sanctions/a boycott/a prohibition/a moratorium

to enforce/tighten/ease a ban/sanctions/an embargo

▶ to comply with a ban/sanctions/a prohibition

▶ to break a ban/sanctions/an embargo/a taboo

to lift a ban/sanctions/a boycott/an embargo/a prohibition/a veto

a ban/sanctions/an embargo come/comes into force

ban [C] an official rule that says that sth is not allowed; the fact of sb being officially stopped from doing sth for a period of time as a punishment: There is to be a total ban on smoking in the office. ◇ The students took to the streets, defying a ban on political gatherings. ◇ The sprinter received a lengthy ban for failing a drugs test. ◇ He faces a possible life ban from international football.

sanction /'sæŋkʃn/ [C, usually pl.] an official order that limits trade or contact with a particular country, in order to make it do sth, such as obeying international law: Trade sanctions were imposed against any country that refused to sign the agreement.

boycott/ˈbɔɪkɒt; AmE -kɑːt/ [C] the act of refusing to buy, use or take part in sth as a way of protesting: Opposition groups declared a boycott of the elections. ◇ The group is calling for a consumer boycott of the company’s products. See also boycott → AVOID verb

embargo /ɪmˈbɑːɡəʊ; AmE ɪmˈbɑːrɡəʊ/ [C] an official order that forbids trade with another country, sometimes of a particular type of goods: There is a strict embargo on oil imports. ◇ We knew the arms embargo was being broken.

prohibition /ˌprəʊˈbɪʃn; AmE ˌprəʊəˈb- / ʌ, C] the act of stopping sth being done or used, especially by law; a law or rule that says that sth is not allowed: The RSPB has called for the prohibition of all imports of wild birds.

moratorium /ˌmɒrəˈtɔːriəm; AmE ˌmɔːr- / (pl. mortatoriums or moratoria) [C] an official agreement that an activity must stop for a period of time: The convention called for a two-year moratorium on commercial whaling. veto /ˈviːtəʊ; AmE -toʊ/ (pl. -oes) [C] an occasion when sb uses their right to refuse to allow sth to be done: For months there was a veto on employing new staff. See also veto → REFUSAL noun, veto → REFUSE verb

taboo/tə'bu:/ [C] a cultural or religious custom that does not allow people to do, use or talk about a particular thing as people find it offensive or embarrassing; a

But the styles, such as strikethroughs and italics, are still omitted.

PaddleOCR-VL should be able to run locally or use APIs.

Thank you for testing this.

刚发现latin模型也能识别德语旧字体,效果也不错:

能否做成Umi-OCR类似的软件,使用最新版的PaddleOCR?

Umi-OCR 可以用 PaddleOCR-VL 的 api,我就不重造轮子了。

况且拿 PaddleOCR-VL 生成双层 pdf 完全是大材小用了——跟我之前说的一样,ai 消灭扫描版书籍的日子已经不远了(文字识别和版面分析已经完全没问题,只有 italic 及字体识别目前还没有很好的解决方案——不过这个没有也问题不大)。估计很快就会有生成纯文本电子书的集成式程序出现。

反馈个 bug

在识别 CJK 汉字时,如果选择的 blank_cjk 不是相对完整的 CJK 字体或者使用的是可变字体,会导致输出的结果中包含大量中日韩兼容表意文字(CJK Compatibility Ideographs)。

这使得两个字看起来长得一样,但它们的 Unicode 完全不同。例如以下情况:

===== CJK 兼容汉字全文检测结果 =====

PDF: .\output.pdf
页数: 1

❌ 共发现 21 个兼容汉字:

[页 001, 行 001] 立(U+F9F7) → 立(U+7ACB) | CJK COMPATIBILITY IDEOGRAPH-F9F7
[页 001, 行 002] 利(U+F9DD) → 利(U+5229) | CJK COMPATIBILITY IDEOGRAPH-F9DD
[页 001, 行 004] 理(U+F9E4) → 理(U+7406) | CJK COMPATIBILITY IDEOGRAPH-F9E4
[页 001, 行 004] 見(U+FA0A) → 見(U+898B) | CJK COMPATIBILITY IDEOGRAPH-FA0A
[页 001, 行 004] 理(U+F9E4) → 理(U+7406) | CJK COMPATIBILITY IDEOGRAPH-F9E4
[页 001, 行 007] 行(U+FA08) → 行(U+884C) | CJK COMPATIBILITY IDEOGRAPH-FA08
[页 001, 行 009] 留(U+F9CD) → 留(U+7559) | CJK COMPATIBILITY IDEOGRAPH-F9CD
[页 001, 行 010] 留(U+F9CD) → 留(U+7559) | CJK COMPATIBILITY IDEOGRAPH-F9CD
[页 001, 行 013] 例(U+F9B5) → 例(U+4F8B) | CJK COMPATIBILITY IDEOGRAPH-F9B5
[页 001, 行 019] 理(U+F9E4) → 理(U+7406) | CJK COMPATIBILITY IDEOGRAPH-F9E4
[页 001, 行 021] 年(U+F98E) → 年(U+5E74) | CJK COMPATIBILITY IDEOGRAPH-F98E
[页 001, 行 022] 律(U+F9D8) → 律(U+5F8B) | CJK COMPATIBILITY IDEOGRAPH-F9D8
[页 001, 行 022] 行(U+FA08) → 行(U+884C) | CJK COMPATIBILITY IDEOGRAPH-FA08
[页 001, 行 024] 論(U+F941) → 論(U+8AD6) | CJK COMPATIBILITY IDEOGRAPH-F941
[页 001, 行 025] 例(U+F9B5) → 例(U+4F8B) | CJK COMPATIBILITY IDEOGRAPH-F9B5
[页 001, 行 026] 年(U+F98E) → 年(U+5E74) | CJK COMPATIBILITY IDEOGRAPH-F98E
[页 001, 行 029] 論(U+F941) → 論(U+8AD6) | CJK COMPATIBILITY IDEOGRAPH-F941
[页 001, 行 030] 理(U+F9E4) → 理(U+7406) | CJK COMPATIBILITY IDEOGRAPH-F9E4
[页 001, 行 030] 論(U+F941) → 論(U+8AD6) | CJK COMPATIBILITY IDEOGRAPH-F941
[页 001, 行 031] 理(U+F9E4) → 理(U+7406) | CJK COMPATIBILITY IDEOGRAPH-F9E4
[页 001, 行 031] 論(U+F941) → 論(U+8AD6) | CJK COMPATIBILITY IDEOGRAPH-F941

因此,我修改了下脚本,使其能够自动使用系统默认的 CJK 字体(虽然也不完整,但够用了),修改后的脚本在这里 paddle_pdf_modified.py (6.2 KB),已在楼主给出的环境下测试通过(样本为一份 511 页的 PDF)。

===== CJK 兼容汉字全文检测结果 =====

PDF: .\output.pdf
页数: 511

✅ 全文未发现 CJK 兼容汉字(U+F900–U+FAFF)

竖排版日语还是有很多问题,paddleocr有时候会内容错位还有或丢失字符,还有日文字体和中文汉字错误的情况也很多

才发现发布的时候忘了把两个空白字体也放进去了【捂脸】现在已经加上了。

还有一个小问题,使用您提供的空白字体的话,生成的 PDF 无法被 Edge 浏览器识别为双层 PDF,也就是说无法选择文本。但奇怪的是,在 Acrobat 中又能正常识别。

另外,如果用系统字体(如黑体),就不会出现上述问题。但识别出的文本框比用您提供的空白字体所识别出的文本框更加歪斜,是不是在注入文字阶段的问题,我找了半天没找到原因 :smiling_face_with_tear:

刚才测试了一下,我这边 edge 下一部分文件还能正常识别,另一些就不行,不知道为什么。

竖版繁体排版的古籍,基本上准确度不高,尤其是生僻字
试试这个:

拿PaddleOCR-VL-1.6识别了第一页:

史記韓非傳

韓非者韓之諸公子也。喜刑名法術之學。而其歸本於黃老。非爲人口吃。不能道說。而善著書。與李斯俱事荀卿。斯自以爲不如非。非見韓之削弱。數以書諫韓王。韓王不能用。於是韓非疾治國不務修明其法制。執勢以御其臣下。富國彊兵。而以求人任賢。反舉浮淫之蠹。而加之於功實之上。以爲儒者用文亂法。而俠者以武犯禁。寬則寵名譽之人。急則用介胄之士。今者所養非所用。非所養。悲廉直不容於邪枉之臣觀往者得失之變。故作孤憤。五蠹。內外儲說。林。林上脫說字。說難十餘萬言。然韓非知說之難爲說難。書甚具終死於秦。不能自脫說難曰。凡說之難。非吾知之有以說之難也。又非

把圈点都识别成了句号——这样好像也行?

不过这样的古籍当然最好还是由专门的模型来处理——北大和字节跳动搞的那个识典古籍应该做了不少这方面的工作,只是不太可能开放出来。

你好厉害,你已经预言家了。确实现在给ai投喂古老书籍了。