Pillow PSDraw 模块

下面给你一个 Pillow(PIL Fork)中 PSDraw 模块 的完整入门指南,包含 PostScript 文档生成、文字/图形绘制、页面设置、嵌入图像、PDF 替代方案、打印机输出等高级应用。
(基于 Pillow ≥ 9.0,Python 3.8+)


1. 安装 Pillow

pip install --upgrade pillow

2. 基本导入

from PIL import Image
from PIL.PSDraw import PSDraw

3. PSDraw 模块概述

PSDraw 是 Pillow 的 PostScript 绘图接口,用于生成 .ps(PostScript)文件,可:

  • 绘制文字、线条、矩形、多边形
  • 嵌入图像(灰度、RGB)
  • 设置页面大小、边距、字体
  • 输出高质量矢量文档
  • 替代 PDF(轻量级矢量格式)

适用场景

  • 打印标签 / 票据
  • 生成矢量报告
  • 嵌入图像的矢量文档
  • 跨平台打印

4. 基础用法:Hello World

# 打开图像(可选)
img = Image.open("photo.jpg")

# 创建 A4 页面(595x842 点,1点=1/72英寸)
ps = PSDraw.PSDraw()  # 默认 A4

# 设置字体(需系统支持)
ps.setfont("Helvetica", 24)

# 绘制文字
ps.text((100, 700), "Hello PostScript!")

# 绘制线条
ps.line([(100, 650), (500, 650)])

# 绘制矩形
ps.rectangle((100, 550), (500, 600))

# 嵌入图像(缩放到 200x150)
img_resized = img.resize((200, 150)).convert("L")  # 灰度更快
ps.image((100, 350), img_resized, dpi=72)

# 结束文档
ps.end()

输出到文件:

with open("output.ps", "wb") as f:
    ps = PSDraw(f)
    # ... 绘制代码 ...

5. 完整示例:带图像的 A4 海报

from PIL import Image, PSDraw
import os

def create_poster(image_path, output_ps="poster.ps"):
    img = Image.open(image_path).convert("RGB")

    with open(output_ps, "wb") as f:
        # A4: 595 x 842 点
        ps = PSDraw(f, size=(595, 842))

        # 页眉
        ps.setfont("Helvetica-Bold", 36)
        ps.text((50, 780), "Pillow PSDraw 示例")

        # 副标题
        ps.setfont("Helvetica", 18)
        ps.text((50, 740), "矢量 + 图像混合文档")

        # 嵌入图像(居中)
        img_thumb = img.resize((400, 300))
        x = (595 - 400) // 2
        ps.image((x, 380), img_thumb)

        # 页脚
        ps.setfont("Helvetica-Oblique", 14)
        ps.text((50, 50), f"生成时间: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M')}")

        # 边框
        ps.setlinewidth(2)
        ps.rectangle((30, 30), (565, 812))  # 留边距

        ps.end()

    print(f"PostScript 已生成: {output_ps}")

create_poster("photo.jpg")

6. 页面设置与字体

方法说明
PSDraw(psfile, size=None)设置页面大小(点)
setfont(name, size)设置字体和大小
setlinewidth(width)设置线宽
setfill(color)设置填充色(0=黑, 1=白)

常用页面尺寸(点)

格式尺寸
A4(595, 842)
A5(420, 595)
Letter(612, 792)
4×6 英寸照片(288, 432)

7. 绘图方法详解

方法示例
text((x,y), "text")文字
line([(x1,y1), (x2,y2)])折线
rectangle((x1,y1), (x2,y2))矩形
polygon([(x1,y1), ...])多边形
image((x,y), pil_img)嵌入图像
ps.setfill(0.5)  # 50% 灰度填充
ps.rectangle((100, 100), (200, 150))

8. 多页文档

def create_multipage_ps():
    with open("multi.ps", "wb") as f:
        ps = PSDraw(f)

        for page in range(1, 4):
            if page > 1:
                ps.newpage()  # 插入新页

            ps.setfont("Helvetica", 36)
            ps.text((200, 400), f"第 {page} 页")

            # 嵌入不同图像
            img = Image.new("RGB", (200, 150), f"hsl({page*90},100%,50%)")
            ps.image((180, 200), img)

        ps.end()

create_multipage_ps()

9. 高级应用

9.1 生成条形码标签(配合 python-barcode

pip install python-barcode[images]
from barcode import Code128
from barcode.writer import ImageWriter
from io import BytesIO

def barcode_label(code, output_ps="label.ps"):
    # 生成条形码图像
    barcode_img = Code128(code, writer=ImageWriter()).render()
    barcode_img = barcode_img.convert("L")

    with open(output_ps, "wb") as f:
        ps = PSDraw(f, size=(288, 432))  # 4x6 英寸

        # 条形码
        ps.image((44, 200), barcode_img.resize((200, 100)))

        # 文字
        ps.setfont("Helvetica", 16)
        ps.text((44, 170), code)

        ps.end()

barcode_label("1234567890")

9.2 批量打印名牌

def print_name_tags(names, output_ps="nametags.ps"):
    with open(output_ps, "wb") as f:
        ps = PSDraw(f, size=(288, 180))  # 4x2.5 英寸

        for i, name in enumerate(names):
            if i > 0 and i % 4 == 0:
                ps.newpage()

            x = 50 + (i % 2) * 150
            y = 100 if i % 4 < 2 else 50

            ps.setfont("Helvetica-Bold", 24)
            ps.text((x, y), name)

        ps.end()

print_name_tags(["张三", "李四", "王五", "赵六"])

10. 输出为 PDF(借助 Ghostscript)

# 安装 Ghostscript
# Windows: https://www.ghostscript.com/download/
# macOS: brew install ghostscript
# Linux: sudo apt install ghostscript
import subprocess

def ps_to_pdf(ps_file, pdf_file):
    subprocess.run([
        "gs", "-dBATCH", "-dNOPAUSE", "-q",
        "-sDEVICE=pdfwrite",
        f"-sOutputFile={pdf_file}",
        ps_file
    ])

ps_to_pdf("poster.ps", "poster.pdf")

11. 性能与限制

项目说明
图像仅支持灰度/RGB,不支持 RGBA
字体依赖系统 PostScript 字体
透明度不支持
性能矢量快,图像慢(建议 < 300dpi)

12. 常见问题

问题解决
字体显示为 Courier使用标准字体:Helvetica, Times-Roman, Courier
图像不显示转换为 LRGB
文件打不开检查是否以 wb 模式写入
中文乱码PostScript 不支持中文,需嵌入图像

13. 官方文档

  • https://pillow.readthedocs.io/en/stable/reference/PSDraw.html

一键工具脚本:psdraw_tool.py

#!/usr/bin/env python3
import argparse
from PIL import Image, PSDraw

def main():
    parser = argparse.ArgumentParser(description="PSDraw 快速生成器")
    parser.add_argument("-i", "--image", help="嵌入图像")
    parser.add_argument("-t", "--text", default="Hello PSDraw!", help="文字内容")
    parser.add_argument("-o", "--output", default="output.ps", help="输出 PS 文件")

    args = parser.parse_args()

    with open(args.output, "wb") as f:
        ps = PSDraw(f)
        ps.setfont("Helvetica", 24)
        ps.text((100, 700), args.text)

        if args.image:
            img = Image.open(args.image).convert("RGB").resize((300, 200))
            ps.image((100, 400), img)

        ps.end()

    print(f"已生成: {args.output}")

if __name__ == "__main__":
    main()

使用

python psdraw_tool.py -i photo.jpg -t "我的海报" -o my.ps

总结:PSDraw 核心优势

优势说明
矢量输出无限放大不失真
轻量级.ps 文件小
打印友好直接发打印机
嵌入图像混合文档

需要我帮你实现 发票打印系统、证件照排版、矢量图表生成、批量标签打印 等完整项目吗?直接说需求,我给你完整可运行代码!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注