From 9c6e980adf584e8ccd7320f52dd20cc1fe1114f3 Mon Sep 17 00:00:00 2001 From: XcantloadX <3188996979@qq.com> Date: Wed, 9 Apr 2025 14:52:19 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20make=5Fresources.py=20=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E5=8A=A0=E5=85=A5=E5=AF=B9=20PyCharm=20=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/image_server.py | 47 ++++++++++++++++++++++++++++++++++++++ tools/make_resources.py | 50 ++++++++++++++++++++++++++++++++--------- 2 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 tools/image_server.py diff --git a/tools/image_server.py b/tools/image_server.py new file mode 100644 index 0000000..5ea4605 --- /dev/null +++ b/tools/image_server.py @@ -0,0 +1,47 @@ +from fastapi import FastAPI, HTTPException +from fastapi.responses import Response +import cv2 +import numpy as np +from pathlib import Path + +app = FastAPI() + + +def cv2_imread(path: str, flags=cv2.IMREAD_COLOR): + """读取图片,支持中文路径""" + return cv2.imdecode(np.fromfile(path, dtype=np.uint8), flags) + + +@app.get("/image") +async def get_image(path: str): + """返回指定路径的图片 + + Args: + path: 图片的文件路径 + + Returns: + 图片数据 + """ + try: + # 检查文件是否存在 + if not Path(path).exists(): + raise HTTPException(status_code=404, detail="Image not found") + + # 读取图片 + img = cv2_imread(path) + if img is None: + raise HTTPException(status_code=400, detail="Invalid image format") + + # 编码为PNG并返回 + _, img_encoded = cv2.imencode('.png', img) + return Response(content=img_encoded.tobytes(), media_type="image/png") + except Exception as e: + if isinstance(e, HTTPException): + raise e + raise HTTPException(status_code=500, detail=str(e)) + + +if __name__ == "__main__": + import uvicorn + + uvicorn.run(app, host="0.0.0.0", port=6532) \ No newline at end of file diff --git a/tools/make_resources.py b/tools/make_resources.py index 1cdeccf..c8bad9f 100644 --- a/tools/make_resources.py +++ b/tools/make_resources.py @@ -148,7 +148,28 @@ def escape(s: str) -> str: return s.replace('\\', '\\\\') def unify_path(path: str) -> str: - return path.replace('/', '\\') + return path.replace('\\', '/') + +def ide_type() -> Literal['vscode', 'pycharm'] | None: + """通过递归枚举父进程判断当前IDE类型""" + import psutil + + me = psutil.Process() + while True: + parent = me.parent() + if parent is None: + break + name = parent.name().lower() + if 'code.exe' in name: + return 'vscode' + elif 'cursor.exe' in name: + return 'vscode' + elif 'windsurf.exe' in name: + return 'vscode' + elif 'pycharm' in name: + return 'pycharm' + me = parent + return None def scan_png_files(path: str) -> list[str]: """扫描所有 PNG 文件""" @@ -269,11 +290,19 @@ def load_sprites(root_path: str, png_files: list[str]) -> list[Resource]: print(f'Loaded basic sprite: {file}') return resources -def make_classes(resources: list[Resource], output_path: str) -> list[OutputClass]: +def make_img(ide: Literal['vscode', 'pycharm'], path: str, title: str, height: str = ''): + if ide == 'vscode': + return f'\n' + elif ide == 'pycharm': + return f'.. image:: http://localhost:6532/image?path={unify_path(path)}\n' + else: + raise ValueError(f'Unknown IDE: {ide}') + +def make_classes(resources: list[Resource], ide: Literal['vscode', 'pycharm']) -> list[OutputClass]: """根据 Sprite 数据生成 R.py 中的类信息。""" # 按照 class_path 对 sprites 进行分组 class_map: dict[str, OutputClass] = {} - + # 创建或获取指定路径的类 def get_or_create_class(path: list[str]) -> Union[OutputClass, None]: if not path: @@ -326,14 +355,14 @@ def make_classes(resources: list[Resource], output_path: str) -> list[OutputClas docstring = ( f"名称:{sprite.display_name}\\n\n" f"描述:{resource.description}\\n\n" - f"路径:{escape(sprite.rel_path)}\\n\n" + f"路径:{unify_path(sprite.rel_path)}\\n\n" f"模块:`{'.'.join(sprite.class_path)}`\\n\n" - f'\\n\n' + + make_img(ide, sprite.abs_path, sprite.display_name) ) if sprite.type == 'metadata': docstring += ( f"原始文件:\\n\n" - f"" + + make_img(ide, sprite.origin_file, '原始文件', height) ) img_attr = ImageAttribute( type='image', @@ -361,9 +390,9 @@ def make_classes(resources: list[Resource], output_path: str) -> list[OutputClas f"模块:`{'.'.join(hint_box.class_path)}`\\n\n" f"值:x1={hint_box.x1}, y1={hint_box.y1}, x2={hint_box.x2}, y2={hint_box.y2}\\n\n" f"裁剪区域:\\n\n" - f"\\n\n" - f"原始图片:\\n\n" - f"" + + make_img(ide, clip_abs_path, '裁剪区域') + + f"原始图片:\\n\n" + + make_img(ide, hint_box.origin_file, '原始文件', '80%') ) img_attr = ImageAttribute( type='image', @@ -425,6 +454,7 @@ if __name__ == '__main__': # 添加命令行参数解析 parser = argparse.ArgumentParser(description='生成图片资源文件') parser.add_argument('-p', '--production', action='store_true', help='生产模式:不输出注释') + parser.add_argument('-i', '--ide', help='IDE 类型', default=ide_type()) args = parser.parse_args() if os.path.exists(r'kotonebot\tasks\sprites'): @@ -433,7 +463,7 @@ if __name__ == '__main__': files = scan_png_files(path) sprites = load_sprites(path, files) sprites = copy_sprites(sprites, r'kotonebot\tasks\sprites') - classes = make_classes(sprites, r'kotonebot\tasks\sprites') + classes = make_classes(sprites, args.ide) env = jinja2.Environment(loader=jinja2.FileSystemLoader('./tools')) env.filters['indent'] = indent