在 Python 中从 PDF 中提取页面大小
Posted
技术标签:
【中文标题】在 Python 中从 PDF 中提取页面大小【英文标题】:Extracting page sizes from PDF in Python 【发布时间】:2011-09-08 00:20:43 【问题描述】:我想阅读 PDF 并获取其页面列表和每页的大小。我不需要以任何方式操纵它,只需阅读即可。
目前正在试用 pyPdf,它可以满足我的所有需求,除了获取页面大小的方法。了解我可能不得不遍历,因为 pdf 文档中的页面大小可能会有所不同。我可以使用其他库/方法吗?
我尝试使用 PIL,一些在线食谱甚至使用 d=Image(imagefilename),但它从不读取我的任何 PDF - 它读取我扔给它的所有其他内容 - 甚至一些我不知道 PIL 可以做的事情.
感谢任何指导 - 我在 windows 7 64, python25 上(因为我也做 GAE 的东西),但我很高兴在 Linux 或更现代的 pythiis 上做。
【问题讨论】:
PIL 不(而且很可能永远不会)支持 PDF,因为它们是一种非常复杂的矢量图形。 PIL 专注于光栅图像。使用 PDF 是专用库的任务,例如 pikepdf 或 pymupdf。 【参考方案1】:这可以通过PyPDF2来完成:
>>> from PyPDF2 import PdfFileReader
>>> input1 = PdfFileReader(open('example.pdf', 'rb'))
>>> input1.getPage(0).mediaBox
RectangleObject([0, 0, 612, 792])
(以前称为pyPdf,现在仍参考其文档。)
【讨论】:
input1 = PdfFileReader(file('example.pdf', 'rb') 这样对我有用。 对我不起作用;我得到 TypeError: 'str' object is not callable as an error. 从 pyPdf 导入 PdfFileReader [0, 0, 宽度, 高度] @Astrophe 是正确的,但有一个更易读(但未记录)的解决方案。如果你看一下the sources,你会发现RectangleObject
类有几个方便的方法,包括getWidth()
(和getHeight()
),这比@987654328 好很多 @【参考方案2】:
与pdfrw:
>>> from pdfrw import PdfReader
>>> pdf = PdfReader('example.pdf')
>>> pdf.pages[0].MediaBox
['0', '0', '595.2756', '841.8898']
长度以磅为单位(1 pt = 1/72 英寸)。格式为[x0, y0, x1, y1]
(谢谢,mara004!)。
【讨论】:
“长度以磅为单位” 除非页面包含可用于在此处更改单位的 UserUnit 条目。诚然,这个选项很少使用。 我试过这个,但它有时无法提取信息,而 PyMuPDF(cges30901 的答案)一直表现良好。原因是 pdfrw 有时无法从 pdf 文件中提取“/MediaBox”键(奇怪)。 "格式为 ['0', '0', width, height]" - 这是错误的。格式为 [x0, y0, x1, y1]。不一定要以0开头。【参考方案3】:2021-07-22 更新:原来的答案并不总是正确的,所以我更新了我的答案。
与PyMuPDF:
>>> import fitz
>>> doc = fitz.open("example.pdf")
>>> page = doc[0]
>>> print(page.rect.width, page.rect.height)
842.0 595.0
>>> print(page.mediabox.width, page.mediabox.height)
595.0 842.0
mediabox 和rect 的返回值属于Rect 类型,具有“宽度”和“高度”属性。 mediabox 和 rect 之间的一个区别是 mediabox 与文档中的 /MediaBox 相同,并且在页面旋转时不会改变。但是,rect 会受到旋转的影响。有关 PyMuPDF 中不同框的更多信息,您可以阅读glossary。
【讨论】:
你也可以简单地写doc[0]
而不是doc.loadPage(0)
:-)
page
这里还有一个属性MediaBoxSize
,它返回大小。
这是读取 PDF 文件最快的包装库
Page
对象的CropBox
属性将未旋转 大小作为Rect
对象返回。 Rect
具有 width
和 height
属性。这是获取相关位的快速方法。
@rain01 顺序没有变化,但是当页面旋转90度或270度时,一列的像素数实际上是真正的宽度,一行的像素数是真正的宽度高度。【参考方案4】:
对于 pdfminer python 3.x (pdfminer.six)(没有在 python 2.7 上尝试):
parser = PDFParser(open(pdfPath, 'rb'))
doc = PDFDocument(parser)
pageSizesList = []
for page in PDFPage.create_pages(doc):
print(page.mediabox) # <- the media box that is the page size as list of 4 integers x0 y0 x1 y1
pageSizesList.append(page.mediabox) # <- appending sizes to this list. eventually the pageSizesList will contain list of list corresponding to sizes of each page
【讨论】:
也适合我。你也知道mediabox
和cropbox
的区别吗?
简而言之,mediabox 是整个页面的大小,包括白边。 cropbox 是页面大小 + 应用程序用来执行任何功能的任何区域。结帐wiki.scribus.net/canvas/…
如果定义了裁剪框,它就是 PDF 查看器通常会显示的页面部分。【参考方案5】:
使用 pikepdf:
import pikepdf
# open the file and select the first page
pdf = pikepdf.Pdf.open("/path/to/file.pdf")
page = pdf.pages[0]
if '/CropBox' in page:
# use CropBox if defined since that's what the PDF viewer would usually display
relevant_box = page.CropBox
elif '/MediaBox' in page:
relevant_box = page.MediaBox
else:
# fall back to ANSI A (US Letter) if neither CropBox nor MediaBox are defined
# unlikely, but possible
relevant_box = [0, 0, 612, 792]
# actually there could also be a viewer preference ViewArea or ViewClip in
# pdf.Root.ViewerPreferences defining which box to use, but most PDF readers
# disregard this option anyway
# check whether the page defines a UserUnit
userunit = 1
if '/UserUnit' in page:
userunit = float(page.UserUnit)
# convert the box coordinates to float and multiply with the UserUnit
relevant_box = [float(x)*userunit for x in relevant_box]
# obtain the dimensions of the box
width = abs(relevant_box[2] - relevant_box[0])
height = abs(relevant_box[3] - relevant_box[1])
rotation = 0
if '/Rotate' in page:
rotation = page.Rotate
# if the page is rotated clockwise or counter-clockwise, swap width and height
# (pdf rotation modifies the coordinate system, so the box always refers to
# the non-rotated page)
if (rotation // 90) % 2 != 0:
width, height = height, width
# now you have width and height in points
# 1 point is equivalent to 1/72in (1in -> 2.54cm)
【讨论】:
【参考方案6】:另一种方法是使用popplerqt4
doc = popplerqt4.Poppler.Document.load('/path/to/my.pdf')
qsizedoc = doc.page(0).pageSize()
h = qsizedoc.height() # given in pt, 1pt = 1/72 in
w = qsizedoc.width()
【讨论】:
Poppler does not currently take UserUnit into account,因此使用 1->1/72in 转换返回的值可能并不总是返回正确的大小。以上是关于在 Python 中从 PDF 中提取页面大小的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 PDFrw 在 Python 中从 PDF 中提取数据