WEBP/PNG/HEIC批量转JPG:李哥的一键式图片格式转换神器

兄弟们,是不是经常遇到这些头疼事?

  • 从网站扒下来的图片全是 WEBP​ 格式,编辑软件打不开?
  • PNG​ 图片虽然清晰,但体积太大,上传发布总受限制?
  • 用苹果设备拍的照片是 HEIC​ 格式,在Windows电脑上就成了“天书”?

别慌!李哥出手,必属精品!今天给大家带来的这款 「批量图片格式转换JPG工具」,就是专门治这些“格式不服”的!它就像你图片库里的“格式统一大师”,管你什么WEBP、PNG还是HEIC,统统给咱变成最通用、最省心的 JPG​ 格式!

真正的“傻瓜式”操作:把脚本和图片放一个文件夹,双击运行,剩下的交给程序。自动安装环境、自动转换、自动整理文件,你只管喝杯茶等着收JPG就行!特别加入了 HEIC 格式支持,再也不用为苹果照片在电脑上打不开而发愁了。转换后的JPG、原始文件、转换失败的图片,会自动分门别类存到 convert/source/failed/三个文件夹里,井井有条,绝不乱套。万一有同名文件?不存在的!程序会自动给你加上序号,保证一个文件都不会被覆盖。

下载脚本 -> 双击运行 -> 收获一文件夹整齐的JPG图片!

李哥已经把代码和详细的使用说明都准备好了,就等你来取。赶紧下载试试,从此告别图片格式转换的烦恼!做人呢,最重要的就是开心!用李哥的工具,让你的图片处理也开心起来!

核心解读:

作用:自动检查并安装必要的Python库(Pillow和pillow-heif)启用HEIC文件格式支持(苹果设备照片格式)

创建虚拟环境并安装python库

# 退出当前环境
deactivate

# 删除损坏的虚拟环境
cd ~/Documents/env
rm -rf myenv

# 重新创建虚拟环境
python3 -m venv myenv

# 激活新环境
source myenv/bin/activate

# 检查pip是否正常
pip --version

# 安装Pillow
pip install Pillow

# 检查安装是否成功
python3 -c "from PIL import Image; print('Pillow安装成功!')"

创建三个目录:

  • convert/– 存放转换后的JPG文件
  • source/– 存放原始图片文件
  • failed/– 存放转换失败的文件

智能移动文件到指定目录,自动处理重名文件(添加序号)输出格式JPG (.jpg) – 通用的有损压缩图片格式

文件整理逻辑

转换前目录结构:
当前目录/
├── image1.webp
├── image2.png
├── image3.heic
└── convert_images.py

转换后目录结构:
当前目录/
├── convert/           # 转换后的JPG文件
│   ├── image1.jpg
│   ├── image2.jpg
│   └── image3.jpg
├── source/            # 原始文件(已移动)
│   ├── image1.webp
│   ├── image2.png
│   └── image3.heic
├── failed/            # 转换失败的文件
└── convert_images.py

实现代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import glob
import shutil
import sys
import subprocess

def check_and_install_dependencies():
    """检查并安装必要的依赖"""
    dependencies = ['Pillow', 'pillow-heif']
    missing_deps = []
    
    # 检查Pillow
    try:
        from PIL import Image
        print("✓ Pillow 已安装")
    except ImportError:
        missing_deps.append('Pillow')
    
    # 检查pillow-heif
    try:
        import pillow_heif
        print("✓ pillow-heif 已安装")
    except ImportError:
        missing_deps.append('pillow-heif')
    
    # 安装缺失的依赖
    if missing_deps:
        print(f"❌ 缺少依赖: {', '.join(missing_deps)}")
        print("正在安装依赖...")
        
        for dep in missing_deps:
            try:
                if dep == 'Pillow':
                    subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'Pillow'])
                elif dep == 'pillow-heif':
                    subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pillow-heif'])
                print(f"✓ {dep} 安装成功")
            except subprocess.CalledProcessError:
                print(f"❌ {dep} 安装失败,尝试使用镜像源...")
                try:
                    subprocess.check_call([sys.executable, '-m', 'pip', 'install', dep, 
                                         '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple/'])
                    print(f"✓ {dep} 安装成功(使用镜像源)")
                except:
                    print(f"❌ {dep} 安装失败,请手动安装: pip install {dep}")
                    return False
        # 重新检查
        try:
            from PIL import Image
            import pillow_heif
            print("✓ 所有依赖安装成功")
            return True
        except ImportError as e:
            print(f"❌ 依赖安装后仍然失败: {e}")
            return False
    return True

def setup_heic_support():
    """设置HEIC支持"""
    try:
        import pillow_heif
        pillow_heif.register_heif_opener()
        print("✓ HEIC格式支持已启用")
        return True
    except Exception as e:
        print(f"❌ HEIC支持初始化失败: {e}")
        return False

def create_directories():
    """创建必要的目录"""
    directories = ['convert', 'source', 'failed']
    for directory in directories:
        if not os.path.exists(directory):
            os.makedirs(directory)
            print(f"✓ 创建目录: {directory}/")

def move_file_to_directory(original_file, directory):
    """移动文件到指定目录"""
    try:
        filename = os.path.basename(original_file)
        destination = os.path.join(directory, filename)
        
        # 如果目标文件已存在,添加序号
        counter = 1
        base_name, ext = os.path.splitext(filename)
        while os.path.exists(destination):
            new_filename = f"{base_name}_{counter}{ext}"
            destination = os.path.join(directory, new_filename)
            counter += 1
        
        shutil.move(original_file, destination)
        return True
    except Exception as e:
        print(f"⚠ 移动文件失败 {original_file}: {e}")
        return False

def convert_image_file(input_file, temp_jpg_file, is_heic=False):
    """转换图片文件"""
    try:
        from PIL import Image
        
        if is_heic:
            # HEIC文件特殊处理
            try:
                import pillow_heif
                heif_file = pillow_heif.open_heif(input_file)
                image = Image.frombytes(
                    heif_file.mode, 
                    heif_file.size, 
                    heif_file.data,
                    "raw",
                    heif_file.mode,
                    heif_file.stride,
                )
            except:
                # 如果直接读取失败,尝试通过PIL打开
                pillow_heif.register_heif_opener()
                image = Image.open(input_file)
        else:
            # 其他格式文件
            image = Image.open(input_file)
        
        # 处理图片模式
        if image.mode in ('RGBA', 'LA', 'P'):
            background = Image.new('RGB', image.size, (255, 255, 255))
            if image.mode == 'P':
                image = image.convert('RGBA')
            if image.mode == 'RGBA':
                background.paste(image, mask=image.split()[-1])
            else:
                background.paste(image)
            image = background
        elif image.mode != 'RGB':
            image = image.convert('RGB')
        
        # 保存为JPG
        image.save(temp_jpg_file, "JPEG", quality=85, optimize=True)
        return True, "成功"
        
    except Exception as e:
        return False, str(e)

def batch_convert_images():
    """批量转换图片"""
    print("=== 图片格式批量转换工具 ===")
    
    # 检查并安装依赖
    if not check_and_install_dependencies():
        print("❌ 依赖安装失败,无法继续")
        return
    
    # 设置HEIC支持
    heic_supported = setup_heic_support()
    
    # 创建目录
    create_directories()
    
    # 收集文件
    files_to_convert = []
    for pattern in ['*.webp', '*.WEBP', '*.png', '*.PNG', '*.heic', '*.HEIC']:
        files_to_convert.extend(glob.glob(pattern))
    
    files_to_convert = sorted(list(set(files_to_convert)))
    files_to_convert = [f for f in files_to_convert if not any(f.startswith(d) for d in ['convert/', 'source/', 'failed/'])]
    
    if not files_to_convert:
        print("❌ 未找到可转换的图片文件")
        return
    
    # 分类统计
    webp_files = [f for f in files_to_convert if f.lower().endswith('.webp')]
    png_files = [f for f in files_to_convert if f.lower().endswith('.png')]
    heic_files = [f for f in files_to_convert if f.lower().endswith('.heic')]
    
    print(f"找到 {len(files_to_convert)} 个文件:")
    print(f"  WEBP: {len(webp_files)} 个, PNG: {len(png_files)} 个, HEIC: {len(heic_files)} 个")
    
    if heic_files and not heic_supported:
        print("⚠ HEIC文件将无法转换")
    
    # 转换统计
    results = {'success': 0, 'failed': 0, 'skipped': 0}
    
    for i, input_file in enumerate(files_to_convert, 1):
        filename_without_ext = os.path.splitext(os.path.basename(input_file))[0]
        temp_jpg_file = filename_without_ext + ".jpg"
        final_jpg_path = os.path.join('convert', temp_jpg_file)
        
        # 跳过已存在
        if os.path.exists(final_jpg_path):
            print(f"{i}/{len(files_to_convert)} ⚡ 跳过已存在: {final_jpg_path}")
            results['skipped'] += 1
            continue
        
        file_size = os.path.getsize(input_file) / 1024
        file_ext = os.path.splitext(input_file)[1].upper()
        is_heic = input_file.lower().endswith('.heic')
        
        print(f"{i}/{len(files_to_convert)} 🔄 转换: {os.path.basename(input_file)} ({file_size:.1f} KB)", end="")
        
        try:
            if is_heic and not heic_supported:
                success, message = False, "HEIC支持未启用"
            else:
                success, message = convert_image_file(input_file, temp_jpg_file, is_heic)
            
            if success:
                # 移动成功文件
                if os.path.exists(temp_jpg_file):
                    move_file_to_directory(temp_jpg_file, 'convert')
                move_file_to_directory(input_file, 'source')
                results['success'] += 1
                print(" -> ✅ 完成")
            else:
                # 移动失败文件
                move_file_to_directory(input_file, 'failed')
                results['failed'] += 1
                print(f" -> ❌ 失败: {message}")
                
        except Exception as e:
            move_file_to_directory(input_file, 'failed')
            results['failed'] += 1
            print(f" -> 💥 异常: {str(e)}")
    
    # 输出结果
    print(f"\n=== 转换完成 ===")
    print(f"✅ 成功: {results['success']}, ❌ 失败: {results['failed']}, ⚡ 跳过: {results['skipped']}")

if __name__ == "__main__":
    batch_convert_images()
    input("\n按Enter键退出...")