WaterMarker - pdf 文件水印添加工具

写在前面

  • 昨天想给 pdf 添加个水印,结果 wps 居然需要收费,果断选择写一个 pdf 文件水印添加工具
  • 本工具能够自适应的为 pdf 文件每页添加水印
  • 本工具完全由 Python 编写,支持脚本运行和编译器内执行
  • 同时支持如下自定义
    • 水印文字 (text)
    • 水印透明度 (alpha)
    • 水印字体 (font)
    • 水印字体大小 (size)
    • 水印旋转角度 (angle)

编写环境

  • Python: 3.7.0
  • pypdf2: 3.0.1
  • reportlab: 3.6.12

核心代码分析

创建水印函数
  • 函数的签名如下
def create_watermark(content, width, height, args)
  • 函数需传入四个参数
    • content: 水印文字
    • width: pdf 当前页的宽
    • height: pdf 当前页的高
    • args: 命令行参数
  • 为了自适应 pdf 每页,使得在不同大小的页面添加水印时均能够以合适的大小添加水印文字
  • 代码中计算了当前页面与标准 A4 页面宽高的比例
# 比例,用于自适应 pdf 页面大小
width = float(width) * 0.0352
height = float(height) * 0.0352
ratio_w = width / 21
ratio_h = height / 29.7
  • 并在设置字体字号和绘制文本部分对相应数值进行修正
# 设置字体,默认采用 SimSun 字体
c.setFont(args.font, args.size * (ratio_w + ratio_h) / 2)

# 画几个文本,注意坐标系旋转的影响
for i in range(5):
    for j in range(10):
        # 使用 比例 自适应水印文字位置
        a = 10 * (i - 1) * ratio_w
        b = 5 * (j - 2) * ratio_h
        c.drawString(a * cm, b * cm, content)
添加水印函数
  • 函数的签名如下
def add_watermark(pdf_file_in, pdf_file_out, args)
  • 函数需传入三个参数

    • pdf_file_in: 需添加水印文件的路径
    • pdf_file_out: 添加水印后文件的输出路径
    • args: 命令行参数
  • 使用 pypdf2 库中的 PdfWriter 类创建 pdf 文件写出对象

  • 根据 pdf_file_in 读取 pdf 文件,并使用 PdfReader 类创建 pdf 文件对象

pdf_output = PdfWriter()
input_stream = open(pdf_file_in, 'rb')
pdf_input = PdfReader(input_stream, strict=False)
  • 对每一页 pdf 分别添加水印
  • 每次获取每页的实际宽高,与前一页对比,若不一致则重新根据当前页面生成水印文件
# 给每一页打水印
for i in range(pageNum):
    page = pdf_input.pages[i]
    # 获取当前页面实际宽高
    width = pdf_input.pages[i].mediabox.width
    height = pdf_input.pages[i].mediabox.height
    if width != last_width or height != last_height:
        pdf_file_mark = create_watermark(watermark_text, width, height, args)  # 生成水印文件
        pdf_watermark = PdfReader(open(pdf_file_mark, 'rb'), strict=False)  # 读入水印pdf文件
        last_width = width
        last_height = height
    page.merge_page(pdf_watermark.pages[0])
    page.compress_content_streams()  # 压缩内容
    pdf_output.add_page(page)
pdf_output.write(open(pdf_file_out, 'wb'))
主函数
  • 为实现脚本方式执行,使用 argparse 库定义命令行解析器对象并添加命令行参数
# 定义命令行解析器对象
parser = argparse.ArgumentParser(description='WaterMarker of argparse')

# 添加命令行参数
parser.add_argument('--text', default='watermark', help="Text to add watermark")
parser.add_argument('-F', '--file', default='', help="The path to the file to add the watermark to")
parser.add_argument('--font', default='SimSun', help="Font used for watermark text")
parser.add_argument('--size', type=int, default=30, help="Font size used for watermark text, defaults to 30, "
                                                         "the size will adjust itself as the page changes")
parser.add_argument('--alpha', type=float, default=0.1, help="Transparency of watermark text, between 0.0 and 1.0")
parser.add_argument('--angle', type=int, default=30, help="Rotate the canvas by the angle theta (in degrees)")
parser.add_argument('-O', '--output', default='', help="File output path after adding watermark (including the "
                                                       "file name), the default is the original file directory")

# 从命令行中结构化解析参数
args = parser.parse_args()
  • 对命令行参数进行分析,以避免用户重复输入水印文字或者需添加水印的 pdf 文件
# 检查命令行参数 text 的值是否为默认值,是则要求用户输入水印文字,若用户输入空,则采用命令行参数的默认值
# 若命令行参数的值不为默认值,则跳过用户输入水印文字
text = ''
if args.text == 'watermark':
    text = input("请输入水印文字:")
watermark_text = args.text if text == '' else text

# 处理方式与上类似
pdf_file_in = ''
if args.file == '':
    pdf_file_in = input("请输入文件路径:").strip('"').strip(' ')
else:
    pdf_file_in = args.file
  • 同时对文件进行了限制,以确保传入文件为 pdf 格式
if os.path.splitext(pdf_file_in)[-1] == ".pdf":
     pdf_file_in = pdf_file_in.replace('\\', '/')
     # 文件输出路径
     if args.output == '':
         pdf_file_out = pdf_file_in.replace('.pdf', '') + '(添加水印).pdf'
     else:
         pdf_file_out = args.output.replace('\\', '/')
     add_watermark(pdf_file_in, pdf_file_out, args)
     print("添加水印成功")
     print("文件路径为: {}".format(pdf_file_out.replace('/', '\\')))
 else:
     print("输入文件不为pdf格式!!!")

使用案例

  • 由于支持使用脚本运行,以下内容将重点介绍脚本执行方式
脚本具体参数如下
optional arguments:
  -h, --help            show this help message and exit
  --text TEXT           Text to add watermark
  -F FILE, --file FILE  The path to the file to add the watermark to
  --font FONT           Font used for watermark text
  --size SIZE           Font size used for watermark text, defaults to 30, the
                        size will adjust itself as the page changes
  --alpha ALPHA         Transparency of watermark text, between 0.0 and 1.0
  --angle ANGLE         Rotate the canvas by the angle theta (in degrees)
  -O OUTPUT, --output OUTPUT
                        File output path after adding watermark (including the
                        file name), the default is the original file directory
具体案例
  • 以下为具体使用案例,其中除 -F-O 参数外均为默认值
  • 若未使用 --text-F 参数将会要求用户手动输入
python watermarker.py --text "WaterMarker" -F "C:\test.pdf" --font "SimSun" --alpha 0.1 --size 30 --angle 30 -O "./result.pdf"

写在最后

  • 感谢大家阅读和使用,本工具源码已上传至 github
  • 本工具采用 GPL2 开源协议,详细内容参见 协议
  • 若有更好的想法或者任何疑问,欢迎评论,或前往 github 提交 issue,或通过邮件 huang_wen_huan@163.com 联系我,我将及时更新和回复
  • 文章已同步至我的 个人博客
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
可以使用Python的第三方库 PyPDF2 来实现PDF文档的格式转换、合并、拆分、页面旋转和加水印等操作。具体的代码实现如下: 1. 安装 PyPDF2 使用 pip 命令安装 PyPDF2: ``` pip install PyPDF2 ``` 2. 实现PDF格式转化 使用 PyPDF2 将 PDF 文件转换为 Word 文件: ```python import os import docx from pdf2docx import Converter def pdf_to_docx(pdf_path, docx_path): cv = Converter(pdf_path) cv.convert(docx_path, start=0, end=None) cv.close() ``` 使用 PyPDF2 将 Word 文件转换为 PDF 文件: ```python import os import win32com.client def docx_to_pdf(docx_path, pdf_path): word = win32com.client.Dispatch('Word.Application') doc = word.Documents.Open(docx_path) doc.SaveAs(pdf_path, FileFormat=17) doc.Close() word.Quit() ``` 3. 实现PDF文件的合并 使用 PyPDF2 将多个 PDF 文件合并成一个 PDF 文件: ```python import os from PyPDF2 import PdfFileMerger def pdf_merger(input_paths, output_path): merger = PdfFileMerger() for path in input_paths: merger.append(path) with open(output_path, 'wb') as fileobj: merger.write(fileobj) ``` 4. 实现PDF文件的拆分 使用 PyPDF2 将一个 PDF 文件拆分成多个 PDF 文件: ```python import os from PyPDF2 import PdfFileReader, PdfFileWriter def pdf_splitter(input_path, output_paths): pdf_reader = PdfFileReader(input_path) for i in range(pdf_reader.getNumPages()): pdf_writer = PdfFileWriter() pdf_writer.addPage(pdf_reader.getPage(i)) output_path = output_paths[i] with open(output_path, 'wb') as fileobj: pdf_writer.write(fileobj) ``` 5. 实现PDF页面旋转 使用 PyPDF2 旋转一个 PDF 文件的所有页面: ```python import os from PyPDF2 import PdfFileReader, PdfFileWriter def pdf_rotator(input_path, output_path, rotation): pdf_reader = PdfFileReader(input_path) pdf_writer = PdfFileWriter() for i in range(pdf_reader.getNumPages()): page = pdf_reader.getPage(i) page.rotateClockwise(rotation) pdf_writer.addPage(page) with open(output_path, 'wb') as fileobj: pdf_writer.write(fileobj) ``` 6. 实现PDF页面增加水印 使用 PyPDF2 在一个 PDF 文件的所有页面上增加水印: ```python import os from PyPDF2 import PdfFileReader, PdfFileWriter from reportlab.pdfgen import canvas def pdf_watermarker(input_path, output_path, text): pdf_reader = PdfFileReader(input_path) pdf_writer = PdfFileWriter() c = canvas.Canvas('watermark.pdf') c.setFont('Helvetica', 80) c.setFillColorRGB(0.5, 0.5, 0.5) c.rotate(45) c.drawString(200, 50, text) c.save() watermark_reader = PdfFileReader('watermark.pdf') watermark = watermark_reader.getPage(0) for i in range(pdf_reader.getNumPages()): page = pdf_reader.getPage(i) page.mergePage(watermark) pdf_writer.addPage(page) with open(output_path, 'wb') as fileobj: pdf_writer.write(fileobj) ``` 注意事项: 1. 此处的代码示例仅供参考,具体实现方法有所差异,需要根据实际情况进行调整。 2. PDF 文件的操作涉及到很多细节问题,尤其是当存在特殊的 PDF 文件时,可能需要使用其他的 Python 第三方库来实现。 3. 如果需要支持更多的 PDF 功能,建议使用更为强大的 Python 第三方库,如 PyMuPDF 等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鞠杉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值