166 lines
5.1 KiB
Python
166 lines
5.1 KiB
Python
"""
|
||
通用页面像素对比脚本。
|
||
支持长页面分页裁剪:将 H5 截图按 MP 一屏高度分段裁剪,逐段对比。
|
||
用法:python scripts/ops/page_compare.py <page_name> [--segment]
|
||
--segment: 长页面分段模式,按 MP 一屏高度切割 H5 截图
|
||
"""
|
||
import sys
|
||
from pathlib import Path
|
||
from PIL import Image
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
SCREENSHOTS = ROOT / "docs" / "h5_ui" / "screenshots"
|
||
|
||
# DPR 常量
|
||
H5_DPR = 3
|
||
MP_DPR = 1.5
|
||
LOGICAL_WIDTH = 430
|
||
TARGET_W = 1290 # H5 原始宽度,MP ×2 缩放到此
|
||
|
||
|
||
def resize_to_width(img: Image.Image, target_w: int) -> Image.Image:
|
||
if img.width == target_w:
|
||
return img.copy()
|
||
ratio = target_w / img.width
|
||
new_h = int(img.height * ratio)
|
||
return img.resize((target_w, new_h), Image.LANCZOS)
|
||
|
||
|
||
def compare_default(page: str) -> dict:
|
||
"""默认态对比:统一到 1290px 宽,裁剪到 MP 一屏高度"""
|
||
h5_path = SCREENSHOTS / f"{page}.png"
|
||
mp_path = SCREENSHOTS / f"mp-{page}.png"
|
||
|
||
for p in [h5_path, mp_path]:
|
||
if not p.exists():
|
||
return {"error": f"文件不存在: {p.name}"}
|
||
|
||
h5_img = Image.open(h5_path)
|
||
mp_img = Image.open(mp_path)
|
||
|
||
print(f"[{page}] H5: {h5_img.width}×{h5_img.height} (DPR {H5_DPR})")
|
||
print(f"[{page}] MP: {mp_img.width}×{mp_img.height} (DPR {MP_DPR})")
|
||
|
||
# 缩放到统一宽度
|
||
h5_scaled = resize_to_width(h5_img, TARGET_W)
|
||
mp_scaled = resize_to_width(mp_img, TARGET_W)
|
||
|
||
# MP 逻辑高度 → H5 物理高度
|
||
mp_logical_h = mp_img.height / MP_DPR
|
||
h5_crop_h = int(mp_logical_h * H5_DPR)
|
||
|
||
# 裁剪到相同高度
|
||
final_h = min(h5_scaled.height, mp_scaled.height, h5_crop_h)
|
||
h5_final = h5_scaled.crop((0, 0, TARGET_W, final_h))
|
||
mp_final = mp_scaled.crop((0, 0, TARGET_W, final_h))
|
||
|
||
# 保存
|
||
h5_out = SCREENSHOTS / "cmp-h5.png"
|
||
mp_out = SCREENSHOTS / "cmp-mp.png"
|
||
h5_final.save(h5_out)
|
||
mp_final.save(mp_out)
|
||
|
||
print(f"[{page}] 对比尺寸: {TARGET_W}×{final_h}")
|
||
print(f"[{page}] 逻辑高度: {final_h / H5_DPR:.0f}px")
|
||
|
||
return {
|
||
"h5_out": str(h5_out),
|
||
"mp_out": str(mp_out),
|
||
"width": TARGET_W,
|
||
"height": final_h,
|
||
"logical_height": final_h / H5_DPR,
|
||
}
|
||
|
||
|
||
def compare_segments(page: str, segment_logical_h: int = 752) -> list:
|
||
"""
|
||
长页面分段对比。
|
||
segment_logical_h: 每段逻辑高度(默认 752px = MP 一屏 1128px / DPR 1.5)
|
||
返回每段的裁剪文件路径列表。
|
||
"""
|
||
h5_path = SCREENSHOTS / f"{page}.png"
|
||
mp_path = SCREENSHOTS / f"mp-{page}.png"
|
||
|
||
for p in [h5_path, mp_path]:
|
||
if not p.exists():
|
||
return [{"error": f"文件不存在: {p.name}"}]
|
||
|
||
h5_img = Image.open(h5_path)
|
||
mp_img = Image.open(mp_path)
|
||
|
||
h5_scaled = resize_to_width(h5_img, TARGET_W)
|
||
mp_scaled = resize_to_width(mp_img, TARGET_W)
|
||
|
||
# 计算 MP 总逻辑高度
|
||
mp_logical_total = mp_img.height / MP_DPR
|
||
h5_logical_total = h5_img.height / H5_DPR
|
||
|
||
print(f"[{page}] H5 逻辑高度: {h5_logical_total:.0f}px")
|
||
print(f"[{page}] MP 逻辑高度: {mp_logical_total:.0f}px")
|
||
|
||
# 按段裁剪
|
||
seg_h5_px = int(segment_logical_h * H5_DPR) # H5 物理像素
|
||
seg_mp_px = int(segment_logical_h * MP_DPR * 2) # MP 缩放后物理像素(×2)
|
||
|
||
segments = []
|
||
seg_idx = 0
|
||
y_h5 = 0
|
||
y_mp = 0
|
||
|
||
while y_h5 < h5_scaled.height and y_mp < mp_scaled.height:
|
||
end_h5 = min(y_h5 + seg_h5_px, h5_scaled.height)
|
||
end_mp = min(y_mp + seg_mp_px, mp_scaled.height)
|
||
|
||
# 确保两段高度一致
|
||
actual_h = min(end_h5 - y_h5, end_mp - y_mp)
|
||
|
||
h5_seg = h5_scaled.crop((0, y_h5, TARGET_W, y_h5 + actual_h))
|
||
mp_seg = mp_scaled.crop((0, y_mp, TARGET_W, y_mp + actual_h))
|
||
|
||
h5_seg_path = SCREENSHOTS / f"seg-h5-{page}-{seg_idx}.png"
|
||
mp_seg_path = SCREENSHOTS / f"seg-mp-{page}-{seg_idx}.png"
|
||
h5_seg.save(h5_seg_path)
|
||
mp_seg.save(mp_seg_path)
|
||
|
||
logical_y_start = y_h5 / H5_DPR
|
||
segments.append({
|
||
"index": seg_idx,
|
||
"h5_path": str(h5_seg_path),
|
||
"mp_path": str(mp_seg_path),
|
||
"logical_y": f"{logical_y_start:.0f}-{logical_y_start + actual_h / H5_DPR:.0f}px",
|
||
"height": actual_h,
|
||
})
|
||
|
||
print(f" 段 {seg_idx}: 逻辑 Y={logical_y_start:.0f}-{logical_y_start + actual_h / H5_DPR:.0f}px, 高度={actual_h}px")
|
||
|
||
y_h5 += seg_h5_px
|
||
y_mp += seg_mp_px
|
||
seg_idx += 1
|
||
|
||
return segments
|
||
|
||
|
||
def main():
|
||
if len(sys.argv) < 2:
|
||
print("用法: python page_compare.py <page_name> [--segment]")
|
||
sys.exit(1)
|
||
|
||
page = sys.argv[1]
|
||
segment_mode = "--segment" in sys.argv
|
||
|
||
if segment_mode:
|
||
print(f"\n=== 分段对比: {page} ===")
|
||
segments = compare_segments(page)
|
||
print(f"\n共 {len(segments)} 段")
|
||
else:
|
||
print(f"\n=== 默认态对比: {page} ===")
|
||
result = compare_default(page)
|
||
if "error" in result:
|
||
print(f"❌ {result['error']}")
|
||
else:
|
||
print(f"✅ 输出: cmp-h5.png + cmp-mp.png ({result['width']}×{result['height']})")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|