diff --git a/renderer.py b/renderer.py index a9c39fe..c932db5 100644 --- a/renderer.py +++ b/renderer.py @@ -40,14 +40,26 @@ class DashboardRenderer: self.F48 = ImageFont.truetype(font_path, 48) # ---------- 基础绘制工具 ---------- - def _tw(self, s, ft): + def _tw(self, s, ft, track=0): + # track:额外字符间距(px)。非整数倍缩放字号(如 F16=16/12x)下,数字字形墨迹宽度 + # 等于步进宽度(无侧边距),相邻字符几乎零间隙,需手动加距才不会紧贴。 + if track: + return sum(self.d.textlength(c, font=ft) for c in s) + track * (len(s) - 1) return self.d.textlength(s, font=ft) - def _draw(self, x, y, s, ft, fill, bold): + def _draw(self, x, y, s, ft, fill, bold, track=0): # 伪粗体:点阵字体单一字重,按 1~bold px 偏移叠绘加粗笔画 - self.d.text((x, y), s, font=ft, fill=fill) - for dx in range(1, bold + 1): - self.d.text((x + dx, y), s, font=ft, fill=fill) + if not track: + self.d.text((x, y), s, font=ft, fill=fill) + for dx in range(1, bold + 1): + self.d.text((x + dx, y), s, font=ft, fill=fill) + return + cx = x + for ch in s: + self.d.text((cx, y), ch, font=ft, fill=fill) + for dx in range(1, bold + 1): + self.d.text((cx + dx, y), ch, font=ft, fill=fill) + cx += self.d.textlength(ch, font=ft) + track def text(self, x, y, s, ft, fill=BLACK, bold=0): self._draw(x, y, s, ft, fill, bold) @@ -102,17 +114,18 @@ class DashboardRenderer: if right: self.rtext(self.W - 10, y, right, self.F12) - def _mid(self, x, cy, s, ft, fill=BLACK, bold=0, align="l"): + def _mid(self, x, cy, s, ft, fill=BLACK, bold=0, align="l", track=0): """按字符串「墨迹竖直中心」对齐到 cy 绘制——跨字号(F12/F24)也能真正居中, - 避免不同字号按顶部对齐时的视觉错位。align: l 左对齐 / r 右对齐 / c 居中于 x。""" + 避免不同字号按顶部对齐时的视觉错位。align: l 左对齐 / r 右对齐 / c 居中于 x。 + track:见 _tw,用于给紧贴的字符手动加间距。""" _, t, _, b = ft.getbbox(s) # 该串墨迹在字身框内的上/下沿 y = cy - (t + b) / 2.0 - w = self._tw(s, ft) + w = self._tw(s, ft, track) if align == "r": x -= w + bold elif align == "c": x -= (w + bold) / 2.0 - self._draw(x, y, s, ft, fill, bold) + self._draw(x, y, s, ft, fill, bold, track) def _pace(self, xr, cy, diff): """时间维度对比(pace = 用量% − 时间%):>0 超前↑红;<0 节余↓黑;=0 持平。 @@ -137,6 +150,7 @@ class DashboardRenderer: pct = max(0, min(100, int(raw))) if ok else 0 color = RED if (ok and pct >= warn) else BLACK LABEL_W, G1, G2, H = 26, 13, 8, 15 # G1 进度条↔百分比、G2 百分比↔pace(视觉约 12/11) + PCT_TRACK = 2 # F16(16/12x 非整数倍缩放)数字墨迹无侧边距、紧贴,手动加字符间距 cy = y + 10 # 行竖直中心 self._mid(x0, cy, bar["k"], self.F13, bold=1) # 左标签 F13 # 右侧从右往左:pace(最右) → 百分比 → 进度条 @@ -144,10 +158,10 @@ class DashboardRenderer: if ok and "time_pct" in bar: pace_w = self._pace(x1, cy, pct - int(bar["time_pct"])) pct_r = x1 - pace_w - G2 - pct_txt = f"{pct}%" if ok else "--" - self._mid(pct_r, cy, pct_txt, self.F16, fill=color, bold=1, align="r") # 百分比 F16(主) + pct_txt = f"{pct:02d}%" if ok else "--" + self._mid(pct_r, cy, pct_txt, self.F16, fill=color, bold=1, align="r", track=PCT_TRACK) # 百分比 F16(主) bx0 = x0 + LABEL_W - bx1 = pct_r - self._tw(pct_txt, self.F16) - G1 + bx1 = pct_r - self._tw(pct_txt, self.F16, PCT_TRACK) - G1 by = cy - H // 2 self.d.rectangle([bx0, by, bx1, by + H], outline=color, width=1) # 轨道边框随条色 fw = (bx1 - bx0) * pct / 100.0