[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虚拟环境下编译,以减小二进制文件的体积
- 创建虚拟环境
python -m venv png2webp
- 激活虚拟环境
# linux
cd png2webp
source ./bin/activate
# windows powershell
cd png2webp
.\Scripts\activate
- 安装依赖
python -m pip install pillow pyinstaller
- 编译。注意修改实际的python文件路径。
pyinstaller -F --clean .\main.py
- 生成的二进制文件在当前目录下的
dist目录,将其放置到PATH环境变量下,如有需要可重命名。 - 测试在其他目录下调用
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 命令行工具 argparse 模块使用详解
先来介绍一把最基本的用法 import argparse parser = argparse.ArgumentParser() parser.parse_args() 在执行 parse_args() ...
- Python -- Scrapy 命令行工具(command line tools)
结合scrapy 官方文档,进行学习,并整理了部分自己学习实践的内容 Scrapy是通过 scrapy 命令行工具进行控制的. 这里我们称之为 “Scrapy tool” 以用来和子命令进行区分. 对 ...
- Python 简易web日志查看工具&可改装为命令行工具
Python 简易web日志查看工具&可改装为命令行工具 效果图 原理 利用python的paramiko库模拟ssh登录操作,并执行tail命令 所需库 flask.paramiko.gev ...
- python笔记42-http请求命令行工具(httpie)
前言 通常我们需要快速的测试某个接口通不通,一般linux上用curl去发http请求,但是这个命令行工具语法有点复杂了,不够直观. python有一个给人类使用的requests库,非常的简单方便. ...
- 将Python模块转变为命令行工具
问:如何输入命令行就能执行python代码呢? 答:要将python模块转变为命令行工具只用在 setup.py 文件中添加参数entry_points 例如: entry_points={ 'con ...
- python制作命令行工具——fire
python制作命令行工具--fire 前言 本篇教程的目的是希望大家可以通读完此篇之后,可以使用python制作一款符合自己需求的linux工具. 本教程使用的是google开源的python第三方 ...
- python开发简单的命令行工具
介绍 Python模块argparse,这是一个命令行选项,参数和子命令的解释器,使用该模块可以编写友好的命令行工具,在程序中定义好需要的参数,argparse将弄清楚如何解析 sys.argv中的参 ...
- windows下的命令行工具babun
什么是babun babun是windows上的一个第三方shell,在这个shell上面你可以使用几乎所有linux,unix上面的命令,他几乎可以取代windows的shell.用官方的题目说就是 ...
- 转:windows下命令行工具
转自: http://www.cnblogs.com/haochuang/p/5593411.html Windows下CMD不好用,远没有Linux,或者一些SSH工具用起来方便.其实Windows ...
- 从零开始打造个人专属命令行工具集——yargs完全指南
前言 使用命令行程序对程序员来说很常见,就算是前端工程师或者开发gui的,也需要使用命令行来编译程序或者打包程序 熟练使用命令行工具能极大的提高开发效率,linux自带的命令行工具都非常的有用,但是这 ...
随机推荐
- Python网络爬虫实践案例:爬取猫眼电影Top100
以下是一个Python网络爬虫的实践案例,该案例将演示如何使用Python爬取猫眼电影Top100的电影名称.主演和上映时间等信息,并将这些信息保存到TXT文件中.此案例使用了requests库来发送 ...
- Python数据存储之shelve和dbm
一.shelve 和 dbm 的介绍 shelve 和 dbm 都是 python 自带的数据库管理模块,可以用于持久化存储和检索 python 中的对象. 虽然这两个模块的本质都是建立 key-va ...
- vue结合element UI做checkbox全选的tree结构
由于element UI中的tree可能不能满足项目中的样式需求,所以自己动手结合element中的checkbox全选功能实现了一个符合项目需求的tree.效果如下: html部分: <tem ...
- JavaWeb 入门到实战
注:看狂神说做的笔记 1.基本概念 1.1 前言 web开发: web:网页的意思,www.baidu.com,就是一个web页面 静态web: 不与数据库进行交互,静态显示网页数据(你刚学 html ...
- C#生成二维码的两种方式(快看二维码)
前言 最近在做项目的时候遇到一个需求是将文本内容生成二维码图片的,对于这个需求那就直接上手(两种方法,我比较喜欢第二种方式,往上面也是有很多的方法.这里只作为个人纪录) 方法一:ThoughtWork ...
- RHCL8无法使用yum install的解决方法
报错如下: Updating Subscription Management repositories. Unable to read consumer identity This system i ...
- RocketMQ系列3:核心技术介绍
1 介绍 RocketMQ是一款分布式消息中间件,其核心技术涉及多个核心概念,包括主题.队列.消息.生产者.消费者.消费者分组以及订阅关系.以下是对这些核心技术的详细说明: 2 核心技术实现 2.1 ...
- 安卓导出已安装app的apk
安卓导出已安装应用APK 有时候想看看别人的APK里面的资源文件或者是逆向,首先就得先搞到APK文件 两种方法获取手机上已安装应用的APK文件 通过adb命令 首先把目标手机连接上电脑 在终端输入 a ...
- 【C#】【报错解决】分析器错误消息: 无法识别的属性“targetFramework”。请注意属性名称区分大小写。
服务器:Windows Server 数据中心 2016 问题描述: 在本地测试正常运行,但是上传到服务器却出现该错误 报错: 分析器错误消息: 无法识别的属性"targetFramewor ...
- Spring源码阅读(一):使用IDEA搭建Spring5.0.x源码阅读环境
说明 Spring源码阅读环境配置如下: Spring 5.x版本 Gradle 4.8.1 JDK8 IDEA2020.1 win10 搭建步骤 1. 下载Spring源码 下载地址:Github链 ...