基于Python实现png转webp的命令行工具

 更新时间:2025年02月05日 08:20:43   作者:花酒锄作田  
网页上使用webp格式的图片更加省网络流量和存储空间,但本地图片一般是png格式的,所以本文就来为大家介绍一下如何使用Python实现png转webp功能吧

前言

网页上使用webp格式的图片更加省网络流量和存储空间,但本地图片一般是png格式的,所以考虑用python的pillow库将png格式的图片转换为webp格式。

需求:

  • 可以在系统任意地方调用。这需要编译成二进制程序或写成脚本放到PATH环境变量下
  • 支持指定图片文件输入目录。默认为当前目录。
  • 支持指定图片文件输出目录。默认为输入文件的同级目录。
  • 支持指定图片压缩质量。默认为80。需要校验传参。
  • 支持并发同时压缩多个图片文件。默认为串行。传参的并发数最大为CPU核心数。

代码

from PIL import Image
import argparse
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
import os
from time import time


def parse_args():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(description="Convert PNG to WEBP", 
        usage="""
        # 直接执行, 默认转换当前目录下的所有png文件到同级目录
        python main.py

        # 将转换后的webp文件保存到output目录下
        python main.py -o output

        # 转换单个png文件, 单独转换时不支持指定输出目录
        python main.py -f 1.png

        # 同时转换, -t 指定最大并发数, 默认为1, 最大不得超过CPU核心数
        python main.py -t 2

        # 指定图片压缩质量, 默认为80, 取值区间为[0, 100], 值越高, 质量越好, 生成图片体积越大
        python main.py -q 75
        """)
    parser.add_argument(
        "-i", type=str, default=os.getcwd(), help="Path to the input PNG image"
    )
    parser.add_argument(
        "-o", type=str, default=os.getcwd(), help="Path to the output WEBP image"
    )
    parser.add_argument("-f", type=str, default="", help="specific file name")
    parser.add_argument("-t", type=int, default=1, help="Number of threads to use")
    parser.add_argument(
        "-q", type=int, default=80, help="Quality of the output WEBP image"
    )
    return parser.parse_args()


def convert_png_to_webp(input_path: Path, output_path: Path, quality=80) -> None:
    """
    转换PNG为WEBP

    Args:
        input_path (Path): 输入文件路径
        output_path (Path): 输出文件路径, 可以是一个目录, 也可以是一个webp文件的路径
        quality (int, optional): 图片压缩质量. 默认为 80.
    """
    # 如果quality不在0到100之间, 则设置为80
    if quality > 100 or quality < 0:
        print("quality must be between 0 and 100, now set to 80")
    real_q = quality if quality <= 100 and quality > 0 else 80

    # 如果输入文件不存在, 则打印错误信息并返回
    if not input_path.exists():
        print(f"input file {input_path} not found")
        return

    # 如果指定了输出目录, 则尝试创建输出目录
    if not output_path.exists() and output_path.suffix.lower() != ".webp":
        try:
            output_path.mkdir(parents=True)
        except Exception as e:
            print(e)
            print("Failed to create output directory")
            return

    # 如果指定了输出目录, 则修改输出文件名为为输入文件名, 并修改扩展名为.webp
    if output_path.suffix.lower() != ".webp":
        output_path = output_path / input_path.with_suffix(".webp").name
    start = time()
    try:
        with Image.open(input_path) as img:
            print(
                f"Converting {input_path}, quality={real_q}, size: {input_path.stat().st_size / 1024:.2f}KB"
            )
            img.save(output_path, "WEBP", quality=real_q)
            print(
                f"Convert png2webp successfully, output file: {output_path.name}, size: {int(output_path.stat().st_size) / 1024:.2f}KB, elapsed time: {time() - start:.2f}s"
            )
    except Exception as e:
        print(f"Convert png2webp failed: {e}")


def multi_thread_convert(max_workers: int, input_path, output_path, quality) -> None:
    """并发转换png为webp"""
    print(f"convert png to webp with multi threads, max_workers: {max_workers}")
    p = Path(input_path)
    op = Path(output_path) if output_path != os.getcwd() else None
    max_workers = max_workers if max_workers < os.cpu_count() else os.cpu_count()
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        for f in p.glob("**/*.png"):
            executor.submit(
                convert_png_to_webp, f, op or f.with_suffix(".webp"), quality
            )


def main():
    start = time()
    args = parse_args()
    if not args.f:
        if args.t > 1:
            multi_thread_convert(args.t, args.i, args.o, args.q)
        else:
            p = Path(args.i)
            op = Path(args.o) if args.o != os.getcwd() else None
            for f in p.glob("**/*.png"):
                convert_png_to_webp(f, op or f.with_suffix(".webp"), args.q)
    else:
        p = Path(args.f)
        convert_png_to_webp(p, p.with_suffix(".webp"), args.q)
    print(f"Finished! Total elapsed time: {time() - start:.2f}s")


if __name__ == "__main__":
    main()

编译

因为是在python虚拟环境中安装的pillow,如果要在其它位置调用这个脚本,个人想了两种方式:

  • 另外编写一个shell脚本,如果是windows,则编写powershell脚本,在这个脚本内编写调用逻辑,并把这个脚本放到PATH环境变量的路径下。
  • 编译成二进制文件,将编译好的二进制文件放到PATH环境变量下。这比较方便发送给别人,这样别人就不需要在电脑上安装python环境。

这里用pyinstaller将程序编译成二进制文件,尽量在python虚拟环境下编译,以减小二进制文件的体积

1.创建虚拟环境

python -m venv png2webp

2.激活虚拟环境

# linux
cd png2webp
source ./bin/activate

# windows powershell
cd png2webp
.\Scripts\activate

3.安装依赖

python -m pip install pillow pyinstaller

4.编译。注意修改实际的python文件路径。

pyinstaller -F --clean .\main.py

5.生成的二进制文件在当前目录下的dist目录,将其放置到PATH环境变量下,如有需要可重命名。

6.测试在其他目录下调用

png2webp --help

使用

# 直接执行, 默认转换当前目录下的所有png文件到同级目录
png2webp

# 将转换后的webp文件保存到output目录下
png2webp -o output

# 转换单个png文件, 单独转换时不支持指定输出目录
png2webp -f 1.png

# 同时转换, -t 指定最大并发数, 默认为1, 最大不得超过CPU核心数
png2webp -t 2

# 指定图片压缩质量, 默认为80, 取值区间为[0, 100], 值越高, 质量越好, 生成图片体积越大
png2webp -q 75

到此这篇关于基于Python实现png转webp的命令行工具 的文章就介绍到这了,更多相关Python png转webp内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python中如何使用xml.dom.minidom模块读取解析xml文件

    python中如何使用xml.dom.minidom模块读取解析xml文件

    xml.dom.minidom模块应该是内置模块不用下载安装,本文给大家介绍python中如何使用xml.dom.minidom模块读取解析xml文件,感兴趣的朋友一起看看吧
    2023-10-10
  • Python django框架应用中实现获取访问者ip地址示例

    Python django框架应用中实现获取访问者ip地址示例

    这篇文章主要介绍了Python django框架应用中实现获取访问者ip地址,涉及Python Request模块相关函数使用技巧,需要的朋友可以参考下
    2019-05-05
  • Python 序列化和反序列化库 MarshMallow 的用法实例代码

    Python 序列化和反序列化库 MarshMallow 的用法实例代码

    marshmallow(Object serialization and deserialization, lightweight and fluffy.)用于对对象进行序列化和反序列化,并同步进行数据验证。这篇文章主要介绍了Python 序列化和反序列化库 MarshMallow 的用法实例代码,需要的朋友可以参考下
    2020-02-02
  • 恢复百度云盘本地误删的文件脚本(简单方法)

    恢复百度云盘本地误删的文件脚本(简单方法)

    下面小编就为大家带来一篇恢复百度云盘本地误删的文件脚本(简单方法)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Python利用缓存流实现压缩PDF文件

    Python利用缓存流实现压缩PDF文件

    在Python中,有许多库可以用来压缩PDF文件,其中最常用的是PyPDF2和PDFMiner,本文将为大家介绍一个新的方法,即使用缓存流压缩PDF文件,感兴趣的可以了解下
    2023-08-08
  • Android基于TCP和URL协议的网络编程示例【附demo源码下载】

    Android基于TCP和URL协议的网络编程示例【附demo源码下载】

    这篇文章主要介绍了Android基于TCP和URL协议的网络编程,结合实例形式分析了Android网络编程的通信原理、实现步骤与相关操作技巧,并附带demo源码供读者下载参考,需要的朋友可以参考下
    2018-01-01
  • Python画图学习入门教程

    Python画图学习入门教程

    这篇文章主要介绍了Python画图的方法,结合实例形式分析了Python基本的线性图、饼状图等绘制技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2016-07-07
  • 基于Python制作一个文件解压缩工具

    基于Python制作一个文件解压缩工具

    经常由于各种压缩格式的不一样用到文件的解压缩时就需要下载不同的解压缩工具去处理不同的文件。本文将用Python制作一个解压缩小工具,以后再也不用下载各种格式的解压缩软件了
    2022-05-05
  • Python编程实现线性回归和批量梯度下降法代码实例

    Python编程实现线性回归和批量梯度下降法代码实例

    这篇文章主要介绍了Python编程实现线性回归和批量梯度下降法代码实例,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • python完全卸载三种方法教程

    python完全卸载三种方法教程

    通常我们在卸载pyhton时会直接使用电脑自备的管家软件中的卸载功能,但是通常这并不会卸载干净,特别是当你卸载完python一个版本之后,重新安装另一个版本就会出错,这篇文章主要给大家介绍了关于python完全卸载三种方法的相关资料,需要的朋友可以参考下
    2023-09-09

最新评论