在Python代码中,如何高效地将PDF的某一页保存为JPEG文件?
使用场景:我有一个Python Flask Web服务器,PDF将上传并存储对应每个页面的JPEG。
这个解决方案很接近,但问题在于它没有将整个页面转换为JPEG。
可以使用pdf2image库。
您可以简单地安装它,使用以下命令:
pip install pdf2image
安装完成后,您可以使用以下代码获取图像。
from pdf2image import convert_from_path
pages = convert_from_path('pdf_file', 500)
将页面保存为jpeg格式
for count, page in enumerate(pages):
page.save(f'out{count}.jpg', 'JPEG')
编辑: Github 仓库 pdf2image 也提到了它使用 pdftoppm
并且需要其他安装:
pdftoppm 是实现实际操作的软件。它作为一个名为poppler的大型软件包的一部分进行分发。 Windows 用户需要安装Windows 的 poppler。 Mac 用户需要安装Mac 的 poppler。 如果没有预先安装 pdftoppm,Linux 用户可以通过运行
sudo apt install poppler-utils
命令来安装(在 Ubuntu 和 Archlinux 上测试过)。
您可以使用 anaconda 在 Windows 上安装最新版本:
conda install -c conda-forge poppler
注意:Windows版本0.67及以下可在http://blog.alivate.com.au/poppler-windows/上获取,但请注意0.68已于2018年8月份发布,因此您将无法获得最新功能或错误修复。
conda install -c conda-forge poppler
安装了 Poppler,安装成功。 - MNAfrom pdf2image import convert_from_path
pages = convert_from_path('file.pdf', 500)
pages = convert_from_path('file.pdf', 500, single_file=True)
pages[0].save('file.jpg', 'JPEG')
注意:该代码需要先安装pdf2image库。 - helgis我找到了这个简单的解决方案,PyMuPDF,可以将其输出为png文件。请注意,该库被导入为“fitz”,这是它使用的渲染引擎的历史名称。
import fitz
pdffile = "infile.pdf"
doc = fitz.open(pdffile)
page = doc.load_page(0) # number of page
pix = page.get_pixmap()
output = "outfile.png"
pix.save(output)
doc.close()
注意:该库已从使用“camelCase”更改为“snake_cased”。如果你遇到一个函数不存在的错误,请查看弃用名称。上面示例中的函数已相应地更新。
fitz.Document
类支持上下文管理器初始化:with fitz.open(pdffile) as doc:
...
pypdfium2
(v4):python3 -m pip install "pypdfium2==4" pillow
import pypdfium2 as pdfium
# Load a document
filepath = "tests/resources/multipage.pdf"
pdf = pdfium.PdfDocument(filepath)
# render a single page (in this case: the first one)
page = pdf[0]
pil_image = page.render(scale=4).to_pil()
pil_image.save("output.jpg")
# render multiple pages concurrently (in this case: all)
page_indices = [i for i in range(len(pdf))]
renderer = pdf.render(pdfium.PdfBitmap.to_pil, page_indices=page_indices)
for index, image in zip(page_indices, renderer):
image.save("output_%02d.jpg" % index)
优势:
PyMuPDF
}}PIL.Image.Image
}}、{{link3:numpy.ndarray
}}或ctypes数组目前已提供以下版本的安装包:
Windows
amd64, win32, arm64macOS
x86_64, arm64Linux (glibc 2.26+)
x86_64, i686, aarch64, armv7lLinux (musl 1.2+)
x86_64, i686还有一个脚本可以从源代码构建。
(免责声明:我是作者)
pip install pypdfium2
即可。 - Timpdf2image
(在其他答案中使用)实际上并没有做更多的事情,只是启动pdttoppm
与subprocess.Popen
,因此这里有一个直接执行的简短版本:PDFTOPPMPATH = r"D:\Documents\software\____PORTABLE\poppler-0.51\bin\pdftoppm.exe"
PDFFILE = "SKM_28718052212190.pdf"
import subprocess
subprocess.Popen('"%s" -png "%s" out' % (PDFTOPPMPATH, PDFFILE))
这里是 Windows 安装链接,用于安装pdftoppm
(包含在名为 poppler 的软件包中): http://blog.alivate.com.au/poppler-windows/。
不必在您的操作系统上安装Poppler。这样就可以工作:
pip install Wand
from wand.image import Image
f = "somefile.pdf"
with(Image(filename=f, resolution=120)) as source:
for i, image in enumerate(source.sequence):
newfilename = f.removesuffix(".pdf") + str(i + 1) + '.jpeg'
Image(image).save(filename=newfilename)
@gaurwraith,为Windows安装Poppler并使用pdftoppm.exe,方法如下:
从http://blog.alivate.com.au/poppler-windows/下载包含Poppler最新二进制文件/动态链接库的zip文件,并将其解压到程序文件夹中的一个新文件夹中。例如:"C:\Program Files (x86)\Poppler"。
将"C:\Program Files (x86)\Poppler\poppler-0.68.0\bin"添加到您的系统环境变量的路径中。
从命令行安装pdf2image模块 -> "pip install pdf2image"。
@vishvAs vAsuki,此代码应该通过子进程模块为给定文件夹中一个或多个PDF的所有页面生成所需的JPG。
import os, subprocess
pdf_dir = r"C:\yourPDFfolder"
os.chdir(pdf_dir)
pdftoppm_path = r"C:\Program Files (x86)\Poppler\poppler-0.68.0\bin\pdftoppm.exe"
for pdf_file in os.listdir(pdf_dir):
if pdf_file.endswith(".pdf"):
subprocess.Popen('"%s" -jpeg %s out' % (pdftoppm_path, pdf_file))
或者使用pdf2image模块:
import os
from pdf2image import convert_from_path
pdf_dir = r"C:\yourPDFfolder"
os.chdir(pdf_dir)
for pdf_file in os.listdir(pdf_dir):
if pdf_file.endswith(".pdf"):
pages = convert_from_path(pdf_file, 300)
pdf_file = pdf_file[:-4]
for page in pages:
page.save("%s-page%d.jpg" % (pdf_file,pages.index(page)), "JPEG")
GhostScript在Linux系统上的性能比Poppler快得多。
下面是PDF转图像的代码。
def get_image_page(pdf_file, out_file, page_num):
page = str(page_num + 1)
command = ["gs", "-q", "-dNOPAUSE", "-dBATCH", "-sDEVICE=png16m", "-r" + str(RESOLUTION), "-dPDFFitPage",
"-sOutputFile=" + out_file, "-dFirstPage=" + page, "-dLastPage=" + page,
pdf_file]
f_null = open(os.devnull, 'w')
subprocess.call(command, stdout=f_null, stderr=subprocess.STDOUT)
在 macOS 上,可以使用 brew install ghostscript
命令安装 GhostScript。
其他平台的安装信息可以在这里找到。如果系统中没有预先安装 GhostScript。
有一个名为pdftojpg的实用工具,可以将pdf转换为img。
你可以在这里找到代码 https://github.com/pankajr141/pdf2jpg
from pdf2jpg import pdf2jpg
inputpath = r"D:\inputdir\pdf1.pdf"
outputpath = r"D:\outputdir"
# To convert single page
result = pdf2jpg.convert_pdf2jpg(inputpath, outputpath, pages="1")
print(result)
# To convert multiple pages
result = pdf2jpg.convert_pdf2jpg(inputpath, outputpath, pages="1,0,3")
print(result)
# to convert all pages
result = pdf2jpg.convert_pdf2jpg(inputpath, outputpath, pages="ALL")
print(result)
每个人都会遇到一个问题,即安装Poppler 。我提供的方法比较繁琐,但效率高。
首先,从这里下载Poppler。
然后将其解压缩,在代码部分添加如下内容poppler_path=r'C:\Program Files\poppler-0.68.0\bin'
(例如),如下所示:
from pdf2image import convert_from_path
images = convert_from_path("mypdf.pdf", 500,poppler_path=r'C:\Program Files\poppler-0.68.0\bin')
for i, image in enumerate(images):
fname = 'image'+str(i)+'.png'
image.save(fname, "PNG")
下面是一个函数,可以将包含单页或多页的PDF文件转换为单个合并的JPEG图像。
import os
import tempfile
from pdf2image import convert_from_path
from PIL import Image
def convert_pdf_to_image(file_path, output_path):
# save temp image files in temp dir, delete them after we are finished
with tempfile.TemporaryDirectory() as temp_dir:
# convert pdf to multiple image
images = convert_from_path(file_path, output_folder=temp_dir)
# save images to temporary directory
temp_images = []
for i in range(len(images)):
image_path = f'{temp_dir}/{i}.jpg'
images[i].save(image_path, 'JPEG')
temp_images.append(image_path)
# read images into pillow.Image
imgs = list(map(Image.open, temp_images))
# find minimum width of images
min_img_width = min(i.width for i in imgs)
# find total height of all images
total_height = 0
for i, img in enumerate(imgs):
total_height += imgs[i].height
# create new image object with width and total height
merged_image = Image.new(imgs[0].mode, (min_img_width, total_height))
# paste images together one by one
y = 0
for img in imgs:
merged_image.paste(img, (0, y))
y += img.height
# save merged image
merged_image.save(output_path)
return output_path
示例用法: -
convert_pdf_to_image("PDF文件路径/1.pdf", "输出路径/output.jpeg")
for i, img in enumerate(imgs): total_height += imgs[i].height
而不是简单地使用for img in imgs: total_height += img.height
? - Vladimir Prudnikov
fitz
输出PNG格式的代码质量明显低于使用JPG格式的被接受代码。我怀疑图像分辨率会根据PDF纸张大小进行调整。 - Nelson