使用Python从PDF中提取页面大小

37

我想读取一个PDF文件,并获取每一页的页面列表和每页的大小。 我不需要对其进行任何操作,只需要读取它。

目前正在尝试使用pyPdf,在获取页面大小方面它可以满足我所有需求,但是要了解pdf文档中的页面大小可能会有所不同,因此可能需要迭代。 有没有其他库/方法可以使用?

我尝试过使用PIL,一些在线教程甚至有使用d=Image(imagefilename)的用法,但它从来没有读取过我的PDF文件-它可以读取我投入的其他所有东西-甚至一些我不知道PIL可以做到的事情。

欢迎任何指导-我使用的是Windows 7 64位,python25(因为我也使用GAE),但我很乐意在Linux或更现代的Python版本中进行操作。


1
PIL不支持PDF(很可能永远也不会支持),因为它们是一种非常复杂的矢量图形。PIL专注于栅格图像。处理PDF是专门库(如pikepdf或pymupdf)的任务。 - mara004
9个回答

54

这可以通过 pypdf 完成:

>>> from pypdf import PdfReader
>>> reader = PdfReader('example.pdf')
>>> box = reader.pages[0].mediabox
>>> box
RectangleObject([0, 0, 612, 792])
>>> box.width
Decimal('612')
>>> box.height
Decimal('792')

(之前称为pyPdf / PyPDF2


1
这样使用input1 = PdfFileReader(file('example.pdf', 'rb'))对我来说是有效的。 - bluerubez
对我不起作用;我得到了TypeError:'str'对象不能作为错误调用。 - Tensigh
1
坐标值被称为点,其中默认情况下1个点相当于1/72英寸。然而,每个页面都可以定义自定义的用户单位(UserUnit),它是一个因子,用于缩放所有坐标。 - mara004
点单位是什么?它是像素吗?还是其他的度量单位? - alexW
PyPDF2同样可用,导入库的代码为"from PyPDF2 import PdfReader",其余与上述相同。 - Harry

22
2023-08-30更新:提供示例pdf,添加裁剪框。
2021-07-22更新:原始答案并不总是正确的,因此我更新了我的答案。
使用PyMuPDF
>>> import fitz
>>> doc = fitz.open("example.pdf")
>>> page = doc[0]
>>> print(page.rect.width, page.rect.height)
284.0 473.0
>>> print(page.mediabox.width, page.mediabox.height)
595.304 841.89
>>> print(page.cropbox.width, page.cropbox.height)
473.0 284.0
mediaboxcropboxrect的返回值类型为Rect,它们具有"width"和"height"属性。对于大多数人来说,rect可能是最有用的。
这三个值在大多数情况下是相同的,但偶尔它们可能非常不同:cropbox和rect是页面的可见区域(从常规pdf查看器中看到的内容),而mediabox是物理介质。
cropbox和rect之间的一个区别是,cropbox与文档中的/CropBox相同,并且在页面旋转时不会改变。然而,rect会受到旋转的影响。有关PyMuPDF中不同框的更多信息,请阅读术语表。还可以参考PDF文档 14.11.2.1。
可以在此处下载示例pdf链接

2
你可以用doc[0]来代替 doc.loadPage(0) ,两者是等价的 :-) - Martin Thoma
2
这是最快速的封装库,用于读取PDF文件。 - am.rez
如果页面没有旋转,那么如果页面被旋转了呢?MediaBox中的宽度/高度顺序是否会改变? - rain01
1
@rain01 顺序不变,但当页面旋转90或270度时,列中的像素数实际上是实际宽度,而行中的像素数是实际高度。 - cges30901
非常感谢。提供了一个很好的例子。 - Pogger
显示剩余7条评论

17

使用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!)。


3
除非页面包含一个 UserUnit 条目可以用来改变单位,否则长度以点为单位给出。这个选项通常很少使用。 - mkl
我尝试过这个方法,但有时无法提取信息,而 PyMuPDF(cges30901的答案)始终表现良好。原因是 pdfrw 有时无法从 pdf 文件中提取“/MediaBox”键(很奇怪)。 - Dzhuang
3
这是错误的。格式应该是[x0,y0,x1,y1]。它不一定要以0开始。 - mara004

7
使用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)

7

对于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”的区别吗? - ferdynator
简而言之,mediabox 是整个页面的大小,包括白色边距。cropbox 是页面的大小加上应用程序用于执行任何功能的任何区域。请查看 https://wiki.scribus.net/canvas/PDF_Boxes_:_mediabox,_cropbox,_bleedbox,_trimbox,_artbox。 - Myonaiz
如果定义了裁剪框,则PDF查看器通常会显示页面的该部分。 - mara004

1

免责声明:本答案中使用的库borb是由我编写的。

#!chapter_005/src/snippet_002.py
import typing
from borb.pdf import Document
from borb.pdf import PDF


def main():

    # read the Document
    doc: typing.Optional[Document] = None
    with open("output.pdf", "rb") as in_file_handle:
        doc = PDF.loads(in_file_handle)

    # check whether we have read a Document
    assert doc is not None

    # get the width/height
    w = doc.get_page(0).get_page_info().get_width()
    h = doc.get_page(0).get_page_info().get_height()

    # do something with these dimensions
    # TODO

if __name__ == "__main__":
    main()

我们通过使用 PDF.loads 加载 PDF 来开始编写代码。 然后我们获取一个 Page(您可以更改此代码以打印每个 Page 的尺寸,而不仅仅是 Page 0)。 从那个 Page 中,我们获取包含宽度和高度的 PageInfo

您可以使用 pip 安装 borb

pip install borb

你也可以从源代码 这里 下载它。

如果你需要更多的例子,可以查看 示例库


请问您的库中的宽度和高度是以哪种单位来表示的? - undefined
点数。默认情况下,每英寸有72个点。 - undefined
你们的图书馆如何处理非默认的PPI?有没有PDFDocument.get_ppi()函数? - undefined
没有这样的功能。但请记住,borb会将PDF文档转换为类似JSON的数据结构。因此,如果你知道在哪里查找(通过查看规范,可以在存储库中找到),你可以简单地执行类似doc['Info']['Props']['ppi']的操作(请记住,这是一个虚构的路径)。 - undefined

0
使用pypdfium2:
import pypdfium2 as pdfium

PAGEINDEX = 0  # the first page
FILEPATH = "/path/to/file.pdf"
pdf = pdfium.PdfDocument(FILEPATH)

# option 1
width, height = pdf.get_page_size(PAGEINDEX)

# option 2
page = pdf[PAGEINDEX]
width, height = page.get_size()

# len(pdf) provides the number of pages, so you can iterate through the document

免责声明:我是维护者。

-1

另一种方法是使用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() 

1
Poppler目前不考虑UserUnit,因此将返回值转换为1->1/72in可能并不总是返回正确的大小。 - mara004

-2

适用于 Python 3.9 和库 PyPDF2 的正确代码:

from PyPDF2 import PdfFileReader

reader = PdfFileReader('C:\\MyFolder\\111.pdf')
box = reader.pages[0].mediaBox
print(box.getWidth())
print(box.getHeight())

对于所有页面

from PyPDF2 import PdfFileReader

reader = PdfFileReader('C:\\MyFolder\\111.pdf')

i = 0
for p in reader.pages:
    box = p.mediaBox
    print(f"i:{i}   page:{i+1}   Width = {box.getWidth()}   Height = {box.getHeight()}")
    i=i+1
    
input("Press Enter to continue...")

2023年更新:PyPDF2已经合并回pypdf。请使用pypdf。PyPDF2已被弃用。 - Martin Thoma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接