我需要使用Python从pdf文件中提取页面数及其大小(以px / mm / cm / some-unit为单位)(不幸的是,因为它是一个遗留项目,所以为2.7)。问题在于文件可能真的很大(数百个MiB),因为它们将包含大图像。
我不在乎这些内容,我真的只希望从文件中获取页面大小的列表,并且尽可能少地消耗RAM。
我发现很多库可以做到这一点(包括但不限于答案here中的库),但是没有一个库提供有关内存使用的任何注释,我怀疑其中大多数-如果不是全部-在执行任何操作之前先读取内存中的整个文件,这不符合我的目的。
有没有只提取结构并提供我所需数据而又不会阻塞RAM的库?
答案 0 :(得分:1)
pyvips可以做到这一点。当您打开PDF时,它会加载文件结构,而仅当您要求像素时才渲染每个页面。
例如:
#!/usr/bin/python
import sys
import pyvips
i = 0
while True:
try:
x = pyvips.Image.new_from_file(sys.argv[1], dpi=300, page=i)
print("page =", i)
print("width =", x.width)
print("height =", x.height)
except:
break
i += 1
libvips 8.7大约需要一周的时间,它添加了一个名为n-pages
的新元数据项,可用于获取文档的长度。在此发布之前,尽管您只需要不断增加页码,直到遇到错误为止即可。
使用this PDF,当我运行程序时,我看到:
$ /usr/bin/time -f %M:%e ./sizes.py ~/pics/r8.pdf
page = 0
width = 2480
height = 2480
page = 1
width = 2480
height = 2480
page = 2
width = 4960
height = 4960
...
page = 49
width = 2480
height = 2480
55400:0.19
因此它以0.2s的实时速度打开了50页,总峰值内存使用量为55mb。与py3一起使用,但也可以与py2一起使用。尺寸以像素为单位,像素为300 DPI。
如果将page
设置为-1,它将把文档中的所有页面加载为一个非常高的图像。遗憾的是,所有页面的大小都必须相同。
答案 1 :(得分:0)
受other answer的启发,我发现那里建议的libvips
使用poppler
(如果找不到poppler
,它可以退回到其他库中)。
因此,我没有使用poppler
,它具有多个Python库,而pyvips
似乎对多种类型的文档都很有用,而没有使用它。我选择了pdflib
,并提出了以下解决方案:
from sys import argv
from pdflib import Document
doc = Document(argv[1])
for num, page in enumerate(doc, start=1):
print(num, tuple(2.54 * x / 72 for x in page.size))
2.54 * x / 72
部分从px
转换为cm
。
对264MiB文件进行速度和内存测试,每页一张大图像:
$ /usr/bin/time -f %M\ %e python t2.py big.pdf
1 (27.99926666666667, 20.997333333333337)
2 (27.99926666666667, 20.997333333333337)
...
56 (27.99926666666667, 20.997333333333337)
21856 0.09
仅供参考,如果有人在寻找纯Python解决方案,我会提供here可用的粗略解决方案。没有经过全面测试,并且比这慢得多(上述速度大约30秒)。