from PIL import Image, ImageChops, ImageDraw, ImageFont from pathlib import Path out=Path(r'C:\projects\wheel\models\kfl_plate_b38_concept') font=r'C:\Windows\Fonts\msyh.ttc' title=ImageFont.truetype(font,38); normal=ImageFont.truetype(font,24); small=ImageFont.truetype(font,21) im=Image.new('RGB',(1920,1300),'white');d=ImageDraw.Draw(im) d.text((42,18),'KFL001 反装 · 铝板中心孔 Ø39 mm',font=title,fill='#193450') d.text((42,80),'Ø38 外包络假设;8 mm 铝板;150 mm 轴;60 mm 开关与接线包络',font=normal,fill='#52657b') d.rounded_rectangle((40,123,1880,177),radius=8,fill='#fff0eb') d.text((55,134),'概念示意:仅用于讨论;轴承凸起轮廓及承载强度未验证,不可直接 CNC',font=normal,fill='#9b2b22') def load(name,maxsize,rotation=0): img=Image.open(out/name).convert('RGB') if rotation:img=img.rotate(rotation,expand=True) mask=ImageChops.difference(img,Image.new('RGB',img.size,'white')).convert('L').point(lambda p:255 if p>12 else 0) b=mask.getbbox() if b:img=img.crop(b) img.thumbnail(maxsize);return img side=load('side.png',(1730,370),90) d.text((40,194),'整体侧视:电机在左,方向盘侧在右',font=normal,fill='#243a55') im.paste(side,(95+(1730-side.width)//2,230+(370-side.height)//2)) d.line((40,620,1880,620),fill='#d8e0e9',width=2) d.text((40,638),'反装结构(外形简化)',font=normal,fill='#243a55') d.text((980,638),'铝板背面:垫圈与大孔的相对位置',font=normal,fill='#243a55') detail=load('bearing_detail.png',(800,350));plate=load('plate_detail.png',(800,350)) im.paste(detail,(80+(800-detail.width)//2,680+(350-detail.height)//2)) im.paste(plate,(1020+(800-plate.width)//2,680+(350-plate.height)//2)) d.line((40,1055,1880,1055),fill='#d8e0e9',width=2) rows=[ ('中心孔 Ø39,轴承凸起按 Ø38 圆形包络示意,名义径向间隙 0.5 mm。','#243a55'), ('安装孔距 48、安装孔 Ø7:距中心孔最近材料宽度为 1 mm(几何值,不作强度结论)。','#243a55'), ('板侧 M6 垫圈按 Ø12 示意,靠中心孔一侧约 1.5 mm 悬空;真实承压须核对。','#9b2b22'), ('角码与对中长槽沿用前版;开关形状、轴承顶丝工具空间等尚未实物验证。','#52657b'), ] for i,(s,c) in enumerate(rows):d.text((42,1073+i*43),s,font=small,fill=c) im.save(out/'KFL_38凸起_39开孔_3D装配示意.png')