使用 Flask 和 pdfkit 生成带透明 PNG 盖章的 PDF 并上传到阿里云 OSS

在现代 Web 开发中,生成 PDF 文档并在其上添加盖章是常见的需求。本文将详细介绍如何使用 Flask 框架和 pdfkit 库来批量生成 PDF,并在其中添加透明 PNG 盖章,最后将生成的 PDF 上传到阿里云 OSS(对象存储服务)。

环境准备

首先,确保您的开发环境中已安装以下依赖:

bash 复制代码
pip install Flask pdfkit Pillow PyPDF2 aliyun-oss2

此外,您还需要安装 wkhtmltopdf,这是 pdfkit 的依赖。根据您的操作系统选择安装方式:

  • Ubuntu:

    bash 复制代码
    sudo apt-get install wkhtmltopdf
  • CentOS:

    bash 复制代码
    sudo yum install wkhtmltopdf

项目结构

以下是 Flask 应用的基本结构:

复制代码
/your_project
│
├── app.py               # 主应用文件
├── uploads              # 存放生成的 PDF 文件
└── stamp.png            # 透明 PNG 盖章文件

确保将您的透明 PNG 盖章文件放在项目目录中。

Flask 应用代码

以下是完整的 Flask 应用代码,包含生成 PDF、添加盖章以及上传到 OSS 的功能:

python 复制代码
from flask import Flask, request, jsonify, send_file
import pdfkit
import os
from PIL import Image
from werkzeug.utils import secure_filename
import oss2

app = Flask(__name__)

# 设置上传文件的目录
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

# OSS 配置
OSS_ACCESS_KEY_ID = 'your_access_key_id'
OSS_ACCESS_KEY_SECRET = 'your_access_key_secret'
OSS_ENDPOINT = 'your_oss_endpoint'  # 例如 'oss-cn-region.aliyuncs.com'
OSS_BUCKET_NAME = 'your_bucket_name'

# 初始化 OSS 客户端
auth = oss2.Auth(OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET)
bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUCKET_NAME)

# PDF 生成函数
def create_pdf(html_content, output_path):
    pdfkit.from_string(html_content, output_path)

# 加盖章函数
def add_stamp_to_pdf(pdf_path, stamp_path, output_path):
    from PyPDF2 import PdfWriter, PdfReader

    stamp = Image.open(stamp_path)
    stamp.save('temp_stamp.pdf', "PDF")

    with open(pdf_path, "rb") as pdf_file, open('temp_stamp.pdf', "rb") as stamp_file:
        pdf_reader = PdfReader(pdf_file)
        stamp_reader = PdfReader(stamp_file)
        writer = PdfWriter()

        for page in pdf_reader.pages:
            page.merge_page(stamp_reader.pages[0])
            writer.add_page(page)

        with open(output_path, "wb") as output_file:
            writer.write(output_file)

# 上传文件到 OSS
def upload_to_oss(file_path, object_name):
    bucket.put_object_from_file(object_name, file_path)

@app.route('/generate_pdf', methods=['POST'])
def generate_pdf():
    data = request.get_json()
    if not data or 'html_content' not in data:
        return jsonify({"error": "Invalid input"}), 400

    html_content = data['html_content']
    stamp_path = data.get('stamp_path')  # 可选盖章路径
    filename = secure_filename('output.pdf')
    output_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)

    try:
        create_pdf(html_content, output_path)
        if stamp_path:
            output_path_with_stamp = os.path.join(app.config['UPLOAD_FOLDER'], 'stamped_' + filename)
            add_stamp_to_pdf(output_path, stamp_path, output_path_with_stamp)
            # 上传到 OSS
            upload_to_oss(output_path_with_stamp, 'pdfs/' + filename)
            return send_file(output_path_with_stamp, as_attachment=True)
        # 上传到 OSS
        upload_to_oss(output_path, 'pdfs/' + filename)
        return send_file(output_path, as_attachment=True)
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route('/batch_generate', methods=['POST'])
def batch_generate():
    data = request.get_json()
    if not data or 'html_contents' not in data:
        return jsonify({"error": "Invalid input"}), 400

    output_files = []
    stamp_path = data.get('stamp_path')  # 可选盖章路径
    for index, html_content in enumerate(data['html_contents']):
        filename = secure_filename(f'output_{index}.pdf')
        output_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        
        try:
            create_pdf(html_content, output_path)
            if stamp_path:
                output_path_with_stamp = os.path.join(app.config['UPLOAD_FOLDER'], 'stamped_' + filename)
                add_stamp_to_pdf(output_path, stamp_path, output_path_with_stamp)
                # 上传到 OSS
                upload_to_oss(output_path_with_stamp, 'pdfs/' + filename)
                output_files.append(output_path_with_stamp)
            else:
                # 上传到 OSS
                upload_to_oss(output_path, 'pdfs/' + filename)
                output_files.append(output_path)
        except Exception as e:
            return jsonify({"error": f"Failed to generate PDF {index}: {str(e)}"}), 500

    return jsonify({"message": "PDFs generated and uploaded to OSS", "files": output_files}), 200

if __name__ == '__main__':
    app.run(debug=True)

代码解析

1. 环境设置

在代码中设置了上传文件的目录,并确保该目录存在。

2. OSS 配置

配置阿里云 OSS 的访问密钥和存储桶信息,并初始化 OSS 客户端。

3. PDF 生成函数

使用 pdfkit 从 HTML 内容生成 PDF 文件。

4. 加盖章函数

使用 Pillow 加载透明 PNG 盖章,并使用 PyPDF2 将其添加到生成的 PDF 上。

5. 上传文件到 OSS

创建 upload_to_oss 函数,将生成的 PDF 文件上传到阿里云 OSS。

6. API 端点

  • /generate_pdf:接收单个 HTML 内容和可选的盖章 PNG 路径,生成 PDF 并上传到 OSS。
  • /batch_generate:接收多个 HTML 内容和可选的盖章 PNG 路径,批量生成 PDF 并上传到 OSS。

使用示例

生成单个 PDF

/generate_pdf 发送 POST 请求,包含 HTML 内容和可选的 PNG 图片路径:

json 复制代码
{
    "html_content": "<h1>Hello, World!</h1>",
    "stamp_path": "path/to/stamp.png"
}

批量生成 PDF

/batch_generate 发送 POST 请求,包含多个 HTML 内容和可选的 PNG 图片路径:

json 复制代码
{
    "html_contents": [
        "<h1>Document 1</h1>",
        "<h1>Document 2</h1>"
    ],
    "stamp_path": "path/to/stamp.png"
}

注意事项

  • 安全性:妥善管理您的 OSS 密钥信息,避免在公共代码中暴露。
  • OSS 权限:确保您的阿里云 OSS 存储桶具有相应的权限,以允许上传和访问文件。

总结

通过使用 Flask、pdfkit、透明 PNG 图片和阿里云 OSS,您可以轻松地生成带有盖章的 PDF 文档,并将其上传到云端存储。这种方法在处理大量文档时特别有用,可以有效提高工作效率。

相关推荐
weixin_453066371 小时前
使用阿里云创建公司官网(使用wordpress)
阿里云·wordpress
码农的救赎1 小时前
阿里云ECS访问不了
阿里云·云计算
一一Null3 小时前
Access Token 和 Refresh Token 的双令牌机制,维持登陆状态
android·python·安全·flask
zyk_5204 小时前
前端渲染pdf文件解决方案
javascript·pdf·react
XINVRY-FPGA9 小时前
XC6SLX100T-2FGG484I 赛灵思 XilinxFPGA Spartan-6
c++·人工智能·嵌入式硬件·阿里云·ai·fpga开发·fpga
小希与阿树10 小时前
阿里云RAM账号免密登录Java最佳实践
java·数据库·阿里云
Sherlock Ma10 小时前
基于LightRAG进行本地RAG部署(包括单卡多卡本地模型部署、调用阿里云或DeepSeekAPI的部署方法、RAG使用方法)
人工智能·阿里云·大模型·aigc·检索增强·rag·deepseek
Freddy_Ssc10 小时前
ESP32之阿里云IoT物模型通信(MQTT-TLS连接通信),基于VSCode环境下的ESP-IDF开发(附源码)
vscode·物联网·阿里云·esp32·物模型
网络风云14 小时前
Flask(补充内容)配置SSL 证书 实现 HTTPS 服务
python·https·flask·ssl