# Mixed Inherited/Explicit Font Size Fix (Document-Wide) ## Problem (2026-07-01 生育友好宣传阵地建设协议) Source document has **mixed font sizing** in body text: - Some runs have explicit `sz=24` (12pt) — e.g., section headings, specific clauses - Other runs have **no explicit sz** — inherit from Normal style (`sz=21` / 10.5pt) - WB INS runs mostly got `sz=24` correctly, but the mix of explicit + inherited in **original** runs creates visual inconsistency Doro complaint: "文字大小不一致,修改" — the rendered result shows mixed sizes. ## Root Cause - `docDefaults` / Normal style = 10.5pt (sz=21) - Many body runs (P12+) have explicit sz=24 (from original author or conversion) - ~72 original runs have NO explicit sz → inherit 10.5pt → render smaller - OnlyOffice renders the mix faithfully → visible inconsistency ## Diagnosis ```python from docx import Document from collections import Counter doc = Document('file.docx') print(f'Normal style sz: {doc.styles["Normal"].font.size}') # If 133350 EMU = 10.5pt sizes = Counter() for p in doc.paragraphs[BODY_START:BODY_END]: for run in p.runs: if run.text.strip(): sizes[run.font.size.pt if run.font.size else 'inherited'] += 1 # If both 'inherited' and explicit size (e.g. 12.0) appear → mixed problem print(sizes.most_common()) ``` ## Fix Pattern (Full Body Range) Unlike the INS-only sweep, this fix targets ALL runs in the body text range: ```python import zipfile, re from lxml import etree WNS = '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}' # 1. Identify body range (skip title/preamble and signature) BODY_START = 12 # First body content paragraph index BODY_END = 56 # Last body paragraph (exclusive) TARGET_SZ = '24' # From explicit runs in body (majority value) # 2. Fix ALL runs in body range for pidx in range(BODY_START, min(BODY_END, len(paras))): p = paras[pidx] # Plain runs for r in p.findall(f'{WNS}r'): t_elem = r.find(f'{WNS}t') if t_elem is None or not (t_elem.text or '').strip(): continue rpr = r.find(f'{WNS}rPr') if rpr is None: rpr = etree.SubElement(r, f'{WNS}rPr') r.insert(0, rpr) sz = rpr.find(f'{WNS}sz') if sz is None: sz = etree.SubElement(rpr, f'{WNS}sz') sz.set(f'{WNS}val', TARGET_SZ) szCs = rpr.find(f'{WNS}szCs') if szCs is None: szCs = etree.SubElement(rpr, f'{WNS}szCs') szCs.set(f'{WNS}val', TARGET_SZ) # INS runs for ins in p.findall(f'{WNS}ins'): for r in ins.findall(f'{WNS}r'): # same logic as above ... # DEL runs (for visual consistency in markup view) for d in p.findall(f'{WNS}del'): for r in d.findall(f'{WNS}r'): # same logic ... ``` ## Key Distinctions from INS-Only Fix | Aspect | INS-only sweep | Full body range fix | |--------|---------------|---------------------| | Scope | Only WB INS runs | ALL runs (plain + INS + DEL) | | Trigger | INS runs missing sz | Doro reports "文字大小不一致" | | Root cause | add_clause/tracked_replace gaps | Source document mixed inheritance | | Target sz | From neighboring runs | From majority explicit sz in body | ## When to Apply - Doro says "文字大小不一致" on a delivered file - `wb-ins-font-verify.py` passes (INS runs OK) but rendered output still shows mixed sizes - Diagnostic shows body runs split between `inherited` and explicit sz ## Important: Don't Change Preamble/Signature - Title/header (e.g., P0-P2): larger sz by design (22pt/sz=44) — don't touch - Party info (P3-P10): may use different sz — don't touch unless in body range - Signature area (P56+): often sz=21 (10.5pt) — don't touch - Only fix the **body text range** where sz should be uniform ## Relationship to 格式保留铁律 This fix does NOT violate "格式保留铁律" (don't change original formatting) because: - The original document's **intent** is uniform 12pt body text (evidenced by majority explicit sz=24) - The missing sz is a **formatting omission** (author forgot to set explicit sz on some runs) - The fix makes the document render as the original author intended - This is different from "changing 仿宋_GB2312 to 仿宋" (that changes the actual format choice) BUT: if the original document intentionally uses different sizes in body (e.g., smaller text for notes, larger for headings), don't blindly unify. Check the pattern first.