【DuodooBMS】给PDF附件加“受控”水印的完整Python实现

打印 上一主题 下一主题

主题 1952|帖子 1952|积分 5856

给PDF附件加“受控”水印的完整Python实现

功能需求
在实际工作中,许多文件需要添加水印以标识其状态,比方“受控”“秘密”等。对于PDF文件,添加水印不仅可以增强文件的可识别性,还可以防止未经授权的使用。本代码的功能需求是:

  • 修复PDF文件:在添加水印之前,确保PDF文件是完整且可读的,避免因文件损坏导致操纵失败。
  • 添加水印:在PDF的每一页上添加指定的水印图像或笔墨,水印可以设置位置、角度和透明度。
  • 生存输出:将添加水印后的PDF文件生存到指定路径,并返回其二进制数据以便后续处理。

实现过程

  • 修复PDF文件

    • 使用PyMuPDF库打开PDF文件,并实验修复。如果文件损坏,PyMuPDF可以实验修复并生存为一个新的二进制流。
    • 如果修复失败,则直接返回原始的PDF二进制数据。
    Python复制
    1. def repair_pdf(self, input_pdf_binary):
    2.     try:
    3.         # 使用 PyMuPDF 打开并修复 PDF
    4.         doc = fitz.open(stream=input_pdf_binary, filetype="pdf")
    5.         repaired_pdf_binary = BytesIO()
    6.         doc.save(repaired_pdf_binary)
    7.         doc.close()
    8.         repaired_pdf_binary.seek(0)
    9.         return repaired_pdf_binary.read()
    10.     except Exception as e:
    11.         print(f"Error repairing PDF: {e}")
    12.         return input_pdf_binary
    复制代码

  • 添加水印

    • 使用reportlab库创建一个临时的PDF文件作为水印。水印可以是图像或笔墨,支持设置位置、角度和透明度。
    • 使用PyPDF2库将水印PDF与原始PDF合并。通过merge_page方法,将水印添加到每一页。
    Python复制
    1. def add_watermark(self, input_pdf_binary, output_pdf, watermark_image, x_position=30, y_position=50, opacity=1):
    2.     # 尝试修复 PDF
    3.     repaired_pdf_binary = self.repair_pdf(input_pdf_binary)
    4.     input_pdf_obj = PdfReader(BytesIO(repaired_pdf_binary))  # 从二进制数据中读取 PDF
    5.     output_pdf_obj = PdfWriter()
    6.     output_buffer = BytesIO()
    7.     # 创建一个临时的 PDF 作为水印
    8.     page_width, page_height = A4[1], A4[0]
    9.     c = canvas.Canvas(output_buffer, pagesize=(page_width, page_height))
    10.     try:
    11.         c.setFillColor(colors.white)  # 将背景设置为白色
    12.         c.setFillColor(colors.red)  # 设置字体颜色为红色
    13.         c.setFont("Helvetica", 12)  # 设置字体和字体大小
    14.         c.setFillAlpha(opacity)  # 设置透明度
    15.         c.setStrokeColor(colors.transparent)  # 设置笔触颜色为透明
    16.         img = ImageReader(watermark_image)
    17.         if x_position is not None and y_position is not None:
    18.             c.saveState()
    19.             c.translate(x_position, y_position)
    20.             c.rotate(20)
    21.             c.drawImage(img, 0, 0, width=60, height=25)
    22.             c.restoreState()
    23.         else:
    24.             x = (page_width - 60) / 2
    25.             y = (page_height - 25) / 2
    26.             c.saveState()
    27.             c.translate(x, y)
    28.             c.rotate(20)
    29.             c.drawImage(img, 0, 0, width=60, height=25)
    30.             c.restoreState()
    31.     except Exception as e:
    32.         raise ValueError(f"Error drawing image: {e}")
    33.     c.showPage()
    34.     c.save()
    35.     # 将水印 PDF 与原始 PDF 合并
    36.     watermark_pdf = PdfReader(output_buffer)
    37.     for page in input_pdf_obj.pages:
    38.         page.merge_page(watermark_pdf.pages[0])
    39.         output_pdf_obj.add_page(page)
    40.     # 保存输出 PDF
    41.     final_output_buffer = BytesIO()
    42.     output_pdf_obj.write(final_output_buffer)
    43.     binary_data = final_output_buffer.getvalue()
    44.     with open(output_pdf, 'wb') as f:
    45.         output_pdf_obj.write(f)
    46.     return binary_data
    复制代码

  • 调用示例

    • 准备一个PDF文件和一个水印图像文件。
    • 调用add_watermark方法,指定输入PDF、输出路径、水印图像路径等参数。
    Python复制
    1. if __name__ == "__main__":
    2.     from io import BytesIO
    3.     from PyPDF2 import PdfReader, PdfWriter
    4.     from reportlab.pdfgen import canvas
    5.     from reportlab.lib.pagesizes import A4
    6.     from reportlab.lib import colors
    7.     from reportlab.lib.utils import ImageReader
    8.     import fitz
    9.     class WatermarkPDF:
    10.         def repair_pdf(self, input_pdf_binary):
    11.             try:
    12.                 doc = fitz.open(stream=input_pdf_binary, filetype="pdf")
    13.                 repaired_pdf_binary = BytesIO()
    14.                 doc.save(repaired_pdf_binary)
    15.                 doc.close()
    16.                 repaired_pdf_binary.seek(0)
    17.                 return repaired_pdf_binary.read()
    18.             except Exception as e:
    19.                 print(f"Error repairing PDF: {e}")
    20.                 return input_pdf_binary
    21.         def add_watermark(self, input_pdf_binary, output_pdf, watermark_image, x_position=30, y_position=50, opacity=1):
    22.             repaired_pdf_binary = self.repair_pdf(input_pdf_binary)
    23.             input_pdf_obj = PdfReader(BytesIO(repaired_pdf_binary))
    24.             output_pdf_obj = PdfWriter()
    25.             output_buffer = BytesIO()
    26.             page_width, page_height = A4[1], A4[0]
    27.             c = canvas.Canvas(output_buffer, pagesize=(page_width, page_height))
    28.             try:
    29.                 c.setFillColor(colors.white)
    30.                 c.setFillColor(colors.red)
    31.                 c.setFont("Helvetica", 12)
    32.                 c.setFillAlpha(opacity)
    33.                 c.setStrokeColor(colors.transparent)
    34.                 img = ImageReader(watermark_image)
    35.                 if x_position is not None and y_position is not None:
    36.                     c.saveState()
    37.                     c.translate(x_position, y_position)
    38.                     c.rotate(20)
    39.                     c.drawImage(img, 0, 0, width=60, height=25)
    40.                     c.restoreState()
    41.                 else:
    42.                     x = (page_width - 60) / 2
    43.                     y = (page_height - 25) / 2
    44.                     c.saveState()
    45.                     c.translate(x, y)
    46.                     c.rotate(20)
    47.                     c.drawImage(img, 0, 0, width=60, height=25)
    48.                     c.restoreState()
    49.             except Exception as e:
    50.                 raise ValueError(f"Error drawing image: {e}")
    51.             c.showPage()
    52.             c.save()
    53.             watermark_pdf = PdfReader(output_buffer)
    54.             for page in input_pdf_obj.pages:
    55.                 page.merge_page(watermark_pdf.pages[0])
    56.                 output_pdf_obj.add_page(page)
    57.             final_output_buffer = BytesIO()
    58.             output_pdf_obj.write(final_output_buffer)
    59.             binary_data = final_output_buffer.getvalue()
    60.             with open(output_pdf, 'wb') as f:
    61.                 output_pdf_obj.write(f)
    62.             return binary_data
    63.     # 示例调用
    64.     watermark_pdf = WatermarkPDF()
    65.     with open("example.pdf", "rb") as f:
    66.         input_pdf_binary = f.read()
    67.     watermark_image = "watermark.png"
    68.     output_pdf = "output_with_watermark.pdf"
    69.     watermark_pdf.add_watermark(input_pdf_binary, output_pdf, watermark_image)
    复制代码

实现总结
本代码通过PyMuPDF修复PDF文件,使用reportlab创建水印PDF,并通过PyPDF2将水印合并到原始PDF中。整个过程支持自界说水印的位置、角度和透明度,可以或许灵活地满足差别场景的需求。代码结构清晰,易于扩展和维护,得当在实际项目中使用。
 
让转型不迷航——邹工转型手札
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

知者何南

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表