""" 通用页面像素对比脚本。 支持长页面分页裁剪:将 H5 截图按 MP 一屏高度分段裁剪,逐段对比。 用法:python scripts/ops/page_compare.py [--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 [--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()