手把手零门槛搭建支持下载加水印的轻量档案系统

前期准备

1. 安装Docker和Docker Compose

我们用Docker快速搭建环境,避免繁琐的依赖配置。

  • Windows/macOS用户:直接下载Docker Desktop安装包,地址为https://www.docker.com/products/docker-desktop/,安装后启动并确保右下角托盘Docker图标显示为绿色。
  • Linux(Ubuntu/Debian)用户:依次执行以下命令:
```bash 更新软件源 sudo apt update 安装依赖包 sudo apt install -y ca-certificates curl gnupg lsb-release 添加Docker官方GPG密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg 设置Docker稳定版仓库 echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 再次更新软件源并安装Docker sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 启动Docker服务 sudo systemctl start docker sudo systemctl enable docker ```

2. 准备项目目录

在任意位置创建项目文件夹,命名为watermark-archive,然后进入该文件夹,后续操作都在此目录下进行。

  • Windows/macOS用户:右键新建文件夹,重命名后双击进入。
  • Linux用户:执行命令mkdir watermark-archive && cd watermark-archive

核心配置文件

1. 配置docker-compose.yml

该文件定义我们的两个核心服务:MinIO(轻量对象存储,作为档案存储载体)和Watermark-Service(我们自己写的轻量下载水印添加服务)。在项目目录下新建docker-compose.yml,复制以下内容:

```yaml version: '3.8' services: minio: image: minio/minio:latest container_name: watermark-minio restart: always ports: - "9000:9000" MinIO管理后台/API端口 - "9001:9001" MinIO Web Console端口 environment: MINIO_ROOT_USER: admin 管理员账号(自定义) MINIO_ROOT_PASSWORD: admin123456 管理员密码(自定义,至少8位) volumes: - ./minio-data:/data 档案数据持久化到本地 command: server /data --console-address ":9001" watermark-service: image: python:3.11-slim 基础Python镜像 container_name: watermark-api restart: always ports: - "5000:5000" 水印服务API端口 volumes: - ./app:/app 映射本地代码到容器 working_dir: /app command: > bash -c "pip install --no-cache-dir -r requirements.txt && python app.py" depends_on: - minio ```

2. 创建Python代码目录和文件

在项目目录下新建app子文件夹,然后在app中创建3个文件:requirements.txt(依赖包列表)、app.py(核心业务逻辑)、config.py(参数配置)。

requirements.txt

复制以下内容:

``` minio==7.2.10 flask==3.0.3 Pillow==10.3.0 python-dotenv==1.0.1 ```

config.py

复制以下内容,注意替换MINIO_ROOT_PASSWORD为你在docker-compose.yml中设置的密码:

```python import os MinIO配置 MINIO_ENDPOINT = 'minio:9000' MINIO_ACCESS_KEY = 'admin' MINIO_SECRET_KEY = 'admin123456' MINIO_BUCKET_NAME = 'archives' MINIO_SECURE = False 本地测试不需要HTTPS 水印配置 WATERMARK_TEXT = os.getenv('WATERMARK_TEXT', '内部资料 请勿外传') 可通过环境变量修改 WATERMARK_FONT_SIZE = int(os.getenv('WATERMARK_FONT_SIZE', 36)) WATERMARK_OPACITY = float(os.getenv('WATERMARK_OPACITY', 0.2)) 0-1,0完全透明,1完全不透明 WATERMARK_ANGLE = int(os.getenv('WATERMARK_ANGLE', 30)) WATERMARK_COLOR = tuple(map(int, os.getenv('WATERMARK_COLOR', '128,128,128').split(','))) RGB格式 Flask配置 FLASK_HOST = '0.0.0.0' FLASK_PORT = 5000 ```

app.py

手把手零门槛搭建支持下载加水印的轻量档案系统

复制以下内容,这是完整的带水印下载服务代码:

```python from flask import Flask, send_file, request, abort from minio import Minio from minio.error import S3Error from PIL import Image, ImageDraw, ImageFont from io import BytesIO import os from config import app = Flask(__name__) 初始化MinIO客户端 minio_client = Minio( MINIO_ENDPOINT, access_key=MINIO_ACCESS_KEY, secret_key=MINIO_SECRET_KEY, secure=MINIO_SECURE ) 创建默认存储桶(如果不存在) def create_bucket_if_not_exists(): try: if not minio_client.bucket_exists(MINIO_BUCKET_NAME): minio_client.make_bucket(MINIO_BUCKET_NAME) print(f"存储桶 {MINIO_BUCKET_NAME} 创建成功") except S3Error as e: print(f"存储桶操作失败: {e}") 添加图片水印 def add_image_watermark(image_data, username): img = Image.open(BytesIO(image_data)).convert('RGBA') width, height = img.size 准备水印文本 text = f"{WATERMARK_TEXT}\n用户: {username}\n时间: {request.remote_addr}" if username else WATERMARK_TEXT 尝试加载系统字体,失败则用默认 try: if os.name == 'nt': font = ImageFont.truetype('C:/Windows/Fonts/simhei.ttf', WATERMARK_FONT_SIZE) else: font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', WATERMARK_FONT_SIZE) except IOError: font = ImageFont.load_default() 创建水印图层 watermark_layer = Image.new('RGBA', img.size, (255, 255, 255, 0)) draw = ImageDraw.Draw(watermark_layer) 计算文本尺寸(兼容Pillow 9.2.0+的getbbox) bbox = draw.textbbox((0, 0), text, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] 平铺水印 step_x = text_width + 100 step_y = text_height + 100 for y in range(-text_height, height + step_y, step_y): for x in range(-text_width, width + step_x, step_x): 旋转单个水印 rotated_text = Image.new('RGBA', (text_width + 20, text_height + 20), (255, 255, 255, 0)) rotated_draw = ImageDraw.Draw(rotated_text) rotated_draw.text((10, 10), text, font=font, fill=(WATERMARK_COLOR, int(255 WATERMARK_OPACITY))) rotated_text = rotated_text.rotate(WATERMARK_ANGLE, expand=1) 计算旋转后的左上角坐标 rw, rh = rotated_text.size watermark_layer.paste(rotated_text, (x - rw//2, y - rh//2), rotated_text) 合并原图和水印 result = Image.alpha_composite(img, watermark_layer).convert('RGB') output = BytesIO() result.save(output, format=img.format if img.format else 'JPEG') output.seek(0) return output 下载档案接口 @app.route('/download/', methods=['GET']) def download_file(filename): username = request.args.get('username', 'unknown') try: 从MinIO获取文件 response = minio_client.get_object(MINIO_BUCKET_NAME, filename) file_data = BytesIO(response.read()) file_ext = filename.split('.')[-1].lower() 判断是否为图片(支持JPG/PNG/GIF/BMP/TIFF) if file_ext in ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff']: output = add_image_watermark(file_data.getvalue(), username) return send_file(output, download_name=filename, as_attachment=True) else: 非图片文件直接返回(可后续扩展PDF/Word水印) return send_file(file_data, download_name=filename, as_attachment=True) except S3Error as e: if e.code == 'NoSuchKey': abort(404, description="文件不存在") else: abort(500, description=f"MinIO错误: {e}") if __name__ == '__main__': create_bucket_if_not_exists() app.run(host=FLASK_HOST, port=FLASK_PORT, debug=False) ```

启动系统

回到watermark-archive项目根目录,打开终端(Windows用PowerShell/CMD,macOS/Linux用Terminal),执行以下命令:

```bash docker-compose up -d ```

等待1-2分钟,直到两个容器都启动完成,可通过docker-compose ps查看状态,当STATUS列显示Up时表示成功。

上传档案并测试带水印下载

1. 登录MinIO Web Console

在浏览器中访问http://你的服务器IP:9001(本地测试用http://localhost:9001),输入在docker-compose.yml中设置的MINIO_ROOT_USERMINIO_ROOT_PASSWORD登录。

2. 上传测试档案

登录后点击左侧菜单的Buckets,找到自动创建的archives存储桶,点击进入后点击右上角Upload按钮,选择一张图片(如test.jpg)上传。

3. 测试带水印下载

在浏览器地址栏输入:http://你的服务器IP:5000/download/test.jpg?username=张三(本地用http://localhost:5000/download/test.jpg?username=张三),按下回车即可下载带有“内部资料 请勿外传\n用户: 张三\n时间: [你的IP]”水印的图片。

后续优化说明

  • 修改水印样式:可通过修改config.py中的参数或在docker-compose.ymlwatermark-service服务下添加environment字段覆盖环境变量(修改后需执行docker-compose restart watermark-service生效)。
  • 扩展PDF水印:可使用PyPDF2pdfplumber库添加PDF水印,只需在app.pydownload_file函数中新增PDF判断分支即可。
  • 权限控制:可接入简单的Token验证或MinIO的IAM权限,防止未授权下载。
AI咨询
热线电话

028-85154420

15388110056

全国售前咨询电话

扫码咨询
安答联动微信公众号二维码

微信扫码关注安答联动

申请试用
热线电话
申请试用

安答联动档案管理系统