在阅读或归档扫描件、截图类PDF时,页面四周的多余留白和不相关区域往往会影响效率。比如只想保留一页中的图表、表格或某一栏正文,此时可以通过“裁剪”方式切掉不需要的部分。使用Spire.PDF库,Python脚本可以实现按任意矩形范围精确裁剪,也能快速去除四周空白,适合批量处理日常文档。其核心原理并不复杂:新建一个和目标区域等大小的新页面,把源页面内容通过偏移重绘过去,最终只留下需要的内容。
环境准备
先通过pip安装Spire.PDF:
然后在脚本中引入相关命名空间,后续所有操作都会围绕PdfDocument和PdfPageBase进行:- from spire.pdf.common import *
- from spire.pdf import *
复制代码
按指定矩形区域裁剪
最常见需求是给定一个矩形(左上角坐标+宽度+高度),把源页面中该矩形内的内容保存到新页面。实现思路是创建一个与目标矩形尺寸完全相同的新页面,然后使用DrawTemplate绘制源页面模板,并传入负的偏移坐标,使目标区域的左上角恰好对齐新页面原点。- from spire.pdf.common import *
- from spire.pdf import *
- input_file = "/示例.pdf"
- output_file = "/裁剪pdf.pdf"
- doc = PdfDocument()
- doc.LoadFromFile(input_file)
- page = doc.Pages[0]
- # 裁剪区域:左上角坐标 + 宽高,单位均为“点”(1英寸=72点)
- crop_x, crop_y = 50.0, 80.0
- crop_w, crop_h = 400.0, 500.0
- new_doc = PdfDocument()
- new_page = new_doc.Pages.Add(SizeF(crop_w, crop_h), PdfMargins(0.0))
- # 负偏移让源页面整体向左上移动,从而把指定区域放入新页面
- new_page.Canvas.DrawTemplate(page.CreateTemplate(), PointF(-crop_x, -crop_y))
- new_doc.SaveToFile(output_file)
- new_doc.Close()
- doc.Close()
复制代码
这里有几个关键细节:SizeF的参数必须与裁剪矩形保持一致,否则内容会被缩放或出现留白;PdfMargins(0.0)用于去掉新页面默认边距;PointF(-crop_x, -crop_y)的负号决定了裁剪位置的准确对齐。修改这四个数值,即可获得页面上任意位置的子区域。
裁剪掉四周空白边距
很多PDF页面自带较大白边,正文只占中间部分。如果各页边距均匀,可以通过PageSettings.Margins读取边距值,再按边距偏移重绘,一次处理所有页面。- from spire.pdf.common import *
- from spire.pdf import *
- input_file = "/示例.pdf"
- output_file = "移除页边距.pdf"
- doc = PdfDocument()
- doc.LoadFromFile(input_file)
- new_doc = PdfDocument()
- margins = doc.PageSettings.Margins
- left, right = margins.Left, margins.Right
- top, bottom = margins.Top, margins.Bottom
- for i in range(doc.Pages.Count):
- page = doc.Pages.get_Item(i)
- # 新页面尺寸 = 原页面尺寸 - 四周边距
- w = page.Size.Width - left - right
- h = page.Size.Height - top - bottom
- new_page = new_doc.Pages.Add(SizeF(w, h), PdfMargins(0.0))
- # 向左上偏移绘制,去除白边
- new_page.Canvas.DrawTemplate(page.CreateTemplate(), PointF(-left, -top))
- new_doc.SaveToFile(output_file)
- new_doc.Close()
- doc.Close()
复制代码
这种方法利用page.Size拿到包含边距的整页尺寸,doc.PageSettings.Margins则描述白边厚度,两者相减得到真正的内容区。再用PointF(-left, -top)将内容重新对齐到原点,就完成了去白边裁剪。循环遍历Pages集合时,每一页都会套用相同逻辑,尤其适合多页文档。
读取页面尺寸与裁剪框确认结果
裁剪前后往往需要确认页面物理尺寸和当前可见区域。PDF每页都带有MediaBox(物理尺寸)和CropBox(当前可见区域)等边界框,PdfPageBase将这些属性直接暴露出来,可用于核对裁剪是否生效,也可作为下一次裁剪的输入。- from spire.pdf.common import *
- from spire.pdf import *
- doc = PdfDocument()
- doc.LoadFromFile("Sample.pdf")
- page = doc.Pages[0]
- print("MediaBox:", page.MediaBox.Width, page.MediaBox.Height)
- print("CropBox:", page.CropBox.Width, page.CropBox.Height,
- page.CropBox.X, page.CropBox.Y)
- print("实际尺寸:", page.ActualSize.Width, page.ActualSize.Height)
- doc.Close()
复制代码
通过对比MediaBox与CropBox(或重绘后新页面的ActualSize),可以直观地确认页面是否已缩小到目标区域。如果源文档本身设置了CropBox,它的(X, Y)坐标可直接作为裁剪矩形的起点,省去手动测量坐标的步骤。
实用技巧:批量裁剪文件夹内所有PDF
把按矩形裁剪的逻辑放进目录遍历循环,即可批量处理某个文件夹下的所有PDF。下面示例使用os模块遍历文件,并为输出文件加上前缀避免重名。- import os
- from spire.pdf.common import *
- from spire.pdf import *
- folder = "./pdfs"
- for name in os.listdir(folder):
- if not name.lower().endswith(".pdf"):
- continue
- doc = PdfDocument()
- doc.LoadFromFile(os.path.join(folder, name))
- page = doc.Pages[0]
- new_doc = PdfDocument()
- new_page = new_doc.Pages.Add(SizeF(400.0, 500.0), PdfMargins(0.0))
- new_page.Canvas.DrawTemplate(page.CreateTemplate(), PointF(-50.0, -80.0))
- out = os.path.join(folder, "cropped", f"cropped-{name}")
- new_doc.SaveToFile(out)
- new_doc.Close()
- doc.Close()
复制代码
注意使用该脚本前需先创建“cropped”输出目录,否则保存时会因路径不存在而失败。
用厘米指定裁剪区域
前面的坐标都以“点”为单位,不直观。借助PdfUnitConvertor可以将厘米换算成点,让裁剪矩形的描述更符合日常习惯。- from spire.pdf.common import *
- from spire.pdf import *
- cvtr = PdfUnitConvertor()
- # 将2厘米换算为点
- pt = cvtr.ConvertUnits(2.0, PdfGraphicsUnit.Centimeter, PdfGraphicsUnit.Point)
- print("2 厘米 =", pt, "点")
复制代码
定义crop_x、crop_y、crop_w、crop_h时,先用厘米描述,再用ConvertUnits转换成点,传入SizeF和PointF。这样代码可读性更好,也不容易算错比例。
小结
本文介绍了Python下裁剪PDF页面的两种主要做法:按任意矩形区域精确裁剪,以及按边距自动去除白边。两者的共同原理都是“新建目标尺寸的新页面,用DrawTemplate按偏移量重绘源页面”,区别仅在于矩形坐标来源:前者手动指定,后者从PageSettings.Margins自动推导。结合MediaBox/CropBox读取、os目录遍历以及PdfUnitConvertor单位换算,可以轻松扩展到批量自动化场景。若只想“隐藏”而非“删除”页面外内容,也可以直接调整CropBox来定义可见区域,按需选择即可。 |