从图像列表创建 PDF
Posted
技术标签:
【中文标题】从图像列表创建 PDF【英文标题】:Create PDF from a list of images 【发布时间】:2015-02-04 07:25:24 【问题描述】:有没有任何实用的方法可以使用 Python 从图像文件列表创建 PDF?
在 Perl 中我知道 that module。有了它,我只需 3 行就可以创建一个 PDF:
use PDF::FromImage;
...
my $pdf = PDF::FromImage->new;
$pdf->load_images(@allPagesDir);
$pdf->write_file($bookName . '.pdf');
我需要做一些与此非常相似的事情,但在 Python 中。我知道pyPdf 模块,但我想要一些简单的东西。
【问题讨论】:
您能否从问题中删除答案部分并正确发布,作为单独的答案?PIL
也是第三个包吗?我无法使用pip install PIL
安装它。
@RaviChandra PIL
是一个已停产的软件包。 Pillow
是一个 PIL 分支和活跃项目。
图片大小不同怎么办?
【参考方案1】:
安装FPDF for Python:
pip install fpdf
现在你可以使用相同的逻辑:
from fpdf import FPDF
pdf = FPDF()
# imagelist is the list with all image filenames
for image in imagelist:
pdf.add_page()
pdf.image(image,x,y,w,h)
pdf.output("yourfile.pdf", "F")
您可以找到更多信息at the tutorial page 或official documentation。
【讨论】:
谢谢,但我无法成功。我正在处理的图像是 JPG; FDPF 没有对 JPG 的原生支持。为此,需要 PIL。由于 PIL 不再支持 Python 3,因此我安装了 PILLOW。但是,FDPF 显然无法识别:“PIL 未安装”。出于测试目的,我使用 PNG 图像进行了测试,但是,导致以下错误:“Not a PNG file: 0.png” 对于 A4 尺寸的分页 PDF,w 和 h 的值分别为 210 和 297。 我使用这种方法遇到的问题是,由于某种原因,每隔一页都是空白的。 你能说出 x,y,w 和 h 的值是什么吗? 对于标准 (a4) 页面,x,y,w,h 的值应该是多少?编辑:看起来像 0,0,210,297 作品【参考方案2】:pgmagick 是 Python 的 GraphicsMagick(Magick++)
绑定。
它是 ImageMagick(或 GraphicsMagick)的 Python 包装器。
import os
from os import listdir
from os.path import isfile, join
from pgmagick import Image
mypath = "\Images" # path to your Image directory
for each_file in listdir(mypath):
if isfile(join(mypath,each_file)):
image_path = os.path.join(mypath,each_file)
pdf_path = os.path.join(mypath,each_file.rsplit('.', 1)[0]+'.pdf')
img = Image(image_path)
img.write(pdf_path)
Sample input Image:
PDF looks like this:
pgmagick iinstallation for windows:
1) 从Unofficial Windows Binaries for Python Extension Packages(如pgmagick 网页中所述)下载预编译的二进制包并安装。
注意: 尝试下载与您机器上安装的 python 版本相对应的正确版本,无论是 32 位安装还是 64 位安装。
您可以通过在终端输入 python 并按 Enter 来检查您是 32 位还是 64 位 python。
D:\>python
ActivePython 2.7.2.5 (ActiveState Software Inc.) based on
Python 2.7.2 (default, Jun 24 2011, 12:21:10) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
所以它有python version 2.7
和它的32 bit (Intel)] on win32
所以你必须下载并安装pgmagick‑0.5.8.win32‑py2.7.exe
。
这些是pgmagick 的以下可用 Python 扩展包:
pgmagick-0.5.8.win-amd64-py2.6.exe pgmagick-0.5.8.win-amd64-py2.7.exe pgmagick-0.5.8.win-amd64-py3.2.exe pgmagick-0.5.8.win32-py2.6.exe pgmagick-0.5.8.win32-py2.7.exe pgmagick‑0.5.8.win32‑py3.2.exe2) 然后您可以按照here 的安装说明进行操作。
pip install pgmagick
然后尝试导入它。
>>> from pgmagick import gminfo
>>> gminfo.version
'1.3.x'
>>> gminfo.library
'GraphicsMagick'
>>>
【讨论】:
我看到了你的回答,但我无法安装 ImageMagick。当我尝试安装模块时,总是收到错误消息“Magick ++ not found”。我尝试通过二进制文件安装。好像已经安装成功了,但是好像没有生效。我真的需要通过源安装吗?还是我做错了什么? @KeplerBR 您使用的是哪个操作系统?是的,我知道 Magic++ 是安装 pgmagick 所需的依赖项,但它值得,因为它在许多情况下都很棒。 @KeplerBR 见上文我已经添加了 pgmagick for windows 的安装说明。 我看到了 lfd 页面,但是,我使用的是 python 3.4,它最高支持 3.2。我无法成功编译源代码。否则会有,否则我必须编译? 你应该尝试编译它或其他明智的切换回 Python 3.2 也是一种选择。【参考方案3】:这个怎么样??
from fpdf import FPDF
from PIL import Image
import glob
import os
# set here
image_directory = '/path/to/imageDir'
extensions = ('*.jpg','*.png','*.gif') #add your image extentions
# set 0 if you want to fit pdf to image
# unit : pt
margin = 10
imagelist=[]
for ext in extensions:
imagelist.extend(glob.glob(os.path.join(image_directory,ext)))
for imagePath in imagelist:
cover = Image.open(imagePath)
width, height = cover.size
pdf = FPDF(unit="pt", format=[width + 2*margin, height + 2*margin])
pdf.add_page()
pdf.image(imagePath, margin, margin)
destination = os.path.splitext(imagePath)[0]
pdf.output(destination + ".pdf", "F")
【讨论】:
【参考方案4】:从文件所在的目录制作 pdf 的一些更改
我获取了代码并进行了一些细微的更改以使其可以正常使用。
from fpdf import FPDF
from PIL import Image
import os # I added this and the code at the end
def makePdf(pdfFileName, listPages, dir=''):
if (dir):
dir += "/"
cover = Image.open(dir + str(listPages[0]))
width, height = cover.size
pdf = FPDF(unit="pt", format=[width, height])
for page in listPages:
pdf.add_page()
pdf.image(dir + str(page), 0, 0)
pdf.output(dir + pdfFileName + ".pdf", "F")
# this is what I added
x = [f for f in os.listdir() if f.endswith(".jpg")]
y = len(x)
makePdf("file", x)
【讨论】:
【参考方案5】:如果你使用 Python 3,你可以使用 python 模块img2pdf
使用pip3 install img2pdf
安装它,然后你可以在脚本中使用它
使用import img2pdf
示例代码
import os
import img2pdf
with open("output.pdf", "wb") as f:
f.write(img2pdf.convert([i for i in os.listdir('path/to/imageDir') if i.endswith(".jpg")]))
或(如果由于某些路径问题而使用以前的方法出现任何错误)
# convert all files matching a glob
import glob
with open("name.pdf","wb") as f:
f.write(img2pdf.convert(glob.glob("/path/to/*.jpg")))
【讨论】:
我无法使用字符串指定目录。我必须先用os.chdir('path')
更改目录,然后[i for i in os.listdir(os.getcwd()) if i.endswith(".jpg")]
TypeError: 既不实现 read() 也不实现 str 或 bytes 给出此错误【参考方案6】:
我遇到了同样的问题,所以我创建了一个 python 函数来将多张图片合并到一个 pdf 中。该代码(可从my github page 获得,使用reportlab
,并基于以下链接的答案:
以下是如何将图像合并为 pdf 的示例:
我们有包含 png 和 jpg 类型图片的文件夹“D:\pictures”,我们想从中创建文件 pdf_with_pictures.pdf 并将其保存在同一文件夹中。
outputPdfName = "pdf_with_pictures"
pathToSavePdfTo = "D:\\pictures"
pathToPictures = "D:\\pictures"
splitType = "none"
numberOfEntitiesInOnePdf = 1
listWithImagesExtensions = ["png", "jpg"]
picturesAreInRootFolder = True
nameOfPart = "volume"
unite_pictures_into_pdf(outputPdfName, pathToSavePdfTo, pathToPictures, splitType, numberOfEntitiesInOnePdf, listWithImagesExtensions, picturesAreInRootFolder, nameOfPart)
【讨论】:
【参考方案7】:到目前为止,我尝试过的将多个图像转换为 PDF 的最佳方法是纯粹使用 PIL
。它非常简单但功能强大:
from PIL import Image
im1 = Image.open("/Users/apple/Desktop/bbd.jpg")
im2 = Image.open("/Users/apple/Desktop/bbd1.jpg")
im3 = Image.open("/Users/apple/Desktop/bbd2.jpg")
im_list = [im2,im3]
pdf1_filename = "/Users/apple/Desktop/bbd1.pdf"
im1.save(pdf1_filename, "PDF" ,resolution=100.0, save_all=True, append_images=im_list)
只需将save_all
设置为True
并将append_images
设置为您要添加的图像列表。
您可能会遇到AttributeError: 'JpegImageFile' object has no attribute 'encoderinfo'
。解决方法在这里Error while saving multiple JPEGs as a multi-page PDF
注意:安装最新的PIL
以确保save_all
参数可用于PDF。
【讨论】:
最佳方法,直接使用 PIL! 这种方法对我有用。 最佳答案。这也比 ilya-vinnichenko 的答案快 2 倍左右,即循环所有图像并一张一张地添加到 pdf 中。【参考方案8】:**** Convert images files to pdf file.****
from os import listdir
from fpdf import FPDF
path = "/home/bunny/images/" # get the path of images
imagelist = listdir(path) # get list of all images
pdf = FPDF('P','mm','A4') # create an A4-size pdf document
x,y,w,h = 0,0,200,250
for image in imagelist:
pdf.add_page()
pdf.image(path+image,x,y,w,h)
pdf.output("images.pdf","F")
【讨论】:
【参考方案9】:我知道问题已得到解答,但解决此问题的另一种方法是使用枕头库。 转换整个目录的图像:
from PIL import Image
import os
def makePdf(imageDir, SaveToDir):
'''
imageDir: Directory of your images
SaveToDir: Location Directory for your pdfs
'''
os.chdir(imageDir)
try:
for j in os.listdir(os.getcwd()):
os.chdir(imageDir)
fname, fext = os.path.splitext(j)
newfilename = fname + ".pdf"
im = Image.open(fname + fext)
if im.mode == "RGBA":
im = im.convert("RGB")
os.chdir(SaveToDir)
if not os.path.exists(newfilename):
im.save(newfilename, "PDF", resolution=100.0)
except Exception as e:
print(e)
imageDir = r'____' # your imagedirectory path
SaveToDir = r'____' # diretory in which you want to save the pdfs
makePdf(imageDir, SaveToDir)
在单个图像上使用它:
From PIL import Image
import os
filename = r"/Desktop/document/dog.png"
im = Image.open(filename)
if im.mode == "RGBA":
im = im.convert("RGB")
new_filename = r"/Desktop/document/dog.pdf"
if not os.path.exists(new_filename):
im.save(new_filename,"PDF",resolution=100.0)
【讨论】:
【参考方案10】:这不是一个真正的新答案,但是 - 使用 img2pdf 时,页面大小不正确。所以这是我使用图像大小所做的,我希望它能找到合适的人:
假设 1) 所有图片大小相同,2) 每页放置一张图片,3) 图片填满整个页面
from PIL import Image
import img2pdf
with open( 'output.pdf', 'wb' ) as f:
img = Image.open( '1.jpg' )
my_layout_fun = img2pdf.get_layout_fun(
pagesize = ( img2pdf.px_to_pt( img.width, 96 ), img2pdf.px_to_pt( img.height, 96 ) ), # this is where image size is used; 96 is dpi value
fit = img2pdf.FitMode.into # I didn't have to specify this, but just in case...
)
f.write( img2pdf.convert( [ '1.jpg', '2.jpg', '3.jpg' ], layout_fun = my_layout_fun ))
【讨论】:
【参考方案11】:如果您的图像是您在 matplotlib 中创建的图,您可以使用 matplotlib.backends.backend_pdf.PdfPages
(See documentation)。
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
# generate a list with dummy plots
figs = []
for i in [-1, 1]:
fig = plt.figure()
plt.plot([1, 2, 3], [i*1, i*2, i*3])
figs.append(fig)
# gerate a multipage pdf:
with PdfPages('multipage_pdf.pdf') as pdf:
for fig in figs:
pdf.savefig(fig)
plt.close()
【讨论】:
PDFPages
是一个罕见的 python
库,真的很好用【参考方案12】:
最佳答案已经存在!!!我只是稍微改进一下答案。 这是代码:
from fpdf import FPDF
pdf = FPDF()
# imagelist is the list with all image filenames you can create using os module by iterating all the files in a folder or by specifying their name
for image in imagelist:
pdf.add_page()
pdf.image(image,x=0,y=0,w=210,h=297) # for A4 size because some people said that every other page is blank
pdf.output("yourfile.pdf", "F")
您需要为此安装 FPDF。
pip install FPDF
【讨论】:
【参考方案13】:这是 ilovecomputer 的答案,它被打包成一个函数并可以直接使用。它还允许减小图像大小并且效果很好。
代码假定 input_dir 中有一个文件夹,其中包含按名称字母顺序排列的图像,并输出一个包含文件夹名称的 pdf 文件,并且可能是名称的前缀字符串。
import os
from PIL import Image
def convert_images_to_pdf(export_dir, input_dir, folder, prefix='', quality=20):
current_dir = os.path.join(input_dir, folder)
image_files = os.listdir(current_dir)
im_list = [Image.open(os.path.join(current_dir, image_file)) for image_file in image_files]
pdf_filename = os.path.join(export_dir, prefix + folder + '.pdf')
im_list[0].save(pdf_filename, "PDF", quality=quality, optimize=True, save_all=True, append_images=im_list[1:])
export_dir = r"D:\pdfs"
input_dir = r"D:\image_folders"
folders = os.listdir(input_dir)
[convert_images_to_pdf(export_dir, input_dir, folder, prefix='') for folder in folders];
【讨论】:
我尝试通过传递不同的resolution
值(如其他答案中所建议)来更改文件大小,但无济于事。 quality
参数起到了作用。
是的,我遇到了同样的问题。【参考方案14】:
受@ilovecomputer 的回答启发,将当前文件夹中的所有 PNG 转换为 PDF 的即用型解决方案:
import glob, PIL.Image
L = [PIL.Image.open(f) for f in glob.glob('*.png')]
L[0].save('out.pdf', "PDF" ,resolution=100.0, save_all=True, append_images=L[1:])
除了 PIL 什么都不需要 :)
【讨论】:
【参考方案15】:如果您的图像处于横向模式,您可以这样做。
from fpdf import FPDF
import os, sys, glob
from tqdm import tqdm
pdf = FPDF('L', 'mm', 'A4')
im_width = 1920
im_height = 1080
aspect_ratio = im_height/im_width
page_width = 297
# page_height = aspect_ratio * page_width
page_height = 200
left_margin = 0
right_margin = 0
# imagelist is the list with all image filenames
for image in tqdm(sorted(glob.glob('test_images/*.png'))):
pdf.add_page()
pdf.image(image, left_margin, right_margin, page_width, page_height)
pdf.output("mypdf.pdf", "F")
print('Conversion completed!')
这里的 page_width 和 page_height 是“A4”纸的尺寸,横向宽度为 297 毫米,高度为 210 毫米;但在这里我已经根据我的图像调整了高度。或者,您可以使用我上面评论的保持纵横比来正确缩放图像的宽度和高度。
【讨论】:
【参考方案16】:命令行界面中的第一个pip install pillow
。
图像可以是 jpg 或 png 格式。如果您有 2 张或更多图片并希望制作 1 个 pdf 文件。
代码:
from PIL import Image
image1 = Image.open(r'locationOfImage1\\Image1.png')
image2 = Image.open(r'locationOfImage2\\Image2.png')
image3 = Image.open(r'locationOfImage3\\Image3.png')
im1 = image1.convert('RGB')
im2 = image2.convert('RGB')
im3 = image3.convert('RGB')
imagelist = [im2,im3]
im1.save(r'locationWherePDFWillBeSaved\\CombinedPDF.pdf',save_all=True, append_images=imagelist)
【讨论】:
【参考方案17】:我知道这是一个老问题。就我而言,我使用 Reportlab。
图纸尺寸以点而不是像素表示,点等于 1/72 英寸。一张 A4 纸由 595.2 磅宽和 841.8 磅高组成。位置坐标 (0, 0) 的原点在左下角。创建 canvas.Canvas 的实例时,您可以使用 pagesize 参数指定工作表的大小,传递一个元组,其第一个元素表示宽度(以磅为单位),第二个元素表示高度。 c.showPage () 方法告诉 ReportLab 它已经完成了当前工作表的工作并继续处理下一个工作表。尽管第二张纸尚未处理(只要没有绘制任何内容就不会出现在文档中),但最好记住在调用 c.save () 之前这样做。要将图像插入 PDF 文档,ReportLab 使用 Pillow 库。 drawImage() 方法的参数是图像的路径(支持PNG、JPEG 和GIF 等多种格式)和要插入的图像中的位置(x,y)。可以通过宽度和高度参数来缩小或放大图像以指示其尺寸。
以下代码提供了 pdf 文件名、png 文件列表、插入图像的坐标以及适合纵向字母页面的大小。
def pntopd(file, figs, x, y, wi, he):
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4, letter, landscape, portrait
w, h = letter
c = canvas.Canvas(str(file), pagesize=portrait(letter))
for png in figs:
c.drawImage(png, x, h - y, width=wi, height=he)
c.showPage()
c.save()
from datetime import date
from pathlib import Path
ruta = "C:/SQLite"
today = date.today()
dat_dir = Path(ruta)
tit = today.strftime("%y%m%d") + '_ParameterAudit'
pdf_file = tit + ".pdf"
pdf_path = dat_dir / pdf_file
pnglist = ['C0.png', 'C4387.png', 'C9712.png', 'C9685.png', 'C4364.png']
pntopd(pdf_path, pnglist, 50, 550, 500, 500)
【讨论】:
【参考方案18】:在 python 3.7 和 img2pdf 版本 0.4.0 中对我有用的是使用与 Syed Shamikh Shabbir 给出的代码类似的东西,但按照 Stu 在对 Syed 的解决方案的评论中建议的那样,使用 OS 更改当前工作目录
import os
import img2pdf
path = './path/to/folder'
os.chdir(path)
images = [i for i in os.listdir(os.getcwd()) if i.endswith(".jpg")]
for image in images:
with open(image[:-4] + ".pdf", "wb") as f:
f.write(img2pdf.convert(image))
值得一提的是,上面的这个解决方案将每个 .jpg 分别保存在一个 pdf 中。如果您希望将所有 .jpg 文件放在一个 .pdf 中,您可以这样做:
import os
import img2pdf
path = './path/to/folder'
os.chdir(path)
images = [i for i in os.listdir(os.getcwd()) if i.endswith(".jpg")]
with open("output.pdf", "wb") as f:
f.write(img2pdf.convert(images))
【讨论】:
【参考方案19】:您可以使用pdfme。它是python中最强大的创建PDF文档的库。
from pdfme import build_pdf
...
pdf_image_list = ["image": img for img in images]
with open('images.pdf', 'wb') as f:
build_pdf("sections": ["content": pdf_image_list])
查看文档here
【讨论】:
【参考方案20】:添加到@ilovecomputer 的答案,如果您想将 pdf 保存在内存中而不是磁盘中,那么您可以这样做:
import io
from pdf2image import convert_from_bytes
pil_images = convert_from_bytes(original_pdf_bytes, dpi=100) # (OPTIONAL) do this if you're converting a normal pdf to images first and then back to only image pdf
pdf_output = io.BytesIO()
pil_images[0].save(pdf_output, "PDF", resolution=100.0, save_all=True, append_images=pil_images[1:])
pdf_bytes = pdf_output.getvalue()
【讨论】:
以上是关于从图像列表创建 PDF的主要内容,如果未能解决你的问题,请参考以下文章
如何使用图像的 tesseract 输出从另一个图像创建可搜索的 pdf
使用 Ghostscript 从单个 JPG 文件创建 PDF - PDF 中的图像放置问题