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 |
| 图像不显示 | 转换为 L 或 RGB |
| 文件打不开 | 检查是否以 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 文件小 |
| 打印友好 | 直接发打印机 |
| 嵌入图像 | 混合文档 |
需要我帮你实现 发票打印系统、证件照排版、矢量图表生成、批量标签打印 等完整项目吗?直接说需求,我给你完整可运行代码!