Python文件管理之批量壓縮指定目錄中的圖片
簡(jiǎn)介
在數(shù)字時(shí)代,圖片文件占據(jù)了我們存儲(chǔ)空間的很大一部分。高清照片、截圖和其他圖像文件往往體積龐大,不僅占用大量存儲(chǔ)空間,還會(huì)在網(wǎng)絡(luò)傳輸時(shí)造成延遲。本文將介紹一個(gè)實(shí)用的Python腳本——批量圖片壓縮工具,它可以自動(dòng)壓縮指定目錄中的圖片文件,在保持可接受畫質(zhì)的前提下顯著減小文件大小。
功能介紹
這個(gè)批量圖片壓縮工具具有以下核心功能:
- 批量壓縮:可以同時(shí)處理目錄中的多個(gè)圖片文件
- 質(zhì)量控制:支持自定義壓縮質(zhì)量參數(shù),平衡文件大小和畫質(zhì)
- 格式支持:支持JPEG、PNG、BMP等多種常見圖片格式
- 尺寸調(diào)整:可選地調(diào)整圖片尺寸以進(jìn)一步減小文件大小
- 進(jìn)度顯示:實(shí)時(shí)顯示處理進(jìn)度,讓用戶了解處理狀態(tài)
- 備份保留:可選擇保留原始文件或直接覆蓋
- 日志記錄:記錄壓縮操作的詳細(xì)信息,包括壓縮率等統(tǒng)計(jì)數(shù)據(jù)
應(yīng)用場(chǎng)景
這個(gè)工具適用于以下場(chǎng)景:
- 網(wǎng)站優(yōu)化:壓縮網(wǎng)站圖片以提高加載速度
- 存儲(chǔ)空間管理:減小圖片文件大小以節(jié)省存儲(chǔ)空間
- 社交媒體分享:壓縮圖片以便更快上傳到社交平臺(tái)
- 郵件附件:減小圖片文件大小以便通過郵件發(fā)送
- 移動(dòng)設(shè)備傳輸:壓縮圖片以便在移動(dòng)設(shè)備間快速傳輸
- 相冊(cè)整理:批量處理相機(jī)照片以節(jié)省空間
報(bào)錯(cuò)處理
腳本包含了完善的錯(cuò)誤處理機(jī)制:
- 文件格式檢查:自動(dòng)識(shí)別并跳過不支持的文件格式
- 路徑驗(yàn)證:檢查輸入目錄和輸出目錄的有效性
- 權(quán)限檢測(cè):檢測(cè)文件讀寫權(quán)限,防止因權(quán)限不足導(dǎo)致的錯(cuò)誤
- 內(nèi)存保護(hù):處理大尺寸圖片時(shí)防止內(nèi)存溢出
- 磁盤空間檢查:在處理前檢查是否有足夠的磁盤空間
- 異常捕獲:捕獲并處理運(yùn)行過程中可能出現(xiàn)的各種異常
代碼實(shí)現(xiàn)
import os
import sys
import argparse
from PIL import Image
import shutil
from datetime import datetime
class BatchImageCompressor:
def __init__(self, input_dir, output_dir=None, quality=85, resize_ratio=1.0):
self.input_dir = input_dir
self.output_dir = output_dir or input_dir
self.quality = quality
self.resize_ratio = resize_ratio
self.supported_formats = ('.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp')
self.compression_log = []
def check_directories(self):
"""檢查輸入和輸出目錄"""
if not os.path.exists(self.input_dir):
raise FileNotFoundError(f"輸入目錄 '{self.input_dir}' 不存在")
if not os.path.exists(self.output_dir):
try:
os.makedirs(self.output_dir)
print(f"創(chuàng)建輸出目錄: {self.output_dir}")
except Exception as e:
raise OSError(f"無法創(chuàng)建輸出目錄 '{self.output_dir}': {e}")
def is_supported_image(self, filename):
"""檢查文件是否為支持的圖片格式"""
return filename.lower().endswith(self.supported_formats)
def get_image_files(self):
"""獲取目錄中的所有圖片文件"""
try:
files = os.listdir(self.input_dir)
image_files = [f for f in files if self.is_supported_image(f)]
return sorted(image_files)
except Exception as e:
print(f"讀取目錄時(shí)出錯(cuò): {e}")
return []
def get_file_size(self, filepath):
"""獲取文件大小(MB)"""
size_bytes = os.path.getsize(filepath)
return size_bytes / (1024 * 1024)
def compress_image(self, filename):
"""壓縮單個(gè)圖片文件"""
input_path = os.path.join(self.input_dir, filename)
output_path = os.path.join(self.output_dir, filename)
try:
# 獲取原始文件大小
original_size = self.get_file_size(input_path)
# 打開圖片
with Image.open(input_path) as img:
# 如果需要調(diào)整尺寸
if self.resize_ratio < 1.0:
width, height = img.size
new_width = int(width * self.resize_ratio)
new_height = int(height * self.resize_ratio)
img = img.resize((new_width, new_height), Image.LANCZOS)
# 處理RGBA模式的圖片(如PNG)
if img.mode in ('RGBA', 'LA', 'P'):
# 轉(zhuǎn)換為RGB模式以支持JPEG格式
if filename.lower().endswith(('.jpg', '.jpeg')):
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
img = background
# 保存壓縮后的圖片
if filename.lower().endswith(('.jpg', '.jpeg')):
img.save(output_path, 'JPEG', quality=self.quality, optimize=True)
elif filename.lower().endswith('.png'):
img.save(output_path, 'PNG', optimize=True)
else:
img.save(output_path, optimize=True)
# 獲取壓縮后文件大小
compressed_size = self.get_file_size(output_path)
compression_ratio = (1 - compressed_size / original_size) * 100
return {
'filename': filename,
'original_size': original_size,
'compressed_size': compressed_size,
'compression_ratio': compression_ratio,
'status': 'success'
}
except Exception as e:
return {
'filename': filename,
'error': str(e),
'status': 'failed'
}
def process_images(self, backup_original=False):
"""批量處理圖片"""
try:
self.check_directories()
image_files = self.get_image_files()
if not image_files:
print("未找到支持的圖片文件")
return
print(f"找到 {len(image_files)} 個(gè)圖片文件")
print(f"壓縮質(zhì)量: {self.quality}%")
if self.resize_ratio < 1.0:
print(f"尺寸調(diào)整比例: {self.resize_ratio}")
# 如果需要備份且輸入輸出目錄相同,則創(chuàng)建備份目錄
if backup_original and self.input_dir == self.output_dir:
backup_dir = self.input_dir + "_backup"
if not os.path.exists(backup_dir):
os.makedirs(backup_dir)
print(f"原始文件將備份到: {backup_dir}")
processed_count = 0
failed_count = 0
for i, filename in enumerate(image_files, 1):
print(f"\r處理進(jìn)度: {i}/{len(image_files)} ({i/len(image_files)*100:.1f}%)", end='')
# 如果需要備份,先復(fù)制原始文件
if backup_original and self.input_dir == self.output_dir:
backup_path = os.path.join(self.input_dir + "_backup", filename)
if not os.path.exists(backup_path):
shutil.copy2(os.path.join(self.input_dir, filename), backup_path)
result = self.compress_image(filename)
if result['status'] == 'success':
self.compression_log.append(result)
processed_count += 1
print(f"\n{filename}: {result['original_size']:.2f}MB -> {result['compressed_size']:.2f}MB "
f"(壓縮率: {result['compression_ratio']:.1f}%)")
else:
failed_count += 1
print(f"\n{filename}: 處理失敗 - {result['error']}")
print(f"\n\n處理完成!")
print(f"成功處理: {processed_count}")
print(f"處理失敗: {failed_count}")
if processed_count > 0:
total_original = sum(item['original_size'] for item in self.compression_log)
total_compressed = sum(item['compressed_size'] for item in self.compression_log)
avg_compression = (1 - total_compressed / total_original) * 100
print(f"總壓縮率: {avg_compression:.1f}%")
print(f"節(jié)省空間: {total_original - total_compressed:.2f}MB")
except KeyboardInterrupt:
print("\n\n用戶中斷操作")
except Exception as e:
print(f"\n處理過程中發(fā)生錯(cuò)誤: {e}")
def save_log(self, log_file="compression_log.txt"):
"""保存壓縮日志"""
try:
log_path = os.path.join(self.output_dir, log_file)
with open(log_path, "w", encoding="utf-8") as f:
f.write("批量圖片壓縮操作日志\n")
f.write("=" * 50 + "\n")
f.write(f"操作時(shí)間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"輸入目錄: {self.input_dir}\n")
f.write(f"輸出目錄: {self.output_dir}\n")
f.write(f"壓縮質(zhì)量: {self.quality}%\n")
f.write(f"尺寸調(diào)整比例: {self.resize_ratio}\n\n")
if self.compression_log:
f.write("壓縮詳情:\n")
f.write("-" * 50 + "\n")
for item in self.compression_log:
f.write(f"{item['filename']}:\n")
f.write(f" 原始大小: {item['original_size']:.2f}MB\n")
f.write(f" 壓縮后大小: {item['compressed_size']:.2f}MB\n")
f.write(f" 壓縮率: {item['compression_ratio']:.1f}%\n\n")
print(f"操作日志已保存到: {log_file}")
except Exception as e:
print(f"保存日志時(shí)出錯(cuò): {e}")
def main():
parser = argparse.ArgumentParser(description="批量圖片壓縮工具")
parser.add_argument("input_dir", help="輸入目錄路徑")
parser.add_argument("-o", "--output_dir", help="輸出目錄路徑(默認(rèn)與輸入目錄相同)")
parser.add_argument("-q", "--quality", type=int, default=85,
help="壓縮質(zhì)量 (1-100, 默認(rèn): 85)")
parser.add_argument("-r", "--resize", type=float, default=1.0,
help="尺寸調(diào)整比例 (0.1-1.0, 默認(rèn): 1.0)")
parser.add_argument("-b", "--backup", action="store_true",
help="備份原始文件")
args = parser.parse_args()
# 驗(yàn)證參數(shù)
if not 1 <= args.quality <= 100:
print("錯(cuò)誤: 壓縮質(zhì)量必須在1-100之間")
sys.exit(1)
if not 0.1 <= args.resize <= 1.0:
print("錯(cuò)誤: 尺寸調(diào)整比例必須在0.1-1.0之間")
sys.exit(1)
try:
compressor = BatchImageCompressor(
input_dir=args.input_dir,
output_dir=args.output_dir,
quality=args.quality,
resize_ratio=args.resize
)
compressor.process_images(backup_original=args.backup)
compressor.save_log()
except Exception as e:
print(f"程序執(zhí)行出錯(cuò): {e}")
sys.exit(1)
if __name__ == "__main__":
main()
使用方法
安裝依賴
在使用此腳本之前,需要安裝Pillow庫(kù):
pip install Pillow
基本使用
# 基本用法,使用默認(rèn)壓縮質(zhì)量 python image_compressor.py /path/to/images # 指定壓縮質(zhì)量 python image_compressor.py /path/to/images -q 70 # 指定輸出目錄 python image_compressor.py /path/to/images -o /path/to/compressed # 調(diào)整圖片尺寸(縮小到原來的80%) python image_compressor.py /path/to/images -r 0.8 # 備份原始文件 python image_compressor.py /path/to/images -b
命令行參數(shù)說明
input_dir: 必需參數(shù),指定包含圖片文件的輸入目錄-o, --output_dir: 輸出目錄路徑,默認(rèn)與輸入目錄相同-q, --quality: 壓縮質(zhì)量,范圍1-100,默認(rèn)85-r, --resize: 尺寸調(diào)整比例,范圍0.1-1.0,默認(rèn)1.0(不調(diào)整)-b, --backup: 是否備份原始文件
使用示例
假設(shè)有以下圖片文件(總大小10MB):
photo1.jpg (3MB)
photo2.png (4MB)
screenshot.bmp (3MB)
執(zhí)行命令:
python image_compressor.py ./images -q 70 -r 0.9
壓縮后可能的結(jié)果:
photo1.jpg (1.2MB, 壓縮率60%)
photo2.png (1.8MB, 壓縮率55%)
screenshot.bmp (1.0MB, 壓縮率67%)
總節(jié)省空間約4MB,壓縮率達(dá)到60%
總結(jié)
這個(gè)批量圖片壓縮工具通過簡(jiǎn)單的命令行界面提供了高效的圖片壓縮功能。它支持多種圖片格式,允許用戶自定義壓縮質(zhì)量和尺寸調(diào)整比例,在保持可接受畫質(zhì)的前提下顯著減小文件大小。工具還提供了備份功能和詳細(xì)的日志記錄,確保操作的安全性和可追溯性。無論是網(wǎng)站優(yōu)化、存儲(chǔ)空間管理還是日常圖片處理,這個(gè)工具都能幫助用戶輕松完成批量圖片壓縮任務(wù)。
以上就是Python文件管理之批量壓縮指定目錄中的圖片的詳細(xì)內(nèi)容,更多關(guān)于Python壓縮圖片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python報(bào)錯(cuò):NameError:?name?‘xxx‘?is?not?defined的解決辦法
這篇文章主要給大家介紹了關(guān)于Python報(bào)錯(cuò):NameError:?name?‘xxx‘?is?not?defined的解決辦法,文中通過代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-06-06
Python詳解如何動(dòng)態(tài)給對(duì)象增加屬性和方法
python是動(dòng)態(tài)語(yǔ)?,動(dòng)態(tài)編程語(yǔ)?是?級(jí)程序設(shè)計(jì)語(yǔ)?的?個(gè)類別,在計(jì)算機(jī)科學(xué)領(lǐng)域已被?泛應(yīng)?。它是?類在?運(yùn)?時(shí)可以改變其結(jié)構(gòu)?的語(yǔ)??:例如新的函數(shù)、對(duì)象、甚?代碼可以被引進(jìn),已有的函數(shù)可以被刪除或是其他結(jié)構(gòu)上的變化2022-07-07
tensorflow2.0與tensorflow1.0的性能區(qū)別介紹
今天小編就為大家分享一篇tensorflow2.0與tensorflow1.0的性能區(qū)別介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-02-02
Python 的第三方調(diào)試庫(kù) ???pysnooper?? 使用示例
這篇文章主要介紹了Python 的第三方調(diào)試庫(kù) ???pysnooper?? 使用示例的相關(guān)資料,需要的朋友可以參考下2023-02-02
python用BeautifulSoup庫(kù)簡(jiǎn)單爬蟲實(shí)例分析
文章給大家分享了關(guān)于python爬蟲的相關(guān)實(shí)例以及相關(guān)代碼,有興趣的朋友們參考下。2018-07-07

