本文目录导读:

我来帮您设计一个可以控制输出文件大小的图片压缩工具,以下是几种实现方案:
基于质量的迭代压缩(最常用)
from PIL import Image
import os
def compress_to_target_size(image_path, target_size_kb, output_path=None):
"""
将图片压缩到目标大小(KB)
Args:
image_path: 原图路径
target_size_kb: 目标大小(KB)
output_path: 输出路径(可选)
"""
if output_path is None:
name, ext = os.path.splitext(image_path)
output_path = f"{name}_compressed{ext}"
img = Image.open(image_path)
# 保存原格式,如果不是JPEG则转换为JPEG
if img.format != 'JPEG':
img = img.convert('RGB')
output_path = output_path.replace('.png', '.jpg').replace('.webp', '.jpg')
# 二分法查找合适的质量参数
target_size_bytes = target_size_kb * 1024
min_quality = 1
max_quality = 95
while min_quality <= max_quality:
mid_quality = (min_quality + max_quality) // 2
# 临时保存以检查大小
import io
buffer = io.BytesIO()
img.save(buffer, format='JPEG', quality=mid_quality, optimize=True)
current_size = buffer.tell()
if current_size < target_size_bytes:
min_quality = mid_quality + 1
elif current_size > target_size_bytes:
max_quality = mid_quality - 1
else:
break
# 保存最终结果
img.save(output_path, format='JPEG', quality=mid_quality, optimize=True)
actual_size = os.path.getsize(output_path) / 1024
print(f"压缩完成!质量: {mid_quality}%, 大小: {actual_size:.2f}KB")
return output_path
# 使用示例
compress_to_target_size("input.jpg", 500) # 压缩到500KB
支持多种格式的全功能压缩
from PIL import Image
import os
import io
class ImageCompressor:
"""全能图片压缩器"""
def __init__(self, max_iterations=20, tolerance=0.1):
self.max_iterations = max_iterations
self.tolerance = tolerance # 允许的误差范围(10%)
def compress_to_target(self, input_path, target_size_kb, output_path=None):
"""压缩图片到目标大小"""
if output_path is None:
name, ext = os.path.splitext(input_path)
output_path = f"{name}_compressed_{target_size_kb}kb{ext}"
img = Image.open(input_path)
img_format = img.format or 'JPEG'
# 转换为RGB(处理RGBA图片)
if img.mode in ('RGBA', 'LA', 'P'):
rgb_img = Image.new('RGB', img.size, (255, 255, 255))
rgb_img.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
img = rgb_img
target_bytes = target_size_kb * 1024
self.original_size = os.path.getsize(input_path) / 1024
print(f"原图大小: {self.original_size:.2f}KB")
# 策略1:调整质量(JPEG)
if img_format in ('JPEG', 'JPG'):
result_path = self._compress_jpeg(img, output_path, target_bytes)
else:
# 策略2:调整尺寸+质量
result_path = self._compress_other_formats(img, output_path, target_bytes)
actual_size = os.path.getsize(result_path) / 1024
print(f"压缩完成: {actual_size:.2f}KB (目标: {target_size_kb}KB)")
return result_path
def _compress_jpeg(self, img, output_path, target_bytes):
"""JPEG图片压缩"""
quality = 95
best_quality = quality
for _ in range(self.max_iterations):
buffer = io.BytesIO()
img.save(buffer, format='JPEG', quality=quality, optimize=True)
size = buffer.tell()
if abs(size - target_bytes) / target_bytes <= self.tolerance:
break
elif size > target_bytes:
quality = max(1, quality - 5)
best_quality = quality
else:
quality = min(95, quality + 5)
img.save(output_path, format='JPEG', quality=best_quality, optimize=True)
return output_path
def _compress_other_formats(self, img, output_path, target_bytes):
"""其他格式图片压缩(先调整尺寸)"""
width, height = img.size
scale = 1.0
for _ in range(self.max_iterations):
new_width = int(width * scale)
new_height = int(height * scale)
resized_img = img.resize((new_width, new_height), Image.LANCZOS)
buffer = io.BytesIO()
resized_img.save(buffer, format='JPEG', quality=85, optimize=True)
size = buffer.tell()
if abs(size - target_bytes) / target_bytes <= self.tolerance:
break
elif size > target_bytes:
scale *= 0.8
else:
break
output_path = output_path.rsplit('.', 1)[0] + '.jpg'
resized_img.save(output_path, format='JPEG', quality=85, optimize=True)
return output_path
# 使用示例
compressor = ImageCompressor()
compressor.compress_to_target("input.png", 300) # 压缩到300KB
WebP格式(更高效的压缩)
from PIL import Image
import os
def compress_to_webp(image_path, target_size_kb, output_path=None):
"""转换为WebP格式并控制大小"""
if output_path is None:
name = os.path.splitext(image_path)[0]
output_path = f"{name}.webp"
img = Image.open(image_path)
target_bytes = target_size_kb * 1024
# WebP支持很好的压缩率
quality = 80
for _ in range(20):
import io
buffer = io.BytesIO()
img.save(buffer, format='WEBP', quality=quality, method=6)
size = buffer.tell()
if abs(size - target_bytes) / target_bytes < 0.05:
break
elif size > target_bytes:
quality -= 5
else:
quality += 5
quality = max(1, min(100, quality))
img.save(output_path, format='WEBP', quality=quality, method=6)
print(f"WebP压缩完成: {os.path.getsize(output_path)/1024:.2f}KB")
return output_path
GUI工具(简易版)
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image
import os
class ImageCompressorGUI:
def __init__(self):
self.root = tk.Tk()
self.root.title("图片压缩工具")
self.root.geometry("400x300")
# 文件选择
tk.Label(self.root, text="选择图片:").pack(pady=10)
self.file_path = tk.StringVar()
tk.Entry(self.root, textvariable=self.file_path, width=50).pack()
tk.Button(self.root, text="浏览", command=self.select_file).pack()
# 目标大小
tk.Label(self.root, text="目标大小 (KB):").pack(pady=10)
self.target_size = tk.IntVar(value=200)
tk.Scale(self.root, from_=10, to=1000, orient="horizontal",
variable=self.target_size).pack()
# 压缩按钮
tk.Button(self.root, text="开始压缩", command=self.compress,
bg="blue", fg="white", font=("Arial", 12)).pack(pady=20)
# 状态显示
self.status_label = tk.Label(self.root, text="")
self.status_label.pack()
self.root.mainloop()
def select_file(self):
filename = filedialog.askopenfilename(
filetypes=[("图片文件", "*.jpg *.jpeg *.png *.webp")]
)
if filename:
self.file_path.set(filename)
def compress(self):
if not self.file_path.get():
messagebox.showerror("错误", "请选择图片文件")
return
try:
target_kb = self.target_size.get()
# 调用上面的压缩函数
output_path = compress_to_target_size(self.file_path.get(), target_kb)
self.status_label.config(text=f"压缩完成!保存为: {output_path}")
except Exception as e:
messagebox.showerror("错误", str(e))
# 运行GUI
# ImageCompressorGUI()
使用建议
-
选择合适的格式:
- JPEG:适合照片,控制质量参数
- WebP:比JPEG压缩率高30%
- PNG:适合带透明度的图像
-
平衡质量与大小:
- 一般图片质量设置在80-85%即可
- 如果需要精确控制,使用二分法迭代
-
性能优化:
# 多线程批量处理 from concurrent.futures import ThreadPoolExecutor def batch_compress(image_list, target_size_kb): with ThreadPoolExecutor(max_workers=4) as executor: futures = [] for img_path in image_list: future = executor.submit(compress_to_target_size, img_path, target_size_kb) futures.append(future) for future in futures: future.result()
这个工具可以根据需要灵活调整,既能精确控制文件大小,又能保持良好的图像质量。
标签: 指定大小
版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。