Featured image of post Python 脚本 - 将图片转换为 WebP

Python 脚本 - 将图片转换为 WebP

概述

这个Python脚本旨在处理图片文件,将它们转换为WebP格式,组织到特定的文件夹中,并保留它们的元数据。它还处理文件重命名,以去除空格,并确保在转换后的文件中保留原始图片的元数据。

使用说明

要使用此脚本,请在命令行中运行并提供以下参数:

  • input_dir: 包含要处理的图片文件的目录路径。
  • output_dir: 转换后的图片将被保存的目录路径。
  • --ext: (可选) 要处理的图片文件扩展名列表。默认为 ["all"]
  • --subdir: (可选) 一个标志,表示是否要在子目录中递归搜索图片。默认为 False

示例命令:

python image_processing_script.py /path/to/input /path/to/output --ext jpg,png --subdir

功能特点

  • 使用 cwebp 命令将图片转换为WebP格式。
  • 根据转换选项将转换后的图片组织到不同的文件夹中。
  • 重命名文件以去除空格。
  • 使用 exiftool 保留原始图片的元数据到转换后的文件中。
  • 提供带有时间戳和日志级别的日志信息。

函数说明

  • process_single_image: 转换单个图片并将其Markdown链接写入文件。
  • process_images: 使用指定的扩展名处理输入目录中的所有图片文件。
  • expand_image_extensions: 扩展图片扩展名列表以包含常见变体。
  • find_image_files: 在给定目录中查找具有指定扩展名的所有图片文件。
  • create_output_directories: 在基础目录中创建必要的输出目录。
  • convert_image_with_cwebp: 使用 cwebp 转换图片并保存到输出目录。
  • build_converted_path: 构建转换后图片文件的路径。

运行要求

  • Python 3.x
  • 必须安装并配置 cwebp 命令行工具,并在系统PATH中可用。
  • 必须安装并配置 exiftool 命令行工具,并在系统PATH中可用。

注意事项

  • 确保您有权限在指定目录中读取和写入文件。
  • 在运行脚本之前,请始终备份您的原始图片以防止数据丢失。
  • 脚本假设 cwebpexiftool 工具已正确安装并配置在您的系统上。

代码

import argparse
import subprocess
from pathlib import Path
import logging

# Enable logger, print to console with timestamp and log level
logging.basicConfig(
    level=logging.INFO, format="\n%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)


def process_single_image(
    image_path: Path,
    output_dir: Path,
) -> None:
    """
    Processes a single image file: converts it, uploads it, and writes the markdown link to a file.

    Args:
    image_path (Path): The path to the input image file.
    output_dir (Path): The directory where the converted images will be saved.

    Returns:
    None
    """
    folder_options = [
        # ("Lossless", ["-z", "8", "-mt"]),
        # ("6MB", ["-size", "6291456", "-pass", "10", "-qrange", "80", "100", "-mt"]),
        ("Web", ["-resize", "1280", "0", "-mt"]),
    ]

    for folder_name, options in folder_options:
        folder_path = output_dir / folder_name
        create_output_directories(output_dir, folder_name)
        convert_image_with_cwebp(image_path, folder_path, options)


def process_images(
    input_dir: Path,
    output_dir: Path,
    extensions: list[str],
    subdir: bool,
) -> None:
    """
    Processes all image files in the input directory with the specified extensions.

    Args:
    input_dir (Path): The directory containing the input image files.
    output_dir (Path): The directory where the converted images and markdown links will be saved.
    extensions (list[str]): A space-separated list of image extensions.
    subdir (bool): Whether to search recursively in subdirectories.
    md_links_file_name (str): The name of the file where the markdown links will be written.
    """
    image_files = find_image_files(input_dir, extensions, subdir)

    for image_path in image_files:
        image_path.rename(image_path.parent / image_path.name.replace(" ", "-"))
        process_single_image(image_path, output_dir)


def expand_image_extensions(extensions: list[str]) -> list[str]:
    """
    Expands a comma-separated list of image extensions to include common variants.

    Args:
    extensions (list[str]): A list of image extensions.

    Returns:
    list[str]: A list of expanded image extensions.
    """
    supported_extensions = ["jpg", "jpeg", "png", "tif", "tiff", "webp"]

    expanded_extensions = []
    for ext in [s.lower() for s in extensions]:
        if ext == "all":
            expanded_extensions = supported_extensions
            break
        elif ext in ["jpg", "jpeg"]:
            expanded_extensions.extend(["jpg", "jpeg"])
        elif ext in ["tif", "tiff"]:
            expanded_extensions.extend(["tif", "tiff"])
        else:
            expanded_extensions.append(ext)

    return [s.lower() for s in expanded_extensions] + [
        s.upper() for s in expanded_extensions
    ]


def find_image_files(
    directory: Path, extensions: list[str], subdir: bool
) -> list[Path]:
    """
    Finds all image files in the given directory with the specified extensions.

    Args:
    directory (Path): The directory to search for image files.
    extensions (list[str]): A list of image file extensions.
    subdir (bool): Whether to search recursively in subdirectories.

    Returns:
    list[Path]: A list of paths to the found image files.
    """
    return sorted(
        [
            file
            for ext in extensions
            for file in directory.rglob(f"*.{ext}")
            if not file.name.startswith(".")
        ]
        if subdir
        else [
            file
            for ext in extensions
            for file in directory.glob(f"*.{ext}")
            if not file.name.startswith(".")
        ]
    )


def create_output_directories(base_dir: Path, *folder_names: str) -> None:
    """
    Creates the necessary output directories within the base directory.

    Args:
    base_dir (Path): The base directory where the output directories will be created.
    *folder_names (str): Variable number of folder names to create.
    """
    for folder_name in folder_names:
        Path(base_dir, folder_name).mkdir(parents=True, exist_ok=True)


def convert_image_with_cwebp(input_path: Path, output_dir: Path, options: list) -> None:
    """
    Converts an image using cwebp and saves it to the output directory.

    Args:
    input_path (Path): The path to the input image file.
    output_dir (Path): The directory where the converted image will be saved.
    options (list): A list of options to pass to the cwebp command.
    """
    output_path = build_converted_path(input_path, output_dir)
    cweb_cmd = [
        "cwebp",
        *options,
        "-metadata",
        "all",
        str(input_path),
        "-o",
        str(output_path),
    ]
    try:
        subprocess.run(cweb_cmd, check=True)
        subprocess.run(
            [
                "exiftool",
                "-TagsFromFile",
                str(input_path),
                "-overwrite_original",
                str(output_path),
            ],
            check=True,
        )
    except subprocess.CalledProcessError as e:
        logger.error(f"Failed to convert {input_path}: {e}")


def build_converted_path(input_path: Path, output_dir: Path) -> Path:
    """
    Builds the path for the converted image file.

    Args:
    input_path (Path): The path to the input image file.
    output_dir (Path): The directory where the converted image will be saved.

    Returns:
    Path: The path to the converted image file.
    """
    return output_dir / (input_path.stem + ".webp")


def main() -> None:
    """
    The main function that parses command line arguments and processes images.
    """
    parser = argparse.ArgumentParser(description="Convert and upload images.")
    parser.add_argument("input_dir", type=str, help="Input directory path")
    parser.add_argument("output_dir", type=str, help="Output directory path")
    parser.add_argument(
        "--ext",
        nargs="+",
        default=["all"],
        help="List of input image extensions",
    )
    parser.add_argument(
        "--subdir",
        action="store_false",
        help="Search for images recursively in subdirectories",
    )

    args = parser.parse_args()

    input_dir = Path(args.input_dir)
    output_dir = Path(args.output_dir)

    process_images(
        input_dir, output_dir, expand_image_extensions(args.ext), args.subdir
    )


if __name__ == "__main__":
    main()
使用 Hugo 构建
主题 StackJimmy 设计