本文目录导读:

使用 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
注意事项
- 备份重要文件:建议先对重要图片进行备份
- PSD文件:不支持PSD格式
- GIF动画:可能无法保持动画效果
- EXIF数据:exiftool方式可以完全去除,Pillow方式可能保留部分数据
选择哪种方案取决于你的具体需求和对第三方工具的偏好。