"""检查 signed.docx 中签名图片对应的 drawing XML,看实际显示尺寸(EMU)。 目的: 字节已经证明一致(e2e_test.py),但用户仍看到"空白"。 本脚本读 document.xml,找到图片所在段落的: - wp:extent (图片显示尺寸 EMU) - 段落 pPr/spacing (line 行高) - 段落所在表格单元格 tcW (单元格宽度) 对比图片实际像素 vs 显示尺寸 vs 段落行高,定位空白的视觉来源。 EMU 换算: 1 inch = 914400 EMU = 2.54 cm 1 cm = 360000 EMU """ import sys import zipfile import xml.etree.ElementTree as ET from pathlib import Path BASE_DIR = Path(__file__).resolve().parent DOCX_PATH = BASE_DIR / "output" / "e2e" / "signed.docx" W = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' WP = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing' A = 'http://schemas.openxmlformats.org/drawingml/2006/main' def emu_to_cm(emu): try: return int(emu) / 360000.0 except (TypeError, ValueError): return None def main(): if not DOCX_PATH.exists(): print(f"docx 不存在: {DOCX_PATH}") print("请先运行: python image_test/e2e_test.py") sys.exit(1) with zipfile.ZipFile(DOCX_PATH) as z: xml_bytes = z.read('word/document.xml') root = ET.fromstring(xml_bytes) print("=== 段落列表(含 spacing / drawing)===\n") for i, p in enumerate(root.iter(f'{{{W}}}p'), 1): pPr = p.find(f'{{{W}}}pPr') spacing_info = "" if pPr is not None: sp = pPr.find(f'{{{W}}}spacing') if sp is not None: line = sp.get(f'{{{W}}}line') rule = sp.get(f'{{{W}}}lineRule') before = sp.get(f'{{{W}}}before') after = sp.get(f'{{{W}}}after') if line or before or after: parts = [] if line: cm = emu_to_cm(int(line) / 20 * 12700) if rule == 'exact' else None parts.append(f"line={line}({rule})->{cm:.2f}cm" if cm else f"line={line}({rule})") if before: parts.append(f"before={before}({int(before)/20:.1f}pt)") if after: parts.append(f"after={after}({int(after)/20:.1f}pt)") spacing_info = " | ".join(parts) text = "".join(t.text or '' for t in p.iter(f'{{{W}}}t')) has_drawing = len(list(p.iter(f'{{{WP}}}inline'))) > 0 marker = "[图]" if has_drawing else " " print(f"[段{i:02d}] {marker} text={text[:40]!r}") if spacing_info: print(f" spacing: {spacing_info}") for inline in p.iter(f'{{{WP}}}inline'): extent = inline.find(f'{{{WP}}}extent') if extent is not None: cx = extent.get('cx') cy = extent.get('cy') print(f" drawing extent: cx={cx}({emu_to_cm(cx):.2f}cm) cy={cy}({emu_to_cm(cy):.2f}cm)") tc_parent = None parent = p while parent is not None: parent_iter = list(root.iter()) break for tc in root.iter(f'{{{W}}}tc'): if p in list(tc.iter(f'{{{W}}}p')): tcPr = tc.find(f'{{{W}}}tcPr') if tcPr is not None: tcW = tcPr.find(f'{{{W}}}tcW') if tcW is not None: w = tcW.get(f'{{{W}}}w') t = tcW.get(f'{{{W}}}type') print(f" cell width: w={w} type={t}") if __name__ == '__main__': main()