基于Python实现向指定PDF指定页面指定位置插入图片的方法

 更新时间:2025年09月02日 08:44:13   作者:Ratten  
这篇文章主要介绍了使用Python批量为PDF添加虚拟章的方法,通过ReportLab创建覆盖层并结合PyPDF2实现精准合并,确保不破坏原有分辨率和文字可识别性,同时支持位置自定义与参数调整,需要的朋友可以参考下

1. 需求

  1. 想要能否实现批量自动为多个pdf加盖不同六格虚拟章(不改变pdf原有分辨率和文字可识别性);
  2. 改在pdf首页上方空白位置,一般居中即可;
  3. 如可由使用者自主选择靠页边距更好,以便部分首页上方有字的文件时人工可微调位置。

2. 需求分析

  1. 直接将 pdf 文件转换为图片,在将图片绘制到对应页的对应位置,最后将全部图片在转换为 pdf 文件;
  2. 使用 reportlab 创建一个 pdf 页,然后将图片插入到对应位置;
  3. 使用 PyPDF2 将 reportlab 创建的含有图片 pdf 和目标页面进行合并。

3. 实现效果

4. 方案选择

  1. 由于要求不改变pdf原有分辨率和文字可识别性,因此就不能将 pdf 转图片,因为进行此步操作后,重新生成的 pdf 不能进行文字可识别性;
  2. 所以采用方案二 reportlab 配合 PyPDF2 完成需求的实现。

5. 设置插入图片宽高

  1. init 默认插入图片的宽高;
  2. reset_image_width_and_height 方法提供修改插入图片宽高的方法。
  def __init__(self):
    self.image_width = int(237 * 0.6)
    self.image_height = int(60 * 0.8)

  # 设置图片的宽高
  def reset_image_width_and_height(self, w, h):
    self.image_width = w
    self.image_height = h

6. 创建 pdf 插入图片

  1. 创建一个 BytesIO 对象;
  2. Canvas 类是 ReportLab PDF 创建工具包的核心,它提供了一个画布,你可以在上面绘制文本、图形、图像等,以生成 PDF 文档;
  3. 创建一个 Canvas 对象,指定 packet 和页面大小;
  4. drawImage 方法插入图像;
  5. 调用 save() 方法将绘制的内容保存到 packet 对象中;
  6. packet.seek(0) 将文件指针移动到 BytesIO 对象的开头;
  7. 使用 PdfReader 读取 pdf 文件,并将第一页返回。
  # 创建一个PDF页面,并在其中放置图片
  def create_overlay(self, image_path, x_pos, y_pos, page_width, page_height):
    packet = io.BytesIO()
    can = canvas.Canvas(packet, pagesize=(page_width, page_height))
    can.drawImage(image_path, x_pos, y_pos, width=self.image_width, height=self.image_height)  # 图片位置和大小
    can.save()
    packet.seek(0)
    overlay = PdfReader(packet)
    return overlay.pages[0]

7. 合并插入图片的 pdf 页到目标 pdf

  1. 读取原始PDF文件【需要插入图片的 pdf】;
  2. 创建一个PDF writer对象;
  3. 遍历PDF的每一页,找到目标页面;
  4. 获取当前页面对象;
  5. 判断当前页是否是目标页面;
  6. 计算图片的插入位置;
  7. 调用 create_overlay 创建一个插入图片的 pdf 页面对象;
  8. 将 create_overlay 返回的页面通过 merge_page 合并到当前 page;
  9. 将每一个循环的 page 通过 add_page 添加到第二步中创建的 writer 对象中;
  10. 判断输出路径是否存在,然后写入 pdf。
  # 将创建的覆盖层合并到目标PDF的指定页面
  def merge_image_to_pdf(self, input_pdf_path, output_pdf_path, image_path, page_number, x_pos, y_pos):
    # 读取原始PDF文件
    original_pdf = PdfReader(open(input_pdf_path, "rb"))
    # 创建一个PDF writer对象
    pdf_writer = PdfWriter()
    # 遍历PDF的每一页
    for page_num in range(len(original_pdf.pages)):
      page = original_pdf.pages[page_num]
      if page_number == page_num:
        # 计算距离
        left_distance = int((page.mediabox.width - self.image_width) / 2 + x_pos)
        top_distance = int((page.mediabox.height - self.image_height) - y_pos)

        overlay = self.create_overlay(image_path, left_distance, top_distance, page.mediabox.width, page.mediabox.height)
        page.merge_page(overlay)
      pdf_writer.add_page(page)

    # 写入修改后的PDF
    with open(output_pdf_path, "wb") as out_file:
      pdf_writer.write(out_file)

8. 调用

  1. 初始化 InsertImageToPDF;
  2. 调用插入图片的方法 merge_image_to_pdf;
  3. 将图片 【"./out_images/pdf.png"】插入pdf 【"./pdf/pdf-1/pdf-1.pdf"】,输出路径【"./out_images/pdf.png"】;
  4. 【0, 0, 10】插入第几页,图片距离左侧边距,图片距离顶部边距。
if __name__ == "__main__":
  pdf = InsertImageToPDF()
  # 使用函数
  pdf.merge_image_to_pdf(
    "./pdf/pdf-1/pdf-1.pdf", 
    "./out_pdf/pdf-1.pdf", 
    "./out_images/pdf.png", 
    0, 0, 10)

9. 运行结果

10. 完整代码

  1. 引入所需使用的库 reportlab, PyPDF2, io;
  2. 初始化插入图片的宽高,设置图片的宽高的函数;
  3. 创建一个PDF页面,并在其中放置图片;
  4. 将创建的覆盖层合并到目标PDF的指定页面。
from reportlab.pdfgen import canvas
from PyPDF2 import PdfWriter, PdfReader
import io

class InsertImageToPDF:
  def __init__(self):
    self.image_width = int(237 * 0.6)
    self.image_height = int(60 * 0.8)

  # 设置图片的宽高
  def reset_image_width_and_height(self, w, h):
    self.image_width = w
    self.image_height = h

  # 创建一个PDF页面,并在其中放置图片
  def create_overlay(self, image_path, x_pos, y_pos, page_width, page_height):
    packet = io.BytesIO()
    can = canvas.Canvas(packet, pagesize=(page_width, page_height))
    can.drawImage(image_path, x_pos, y_pos, width=self.image_width, height=self.image_height)  # 图片位置和大小
    can.save()
    packet.seek(0)
    overlay = PdfReader(packet)
    return overlay.pages[0]

  # 将创建的覆盖层合并到目标PDF的指定页面
  def merge_image_to_pdf(self, input_pdf_path, output_pdf_path, image_path, page_number, x_pos, y_pos):
    # 读取原始PDF文件
    original_pdf = PdfReader(open(input_pdf_path, "rb"))
    # 创建一个PDF writer对象
    pdf_writer = PdfWriter()
    # 遍历PDF的每一页
    for page_num in range(len(original_pdf.pages)):
      page = original_pdf.pages[page_num]
      if page_number == page_num:
        # 计算距离
        left_distance = int((page.mediabox.width - self.image_width) / 2 + x_pos)
        top_distance = int((page.mediabox.height - self.image_height) - y_pos)

        overlay = self.create_overlay(image_path, left_distance, top_distance, page.mediabox.width, page.mediabox.height)
        page.merge_page(overlay)
      pdf_writer.add_page(page)

    # 写入修改后的PDF
    with open(output_pdf_path, "wb") as out_file:
      pdf_writer.write(out_file)

if __name__ == "__main__":
  pdf = InsertImageToPDF()
  # 使用函数
  pdf.merge_image_to_pdf(
    "./pdf/pdf-1/pdf-1.pdf", 
    "./out_pdf/pdf-1.pdf", 
    "./out_images/pdf.png", 
    0, 0, 10)

11. 总结

  1. 实现同一个需求的方法和技术很多,我们需要选择最接近需求的方案;
  2. 技术尽量选择自己熟悉的,或者曾经实现或者学习过的技术,能够更快开发;
  3. 尽量多的接触更多的技术,直到每种技术之间的优劣势。

以上就是基于Python实现向指定PDF指定页面指定位置插入图片的方法的详细内容,更多关于Python向指定PDF指定位置插入图片的资料请关注脚本之家其它相关文章!

相关文章

  • Python 如何反方向迭代一个序列

    Python 如何反方向迭代一个序列

    这篇文章主要介绍了Python 如何反方向迭代一个序列,文中讲解非常细致,代码帮助大家更好理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • Python利用Flask-Mail实现发送邮件详解

    Python利用Flask-Mail实现发送邮件详解

    Flask 的扩展包 Flask - Mail 通过包装了 Python 内置的smtplib包,可以用在 Flask 程序中发送邮件。本文将利用这特性实现邮件发送功能,感兴趣的可以了解一下
    2022-08-08
  • python内置函数zip详解

    python内置函数zip详解

    这篇文章主要为大家介绍了python内置函数zip,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • Django CSRF验证失败请求被中断的问题

    Django CSRF验证失败请求被中断的问题

    这篇文章主要介绍了Django CSRF验证失败请求被中断的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • 利用Python将社交网络进行可视化

    利用Python将社交网络进行可视化

    这篇文章介绍了利用Python将社交网络进行可视化,主要是一些Python的第三方库来进行社交网络的可视化,利用领英(Linkedin)的社交关系数据展开介绍,内容可当学习练习题有一定的参考价值,需要的小伙伴可以参考一下
    2022-06-06
  • django 修改server端口号的方法

    django 修改server端口号的方法

    今天小编就为大家分享一篇django 修改server端口号的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-05-05
  • python 列表推导式使用详解

    python 列表推导式使用详解

    这篇文章主要介绍了python 列表推导式使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • django inspectdb 操作已有数据库数据的使用步骤

    django inspectdb 操作已有数据库数据的使用步骤

    这篇文章主要介绍了django inspectdb 操作已有数据库数据的使用步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • Python tkinter模块弹出窗口及传值回到主窗口操作详解

    Python tkinter模块弹出窗口及传值回到主窗口操作详解

    这篇文章主要介绍了Python tkinter模块弹出窗口及传值回到主窗口操作,结合实例形式分析了Python使用tkinter模块实现的弹出窗口及参数传递相关操作技巧,需要的朋友可以参考下
    2017-07-07
  • Python正则表达式的小练习分享

    Python正则表达式的小练习分享

    为了让大家更进一步了解Python中的正则表达式使用,本文为大家分享了三个正则表达式使用小练习,感兴趣的小伙伴可以学习一下
    2022-04-04

最新评论