Files
SignatureSystem/image_test/extract_docx_images.py

82 lines
2.5 KiB
Python
Raw Normal View History

2026-07-20 13:16:17 +08:00
"""从 docx 提取所有内嵌图片,方便定位实际插入到文档里的图片字节。
用法:
python image_test/extract_docx_images.py <signed.docx>
输出:
image_test/output/docx_images/<图片名>.png ( docx 内顺序编号)
每张图打印尺寸 + 紧致度诊断
"""
import io
import sys
import zipfile
from pathlib import Path
from PIL import Image, ImageChops
BASE_DIR = Path(__file__).resolve().parent
OUT_DIR = BASE_DIR / "output" / "docx_images"
def analyze_image(data):
img = Image.open(io.BytesIO(data))
if img.mode != 'RGBA':
img = img.convert('RGBA')
r, g, b, a = img.split()
luma = Image.merge('RGB', (r, g, b)).convert('L')
alpha_mask = a.point(lambda p: 255 if p > 30 else 0)
luma_mask = luma.point(lambda p: 255 if p < 210 else 0)
combined = ImageChops.darker(alpha_mask, luma_mask)
total = img.size[0] * img.size[1] or 1
return {
'size': img.size,
'mode': img.mode,
'content_pct': 100.0 * sum(combined.histogram()[1:]) / total,
'bbox': combined.getbbox(),
'alpha_pct': 100.0 * sum(alpha_mask.histogram()[1:]) / total,
}
def main():
if len(sys.argv) < 2:
print("用法: python image_test/extract_docx_images.py <signed.docx>")
sys.exit(1)
docx_path = Path(sys.argv[1])
if not docx_path.exists():
print(f"文件不存在: {docx_path}")
sys.exit(1)
OUT_DIR.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(docx_path, 'r') as z:
media_files = sorted([n for n in z.namelist()
if n.startswith('word/media/')])
if not media_files:
print("docx 内未找到 word/media/ 下的图片")
return
print(f"找到 {len(media_files)} 张图片\n")
for i, name in enumerate(media_files, 1):
data = z.read(name)
ext = Path(name).suffix or '.png'
out_path = OUT_DIR / f"image_{i:02d}{ext}"
with open(out_path, 'wb') as f:
f.write(data)
try:
stats = analyze_image(data)
print(f"[{i:02d}] {name}")
print(f" 尺寸={stats['size']} 模式={stats['mode']} "
f"alpha像素={stats['alpha_pct']:.1f}% "
f"内容={stats['content_pct']:.1f}% bbox={stats['bbox']}")
print(f" 已保存: {out_path}")
except Exception as e:
print(f"[{i:02d}] {name}: 解析失败 {e}")
print()
if __name__ == '__main__':
main()