first commit
This commit is contained in:
100
image_test/inspect_xml.py
Normal file
100
image_test/inspect_xml.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""检查 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()
|
||||
Reference in New Issue
Block a user