from PIL import Image, ImageChops, ImageDraw, ImageFont from pathlib import Path R=Path(r'C:\projects\wheel\models'); A=R/'kfl_100_concept'; B=R/'kfl_100_narrow_concept' font=r'C:\Windows\Fonts\msyh.ttc' f=ImageFont.truetype(font,42);small=ImageFont.truetype(font,25); tiny=ImageFont.truetype(font,22) out=Image.new('RGB',(2100,1430),'white'); d=ImageDraw.Draw(out) d.text((45,18),'100 mm 轴与反装 KFL001 · 3D 布局探索',font=f,fill='#182b45') d.text((45,78),'两块 8 mm 铝板 / 开关 50 mm 包络 / Ø12 × 100 mm 轴 / 已有两块铝转接盘',font=small,fill='#536478') d.rounded_rectangle((40,119,2060,174),radius=7,fill='#fff0eb') d.text((55,129),'空间预算用尽:零间隙;前端 9 mm 插入深度是假设。不能据此认定可装配!',font=small,fill='#9c2a25') def panel(path,box): im=Image.open(path).convert('RGB').rotate(90,expand=True) diff=ImageChops.difference(im,Image.new('RGB',im.size,'white')).convert('L').point(lambda p:255 if p>12 else 0) bounds=diff.getbbox();im=im.crop(bounds) if bounds else im im.thumbnail((box[2]-box[0],box[3]-box[1]));out.paste(im,(box[0]+(box[2]-box[0]-im.width)//2,box[1])) d.text((60,194),'方案 A:假设轴毂外径 20 mm;红色为示意碰撞',font=small,fill='#223955') panel(A/'side.png',(30,235,2070,650)) d.ellipse((945,370,1030,465),outline='#dc2929',width=5) d.ellipse((1195,370,1280,465),outline='#dc2929',width=5) d.text((60,670),'方案 B:假设缩至 18.4 mm;所检查的轴毂碰撞消失,轴向仍无余量',font=small,fill='#223955') panel(B/'side.png',(30,710,2070,1120)) d.line((42,1150,2058,1150),fill='#d8e0e9',width=2) d.text((45,1172),'绿色半透明体:开关 50 mm 包络占位,不是实物形状;中心孔 Ø47 mm 仅为示意。',font=small,fill='#3a6350') d.text((45,1214),'KFL 中央凸起、法兰轮毂尺寸与轴端键槽均未实测;实际白色回正机构未建模。',font=small,fill='#47576b') d.text((45,1256),'轴向示意:12 + 14.5 + 50 + 14.5 + 9 = 100 mm;20 mm 轴套已包含在开关包络内。',font=small,fill='#47576b') d.text((45,1298),'缩小轮毂只是几何探索,未验证键槽强度、轴向间隙、装配工具或 100 mm 轴的可用性。',font=small,fill='#9c2a25') out.save(A/'装配比较示意.png')