Files
wehub-resource-sync a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:34 +08:00

296 lines
12 KiB
Python
Executable File

#!/usr/bin/env python3
"""Probe Jcode pinned Mermaid fit planning for screenshot repros.
This intentionally mirrors the geometry math in src/tui/ui_diagram_pane.rs so a
bad crop can be reproduced without compiling the whole Rust test binary.
Defaults are the 2026-05-07 Beetle/Harbor clipped Mermaid screenshot:
inner pane 73x46 cells, font 8x16 px, PNG 1180x1470 px.
"""
from __future__ import annotations
import argparse
import json
import math
from pathlib import Path
from typing import Any
TARGET_UTILIZATION_PERCENT = 85.0
MIN_READABLE_ZOOM_PERCENT = 70
MAX_AUTO_FILL_ZOOM_PERCENT = 1000
def clamp(value: int, lo: int, hi: int) -> int:
return max(lo, min(hi, value))
def utilization_percent(used: int, total: int) -> float:
return 0.0 if total == 0 else (used * 100.0) / total
def div_ceil(value: int, divisor: int) -> int:
return 0 if divisor == 0 else (value + divisor - 1) // divisor
def axis_fill_zoom_percent(available_cells: int, image_px: int, cell_px: int) -> int:
if available_cells == 0 or image_px == 0 or cell_px == 0:
return 100
return clamp((available_cells * cell_px * 100) // max(image_px, 1), 1, MAX_AUTO_FILL_ZOOM_PERCENT)
def fit_zoom_percent_for_area(width_cells: int, height_cells: int, img_w_px: int, img_h_px: int, font_w: int, font_h: int) -> int:
if width_cells == 0 or height_cells == 0 or img_w_px == 0 or img_h_px == 0:
return 100
zoom_w = (width_cells * max(font_w, 1) * 100) // max(img_w_px, 1)
zoom_h = (height_cells * max(font_h, 1) * 100) // max(img_h_px, 1)
return clamp(min(zoom_w, zoom_h), 1, MAX_AUTO_FILL_ZOOM_PERCENT)
def vcenter_fitted(width_cells: int, height_cells: int, img_w_px: int, img_h_px: int, font_w: int, font_h: int) -> dict[str, int]:
if width_cells == 0 or height_cells == 0 or img_w_px == 0 or img_h_px == 0:
return {"x": 0, "y": 0, "width": width_cells, "height": height_cells}
area_w_px = width_cells * max(font_w, 1)
area_h_px = height_cells * max(font_h, 1)
scale = min(area_w_px / img_w_px, area_h_px / img_h_px)
fitted_w = min(math.ceil((img_w_px * scale) / max(font_w, 1)), width_cells)
fitted_h = min(math.ceil((img_h_px * scale) / max(font_h, 1)), height_cells)
return {
"x": (width_cells - fitted_w) // 2,
"y": (height_cells - fitted_h) // 2,
"width": fitted_w,
"height": fitted_h,
}
def centered_viewport_scroll_cells(image_px: int, area_cells: int, zoom_percent: int, cell_px: int) -> int:
if image_px == 0 or area_cells == 0 or zoom_percent == 0 or cell_px == 0:
return 0
view_px = area_cells * cell_px * 100 // zoom_percent
max_scroll_px = max(0, image_px - view_px)
if max_scroll_px == 0:
return 0
cell_px_at_zoom = max(div_ceil(cell_px * 100, zoom_percent), 1)
return (max_scroll_px // 2) // cell_px_at_zoom
def plan(width_cells: int, height_cells: int, img_w_px: int, img_h_px: int, font_w: int, font_h: int) -> dict[str, Any]:
contain = vcenter_fitted(width_cells, height_cells, img_w_px, img_h_px, font_w, font_h)
fit_zoom = fit_zoom_percent_for_area(width_cells, height_cells, img_w_px, img_h_px, font_w, font_h)
width_fill_zoom = axis_fill_zoom_percent(width_cells, img_w_px, font_w)
height_fill_zoom = axis_fill_zoom_percent(height_cells, img_h_px, font_h)
preferred_fill_zoom = clamp(max(width_fill_zoom, height_fill_zoom), MIN_READABLE_ZOOM_PERCENT, MAX_AUTO_FILL_ZOOM_PERCENT)
width_utilization = utilization_percent(contain["width"], width_cells)
height_utilization = utilization_percent(contain["height"], height_cells)
area_utilization = utilization_percent(contain["width"] * contain["height"], width_cells * height_cells)
underutilized = (
width_utilization < TARGET_UTILIZATION_PERCENT
or height_utilization < TARGET_UTILIZATION_PERCENT
or area_utilization < TARGET_UTILIZATION_PERCENT
)
meaningfully_larger = preferred_fill_zoom > fit_zoom + 5
old_would_fill = (fit_zoom < MIN_READABLE_ZOOM_PERCENT or underutilized) and meaningfully_larger
fixed_would_fill = underutilized and meaningfully_larger
fill_plan = {
"mode": f"fit-fill@{preferred_fill_zoom}%",
"zoom_percent": preferred_fill_zoom,
"scroll_x": centered_viewport_scroll_cells(img_w_px, width_cells, preferred_fill_zoom, font_w),
"scroll_y": centered_viewport_scroll_cells(img_h_px, height_cells, preferred_fill_zoom, font_h),
}
return {
"input": {
"inner_width_cells": width_cells,
"inner_height_cells": height_cells,
"image_width_px": img_w_px,
"image_height_px": img_h_px,
"font_width_px": font_w,
"font_height_px": font_h,
},
"contain_rect_cells": contain,
"utilization_percent": {
"width": width_utilization,
"height": height_utilization,
"area": area_utilization,
},
"fit_zoom_percent": fit_zoom,
"axis_fill_zoom_percent": {"width": width_fill_zoom, "height": height_fill_zoom},
"preferred_fill_zoom_percent": preferred_fill_zoom,
"underutilized": underutilized,
"meaningfully_larger": meaningfully_larger,
"old_buggy_plan": fill_plan if old_would_fill else {"mode": "fit", "rect": contain},
"fixed_plan": fill_plan if fixed_would_fill else {"mode": "fit", "rect": contain},
"repro_was_clipping_bug": old_would_fill and not fixed_would_fill,
}
def maybe_png_info(path: str | None) -> dict[str, Any] | None:
if not path:
return None
png = Path(path).expanduser()
info: dict[str, Any] = {"path": str(png), "exists": png.exists()}
if not png.exists():
return info
try:
from PIL import Image # type: ignore
except Exception as exc: # pragma: no cover - diagnostic fallback
info["pil_error"] = str(exc)
return info
im = Image.open(png).convert("RGBA")
bbox = im.getchannel("A").getbbox()
info["size"] = list(im.size)
info["alpha_bbox"] = list(bbox) if bbox else None
if bbox:
left, top, right, bottom = bbox
info["content_size"] = [right - left, bottom - top]
info["transparent_margins"] = {
"left": left,
"top": top,
"right": im.size[0] - right,
"bottom": im.size[1] - bottom,
}
return info
def visual_fit_metrics(
*,
width_cells: int,
height_cells: int,
img_w_px: int,
img_h_px: int,
font_w: int,
font_h: int,
contain_rect: dict[str, int],
alpha_bbox: list[int] | tuple[int, int, int, int] | None,
) -> dict[str, Any] | None:
"""Project the visible PNG alpha bbox into the TUI pane.
The layout planner works in cells and the PNG alpha bbox works in pixels.
Projecting the bbox into cells gives a camera-like metric that matches the
visual complaint: even if the full image rect is centered, is the actual
non-transparent diagram content centered in the pane?
"""
if not alpha_bbox or img_w_px <= 0 or img_h_px <= 0 or font_w <= 0 or font_h <= 0:
return None
left_px, top_px, right_px, bottom_px = [float(value) for value in alpha_bbox]
render_w_px = contain_rect["width"] * font_w
render_h_px = contain_rect["height"] * font_h
scale_x = render_w_px / img_w_px
scale_y = render_h_px / img_h_px
content_left = contain_rect["x"] + (left_px * scale_x / font_w)
content_top = contain_rect["y"] + (top_px * scale_y / font_h)
content_right = contain_rect["x"] + (right_px * scale_x / font_w)
content_bottom = contain_rect["y"] + (bottom_px * scale_y / font_h)
content_width = max(0.0, content_right - content_left)
content_height = max(0.0, content_bottom - content_top)
left_blank = content_left
right_blank = width_cells - content_right
top_blank = content_top
bottom_blank = height_cells - content_bottom
center_x = (content_left + content_right) / 2.0
center_y = (content_top + content_bottom) / 2.0
pane_center_x = width_cells / 2.0
pane_center_y = height_cells / 2.0
offset_x = center_x - pane_center_x
offset_y = center_y - pane_center_y
return {
"content_bbox_cells": {
"left": content_left,
"top": content_top,
"right": content_right,
"bottom": content_bottom,
"width": content_width,
"height": content_height,
},
"blank_cells": {
"left": left_blank,
"right": right_blank,
"top": top_blank,
"bottom": bottom_blank,
},
"blank_imbalance_cells": {
"horizontal_right_minus_left": right_blank - left_blank,
"vertical_bottom_minus_top": bottom_blank - top_blank,
},
"content_center_offset_cells": {
"x": offset_x,
"y": offset_y,
},
"content_area_utilization_percent": utilization_percent(
int(round(content_width * content_height * 1000)),
int(width_cells * height_cells * 1000),
),
"camera_centered": abs(offset_x) <= 1.0 and abs(offset_y) <= 1.0,
"note": (
"Low content_area_utilization can be normal for a wide/short or tall/narrow diagram. "
"A large content_center_offset or top/bottom blank imbalance means the camera/placement is wrong."
),
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--inner", default="73x46", help="inner pane size in cells, WIDTHxHEIGHT")
parser.add_argument("--image", default="1180x1470", help="rendered PNG size in px, WIDTHxHEIGHT")
parser.add_argument("--font", default="8x16", help="terminal cell size in px, WIDTHxHEIGHT")
parser.add_argument("--png", help="optional rendered PNG path to inspect alpha bounds")
parser.add_argument(
"--alpha-bbox",
help="optional alpha/content bbox LEFT,TOP,RIGHT,BOTTOM in PNG pixels when --png is unavailable",
)
parser.add_argument(
"--assert-camera-centered",
action="store_true",
help="fail if projected visible content is more than one cell away from pane center",
)
parser.add_argument(
"--assert-old-clipping-repro",
action="store_true",
help="fail unless the old readability-floor rule would have produced the known clipping bug",
)
args = parser.parse_args()
def parse_pair(raw: str) -> tuple[int, int]:
left, right = raw.lower().split("x", 1)
return int(left), int(right)
width_cells, height_cells = parse_pair(args.inner)
img_w_px, img_h_px = parse_pair(args.image)
font_w, font_h = parse_pair(args.font)
result = plan(width_cells, height_cells, img_w_px, img_h_px, font_w, font_h)
png_info = maybe_png_info(args.png)
if png_info is not None:
result["png"] = png_info
alpha_bbox = None
if args.alpha_bbox:
alpha_bbox = [int(part) for part in args.alpha_bbox.split(",")]
elif png_info is not None:
alpha_bbox = png_info.get("alpha_bbox")
metrics = visual_fit_metrics(
width_cells=width_cells,
height_cells=height_cells,
img_w_px=img_w_px,
img_h_px=img_h_px,
font_w=font_w,
font_h=font_h,
contain_rect=result["contain_rect_cells"],
alpha_bbox=alpha_bbox,
)
if metrics is not None:
result["visual_fit_metrics"] = metrics
print(json.dumps(result, indent=2, sort_keys=True))
if args.assert_camera_centered and metrics is not None:
return 0 if metrics["camera_centered"] else 2
if args.assert_old_clipping_repro:
return 0 if result["repro_was_clipping_bug"] else 3
return 0
if __name__ == "__main__":
raise SystemExit(main())