起因
如果你在 Kindle 等小屏设备上看 PDF 电子书,应该有过这样的烦恼:
书页四周留着大块空白,而这种老一点的设备并不支持缩放功能;即使支持,频繁缩放、拖动也会让阅读体验大打折扣。
于是我想,能不能借助一个脚本:
- 可以裁切 PDF 的页边;
- 支持奇偶页不同的边距裁切(很多扫描版书籍奇偶页边不同)。
于是就写了这个小工具——CutEBookMargin(在 GPT 的帮助下)。项目链接:CutEBookMargin
核心功能
1. 自动分析白边
通过 --analyze
参数指定需要分析白边的页码,支持离散页面和连续页面,目标是找出 PDF 页面有效内容的最小包围盒,然后把它转成可以直接用于裁剪的边距值。实现过程分为几步:
将指定页栅格化(Rasterize):以 200 的 dpi 将页面渲染成位图。
转换为灰度图并二值化 : 如果是彩色/灰度 PDF,都统一转成灰度矩阵;使用亮度阈值
_WHITE_THRESH = 245
区分“空白像素”和“内容像素”。阈值略低于纯白(255),可以容忍轻微的扫描底色或纸张纹理。扫描非空白区域 :用
numpy.where()
分别找出有内容的行和列索引。第一行/最后一行非空像素对应的就是内容区上下边界,同理左右边界。安全边距 :在四个方向各留 6 pt 作为安全边距,避免裁到文字或页码。
多页聚合 :先得到每页的
{left, top, right, bottom}
,再按 10% 分位数(p10
)聚合成推荐值,能有效避免单页异常值的干扰。 同时会分别计算奇数页和偶数页的推荐值,以应对左右版心不同的扫描书。
最终,程序会打印统一边距和奇偶页边距两种方案,直接给出可以运行的命令。
使用示例:
python run.py -i "book.pdf" --analyze 8-11,13
这样程序会检测第 8 到第 11 页,以及第 13 页的边距,然后会给出类似于下面的推荐指令:
Analyzed pages (1-based): 8, 9, 10, 11, 13
Suggested uniform margins (pt): left=38.0, top=52.0, right=38.0, bottom=50.0
Paste to crop (uniform):
python run.py -i book.pdf -o book.trimmed.pdf -m 38.0,52.0,38.0,50.0
(to add page numbers: append --numbers --num-from 1 --num-pos br|bc|bl)
Suggested odd/even margins (pt): odd=38.0,52.0,38.0,50.0 | even=36.0,51.0,39.0,50.0
Paste to crop (odd/even):
python run.py -i book.pdf -o book.trimmed.pdf --odd 38.0,52.0,38.0,50.0 --even 36.0,51.0,39.0,50.0
(to add page numbers: append --numbers --num-from 1 --num-pos br|bc|bl)
2. 裁切页面
直接复制分析得到的推荐大小和指令,也可以手动微调四个方向裁切掉的大小。
在裁切的同时,可以加上 --numbers
参数为页面添加页码。这样做有两个好处:
- 有的扫描书籍原本就没有页码,添加后方便引用和查找;
- 有些书的页码位置占用过多空间,我希望手动裁切掉原来的页码,替换成更小巧紧凑的新页码。
下面这个例子使用了奇偶页不同的边距,并且从第 2 页开始编号,页码放在底部居中位置(bc
):
python run.py -i book.pdf -o book.trimmed.pdf \
--odd 38.0,52.0,38.0,50.0 \
--even 36.0,51.0,39.0,50.0 \
--numbers --num-from 2 --num-pos bc