在 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 具有 widthheight 属性。这是获取相关位的快速方法。 @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

【讨论】:

也适合我。你也知道mediaboxcropbox的区别吗? 简而言之,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 中提取数据

在 Python 中从 PDF 中提取超链接

在 Python 3.4 中从 PDF 中提取文本的最佳工具 [关闭]

在java中从PDF中提取文本的最佳方法

如何在 JavaScript 中从 PDF 中提取文本

在python中从HTML中提取文本[重复]