【问题标题】:Create PDF from a list of images从图像列表创建 PDF
【发布时间】: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 分支和活跃项目。
  • 图片大小不同怎么办?

标签: python pdf


【解决方案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 pageofficial 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.exe

2) 然后您可以按照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()
                            

                            【讨论】:

                              猜你喜欢
                              • 2020-09-18
                              • 1970-01-01
                              • 2013-07-25
                              • 2012-01-11
                              • 2012-07-17
                              • 1970-01-01
                              • 2014-12-25
                              • 2020-01-03
                              相关资源
                              最近更新 更多