python-hwpx 2.21.0__py3-none-any.whl → 2.22.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hwpx/table_patch.py +58 -0
- {python_hwpx-2.21.0.dist-info → python_hwpx-2.22.0.dist-info}/METADATA +1 -1
- {python_hwpx-2.21.0.dist-info → python_hwpx-2.22.0.dist-info}/RECORD +8 -8
- {python_hwpx-2.21.0.dist-info → python_hwpx-2.22.0.dist-info}/WHEEL +0 -0
- {python_hwpx-2.21.0.dist-info → python_hwpx-2.22.0.dist-info}/entry_points.txt +0 -0
- {python_hwpx-2.21.0.dist-info → python_hwpx-2.22.0.dist-info}/licenses/LICENSE +0 -0
- {python_hwpx-2.21.0.dist-info → python_hwpx-2.22.0.dist-info}/licenses/NOTICE +0 -0
- {python_hwpx-2.21.0.dist-info → python_hwpx-2.22.0.dist-info}/top_level.txt +0 -0
hwpx/table_patch.py
CHANGED
|
@@ -600,6 +600,57 @@ def _insert_row_by_clone(table: str, ref_row: int, count: int = 1) -> str:
|
|
|
600
600
|
return _rebuild(prefix, new_rows, suffix, rowcnt=len(new_rows))
|
|
601
601
|
|
|
602
602
|
|
|
603
|
+
def _set_column_widths(table: str, new_widths: dict[int, int]) -> str:
|
|
604
|
+
"""Set logical column widths (HWPUNIT). Each cell's cellSz.width = sum of its
|
|
605
|
+
spanned columns' new widths. Byte-preserving cellSz edits; grid unchanged."""
|
|
606
|
+
_guard_flat(table)
|
|
607
|
+
prefix, rows, suffix = _parse_table(table)
|
|
608
|
+
|
|
609
|
+
def fix(tc: str):
|
|
610
|
+
ca = _si(tc, "cellAddr", "colAddr")
|
|
611
|
+
cs = _si(tc, "cellSpan", "colSpan") or 1
|
|
612
|
+
w = sum(int(new_widths.get(c, 0)) for c in range(ca, ca + cs))
|
|
613
|
+
if w > 0:
|
|
614
|
+
tc = _ss(tc, "cellSz", "width", w)
|
|
615
|
+
return tc
|
|
616
|
+
|
|
617
|
+
rows = [_map_cells(r, fix) for r in rows]
|
|
618
|
+
return _rebuild(prefix, rows, suffix)
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def _autofit_columns(table: str, *, min_frac: float = 0.06, damp: float = 0.5) -> str:
|
|
622
|
+
"""Rebalance column widths to content: content-heavy columns widen, light ones
|
|
623
|
+
narrow, table total width preserved. Demand = longest single-span cell's text
|
|
624
|
+
width (form_fit advance model), sqrt-damped so a paragraph column doesn't run
|
|
625
|
+
away; every column keeps a floor of *min_frac* of the total."""
|
|
626
|
+
from .form_fit.measure import estimate_text_width
|
|
627
|
+
|
|
628
|
+
prefix, rows, suffix = _parse_table(table)
|
|
629
|
+
cur = _uniform_col_widths(rows)
|
|
630
|
+
if cur is None:
|
|
631
|
+
raise TableStructureError("no uniform (all colSpan=1) row to autofit widths")
|
|
632
|
+
ncol = max(cur) + 1
|
|
633
|
+
total = sum(cur.values())
|
|
634
|
+
demand = {c: 0.0 for c in range(ncol)}
|
|
635
|
+
for r in rows:
|
|
636
|
+
for tc in _S_TC.findall(r):
|
|
637
|
+
if (_si(tc, "cellSpan", "colSpan") or 1) != 1:
|
|
638
|
+
continue
|
|
639
|
+
ca = _si(tc, "cellAddr", "colAddr")
|
|
640
|
+
txt = "".join(re.findall(r"<hp:t>(.*?)</hp:t>", tc, re.DOTALL))
|
|
641
|
+
demand[ca] = max(demand[ca], estimate_text_width(txt, 10.0))
|
|
642
|
+
weight = {c: max(demand[c], 1.0) ** damp for c in range(ncol)}
|
|
643
|
+
sw = sum(weight.values()) or 1.0
|
|
644
|
+
floor = total * min_frac
|
|
645
|
+
raw = {c: max(floor, total * weight[c] / sw) for c in range(ncol)}
|
|
646
|
+
scale = total / (sum(raw.values()) or 1.0)
|
|
647
|
+
new = {c: int(round(raw[c] * scale)) for c in range(ncol)}
|
|
648
|
+
# absorb rounding drift into the widest column so the total is exact
|
|
649
|
+
drift = total - sum(new.values())
|
|
650
|
+
new[max(new, key=lambda c: new[c])] += drift
|
|
651
|
+
return _set_column_widths(table, new)
|
|
652
|
+
|
|
653
|
+
|
|
603
654
|
def _validate_or_raise(table: str) -> None:
|
|
604
655
|
_grid, rep = build_grid(table.encode("utf-8"))
|
|
605
656
|
if not rep.ok:
|
|
@@ -608,10 +659,17 @@ def _validate_or_raise(table: str) -> None:
|
|
|
608
659
|
|
|
609
660
|
# --- section-level application (byte-region splice back) ----------------------
|
|
610
661
|
|
|
662
|
+
def _widths_arg(o: Mapping[str, Any]) -> dict[int, int]:
|
|
663
|
+
w = o["widths"]
|
|
664
|
+
return {int(k): int(v) for k, v in w.items()} if isinstance(w, Mapping) else {i: int(v) for i, v in enumerate(w)}
|
|
665
|
+
|
|
666
|
+
|
|
611
667
|
_STRUCT_OPS = {
|
|
612
668
|
"delete_column": lambda t, o: _collapse_empty_rows(_delete_columns(t, o["cols"] if "cols" in o else [o["col"]])),
|
|
613
669
|
"delete_row": lambda t, o: _delete_rows(t, o["rows"] if "rows" in o else [o["row"]]),
|
|
614
670
|
"insert_row_by_clone": lambda t, o: _insert_row_by_clone(t, o["ref_row"], int(o.get("count", 1))),
|
|
671
|
+
"set_column_widths": lambda t, o: _set_column_widths(t, _widths_arg(o)),
|
|
672
|
+
"autofit_columns": lambda t, o: _autofit_columns(t, min_frac=float(o.get("min_frac", 0.06)), damp=float(o.get("damp", 0.5))),
|
|
615
673
|
}
|
|
616
674
|
|
|
617
675
|
|
|
@@ -5,7 +5,7 @@ hwpx/form_fill.py,sha256=VUIU53Qa9Ho2aP72biDvJwnDW7ngdAzu3PSd5A7d1JM,9908
|
|
|
5
5
|
hwpx/package.py,sha256=0rKjGCJbPQvrVBIy07Jpjsu3fI7HhbqFCGWTiTDsJpo,1141
|
|
6
6
|
hwpx/patch.py,sha256=8G1wgGVgCp0KyhQb-y0ZI2FJEatCwLt_JpepHJmYhYQ,23799
|
|
7
7
|
hwpx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
hwpx/table_patch.py,sha256=
|
|
8
|
+
hwpx/table_patch.py,sha256=OqQfw8udCnZsM5wL1lBBOPOpF43actIRogSOyU7LTtw,34731
|
|
9
9
|
hwpx/template_formfit.py,sha256=dlxf98FatT5Nl4hN15TuMXqj5NlDTGSnLaqXVo_PoBo,23424
|
|
10
10
|
hwpx/templates.py,sha256=28bYqeJVeDb1Cq8G9NZG9Mhnu4K2GamAKC4QhxvUZyA,1187
|
|
11
11
|
hwpx/builder/__init__.py,sha256=8tcxClbeuNle_R_2nDAauyy518OCegG8qVPjwIKRUZA,849
|
|
@@ -153,10 +153,10 @@ hwpx/visual/diff.py,sha256=0X5T9IgwRZU3td-7vnPrlowovtGud7P_ymq0KVehlKk,5677
|
|
|
153
153
|
hwpx/visual/masks.py,sha256=oXhgynAb4uKjJtZ2BGHHdAjyvWGqSFlZFQ-iJxzHiuo,1832
|
|
154
154
|
hwpx/visual/oracle.py,sha256=VNO-tAB-lzTdW5XtSELxg_Aau369qRFBsJvNryHF_D8,31319
|
|
155
155
|
hwpx/visual/report.py,sha256=2RhXN1KBYOZTim9FNpeUhaaDHR7oFxI6Z2DLUkDIiwE,1717
|
|
156
|
-
python_hwpx-2.
|
|
157
|
-
python_hwpx-2.
|
|
158
|
-
python_hwpx-2.
|
|
159
|
-
python_hwpx-2.
|
|
160
|
-
python_hwpx-2.
|
|
161
|
-
python_hwpx-2.
|
|
162
|
-
python_hwpx-2.
|
|
156
|
+
python_hwpx-2.22.0.dist-info/licenses/LICENSE,sha256=_ubz4wv-BkkT3l3gu-QuH7JGeVjuRYGZoZK95eNsCHU,9688
|
|
157
|
+
python_hwpx-2.22.0.dist-info/licenses/NOTICE,sha256=k48h6EaGQE8Y1c0dS9sIOOcz4YqkbcImWClF7pBOgsg,2473
|
|
158
|
+
python_hwpx-2.22.0.dist-info/METADATA,sha256=VugoM_5mzaiTEDsaOqqHtDWuNo8CjuTG73Z4uPGsOTU,19982
|
|
159
|
+
python_hwpx-2.22.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
160
|
+
python_hwpx-2.22.0.dist-info/entry_points.txt,sha256=4U6WXYWHxEiWp2VRHo97fvOYNh7ebu6roonk7chxKcY,453
|
|
161
|
+
python_hwpx-2.22.0.dist-info/top_level.txt,sha256=R1iToqDh80Nf2oQhRjTN0rbN2X6kyDUizIocZjkhuxc,5
|
|
162
|
+
python_hwpx-2.22.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|