mirror of
				https://github.com/LiteyukiStudio/LiteyukiBot.git
				synced 2025-11-04 05:16:23 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			420 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			420 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import json
 | 
						||
from typing import List, Any
 | 
						||
 | 
						||
from PIL import Image
 | 
						||
from arclet.alconna import Alconna
 | 
						||
from nb_cli import run_sync
 | 
						||
from nonebot import on_command
 | 
						||
from nonebot_plugin_alconna import on_alconna, Alconna, Subcommand, Args, MultiVar, Arparma, UniMessage
 | 
						||
from pydantic import BaseModel
 | 
						||
 | 
						||
from .canvas import *
 | 
						||
from ...utils.base.resource import get_path
 | 
						||
 | 
						||
resolution = 256
 | 
						||
 | 
						||
 | 
						||
class Entrance(BaseModel):
 | 
						||
    identifier: str
 | 
						||
    size: tuple[int, int]
 | 
						||
    dest: List[str]
 | 
						||
 | 
						||
 | 
						||
class Station(BaseModel):
 | 
						||
    identifier: str
 | 
						||
    chineseName: str
 | 
						||
    englishName: str
 | 
						||
    position: tuple[int, int]
 | 
						||
 | 
						||
 | 
						||
class Line(BaseModel):
 | 
						||
    identifier: str
 | 
						||
    chineseName: str
 | 
						||
    englishName: str
 | 
						||
    color: Any
 | 
						||
    stations: List["Station"]
 | 
						||
 | 
						||
 | 
						||
font_light = get_path("templates/fonts/MiSans/MiSans-Light.woff2")
 | 
						||
font_bold = get_path("templates/fonts/MiSans/MiSans-Bold.woff2")
 | 
						||
 | 
						||
@run_sync
 | 
						||
def generate_entrance_sign(name: str, aliases: List[str], lineInfo: List[Line], entranceIdentifier: str, ratio: tuple[int | float, int | float],
 | 
						||
                           reso: int = resolution):
 | 
						||
    """
 | 
						||
    Generates an entrance sign for the ride.
 | 
						||
    """
 | 
						||
    width, height = ratio[0] * reso, ratio[1] * reso
 | 
						||
    baseCanvas = Canvas(Image.new("RGBA", (width, height), Color.WHITE))
 | 
						||
    # 加黑色图框
 | 
						||
    baseCanvas.outline = Img(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 1),
 | 
						||
        parent_point=(0, 0),
 | 
						||
        point=(0, 0),
 | 
						||
        img=Shape.rectangle(
 | 
						||
            size=(width, height),
 | 
						||
            fillet=0,
 | 
						||
            fill=(0, 0, 0, 0),
 | 
						||
            width=15,
 | 
						||
            outline=Color.BLACK
 | 
						||
        )
 | 
						||
    )
 | 
						||
 | 
						||
    baseCanvas.contentPanel = Panel(
 | 
						||
        uv_size=(width, height),
 | 
						||
        box_size=(width - 28, height - 28),
 | 
						||
        parent_point=(0.5, 0.5),
 | 
						||
        point=(0.5, 0.5),
 | 
						||
    )
 | 
						||
 | 
						||
    linePanelHeight = 0.7 * ratio[1]
 | 
						||
    linePanelWidth = linePanelHeight * 1.3
 | 
						||
 | 
						||
    # 画线路面板部分
 | 
						||
 | 
						||
    for i, line in enumerate(lineInfo):
 | 
						||
        linePanel = baseCanvas.contentPanel.__dict__[f"Line_{i}_Panel"] = Panel(
 | 
						||
            uv_size=ratio,
 | 
						||
            box_size=(linePanelWidth, linePanelHeight),
 | 
						||
            parent_point=(i * linePanelWidth / ratio[0], 1),
 | 
						||
            point=(0, 1),
 | 
						||
        )
 | 
						||
 | 
						||
        linePanel.colorCube = Img(
 | 
						||
            uv_size=(1, 1),
 | 
						||
            box_size=(0.15, 1),
 | 
						||
            parent_point=(0.125, 1),
 | 
						||
            point=(0, 1),
 | 
						||
            img=Shape.rectangle(
 | 
						||
                size=(100, 100),
 | 
						||
                fillet=0,
 | 
						||
                fill=line.color,
 | 
						||
            ),
 | 
						||
            keep_ratio=False
 | 
						||
        )
 | 
						||
 | 
						||
        textPanel = linePanel.TextPanel = Panel(
 | 
						||
            uv_size=(1, 1),
 | 
						||
            box_size=(0.625, 1),
 | 
						||
            parent_point=(1, 1),
 | 
						||
            point=(1, 1)
 | 
						||
        )
 | 
						||
 | 
						||
        # 中文线路名
 | 
						||
        textPanel.namePanel = Panel(
 | 
						||
            uv_size=(1, 1),
 | 
						||
            box_size=(1, 2 / 3),
 | 
						||
            parent_point=(0, 0),
 | 
						||
            point=(0, 0),
 | 
						||
        )
 | 
						||
        nameSize = baseCanvas.get_actual_pixel_size("contentPanel.Line_{}_Panel.TextPanel.namePanel".format(i))
 | 
						||
        textPanel.namePanel.text = Text(
 | 
						||
            uv_size=(1, 1),
 | 
						||
            box_size=(1, 1),
 | 
						||
            parent_point=(0.5, 0.5),
 | 
						||
            point=(0.5, 0.5),
 | 
						||
            text=line.chineseName,
 | 
						||
            color=Color.BLACK,
 | 
						||
            font_size=int(nameSize[1] * 0.5),
 | 
						||
            force_size=True,
 | 
						||
            font=font_bold
 | 
						||
 | 
						||
        )
 | 
						||
 | 
						||
        # 英文线路名
 | 
						||
        textPanel.englishNamePanel = Panel(
 | 
						||
            uv_size=(1, 1),
 | 
						||
            box_size=(1, 1 / 3),
 | 
						||
            parent_point=(0, 1),
 | 
						||
            point=(0, 1),
 | 
						||
        )
 | 
						||
        englishNameSize = baseCanvas.get_actual_pixel_size("contentPanel.Line_{}_Panel.TextPanel.englishNamePanel".format(i))
 | 
						||
        textPanel.englishNamePanel.text = Text(
 | 
						||
            uv_size=(1, 1),
 | 
						||
            box_size=(1, 1),
 | 
						||
            parent_point=(0.5, 0.5),
 | 
						||
            point=(0.5, 0.5),
 | 
						||
            text=line.englishName,
 | 
						||
            color=Color.BLACK,
 | 
						||
            font_size=int(englishNameSize[1] * 0.6),
 | 
						||
            force_size=True,
 | 
						||
            font=font_light
 | 
						||
        )
 | 
						||
 | 
						||
    # 画名称部分
 | 
						||
    namePanel = baseCanvas.contentPanel.namePanel = Panel(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 0.4),
 | 
						||
        parent_point=(0.5, 0),
 | 
						||
        point=(0.5, 0),
 | 
						||
    )
 | 
						||
 | 
						||
    namePanel.text = Text(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 1),
 | 
						||
        parent_point=(0.5, 0.5),
 | 
						||
        point=(0.5, 0.5),
 | 
						||
        text=name,
 | 
						||
        color=Color.BLACK,
 | 
						||
        font_size=int(height * 0.3),
 | 
						||
        force_size=True,
 | 
						||
        font=font_bold
 | 
						||
    )
 | 
						||
 | 
						||
    aliasesPanel = baseCanvas.contentPanel.aliasesPanel = Panel(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 0.5),
 | 
						||
        parent_point=(0.5, 1),
 | 
						||
        point=(0.5, 1),
 | 
						||
 | 
						||
    )
 | 
						||
    for j, alias in enumerate(aliases):
 | 
						||
        aliasesPanel.__dict__[alias] = Text(
 | 
						||
            uv_size=(1, 1),
 | 
						||
            box_size=(0.35, 0.5),
 | 
						||
            parent_point=(0.5, 0.5 * j),
 | 
						||
            point=(0.5, 0),
 | 
						||
            text=alias,
 | 
						||
            color=Color.BLACK,
 | 
						||
            font_size=int(height * 0.15),
 | 
						||
            font=font_light
 | 
						||
        )
 | 
						||
 | 
						||
    # 画入口标识
 | 
						||
    entrancePanel = baseCanvas.contentPanel.entrancePanel = Panel(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(0.2, 1),
 | 
						||
        parent_point=(1, 0.5),
 | 
						||
        point=(1, 0.5),
 | 
						||
    )
 | 
						||
    # 中文文本
 | 
						||
    entrancePanel.namePanel = Panel(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 0.5),
 | 
						||
        parent_point=(1, 0),
 | 
						||
        point=(1, 0),
 | 
						||
    )
 | 
						||
    entrancePanel.namePanel.text = Text(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 1),
 | 
						||
        parent_point=(0, 0.5),
 | 
						||
        point=(0, 0.5),
 | 
						||
        text=f"{entranceIdentifier}出入口",
 | 
						||
        color=Color.BLACK,
 | 
						||
        font_size=int(height * 0.2),
 | 
						||
        force_size=True,
 | 
						||
        font=font_bold
 | 
						||
    )
 | 
						||
    # 英文文本
 | 
						||
    entrancePanel.englishNamePanel = Panel(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 0.5),
 | 
						||
        parent_point=(1, 1),
 | 
						||
        point=(1, 1),
 | 
						||
    )
 | 
						||
    entrancePanel.englishNamePanel.text = Text(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 1),
 | 
						||
        parent_point=(0, 0.5),
 | 
						||
        point=(0, 0.5),
 | 
						||
        text=f"Entrance {entranceIdentifier}",
 | 
						||
        color=Color.BLACK,
 | 
						||
        font_size=int(height * 0.15),
 | 
						||
        force_size=True,
 | 
						||
        font=font_light
 | 
						||
    )
 | 
						||
 | 
						||
    return baseCanvas.base_img.tobytes()
 | 
						||
 | 
						||
 | 
						||
crt_alc = on_alconna(
 | 
						||
    Alconna(
 | 
						||
        "crt",
 | 
						||
        Subcommand(
 | 
						||
            "entrance",
 | 
						||
            Args["name", str]["lines", str, ""]["entrance", int, 1],  # /crt entrance 璧山&Bishan 1号线&Line1&#ff0000,27号线&Line1&#ff0000 1A
 | 
						||
        )
 | 
						||
    )
 | 
						||
)
 | 
						||
 | 
						||
 | 
						||
@crt_alc.assign("entrance")
 | 
						||
async def _(result: Arparma):
 | 
						||
    args = result.subcommands.get("entrance").args
 | 
						||
    name = args["name"]
 | 
						||
    lines = args["lines"]
 | 
						||
    entrance = args["entrance"]
 | 
						||
    line_info = []
 | 
						||
    for line in lines.split(","):
 | 
						||
        line_args = line.split("&")
 | 
						||
        line_info.append(Line(
 | 
						||
            identifier=1,
 | 
						||
            chineseName=line_args[0],
 | 
						||
            englishName=line_args[1],
 | 
						||
            color=line_args[2],
 | 
						||
            stations=[]
 | 
						||
        ))
 | 
						||
    img_bytes = await generate_entrance_sign(
 | 
						||
        name=name,
 | 
						||
        aliases=name.split("&"),
 | 
						||
        lineInfo=line_info,
 | 
						||
        entranceIdentifier=entrance,
 | 
						||
        ratio=(8, 1),
 | 
						||
        reso=256,
 | 
						||
    )
 | 
						||
    await crt_alc.finish(
 | 
						||
        UniMessage.image(raw=img_bytes)
 | 
						||
    )
 | 
						||
 | 
						||
 | 
						||
def generate_platform_line_pic(line: Line, station: Station, ratio=None, reso: int = resolution):
 | 
						||
    """
 | 
						||
    生成站台线路图
 | 
						||
    :param line: 线路对象
 | 
						||
    :param station: 本站点对象
 | 
						||
    :param ratio: 比例
 | 
						||
    :param reso: 分辨率,1:reso
 | 
						||
    :return: 两个方向的站牌
 | 
						||
    """
 | 
						||
    if ratio is None:
 | 
						||
        ratio = [4, 1]
 | 
						||
    width, height = ratio[0] * reso, ratio[1] * reso
 | 
						||
    baseCanvas = Canvas(Image.new("RGBA", (width, height), Color.YELLOW))
 | 
						||
    # 加黑色图框
 | 
						||
    baseCanvas.linePanel = Panel(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(0.8, 0.15),
 | 
						||
        parent_point=(0.5, 0.5),
 | 
						||
        point=(0.5, 0.5),
 | 
						||
    )
 | 
						||
 | 
						||
    # 直线块
 | 
						||
    baseCanvas.linePanel.recLine = Img(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 1),
 | 
						||
        parent_point=(0.5, 0.5),
 | 
						||
        point=(0.5, 0.5),
 | 
						||
        img=Shape.rectangle(
 | 
						||
            size=(10, 10),
 | 
						||
            fill=line.color,
 | 
						||
        ),
 | 
						||
        keep_ratio=False
 | 
						||
    )
 | 
						||
    # 灰色直线块
 | 
						||
    baseCanvas.linePanel.recLineGrey = Img(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 1),
 | 
						||
        parent_point=(0.5, 0.5),
 | 
						||
        point=(0.5, 0.5),
 | 
						||
        img=Shape.rectangle(
 | 
						||
            size=(10, 10),
 | 
						||
            fill=Color.GREY,
 | 
						||
        ),
 | 
						||
        keep_ratio=False
 | 
						||
    )
 | 
						||
    # 生成各站圆点
 | 
						||
    outline_width = 40
 | 
						||
    circleForward = Shape.circular(
 | 
						||
        radius=200,
 | 
						||
        fill=Color.WHITE,
 | 
						||
        width=outline_width,
 | 
						||
        outline=line.color,
 | 
						||
    )
 | 
						||
 | 
						||
    circleThisPanel = Canvas(Image.new("RGBA", (200, 200), (0, 0, 0, 0)))
 | 
						||
    circleThisPanel.circleOuter = Img(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(1, 1),
 | 
						||
        parent_point=(0.5, 0.5),
 | 
						||
        point=(0.5, 0.5),
 | 
						||
        img=Shape.circular(
 | 
						||
            radius=200,
 | 
						||
            fill=Color.WHITE,
 | 
						||
            width=outline_width,
 | 
						||
            outline=line.color,
 | 
						||
        ),
 | 
						||
    )
 | 
						||
    circleThisPanel.circleOuter.circleInner = Img(
 | 
						||
        uv_size=(1, 1),
 | 
						||
        box_size=(0.7, 0.7),
 | 
						||
        parent_point=(0.5, 0.5),
 | 
						||
        point=(0.5, 0.5),
 | 
						||
        img=Shape.circular(
 | 
						||
            radius=200,
 | 
						||
            fill=line.color,
 | 
						||
            width=0,
 | 
						||
            outline=line.color,
 | 
						||
        ),
 | 
						||
    )
 | 
						||
 | 
						||
    circleThisPanel.export("a.png", alpha=True)
 | 
						||
    circleThis = circleThisPanel.base_img
 | 
						||
 | 
						||
    circlePassed = Shape.circular(
 | 
						||
        radius=200,
 | 
						||
        fill=Color.WHITE,
 | 
						||
        width=outline_width,
 | 
						||
        outline=Color.GREY,
 | 
						||
    )
 | 
						||
 | 
						||
    arrival = False
 | 
						||
    distance = 1 / (len(line.stations) - 1)
 | 
						||
    for i, sta in enumerate(line.stations):
 | 
						||
        box_size = (1.618, 1.618)
 | 
						||
        if sta.identifier == station.identifier:
 | 
						||
            arrival = True
 | 
						||
            baseCanvas.linePanel.recLine.__dict__["station_{}".format(sta.identifier)] = Img(
 | 
						||
                uv_size=(1, 1),
 | 
						||
                box_size=(1.8, 1.8),
 | 
						||
                parent_point=(distance * i, 0.5),
 | 
						||
                point=(0.5, 0.5),
 | 
						||
                img=circleThis,
 | 
						||
                keep_ratio=True
 | 
						||
            )
 | 
						||
            continue
 | 
						||
        if arrival:
 | 
						||
            # 后方站绘制
 | 
						||
            baseCanvas.linePanel.recLine.__dict__["station_{}".format(sta.identifier)] = Img(
 | 
						||
                uv_size=(1, 1),
 | 
						||
                box_size=box_size,
 | 
						||
                parent_point=(distance * i, 0.5),
 | 
						||
                point=(0.5, 0.5),
 | 
						||
                img=circleForward,
 | 
						||
                keep_ratio=True
 | 
						||
            )
 | 
						||
        else:
 | 
						||
            # 前方站绘制
 | 
						||
            baseCanvas.linePanel.recLine.__dict__["station_{}".format(sta.identifier)] = Img(
 | 
						||
                uv_size=(1, 1),
 | 
						||
                box_size=box_size,
 | 
						||
                parent_point=(distance * i, 0.5),
 | 
						||
                point=(0.5, 0.5),
 | 
						||
                img=circlePassed,
 | 
						||
                keep_ratio=True
 | 
						||
            )
 | 
						||
    return baseCanvas
 | 
						||
 | 
						||
 | 
						||
def generate_platform_sign(name: str, aliases: List[str], lineInfo: List[Line], entranceIdentifier: str, ratio: tuple[int | float, int | float],
 | 
						||
                           reso: int = resolution
 | 
						||
                           ):
 | 
						||
    pass
 | 
						||
 | 
						||
# def main():
 | 
						||
#     generate_entrance_sign(
 | 
						||
#         "璧山",
 | 
						||
#         aliases=["Bishan"],
 | 
						||
#         lineInfo=[
 | 
						||
#
 | 
						||
#                 Line(identifier="2", chineseName="1号线", englishName="Line 1", color=Color.RED, stations=[]),
 | 
						||
#                 Line(identifier="3", chineseName="27号线", englishName="Line 27", color="#685bc7", stations=[]),
 | 
						||
#                 Line(identifier="1", chineseName="璧铜线", englishName="BT Line", color="#685BC7", stations=[]),
 | 
						||
#         ],
 | 
						||
#         entranceIdentifier="1",
 | 
						||
#         ratio=(8, 1)
 | 
						||
#     )
 | 
						||
#
 | 
						||
#
 | 
						||
# main()
 |