批量去除图片元数据的脚本

wen 实用脚本 1

本文目录导读:

批量去除图片元数据的脚本

  1. 方案一:使用 Python + Pillow(推荐)
  2. 方案二:使用 exiftool(更彻底)
  3. 方案三:shell脚本(Linux/macOS)
  4. 使用说明
  5. 注意事项

使用 Python + Pillow(推荐)

#!/usr/bin/env python3
"""
批量去除图片元数据脚本
支持格式: JPG, PNG, WebP, TIFF, BMP
"""
import os
import sys
from PIL import Image
from concurrent.futures import ThreadPoolExecutor, as_completed
def remove_metadata(input_path, output_path=None, inplace=False):
    """
    去除单张图片的元数据
    Args:
        input_path: 输入文件路径
        output_path: 输出文件路径(inplace=False时使用)
        inplace: 是否原地替换原文件
    """
    try:
        img = Image.open(input_path)
        # 获取图片格式
        img_format = img.format
        if img_format is None:
            img_format = input_path.split('.')[-1].upper()
            if img_format in ['JPG', 'JPEG']:
                img_format = 'JPEG'
        # 提取可用的数据(不包含元数据)
        # 对于PNG,需要保留alpha通道
        if img_format == 'PNG' and img.mode in ('RGBA', 'LA', 'PA'):
            data = img.getdata()
            img_clean = Image.new(img.mode, img.size)
            img_clean.putdata(list(data))
        else:
            # 对于其他格式,直接复制并丢弃元数据
            if img.mode == 'RGBA':
                img_clean = Image.new('RGBA', img.size)
            elif img.mode == 'P':
                img_clean = Image.new('RGBA', img.size)
            else:
                img_clean = Image.new('RGB', img.size)
            img_clean.putdata(list(img.getdata()))
        # 保存(不保留任何元数据)
        if inplace:
            # 先保存到临时文件,再替换
            temp_path = input_path + '.temp_clean'
            img_clean.save(temp_path, format=img_format, quality=95)
            os.replace(temp_path, input_path)
        else:
            img_clean.save(output_path, format=img_format, quality=95)
        return True, input_path, None
    except Exception as e:
        return False, input_path, str(e)
def batch_remove_metadata(input_dir, output_dir=None, inplace=False):
    """
    批量去除图片元数据
    Args:
        input_dir: 输入目录
        output_dir: 输出目录(inplace=False时使用)
        inplace: 是否原地替换
    """
    supported_ext = {'.jpg', '.jpeg', '.png', '.webp', '.tiff', '.tif', '.bmp'}
    # 获取所有图片文件
    files = []
    for root, dirs, filenames in os.walk(input_dir):
        for filename in filenames:
            ext = os.path.splitext(filename)[1].lower()
            if ext in supported_ext:
                files.append(os.path.join(root, filename))
    if not files:
        print("没有找到支持的图片文件")
        return
    print(f"找到 {len(files)} 个图片文件")
    # 创建输出目录(如果需要)
    if output_dir and not inplace:
        os.makedirs(output_dir, exist_ok=True)
    # 使用线程池处理
    success_count = 0
    fail_count = 0
    with ThreadPoolExecutor(max_workers=8) as executor:
        futures = []
        for file_path in files:
            if inplace:
                futures.append(executor.submit(remove_metadata, file_path, inplace=True))
            else:
                # 保留目录结构
                rel_path = os.path.relpath(file_path, input_dir)
                out_path = os.path.join(output_dir, rel_path)
                os.makedirs(os.path.dirname(out_path), exist_ok=True)
                futures.append(executor.submit(remove_metadata, file_path, out_path))
        for future in as_completed(futures):
            success, path, error = future.result()
            if success:
                success_count += 1
                print(f"✓ 处理成功: {path}")
            else:
                fail_count += 1
                print(f"✗ 处理失败: {path} - {error}")
    print(f"\n处理完成: 成功 {success_count}, 失败 {fail_count}")
if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser(description="批量去除图片元数据")
    parser.add_argument("input", help="输入目录")
    parser.add_argument("-o", "--output", help="输出目录(不指定则原地替换)")
    parser.add_argument("--inplace", action="store_true", help="原地替换原文件")
    args = parser.parse_args()
    if args.inplace or args.output is None:
        print("警告: 将原地修改文件!")
        confirm = input("确认继续? (y/n): ")
        if confirm.lower() != 'y':
            sys.exit(0)
        batch_remove_metadata(args.input, inplace=True)
    else:
        batch_remove_metadata(args.input, args.output)

使用 exiftool(更彻底)

#!/usr/bin/env python3
"""
使用exiftool批量去除图片元数据
需要先安装: exiftool
"""
import os
import subprocess
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
def check_exiftool():
    """检查exiftool是否安装"""
    try:
        subprocess.run(['exiftool', '-ver'], capture_output=True, check=True)
        return True
    except (subprocess.CalledProcessError, FileNotFoundError):
        return False
def remove_metadata_exiftool(file_path, inplace=True):
    """
    使用exiftool去除元数据
    Args:
        file_path: 文件路径
        inplace: 是否原地修改
    """
    try:
        if inplace:
            # 原地修改,保留备份
            subprocess.run(
                ['exiftool', '-overwrite_original', '-all=', file_path],
                capture_output=True,
                check=True
            )
        else:
            # 保存到新文件
            base, ext = os.path.splitext(file_path)
            output_path = f"{base}_clean{ext}"
            subprocess.run(
                ['exiftool', '-all=', '-o', output_path, file_path],
                capture_output=True,
                check=True
            )
        return True, file_path, None
    except subprocess.CalledProcessError as e:
        return False, file_path, str(e)
def batch_remove_metadata_exiftool(input_dir, inplace=True):
    """
    批量使用exiftool去除元数据
    """
    if not check_exiftool():
        print("错误: 未安装exiftool,请通过以下方式安装:")
        print("  macOS: brew install exiftool")
        print("  Linux: sudo apt-get install exiftool")
        print("  Windows: 下载 https://exiftool.org/")
        sys.exit(1)
    supported_ext = {'.jpg', '.jpeg', '.png', '.webp', '.tiff', '.tif'}
    # 获取所有图片文件
    files = []
    for root, dirs, filenames in os.walk(input_dir):
        for filename in filenames:
            ext = os.path.splitext(filename)[1].lower()
            if ext in supported_ext:
                files.append(os.path.join(root, filename))
    if not files:
        print("没有找到支持的图片文件")
        return
    print(f"找到 {len(files)} 个图片文件")
    # 使用多线程处理
    success_count = 0
    fail_count = 0
    with ThreadPoolExecutor(max_workers=4) as executor:
        futures = []
        for file_path in files:
            futures.append(executor.submit(remove_metadata_exiftool, file_path, inplace))
        for future in as_completed(futures):
            success, path, error = future.result()
            if success:
                success_count += 1
                print(f"✓ 处理成功: {path}")
            else:
                fail_count += 1
                print(f"✗ 处理失败: {path} - {error}")
    print(f"\n处理完成: 成功 {success_count}, 失败 {fail_count}")
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python script.py <输入目录> [--no-backup]")
        sys.exit(1)
    input_dir = sys.argv[1]
    inplace = True  # 默认原地修改
    if len(sys.argv) > 2 and sys.argv[2] == '--no-backup':
        confirm = input("警告: 将永久修改文件,是否继续? (y/n): ")
        if confirm.lower() != 'y':
            sys.exit(0)
    batch_remove_metadata_exiftool(input_dir, inplace)

shell脚本(Linux/macOS)

#!/bin/bash
# 批量去除图片元数据的Shell脚本
# 使用方法: ./remove_exif.sh [输入目录] [输出目录]
# 如果不指定输出目录,则原地修改
INPUT_DIR="${1:-.}"
OUTPUT_DIR="${2:-}"
# 支持的格式
EXTENSIONS="jpg jpeg png webp tiff tif"
# 检查exiftool
if ! command -v exiftool &> /dev/null; then
    echo "错误: 需要安装exiftool"
    echo "安装方式: brew install exiftool (macOS)"
    echo "          sudo apt-get install exiftool (Linux)"
    exit 1
fi
# 创建输出目录
if [ -n "$OUTPUT_DIR" ]; then
    mkdir -p "$OUTPUT_DIR"
fi
# 处理函数
process_file() {
    local file="$1"
    local rel_path="${file#$INPUT_DIR/}"
    if [ -n "$OUTPUT_DIR" ]; then
        # 输出到新目录
        output_path="$OUTPUT_DIR/$rel_path"
        mkdir -p "$(dirname "$output_path")"
        exiftool -all= -o "$output_path" "$file" >/dev/null 2>&1
    else
        # 原地修改
        exiftool -overwrite_original -all= "$file" >/dev/null 2>&1
    fi
    if [ $? -eq 0 ]; then
        echo "✓ $file"
    else
        echo "✗ $file"
    fi
}
export -f process_file
export INPUT_DIR OUTPUT_DIR
# 遍历处理
echo "开始处理图片文件..."
for ext in $EXTENSIONS; do
    find "$INPUT_DIR" -type f -iname "*.$ext" -exec bash -c 'process_file "$0"' {} \;
done
echo "处理完成!"

使用说明

安装依赖

Python方案

pip install Pillow

exiftool方案

# macOS
brew install exiftool
# Linux (Ubuntu/Debian)
sudo apt-get install exiftool
# Windows
# 下载 https://exiftool.org/ 并安装

运行脚本

Python脚本

# 原地修改
python remove_metadata.py ./images --inplace
# 输出到新目录
python remove_metadata.py ./images -o ./cleaned_images

Shell脚本

# 原地修改
chmod +x remove_exif.sh
./remove_exif.sh ./images
# 输出到新目录
./remove_exif.sh ./images ./cleaned_images

注意事项

  1. 备份重要文件:建议先对重要图片进行备份
  2. PSD文件:不支持PSD格式
  3. GIF动画:可能无法保持动画效果
  4. EXIF数据:exiftool方式可以完全去除,Pillow方式可能保留部分数据

选择哪种方案取决于你的具体需求和对第三方工具的偏好。

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