人生苦短我用Python 剪裁图片

前言

最近裁切图片,却没有趁手工具,手动剪裁的图片忽大忽小,总是差强人意。

想起曾经用过ImageMagick批量剪裁图片,决定减少简单而繁琐的手动操作,通过命令行程序来批量处理。另外,Python可以很方便调用cmd命令,那么不如Pythonimagemagick相结合,来完成批量剪裁图片的目标。

需求

将指定一个目录下的所有图片(如png格式),按照剪裁的区域(左上角起始位置像素,宽度和高度)进行批量剪裁,将剪裁后的文件保存到另一个目录下。即剪裁的参数如下:

  • 输入目录
  • 输出目录
  • 剪裁区域:X偏移量,Y偏移量,宽度和高度

准备工作

  • 安装ImageMagick,了解剪裁的命令。
  • 了解python如何执行cmd命令。
  • 了解python如何获取命令行参数。

ImageMagick的安装与使用

ImageMagick主要用于图像编辑和转换,如调整大小、裁剪、旋转、格式转换等。提供命令行工具和库,方便脚本化和自动化。它具有如下功能和特点:支持基本的图像处理功能,如调整大小、裁剪、旋转、格式转换等。支持多种图像格式,包括常见的 JPEG、PNG、GIF、BMP 等。提供丰富的图像效果和滤镜。跨平台,支持多种编程语言(C、C++、Perl、Python、Ruby等)。

  1. macos上,通过Homebrew 安装 ImageMagick
brew install imagemagick
  1. 验证是否安装成功。
convert -version
  1. 使用 convert 命令来剪裁图片。
convert example.png -crop 300x200+0+0 cropped_example.png
  • example.jpg 是原始图片的路径。
  • -crop 300x200+0+0 指定剪裁的区域,格式是 宽度x高度+X偏移+Y偏移
  • cropped_example.jpg 是输出文件的路径和名称。
  1. 安装后,即可参考上述convert命令,剪裁一张图片进行验证。

python执行cmd命令

subprocess 是 Python 标准库中的一个模块,用于生成新的进程,连接它们的输入、输出和错误管道,并获取它们的返回码。subprocess 模块提供了一个更强大和灵活的接口来替代一些旧的模块和函数,如 os.systemos.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目录下输出剪裁后的图片。

总结

本文通过pythonsubprocess模块来调用ImageMagick命令,实现剪裁图片的批量处理。

除此之外,还可通过wand库来使用 ImageMagick 的强大图像处理功能。wand 是一个 Python 绑定库,用于与 ImageMagickMagickWand C API 进行交互。它有许多优点,如:

  • 提供了对 ImageMagick 的完整访问;
  • 是易于使用的 API
  • Python 生态系统集成,是一个纯 Python 库,可以很好地与 Python 生态系统中的其它库和工具集成。
  • 它还有详细的官方文档,提供了大量的示例和教程等等优点。

以后有机会再看看wand库的用法。

  • 41
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值