图片压缩工具控制在指定大小

联启 电脑工具 16

本文目录导读:

图片压缩工具控制在指定大小-第1张图片-电脑手机工具软件下载 - 免费实用工具合集 | 联启科技

  1. 方案一:基于质量的迭代压缩(最常用)
  2. 方案二:支持多种格式的全功能压缩
  3. 方案三:WebP格式(更高效的压缩)
  4. 方案四:GUI工具(简易版)
  5. 使用建议

我来帮您设计一个可以控制输出文件大小的图片压缩工具,以下是几种实现方案:

基于质量的迭代压缩(最常用)

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()

使用建议

  1. 选择合适的格式

    • JPEG:适合照片,控制质量参数
    • WebP:比JPEG压缩率高30%
    • PNG:适合带透明度的图像
  2. 平衡质量与大小

    • 一般图片质量设置在80-85%即可
    • 如果需要精确控制,使用二分法迭代
  3. 性能优化

    # 多线程批量处理
    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()

这个工具可以根据需要灵活调整,既能精确控制文件大小,又能保持良好的图像质量。

标签: 指定大小

抱歉,评论功能暂时关闭!