1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
import os
import zipfile
import shutil
from PIL import Image
def compress_image(image_path, quality=80, max_width=1920):
"""压缩单张图片:降低质量并限制最大宽度"""
try:
with Image.open(image_path) as img:
# 如果是透明图(RGBA),转为RGB防止转JPEG报错
if img.mode in ('RGBA', 'LA'):
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[-1])
img = background
elif img.mode != 'RGB':
img = img.convert('RGB')
# 限制最大宽度,防止超大截图
if img.width > max_width:
ratio = max_width / img.width
new_height = int(img.height * ratio)
img = img.resize((max_width, new_height), Image.Resampling.LANCZOS)
# 保存为压缩后的 JPEG
img.save(image_path, 'JPEG', quality=quality, optimize=True)
except Exception as e:
print(f"处理图片失败 {image_path}: {e}")
def optimize_docx_images(docx_path, output_path, quality=80):
"""解压docx,压缩media中的图片,再重新打包"""
temp_dir = "temp_docx_extracted"
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)
# 1. 解压 docx
with zipfile.ZipFile(docx_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir)
# 2. 遍历并压缩图片
media_dir = os.path.join(temp_dir, 'word', 'media')
if os.path.exists(media_dir):
for filename in os.listdir(media_dir):
if filename.lower().endswith(('png', 'jpg', 'jpeg', 'bmp', 'tiff')):
file_path = os.path.join(media_dir, filename)
# 针对 png 截图,统一转成更小的 jpg 压缩
base_name, _ = os.path.splitext(filename)
new_filename = f"{base_name}.jpg"
new_file_path = os.path.join(media_dir, new_filename)
# 如果是png,重命名或转换
if file_path != new_file_path and os.path.exists(file_path):
os.remove(file_path) # 实际操作中直接用原路径保存为jpg更方便
# 简化处理:直接原地用PIL处理
compress_image(file_path, quality=quality)
# 3. 重新打包为 docx
with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zip_out:
for foldername, subfolders, filenames in os.walk(temp_dir):
for filename in filenames:
file_path = os.path.join(foldername, filename)
arcname = os.path.relpath(file_path, temp_dir)
zip_out.write(file_path, arcname)
# 4. 清理临时文件
shutil.rmtree(temp_dir)
print(f"优化完成!生成的新文件:{output_path}")
# 使用示例
if __name__ == '__main__':
optimize_docx_images("input.docx", "output_compressed.docx", quality=75)
|