如何将ImageMagick convert的-gravity与-extent转为Python/PIL实现
将ImageMagick的
convert命令转换为PIL脚本:实现-gravity center和-extent 200x200功能 问题背景
我正在尝试将使用ImageMagick的convert命令的Shell脚本转换为Python/PIL脚本。
原Shell脚本如下:
convert \ -resize 25% \ +repage \ -background white -quality 95 \ -flatten \ -gravity center \ -extent 200x200 \ img_a.png img_b.jpg
我已完成部分转换,代码如下:
# Paths img_a_png_filepath = '/foo/bar/img_a.png' img_a_name = Path(img_a_png_filepath).stem img_b_name = f'{img_a_name}.jpg' img_b_jpg_filepath = f'/foo/bar/{img_b_name}' # Converting to JPEG img_a_png = Image.open(img_a_png_filepath) # -background white white_bg = Image.new('RGBA',img_a_png.size ,(255, 255, 255, 255)) white_bg.paste(img_a_png, (0, 0), img_a_png) white_bg = white_bg.convert('RGB') white_bg.save(img_b_name, 'JPEG') # -resize 25% img_b_jpg = Image.open(img_b_jpg_filepath) img_b_jpg = img_b_jpg.resize((img_b_jpg.size[0]*0.25, img_b_jpg.size[0]*0.25)) img_b_jpg.save(img_b_name, 'JPEG')
我猜测原脚本通过-gravity center和-extent 200x200实现居中裁剪,但不知道如何在PIL中实现这两个参数的功能,请求帮助。
解决方案
首先明确:ImageMagick的-gravity center+-extent 200x200不是单纯裁剪,而是将缩放后的图像居中放置在200x200的白色画布上——如果缩放后图像尺寸小于200x200,就补白;如果大于,则居中裁剪到200x200。
另外你当前的代码有冗余(无需存成JPEG再重新打开),可以优化流程一步完成所有操作:
完整代码
from PIL import Image from pathlib import Path # 路径处理 img_a_png_filepath = '/foo/bar/img_a.png' img_a_name = Path(img_a_png_filepath).stem img_b_jpg_filepath = f'/foo/bar/{img_a_name}.jpg' # 打开原图并处理 with Image.open(img_a_png_filepath) as img: # 1. 按25%缩放(用整数运算避免尺寸小数,LANCZOS滤镜保证缩放质量) width, height = img.size scaled_size = (int(width * 0.25), int(height * 0.25)) scaled_img = img.resize(scaled_size, Image.Resampling.LANCZOS) # 2. 替换透明背景为白色(对应-flatten和-background white) if img.mode in ('RGBA', 'LA'): white_bg = Image.new('RGB', scaled_size, (255, 255, 255)) white_bg.paste(scaled_img, mask=scaled_img.split()[-1]) scaled_img = white_bg else: scaled_img = scaled_img.convert('RGB') # 3. 实现-gravity center + -extent 200x200 target_w, target_h = 200, 200 final_img = Image.new('RGB', (target_w, target_h), (255, 255, 255)) if scaled_img.width > target_w or scaled_img.height > target_h: # 图像过大,居中裁剪到目标尺寸 crop_left = (scaled_img.width - target_w) // 2 crop_top = (scaled_img.height - target_h) // 2 cropped_img = scaled_img.crop((crop_left, crop_top, crop_left + target_w, crop_top + target_h)) final_img.paste(cropped_img, (0, 0)) else: # 图像过小,计算居中偏移量后粘贴 offset_x = (target_w - scaled_img.width) // 2 offset_y = (target_h - scaled_img.height) // 2 final_img.paste(scaled_img, (offset_x, offset_y)) # 4. 保存为JPEG,对应-quality 95 final_img.save(img_b_jpg_filepath, 'JPEG', quality=95)
关键步骤说明
- 缩放处理:使用
Image.Resampling.LANCZOS滤镜匹配ImageMagick默认的高质量缩放,同时用整数运算避免尺寸出现小数问题。 - 背景替换:针对带透明通道的图像,通过
paste的mask参数保留原图像的透明区域,实现-flatten的效果。 - 居中+Extent逻辑:
- 若缩放后图像大于200x200:计算居中裁剪坐标,裁剪后直接覆盖到目标画布。
- 若缩放后图像小于200x200:计算中心偏移量,将图像粘贴到画布中心,周围自动补白。
- 保存参数:
save时指定quality=95,对应ImageMagick的-quality 95。
内容的提问来源于stack exchange,提问作者Moraes
相关产品推荐
相关产品推荐

