v1.0.10 两件大事:
1. 界面中英双语(英文界面无中文残留)
- 新增 web/i18n.js(约 4200 条词条),零依赖零构建
- 后端下发中文数据走 bt4() 查表翻译;独立模块(upstream/netdetail/
realtime/update)纳入翻译并注册切语言重绘钩子
- 后端「状态/聚合」接口只回稳定枚举+原始数值,不下发中文文案
- 顺带修一个真实 XSS:顶层 const 不挂 window,独立脚本 esc 静默退化成零转义
2. 修掉「文字竖着排/错位」(多分辨率反复暴露)
- 单元格 min-content 只有 1 字宽 → word-break:keep-all + 表头 nowrap
- 依赖卡片正文被标签/按钮挤成 27px → .dep-body{flex:1 1 200px} + flex-wrap
- 裸 flex:1(下限为0)给正文 → 一律改 flex:1 1 <px>
- .dep-item 横向容器直接塞块级子项 → 退回块级
- 关键陷阱:auto-fill 布局屏越宽列数越多单卡越窄,窄屏反而测不出来,
真机审计推进到「逐视图点按钮 + 1920/2560 宽视口 + 中英双语」
- 守卫 t-layout.py 扩到 35 条,12 处反向验证全红
3. 修真缺陷:_link_since() 重启检测被误改成 if False:(注释还写着「已修」),
uptime 归零后相减得负数 → 恢复比对 boot_id
附带:新增 25 个检查器(t-*.py)、排版审计工具链(shot-*/ocr-*/live-*)、
版本号兜底值同步到 1.0.10、.gitignore 收纳 i18n/排版排查的一次性脚本。
69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""把截图降采样成 ASCII 图打印出来 —— 用文字「看」布局。
|
|
|
|
⚠️ 必须用 **max-pooling(任一像素有墨就算有墨)**,不能用均值/LANCZOS:
|
|
界面文字只有 1~2px 的笔画,一平均就被白色背景冲淡,整张图会变成一片空白
|
|
(第一版踩的就是这个坑)。
|
|
|
|
用法:
|
|
python _dev/shot-ascii.py <图片> [cols] [x y w h] [thresh] [invert]
|
|
cols 每行字符数(默认 150)
|
|
x y w h 只渲染这块区域
|
|
thresh 墨迹阈值(默认 200,灰度 < thresh 算墨迹)
|
|
invert 传 1 表示反色(深色底界面)
|
|
"""
|
|
import sys
|
|
|
|
import numpy as np
|
|
from PIL import Image
|
|
|
|
Image.MAX_IMAGE_PIXELS = None
|
|
|
|
|
|
def pool(ink, rows, cols):
|
|
h, w = ink.shape
|
|
ys = np.linspace(0, h, rows + 1).astype(int)
|
|
xs = np.linspace(0, w, cols + 1).astype(int)
|
|
out = np.zeros((rows, cols), dtype=bool)
|
|
for r in range(rows):
|
|
band = ink[ys[r]:max(ys[r] + 1, ys[r + 1]), :]
|
|
if band.size == 0:
|
|
continue
|
|
for c in range(cols):
|
|
cell = band[:, xs[c]:max(xs[c] + 1, xs[c + 1])]
|
|
if cell.size and cell.any():
|
|
out[r, c] = True
|
|
return out
|
|
|
|
|
|
def render(path, cols=150, box=None, thresh=200, invert=False):
|
|
im = Image.open(path).convert('L')
|
|
if box:
|
|
x, y, w, h = box
|
|
im = im.crop((x, y, x + w, y + h))
|
|
w, h = im.size
|
|
a = np.asarray(im)
|
|
ink = (a > thresh) if invert else (a < thresh)
|
|
rows = max(1, int(round(h / float(w) * cols * 0.5)))
|
|
art = pool(ink, rows, cols)
|
|
print('--- %s crop=%s 原图 %dx%d 输出 %dx%d 墨迹 %.2f%%' % (
|
|
path.split('\\')[-1], box or 'full', w, h, cols, rows,
|
|
100.0 * ink.mean()))
|
|
for r in range(rows):
|
|
line = ''.join('#' if art[r, c] else ' ' for c in range(cols))
|
|
print(line.rstrip())
|
|
print('--- 列标尺(每 10 格): ' + ''.join(
|
|
str((i // 10) % 10) if i % 10 == 0 else ' ' for i in range(cols)))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
p = sys.argv[1]
|
|
cols = int(sys.argv[2]) if len(sys.argv) > 2 else 150
|
|
box = None
|
|
if len(sys.argv) > 6:
|
|
box = tuple(int(v) for v in sys.argv[3:7])
|
|
th = int(sys.argv[7]) if len(sys.argv) > 7 else 200
|
|
inv = len(sys.argv) > 8 and sys.argv[8] == '1'
|
|
render(p, cols, box, th, inv)
|