fix(ppt): 表格行高按内容估算逐行设置——显式换行强制断行+CJK/ASCII显示宽度估算换行数+行距余量1.45;根治实测长文本(含换行项目符号列表)在行底被截断;总高超页截行加提示不跨页拆表
This commit is contained in:
parent
47f191fc81
commit
09d77f7483
@ -233,33 +233,65 @@ def _content_header(slide, title, kicker=""):
|
|||||||
|
|
||||||
# ══════════════════════ 表格渲染(真 Table,非文本) ══════════════════════
|
# ══════════════════════ 表格渲染(真 Table,非文本) ══════════════════════
|
||||||
|
|
||||||
|
def _disp_w(s):
|
||||||
|
"""显示宽度(CJK=1.0、ASCII≈0.55 字符单位),用于估算换行数。"""
|
||||||
|
return sum(1.0 if ord(ch) > 0x2E7F else 0.55 for ch in (s or ""))
|
||||||
|
|
||||||
|
|
||||||
def _add_table(slide, rows, top, width=None):
|
def _add_table(slide, rows, top, width=None):
|
||||||
"""渲染 markdown 表格为 pptx Table;返回占用高度(英寸)。超宽自动缩字号。"""
|
"""渲染 markdown 表格为 pptx Table;返回占用高度(英寸)。超宽自动缩字号。
|
||||||
|
|
||||||
|
行高按内容估算逐行设置(2026-09-11 实测教训:统一行高时 LibreOffice/WPS
|
||||||
|
不按换行撑行 → 长文本在行底被截断)。总高超页则截行加提示(不跨页拆表,
|
||||||
|
保持单表完整可读)。
|
||||||
|
"""
|
||||||
from pptx.util import Inches, Pt
|
from pptx.util import Inches, Pt
|
||||||
|
import math
|
||||||
if not rows or not rows[0]:
|
if not rows or not rows[0]:
|
||||||
return 0.0
|
return 0.0
|
||||||
width = width or (SW - 2 * MARGIN_X)
|
width = width or (SW - 2 * MARGIN_X)
|
||||||
ncol = max(len(r) for r in rows)
|
ncol = max(len(r) for r in rows)
|
||||||
rows = [r + [""] * (ncol - len(r)) for r in rows]
|
rows = [r + [""] * (ncol - len(r)) for r in rows]
|
||||||
nrow = len(rows)
|
nrow = len(rows)
|
||||||
row_h = 0.36
|
|
||||||
avail = SH - 0.95 - top
|
avail = SH - 0.95 - top
|
||||||
max_rows = max(2, int(avail / row_h))
|
|
||||||
if nrow > max_rows:
|
|
||||||
rows = rows[:max_rows - 1] + [["… 其余 %d 行见平台详情页" % (nrow - max_rows + 1)] + [""] * (ncol - 1)]
|
|
||||||
nrow = len(rows)
|
|
||||||
total_h = min(row_h * nrow, avail)
|
|
||||||
gf = slide.shapes.add_table(nrow, ncol, Inches(MARGIN_X), Inches(top),
|
|
||||||
Inches(width), Inches(total_h))
|
|
||||||
tbl = gf.table
|
|
||||||
# 列宽:首列略宽(多为名称),其余均分
|
# 列宽:首列略宽(多为名称),其余均分
|
||||||
first = min(width * 0.30, 4.6)
|
first = min(width * 0.30, 4.6)
|
||||||
rest = (width - first) / max(1, ncol - 1)
|
rest = (width - first) / max(1, ncol - 1)
|
||||||
for ci in range(ncol):
|
col_w = [first if ci == 0 else rest for ci in range(ncol)]
|
||||||
tbl.columns[ci].width = Inches(first if ci == 0 else rest)
|
|
||||||
fs = 11 if ncol <= 5 else (10 if ncol <= 7 else 9)
|
fs = 11 if ncol <= 5 else (10 if ncol <= 7 else 9)
|
||||||
|
line_h = fs * 1.45 / 72.0 # 每行文本高度(英寸,含行距余量)
|
||||||
|
pad = 0.12 # 单元格上下边距+余量
|
||||||
|
|
||||||
|
def row_height(row_vals):
|
||||||
|
lines = 1
|
||||||
|
for ci, val in enumerate(row_vals):
|
||||||
|
cap = max(2.0, (col_w[ci] - 0.16) * 72.0 / fs) # 每行可容纳字符单位
|
||||||
|
n = 0
|
||||||
|
for seg in (val or "")[:180].split("\n"): # 显式换行强制断行
|
||||||
|
n += max(1, math.ceil(_disp_w(seg) / cap))
|
||||||
|
lines = max(lines, n)
|
||||||
|
return lines * line_h + pad
|
||||||
|
|
||||||
|
heights = [row_height(r) for r in rows]
|
||||||
|
total_h = sum(heights)
|
||||||
|
if total_h > avail:
|
||||||
|
# 从尾行往前砍到放得下(至少留表头+1 数据行+提示行)
|
||||||
|
keep = nrow
|
||||||
|
while keep > 3 and sum(heights[:keep]) + row_height(
|
||||||
|
["…"] + [""] * (ncol - 1)) > avail:
|
||||||
|
keep -= 1
|
||||||
|
cut = nrow - keep
|
||||||
|
rows = rows[:keep] + [["… 其余 %d 行见平台详情页" % cut] + [""] * (ncol - 1)]
|
||||||
|
heights = heights[:keep] + [row_height(rows[-1])]
|
||||||
|
nrow = len(rows)
|
||||||
|
total_h = sum(heights)
|
||||||
|
gf = slide.shapes.add_table(nrow, ncol, Inches(MARGIN_X), Inches(top),
|
||||||
|
Inches(width), Inches(total_h))
|
||||||
|
tbl = gf.table
|
||||||
|
for ci in range(ncol):
|
||||||
|
tbl.columns[ci].width = Inches(col_w[ci])
|
||||||
for ri, row in enumerate(rows):
|
for ri, row in enumerate(rows):
|
||||||
tbl.rows[ri].height = Inches(total_h / nrow)
|
tbl.rows[ri].height = Inches(heights[ri])
|
||||||
for ci, val in enumerate(row):
|
for ci, val in enumerate(row):
|
||||||
cell = tbl.cell(ri, ci)
|
cell = tbl.cell(ri, ci)
|
||||||
cell.margin_left = cell.margin_right = Inches(0.07)
|
cell.margin_left = cell.margin_right = Inches(0.07)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user