📅 系列:一起学Python | 难度:⭐⭐ | 预计阅读:8分钟
🔗 上期回顾:第121天:Pillow 隐藏技能
前面四天,我们把 Pillow 拆成了碎片学习:打开、裁剪、缩放、滤镜、增强、水印……但真正工作中,这些操作是串在一起的。
比如老板给你一个任务:"把这张产品图裁成正方形、缩成800×800、调亮一点、加个Logo水印、保存为PNG。"
如果你只会单个操作,就要写一堆零散代码。今天这期,我们把 Pillow 的核心基础操作串成一条流水线——从打开到成品,一气呵成。
from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhancefrom io import BytesIOimport requestsimport os# ================= 1. 字体加载(解决报错的核心) =================font_path = "simhei.ttf" # 确保当前目录有 simhei.ttfif not os.path.exists(font_path):font_path = "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc" # 备用系统字体# Pillow 使用 ImageFont.truetype 加载font = ImageFont.truetype(font_path, size=24)# 通用加载函数:从网络URL读取图片def load_image(url):resp = requests.get(url, timeout=15)return Image.open(BytesIO(resp.content)).convert('RGB')
url = "https://picsum.photos/600/600"img = load_image(url)print(f"格式: {img.format}") # JPEG / PNG / GIFprint(f"尺寸: {img.size}") # (宽, 高)print(f"模式: {img.mode}") # RGB / RGBA / L(灰度)
format | 'JPEG'、 | |
size | (800, 600)→ 宽800,高600 | |
mode | RGBRGBA(带透明)、L(灰度) |
convert('RGB')?网络图片可能是 RGBA 或 P 模式,统一转 RGB 避免后续处理报错。# 转灰度gray = img.convert('L')gray.show()# 转回 RGB(灰度图转彩色,但仍是黑白)rgb_back = gray.convert('RGB')rgb_back.show()# 保存为不同格式img.save("output.png") # 自动识别格式img.save("output.jpg", quality=95) # JPEG 控制质量img.save("output.webp", quality=85) # WebP 更小体积
# crop((左, 上, 右, 下))cropped = img.crop((150, 150, 450, 450))cropped.show()
# 旋转45度,expand=True 扩展画布防止裁剪rotated = img.rotate(45, expand=True)rotated.show()
crop((left, upper, right, bottom)),先左上角,后右下角。# 方法1:resize —— 强制指定尺寸(可能变形)resized = img.resize((300, 300)) # 原图600x600 → 强行拉成300x300# 方法2:thumbnail —— 保持比例,原地修改thumb = img.copy()thumb.thumbnail((300, 300)) # 按比例缩放,长边不超过300
resize((w,h)) | ||
thumbnail((w,h)) |
from PIL import ImageFilterblur = img.filter(ImageFilter.GaussianBlur(radius=5))edge = img.filter(ImageFilter.FIND_EDGES)emboss = img.filter(ImageFilter.EMBOSS)sharpen = img.filter(ImageFilter.SHARPEN)
from PIL import ImageEnhancebright = ImageEnhance.Brightness(img).enhance(1.5) # 亮度 x1.5contrast = ImageEnhance.Contrast(img).enhance(2.0) # 对比度 x2.0color = ImageEnhance.Color(img).enhance(2.0) # 饱和度 x2.0sharp = ImageEnhance.Sharpness(img).enhance(2.5) # 锐度 x2.5
1.0 = 原图,<1 = 减弱,>1 = 增强。建议范围 0.5 ~ 2.5。# 创建画笔draw = ImageDraw.Draw(img)# 绘制形状draw.rectangle([50, 50, 200, 200], outline="red", width=5)draw.line([0, 0, 300, 300], fill="blue", width=3)draw.ellipse([250, 250, 450, 450], outline="green", width=4)# 添加文字(必须加载中文字体!)font = ImageFont.truetype(font_path, size=40)draw.text((50, 50), "Hello Pillow", fill="red", font=font)draw.text((50, 500), "第122天", fill="yellow", font=font)
把以上所有步骤串起来,写一个完整的图像处理函数:
from PIL import Image, ImageDraw, ImageFont, ImageEnhancefrom io import BytesIOimport requestsimport os# ================= 1. 字体加载(解决报错的核心) =================font_path = "simhei.ttf"if not os.path.exists(font_path):font_path = "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"font = ImageFont.truetype(font_path, size=20)def process_pipeline(url, output_path):"""图像处理流水线:下载 → 裁剪 → 缩放 → 调亮 → 加水印 → 保存"""# Step 1: 下载resp = requests.get(url, timeout=15)img = Image.open(BytesIO(resp.content)).convert('RGB')print(f"原图: {img.size}")# Step 2: 居中裁剪为正方形w, h = img.sizesize = min(w, h)left = (w - size) // 2top = (h - size) // 2img = img.crop((left, top, left + size, top + size))print(f"裁剪后: {img.size}")# Step 3: 缩放到 800x800img = img.resize((800, 800), Image.LANCZOS)# Step 4: 调亮 20%enhancer = ImageEnhance.Brightness(img)img = enhancer.enhance(1.2)# Step 5: 加水印draw = ImageDraw.Draw(img)text = "一起学Python"bbox = draw.textbbox((0, 0), text, font=font)text_w = bbox[2] - bbox[0]text_h = bbox[3] - bbox[1]x = img.width - text_w - 20y = img.height - text_h - 20draw.rectangle([x-10, y-5, x+text_w+10, y+text_h+5], fill=(0, 0, 0, 128))draw.text((x, y), text, fill="white", font=font)# Step 6: 保存img.save(output_path, quality=95)print(f"✅ 已保存: {output_path}")# 显示结果img.show()# 使用process_pipeline("https://picsum.photos/1000/800", "final_output.jpg")

import globdef batch_process(url_list, output_dir="output"):os.makedirs(output_dir, exist_ok=True)for i, url in enumerate(url_list):try:process_pipeline(url, f"{output_dir}/img_{i+1}.jpg")except Exception as e:print(f"处理失败 {url}: {e}")# 批量处理urls = [f"https://picsum.photos/800/600?random={i}" for i in range(5)]batch_process(urls)

from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance# 打开网络图片import requestsfrom io import BytesIOimg = Image.open(BytesIO(requests.get(url).content)).convert('RGB')# 信息print(img.format, img.size, img.mode)# 转换img.convert('L') # 灰度img.convert('RGB') # 彩色# 裁剪与旋转img.crop((l, u, r, b))img.rotate(angle, expand=True)# 缩放img.resize((w, h)) # 强制尺寸img.thumbnail((max_w, max_h)) # 保持比例# 滤镜img.filter(ImageFilter.GaussianBlur(radius=5))img.filter(ImageFilter.FIND_EDGES)# 增强ImageEnhance.Brightness(img).enhance(1.5)ImageEnhance.Contrast(img).enhance(2.0)# 绘图draw = ImageDraw.Draw(img)draw.text((x, y), "文字", fill="red", font=font)draw.rectangle([x1, y1, x2, y2], outline="blue", width=3)# 保存img.save("output.jpg", quality=95)
今天我们把 Pillow 的基础操作串成了一条完整的流水线:
✅ 打开 —— Image.open() + convert('RGB')
✅ 读取信息 —— format、size、mode
✅ 格式转换 —— convert() + save()
✅ 裁剪 —— crop((left, upper, right, bottom))
✅ 旋转 —— rotate(angle, expand=True)
✅ 缩放 —— resize() vs thumbnail()
✅ 滤镜 —— ImageFilter 系列
✅ 增强 —— ImageEnhance 系列
✅ 绘图 —— ImageDraw + ImageFont
✅ 流水线 —— 裁 → 缩 → 调 → 印 → 存
关键记忆:Pillow 的日常工作流 = 打开 → 裁剪构图 → 缩放尺寸 → 调色滤镜 → 加水印 → 保存交付。
