根据图像列表创建 PDF

有没有什么实际的方法可以使用 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模块,但我想要一些简单的。

187966 次浏览

安装 FPDF 的 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")

你可以找到更多的信息 在教程页面正式文件

Pgmagick 是 Python 的 GraphicsMagick(Magick++)绑定。

它是用于 图像魔术(或 图形魔术)的 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:

enter image description here

PDF looks like this:

enter image description here

窗口的安装说明:

1) Download precompiled binary packages from the 用于 Python 扩展包的非官方 Windows 二进制文件 (as mentioned in the pgmagick web page) and install it.

注: 尝试下载与您的机器上安装的 python 版本相对应的正确版本,以及它的32位安装还是64位安装。

您可以检查是否有32位或64位 python,只需在终端键入 python,然后按 Enter。

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. exe

2)然后你可以按照 这里的安装说明。

pip install pgmagick

An then try to import it.

>>> from pgmagick import gminfo
>>> gminfo.version
'1.3.x'
>>> gminfo.library
'GraphicsMagick'
>>>

这个怎么样?

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")

从文件所在的目录中创建 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)

如果使用 Python3,则可以使用 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")))

我也有同样的问题,所以我创建了一个 python 函数来将多张图片合并到一个 pdf 中。代码(可从 我的 Github 主页获得,使用 reportlab,并基于以下链接的答案:

下面是如何将图片合并成 pdf 的例子:

我们有文件夹“ D: 图片”与类型的图片 png 和 jpg,我们想创建文件 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)

到目前为止,将多个图像转换成 PDF 的最佳方法是纯粹使用 PIL。它很简单,但是很强大:

from PIL import Image  # install by > python3 -m pip install --upgrade Pillow  # ref. https://pillow.readthedocs.io/en/latest/installation.html#basic-installation


images = [
Image.open("/Users/apple/Desktop/" + f)
for f in ["bbd.jpg", "bbd1.jpg", "bbd2.jpg"]
]


pdf_path = "/Users/apple/Desktop/bbd1.pdf"
    

images[0].save(
pdf_path, "PDF" ,resolution=100.0, save_all=True, append_images=images[1:]
)

只需将 save_all设置为 True,将 append_images设置为要添加的图像列表。

您可能会遇到 AttributeError: 'JpegImageFile' object has no attribute 'encoderinfo'。解决方案是这里的 将多个 JPEG 文件保存为多页 PDF 时出错

注意: 安装最新的 PIL,以确保 save_all参数可用于 PDF。

附言。

以防出现这个错误

无法保存模式 RGBA

应用 解决这个问题

png = Image.open('/path/to/your/file.png')
png.load()
background = Image.new("RGB", png.size, (255, 255, 255))
background.paste(png, mask=png.split()[3]) # 3 is the alpha channel
**** 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")

我知道这个问题已经有了答案,但是还有一个解决方法就是使用枕头图书馆。 转换整个图像目录:

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)

这不是一个真正新的答案,但-当使用 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 ))

如果您的图像是使用 matplotlib 创建的图形,则可以使用 matplotlib.backends.backend_pdf.PdfPages(请参阅文档)。

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()

最好的答案已经存在了! ! ! 我只是稍微改进了一下答案。 密码是这样的:

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

这里是我的电脑的答案打包成一个函数,直接使用。它还允许减少图像大小和工作良好。

该代码假设 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];

随时可用的解决方案,将当前文件夹中的所有 PNG 转换成 PDF,灵感来自@iloveccomputer 的回答:

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:])

只需要私人投资公司:)

如果您的图像是在横向模式,您可以这样做。

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!')

Here page_width and page_height is the size of 'A4' paper where in landscape its width will 297mm and height will be 210mm; but here I have adjusted the height as per my image. OR you can use either maintaining the aspect ratio as I have commented above for proper scaling of both width and height of the image.

命令行接口中的第一个 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)

我知道这是一个古老的问题。在我的情况下,我使用报告实验室。

纸张尺寸以点表示,而不是以像素表示,点等于1/72英寸。A4纸由595.2点宽和841.8点高组成。位置坐标(0,0)的原点在左下角。创建画布实例时。画布,您可以使用 pagesize 参数指定工作表的大小,传递一个元组,该元组的第一个元素表示点的宽度,第二个元素表示高度。 ShowPage ()方法告诉 ReportLab 它已经完成了对当前工作表的处理,并继续处理下一个工作表。尽管第二张工作表尚未处理(只要没有绘制任何内容,它就不会出现在文档中) ,但是在调用 c.save ()之前记住这样做是一个很好的实践。要将图像插入到 PDF 文档中,ReportLab 使用枕头库。DraImage ()方法将图像的路径(支持多种格式,如 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)

在 python 3.7和 img2pdf 0.4.0版本中,我使用的是与 Syed Shamikh Shabbir 给出的代码类似的东西,但是按照 Stu 在对 Syed 的解决方案的评论中建议的那样,使用操作系统改变了当前的工作目录

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

值得一提的是,上面提到的这个解决方案可以节省每一个。在一个单独的 pdf 格式的 jpg。如果你想要你所有的。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))

你可以使用 你好。它是 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}]})

检查 给你号文件

添加到@iloveccomputer 的回答中,如果你想把 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()

在我的情况下,需要转换超过100个不同格式的图像(有和没有 alpha 通道和不同的扩展)。

I tried all the recepts from answers to this question.

Pil = > 不能与 alpha 通道或不能与 alpha 通道组合(neet 用于转换图像)

fpdf => stack on lots of images

在 Gotenberg 中使用 html 打印 = > 极其漫长的处理过程

我最后一次尝试是报告实验室。而且效果又好又快。(但有时在大输入上产生损坏的 pdf)。这是我的密码

from PyPDF2 import PdfMerger
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.platypus import Image, PageBreak, Paragraph, SimpleDocTemplate


async def save_report_lab_story_to_pdf(file_name, story):
doc = SimpleDocTemplate(
file_name,
pagesize=letter,
rightMargin=32,
leftMargin=32,
topMargin=18,
bottomMargin=18,
)
doc.build(story)




async def reportlab_pdf_builder(data, images):
story = []
width = 7.5 * inch
height = 9 * inch


chunk_size = 5 * 70
pdf_chunks = []


files_to_clean_up = []
for trip in data['trips']:
for invoice in trip['invoices']:
for page in invoice['pages']:
if trip['trip_label']:
story.append(Paragraph(
f"TRIP: {trip['trip_label']} {trip['trip_begin']} - {trip['trip_end']}"
))
else:
story.append(Paragraph("No trip"))


story.append(Paragraph(
f"""Document number: {invoice['invoice_number']}
Document date: {invoice['document_date']}
Amount: {invoice['invoice_trip_value']} {invoice['currency_code']}
"""
))
story.append(Paragraph(" "))
img_name = page['filename']
img_bytes = images[page['path']]
tmp_img_filename = f'/tmp/{uuid.uuid4()}.{img_name}'
with open(tmp_img_filename, "wb") as tmp_img:
tmp_img.write(img_bytes)
im = Image(tmp_img_filename, width, height)
story.append(im)
story.append(PageBreak())
files_to_clean_up.append(tmp_img_filename)
# 5 objects per page in story


if len(story) >= chunk_size:
file_name = f"/tmp/{uuid.uuid4()}_{data['tail_number']}.pdf"
await save_report_lab_story_to_pdf(file_name, story)
story = []
pdf_chunks.append(file_name)


merger = PdfMerger()
for pdf in pdf_chunks:
merger.append(pdf)


res_file_name = f"/tmp/{uuid.uuid4()}_{data['tail_number']}.pdf"
merger.write(res_file_name)
merger.close()