前言

网页上使用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,如果要在其它位置调用这个脚本,个人想了两种方式:

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

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

  1. 创建虚拟环境
python -m venv png2webp
  1. 激活虚拟环境
# linux
cd png2webp
source ./bin/activate # windows powershell
cd png2webp
.\Scripts\activate
  1. 安装依赖
python -m pip install pillow pyinstaller
  1. 编译。注意修改实际的python文件路径。
pyinstaller -F --clean .\main.py
  1. 生成的二进制文件在当前目录下的dist目录,将其放置到PATH环境变量下,如有需要可重命名。
  2. 测试在其他目录下调用
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的命令行工具的更多相关文章

  1. Python 命令行工具 argparse 模块使用详解

    先来介绍一把最基本的用法 import argparse parser = argparse.ArgumentParser() parser.parse_args() 在执行 parse_args() ...

  2. Python -- Scrapy 命令行工具(command line tools)

    结合scrapy 官方文档,进行学习,并整理了部分自己学习实践的内容 Scrapy是通过 scrapy 命令行工具进行控制的. 这里我们称之为 “Scrapy tool” 以用来和子命令进行区分. 对 ...

  3. Python 简易web日志查看工具&可改装为命令行工具

    Python 简易web日志查看工具&可改装为命令行工具 效果图 原理 利用python的paramiko库模拟ssh登录操作,并执行tail命令 所需库 flask.paramiko.gev ...

  4. python笔记42-http请求命令行工具(httpie)

    前言 通常我们需要快速的测试某个接口通不通,一般linux上用curl去发http请求,但是这个命令行工具语法有点复杂了,不够直观. python有一个给人类使用的requests库,非常的简单方便. ...

  5. 将Python模块转变为命令行工具

    问:如何输入命令行就能执行python代码呢? 答:要将python模块转变为命令行工具只用在 setup.py 文件中添加参数entry_points 例如: entry_points={ 'con ...

  6. python制作命令行工具——fire

    python制作命令行工具--fire 前言 本篇教程的目的是希望大家可以通读完此篇之后,可以使用python制作一款符合自己需求的linux工具. 本教程使用的是google开源的python第三方 ...

  7. python开发简单的命令行工具

    介绍 Python模块argparse,这是一个命令行选项,参数和子命令的解释器,使用该模块可以编写友好的命令行工具,在程序中定义好需要的参数,argparse将弄清楚如何解析 sys.argv中的参 ...

  8. windows下的命令行工具babun

    什么是babun babun是windows上的一个第三方shell,在这个shell上面你可以使用几乎所有linux,unix上面的命令,他几乎可以取代windows的shell.用官方的题目说就是 ...

  9. 转:windows下命令行工具

    转自: http://www.cnblogs.com/haochuang/p/5593411.html Windows下CMD不好用,远没有Linux,或者一些SSH工具用起来方便.其实Windows ...

  10. 从零开始打造个人专属命令行工具集——yargs完全指南

    前言 使用命令行程序对程序员来说很常见,就算是前端工程师或者开发gui的,也需要使用命令行来编译程序或者打包程序 熟练使用命令行工具能极大的提高开发效率,linux自带的命令行工具都非常的有用,但是这 ...

随机推荐

  1. 黑盒视角下的RESTful API安全测试

    目录 前言 关于OWASP API TOP 10 REST API接口测试思路 接口权限测试 接口校验测试 接口滥用测试 总结 前言 RESTful API(或称RESTful Web API)在线开 ...

  2. Lua 按指定字符切割字符串的方法gsub

    1. 利用string库的gsub函数 function split( str,reps ) local resultStrList = {} string.gsub(str,'[^'..reps.. ...

  3. Spring 开发 Swing GUI 简介

    依赖注入和富客户机 Chad Woolley (thewoolleyman@gmail.com), 软件开发人员, Ionami 简介:  本教程介绍了 Spring 框架以及依赖注入的概念(也称为反 ...

  4. python之typing

    typing介绍 Python是一门动态语言,很多时候我们可能不清楚函数参数类型或者返回值类型,很有可能导致一些类型没有指定方法,在写完代码一段时间后回过头看代码,很可能忘记了自己写的函数需要传什么参 ...

  5. Mybatis【7】-- Mybatis如何知道增删改是否成功执行?

    代码直接放在Github仓库[https://github.com/Damaer/Mybatis-Learning/tree/master/mybatis-05-CURD ] 需要声明的是:此Myba ...

  6. 使用gulp 压缩js

    js 编写后文件太大,可以使用gulp 来进行压缩. 具体步骤如下: 1.创建一个工作目录 在该目录下安装 gulp npm install gulp 安装gulp-uglify 模块 npm ins ...

  7. 渗透测试-Kioptix Level 1靶机getshell及提权教程

    声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无 ...

  8. 开源个人实用XML翻译小工具,实现

    前言 IntelliSense 是一种代码完成辅助工具,可以在不同的集成开发环境 (IDE) 中使用,在开发 .NET 项目时,SDK 仅包含英语版本的 IntelliSense 文件. 对英语不好的 ...

  9. uni-app项目分包后子包中静态资源丢失

    前情 uni-app是我比较喜欢的跨平台框架,它能开发小程序/H5/APP(安卓/iOS),重要的是对前端开发友好,自带的IDE让开发体验非常棒,公司项目就是主推uni-app. 坑位 随着项目越做越 ...

  10. Intel Pin初探

    1.在/home/hf/Desktop/pin/pin-3.30-98830-g1d7b601b3-gcc-linux/source/tools/ManualExamples/目录下写自己的pinto ...