人生苦短我用Python 剪裁图片
前言
最近裁切图片,却没有趁手工具,手动剪裁的图片忽大忽小,总是差强人意。
想起曾经用过ImageMagick
批量剪裁图片,决定减少简单而繁琐的手动操作,通过命令行程序来批量处理。另外,Python
可以很方便调用cmd
命令,那么不如Python
与imagemagick
相结合,来完成批量剪裁图片的目标。
需求
将指定一个目录下的所有图片(如png
格式),按照剪裁的区域(左上角起始位置像素,宽度和高度)进行批量剪裁,将剪裁后的文件保存到另一个目录下。即剪裁的参数如下:
- 输入目录
- 输出目录
- 剪裁区域:X偏移量,Y偏移量,宽度和高度
准备工作
- 安装
ImageMagick
,了解剪裁的命令。 - 了解
python
如何执行cmd
命令。 - 了解
python
如何获取命令行参数。
ImageMagick的安装与使用
ImageMagick主要用于图像编辑和转换,如调整大小、裁剪、旋转、格式转换等。提供命令行工具和库,方便脚本化和自动化。它具有如下功能和特点:支持基本的图像处理功能,如调整大小、裁剪、旋转、格式转换等。支持多种图像格式,包括常见的 JPEG、PNG、GIF、BMP 等。提供丰富的图像效果和滤镜。跨平台,支持多种编程语言(C、C++、Perl、Python、Ruby等)。
- 在
macos
上,通过Homebrew
安装ImageMagick
。
brew install imagemagick
- 验证是否安装成功。
convert -version
- 使用
convert
命令来剪裁图片。
convert example.png -crop 300x200+0+0 cropped_example.png
example.jpg
是原始图片的路径。-crop 300x200+0+0
指定剪裁的区域,格式是宽度x高度+X偏移+Y偏移
。cropped_example.jpg
是输出文件的路径和名称。
- 安装后,即可参考上述convert命令,剪裁一张图片进行验证。
python执行cmd命令
subprocess
是 Python 标准库中的一个模块,用于生成新的进程,连接它们的输入、输出和错误管道,并获取它们的返回码。subprocess
模块提供了一个更强大和灵活的接口来替代一些旧的模块和函数,如 os.system
、os.spawn*
和 os.popen*
。
基本用法:
import subprocess
# 执行命令并捕获输出
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
# 检查返回码
if result.returncode == 0:
print('successful!')
print(result.stdout)
else:
print(f'failed! code is {result.returncode}')
print(result.stderr)
args
:要执行的命令,通常是一个列表,每个元素是一个命令参数。capture_output
:如果为True
,则捕获标准输出和标准错误。text
:如果为True
,则将输出解码为字符串。input
:传递给命令的输入,可以是字符串或字节序列。check
:如果为True
,则当命令返回非零退出码时抛出CalledProcessError
异常。timeout
:命令执行的超时时间,单位为秒。
python获取命令行参数
getopt
是 Python 标准库中的一个模块,用于解析命令行选项和参数。模仿了 Unix 系统中 getopt()
函数的接口,可以处理类似 -a
、-b
、-c value
或 --option value
这样的命令行选项。
示例代码:
import getopt
import sys
def main(argv):
try:
opts, args = getopt.getopt(argv, "ho:v", ["help", "output="])
except getopt.GetoptError:
print('usage: example.py -o <outputfile> -v')
sys.exit(2)
output_file = None
verbose = False
for opt, arg in opts:
if opt in ("-h", "--help"):
print('usage: example.py -o <outputfile> -v')
sys.exit()
elif opt in ("-o", "--output"):
output_file = arg
elif opt in ("-v", "--verbose"):
verbose = True
print(f'Output file: {output_file}')
print(f'Verbose mode: {verbose}')
if __name__ == "__main__":
main(sys.argv[1:])
getopt.getopt
函数:
- 第一个参数是命令行参数列表
- 通常是
sys.argv[1:]
,因为sys.argv[0]
是脚本名。
- 通常是
- 第二个参数是短选项字符串
- 如
"ho:v"
表示-h
、-o
需要一个参数、-v
不需要参数。 - 短选项后面加
:
表示该选项需要一个参数,
- 如
- 第三个参数是长选项列表
- 如
["help", "output="]
表示--help
不需要参数,--output
需要一个参数。 - 长选项后面加
=
表示该选项需要一个参数。
- 如
剪裁示例
准备工作做完,开始编写python
代码。
clip.py 完整代码
import getopt
import os
import subprocess
import sys
def main(argv):
input_path = ''
output_path = ''
left = 0
top = 0
width = 0
height = 0
try:
shortopts = "hi:o:l:t:w:"
longopts = ["ipath=", "opath=", "left=", "top=", "width=", "height="]
opts, args = getopt.getopt(argv, shortopts, longopts)
except getopt.GetoptError:
print('usage: clip.py -i <inputpath> -o <outputpath> -l <left> -t <top> -w <width> --height <height>')
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
print('usage: clip.py -i <inputpath> -o <outputpath> -l <left> -t <top> -w <width> --height <height>')
sys.exit()
elif opt in ("-i", "--ipath"):
input_path = arg
elif opt in ("-o", "--opath"):
output_path = arg
elif opt in ("-l", "--left"):
left = int(arg)
elif opt in ("-t", "--top"):
top = int(arg)
elif opt in ("-w", "--width"):
width = int(arg)
elif opt in ("--height",):
height = int(arg)
print(f'输入路径为:{input_path}')
print(f'输出路径为:{output_path}')
print(f'剪裁区域:({left},{top}),({width},{height})')
clip(input_path, output_path, left, top, width, height)
def clip(input_path, output_path, left, top, width, height):
# 读取目录下的所有文件
files = os.listdir(input_path)
# 创建输出目录
os.makedirs(output_path, exist_ok=True)
filter_files = [file for file in files if file.endswith(".png")]
for file in filter_files:
# convert example.png -crop 300x200+0+0 cropped_example.png
args = ['convert',
f'{input_path}/{file}',
'-crop',
f'{width}x{height}+{left}+{top}',
f'{output_path}/{file}']
subprocess.run(args, capture_output=True, text=True)
if __name__ == "__main__":
main(sys.argv[1:])
clip.sh 脚本
因剪裁区域固定为左上角位置(0, 100),宽高(400, 800),再写个clip.sh
脚本,方便调用。
#!/bin/bash
# clip.py -i <inputpath> -o <outputpath> -l <left> -t <top> -w <width> -h <height>
python clip.py -i $1 -o $1/out -l 0 -t 100 -w 400 --height 800
运行
在终端,输入如下命令:
sh clip.sh input_dir
-
其中
input_dir
为图片文件所在的路径。 -
最终在
input_dir/out
目录下输出剪裁后的图片。
总结
本文通过python
的subprocess
模块来调用ImageMagick
命令,实现剪裁图片的批量处理。
除此之外,还可通过wand
库来使用 ImageMagick
的强大图像处理功能。wand
是一个 Python
绑定库,用于与 ImageMagick
的 MagickWand C API
进行交互。它有许多优点,如:
- 提供了对
ImageMagick
的完整访问; - 是易于使用的
API
; - 与
Python
生态系统集成,是一个纯Python
库,可以很好地与Python
生态系统中的其它库和工具集成。 - 它还有详细的官方文档,提供了大量的示例和教程等等优点。
以后有机会再看看wand
库的用法。