iter48-卡2:卡②(立绘显示档批): 九件素材原稿分辨率入包(紧裁零降采样,STANDEE_SRC_H九键+产物计数自证)+standee_motion显示档PORTRAIT_DISPLAY_H九键钉值(_place_portrait按档算倍率,缺键push_error按1×)+portrait_probe扩display_size/display_scale+闸件standee_asset_check换口径(源高==原稿表值/显示宽≤150酋长157例外逐字)+样张站桩段按显示档取数(A4解冻重校88×92,V10并排30/30)+V13–V18全绿(50checks)+三面对照图

This commit is contained in:
DKChan committed 2026-11-02 01:58:23 +08:00
1 parent 1e35ab947b
commit 4c3f0f6082
9 files changed
+255 -119

No files matched your search

+30 -27
View File
@@ -51,6 +51,7 @@ import hashlib
from collections import deque
from layout_config import load as load_layout
from pixelize_candidates import STANDEE_SLOT_H # 站桩显示档单点(主角=中型档——art-bible §8.2)
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MAIN_ROOT = "D:/code/g-plan2"
@@ -772,7 +773,7 @@ def _armor_tex(armor):
def draw_standee(canvas, ox, oy, kind, name, enemy_id, order=1, armor="light",
hp=1.0, intent="", statuses=(), dead=False):
"""站桩 150×176(standee_body.gd 几何):血条+状态行头顶/立绘盒 96px/底座/敌名行。"""
"""站桩 150×176(standee_body.gd 几何):血条+状态行头顶/立绘盒 96px 槽位(显示档居中溢出)/底座/敌名行。"""
d = ImageDraw.Draw(canvas)
W, H = 150, 176
# 头顶:顺位徽标(敌,FS_HINT 14)+血条(填充=危险红 #A8321F 不因敌我分色;条底=HP_BAR_TRACK)
@@ -788,11 +789,13 @@ def draw_standee(canvas, ox, oy, kind, name, enemy_id, order=1, armor="light",
for i, ic in enumerate(statuses):
icon = STATUS_ICONS[ic].resize((16, 16), Image.NEAREST)
canvas.alpha_composite(icon, (sx + i * 17, oy + 18))
# 立绘盒 96px(48 源 ×2 整数——C5)
# 立绘盒 96px 槽位(hero 显示档 = STANDEE_SLOT_H 绝对高、宽随源比例——§8.2,居中溢出同 _place_portrait)
pbox_y = oy + 44
if kind == "hero":
por = PORTRAIT_SRC.resize((96, 96), Image.NEAREST)
canvas.alpha_composite(por, (ox + (W - 96) // 2, pbox_y))
disp_h = STANDEE_SLOT_H
disp_w = int(round(PORTRAIT_SRC.width * disp_h / float(PORTRAIT_SRC.height)))
por = PORTRAIT_SRC.resize((disp_w, disp_h), Image.NEAREST)
canvas.alpha_composite(por, (ox + (W - disp_w) // 2, pbox_y + (96 - disp_h) // 2))
else:
glyph = {"goblin": "▂", "bugbear": "▆", "ogre_chief": "█"}.get(enemy_id, "敌")
col = (150, 60, 48) if not dead else (110, 104, 98)
@@ -1131,11 +1134,11 @@ def run_checks(board, placement, records, band, gmap, canvas_img=None):
edge_hits = edge_content(canvas_img)
check("A5", "画布四缘 2px 净空(零溢出)", edge_hits == 0, "缘带内容像素 %d" % edge_hits)
# A4 混排相融:小人/立绘/状态图标=在库原件;语义色==UiKit 常量
# A4 尺寸基线按现行资产实态固化——立绘 46×48/棋盘小人源 32×32
# A4 尺寸基线按现行资产实态固化——立绘 88×92(原稿分辨率)/棋盘小人源 32×32
# 硬等断言落锁(资产升档换代须显式解冻重校,断言失败=预期闸)。
check("A4", "混排相融(在库原件可载+UiKit 语义色对表+尺寸基线冻结:立绘 46×48/小人源 32×32)",
PORTRAIT_SRC.size == (46, 48) and HERO_SRC.size == (32, 32),
"小人源 %s(裁透明留白后 %s)/立绘 %s[冻结 46×48]/状态图标原件;INK/封印黑/奖励金 == ui_kit.gd"
check("A4", "混排相融(在库原件可载+UiKit 语义色对表+尺寸基线冻结:立绘 88×92/小人源 32×32)",
PORTRAIT_SRC.size == (88, 92) and HERO_SRC.size == (32, 32),
"小人源 %s(裁透明留白后 %s)/立绘 %s[冻结 88×92]/状态图标原件;INK/封印黑/奖励金 == ui_kit.gd"
% (str(HERO_SRC.size), str(HERO.size), str(PORTRAIT_SRC.size)))
return all(c[2] for c in CHECKS)
@@ -1497,42 +1500,42 @@ def render_outline_overlap():
img = Image.new("RGBA", (W, H), (24, 20, 17, 255))
d = ImageDraw.Draw(img)
meta = {"hero_boxes": [], "overlap": None, "armor": {}}
# ① 战斗舞台语境:主角立绘 96px + 深墨描边
por = PORTRAIT_SRC.resize((96, 96), Image.NEAREST)
# ① 战斗舞台语境:主角立绘显示档(STANDEE_SLOT_H 绝对高、宽随源比例)+深墨描边
por = PORTRAIT_SRC.resize((int(round(PORTRAIT_SRC.width * STANDEE_SLOT_H / float(PORTRAIT_SRC.height))), STANDEE_SLOT_H), Image.NEAREST)
img.alpha_composite(_outline_underlay(por, (40, 19, 13)), (18, 14))
img.alpha_composite(por, (18, 14))
meta["hero_boxes"].append((18, 14, 18 + 96, 14 + 96))
d.text((18, 116), "主角·战斗舞台语境\n描边=深墨 (40,19,13)", font=F_LBL2, fill=(225, 215, 195))
meta["hero_boxes"].append((18, 14, 18 + por.size[0], 14 + por.size[1]))
d.text((18, 166), "主角·战斗舞台语境 描边=深墨 (40,19,13)", font=F_LBL2, fill=(225, 215, 195))
# ② 棋盘格语境:小人 48px 压已开格底
d.rectangle([150, 14, 214, 78], fill=(24, 20, 16))
d.rectangle([210, 14, 274, 78], fill=(24, 20, 16))
fl = FLOORS[0].resize((64, 64), Image.NEAREST)
img.paste(fl.convert("RGB"), (150, 14))
img.paste(fl.convert("RGB"), (210, 14))
h48 = HERO.resize((48, int(48 * HERO.size[1] / HERO.size[0])), Image.NEAREST)
img.alpha_composite(h48, (150 + (64 - h48.size[0]) // 2, 14 + 64 - h48.size[1] - 8))
meta["hero_boxes"].append((150 + (64 - h48.size[0]) // 2, 14 + 64 - h48.size[1] - 8,
150 + (64 - h48.size[0]) // 2 + h48.size[0], 14 + 64 - 8))
d.text((150, 116), "棋盘格语境\n(隔离已开格底)", font=F_LBL2, fill=(225, 215, 195))
img.alpha_composite(h48, (210 + (64 - h48.size[0]) // 2, 14 + 64 - h48.size[1] - 8))
meta["hero_boxes"].append((210 + (64 - h48.size[0]) // 2, 14 + 64 - h48.size[1] - 8,
210 + (64 - h48.size[0]) // 2 + h48.size[0], 14 + 64 - 8))
d.text((210, 116), "棋盘格语境\n(隔离已开格底)", font=F_LBL2, fill=(225, 215, 195))
# ③ 结算明细带语境:小人 24px 压明细带底
d.rectangle([238, 14, 302, 78], fill=(46, 39, 32))
d.rectangle([298, 14, 362, 78], fill=(46, 39, 32))
h24 = HERO.resize((24, int(24 * HERO.size[1] / HERO.size[0])), Image.NEAREST)
img.alpha_composite(h24, (238 + 8, 14 + 52 - h24.size[1]))
meta["hero_boxes"].append((238 + 8, 14 + 52 - h24.size[1], 238 + 8 + h24.size[0], 14 + 52))
d.text((238, 116), "结算明细带语境\n(同剪影 24px)", font=F_LBL2, fill=(225, 215, 195))
img.alpha_composite(h24, (298 + 8, 14 + 52 - h24.size[1]))
meta["hero_boxes"].append((298 + 8, 14 + 52 - h24.size[1], 298 + 8 + h24.size[0], 14 + 52))
d.text((298, 116), "结算明细带语境\n(同剪影 24px)", font=F_LBL2, fill=(225, 215, 195))
# ④ 敌方描边对照:字形多向偏移暖白垫底+本体深朱
for ddx, ddy in [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (1, -1), (-1, 1), (1, 1)]:
d.text((350 + 32 + ddx, 14 + 32 + ddy), "█", font=F_STANDEE, fill=(240, 226, 200), anchor="mm")
d.text((350 + 32, 14 + 32), "█", font=F_STANDEE, fill=(150, 60, 48), anchor="mm")
d.text((350, 116), "敌方描边=暖白族\n(非黑非深褐)", font=F_LBL2, fill=(225, 215, 195))
d.text((410 + 32 + ddx, 14 + 32 + ddy), "█", font=F_STANDEE, fill=(240, 226, 200), anchor="mm")
d.text((410 + 32, 14 + 32), "█", font=F_STANDEE, fill=(150, 60, 48), anchor="mm")
d.text((410, 116), "敌方描边=暖白族\n(非黑非深褐)", font=F_LBL2, fill=(225, 215, 195))
# ⑤ 护甲三枚展示(源 24×24 挂 HP_BAR_BACK 素底——工单 §5.3 挂载底色口径)
for i, key in enumerate(["light", "ward", "heavy"]):
ax = 470 + i * 60
ax = 500 + i * 60
d.rectangle([ax, 14, ax + 40, 54], fill=(40, 34, 32))
tex = _armor_tex(key)
if tex is not None:
img.paste(tex, (ax + 8, 22), tex)
meta["armor"][key] = (ax + 8, 22, ax + 8 + 24, 22 + 24)
d.text((ax + 4, 58), {"light": "轻甲", "ward": "魔甲", "heavy": "重甲"}[key], font=F_LBL2, fill=(225, 215, 195))
d.text((470, 116), "护甲三枚 24×24\n挂载底=名字行素底", font=F_LBL2, fill=(225, 215, 195))
d.text((500, 116), "护甲三枚 24×24\n挂载底=名字行素底", font=F_LBL2, fill=(225, 215, 195))
# ⑥ 遮挡对照组:敌像(最底)→旗→小人+蓝框→数字(最顶)——P5 断言:顶层三件仍可辨
cx, cy0 = 700, 10
d.rectangle([cx, cy0, cx + 68, cy0 + 68], fill=(24, 20, 16))