✨ 全新的帮助图绘制函数, 用于统一管理插件帮助
@ -1,16 +1,13 @@
|
|||||||
import asyncio
|
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from gsuid_core.aps import scheduler
|
from gsuid_core.aps import scheduler
|
||||||
from gsuid_core.logger import logger
|
from gsuid_core.logger import logger
|
||||||
from gsuid_core.server import GsServer
|
from gsuid_core.server import GsServer
|
||||||
from gsuid_core.help.draw_help import get_help_img
|
|
||||||
|
|
||||||
gss = GsServer()
|
gss = GsServer()
|
||||||
if not gss.is_load:
|
if not gss.is_load:
|
||||||
gss.is_load = True
|
gss.is_load = True
|
||||||
gss.load_plugins()
|
gss.load_plugins()
|
||||||
asyncio.run(get_help_img())
|
|
||||||
|
|
||||||
repeat_jobs = {}
|
repeat_jobs = {}
|
||||||
for i in scheduler.get_jobs():
|
for i in scheduler.get_jobs():
|
||||||
|
@ -1,232 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from typing import Dict, List, Tuple, Union, Optional
|
|
||||||
|
|
||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
from gsuid_core.sv import SV, Plugins
|
|
||||||
|
|
||||||
# from gsuid_core.utils.image.image_tools import get_color_bg
|
|
||||||
from gsuid_core.utils.fonts.fonts import core_font
|
|
||||||
from gsuid_core.utils.plugins_config.gs_config import pic_gen_config
|
|
||||||
|
|
||||||
pic_quality: int = pic_gen_config.get_config('PicQuality').data
|
|
||||||
TEXT_PATH = Path(__file__).parent / 'texture2d'
|
|
||||||
CORE_HELP_IMG = Path(__file__).parent / 'core_help.jpg'
|
|
||||||
|
|
||||||
plugin_title = 92
|
|
||||||
sv_title = 67
|
|
||||||
|
|
||||||
tag_color = {
|
|
||||||
'prefix': (137, 228, 124),
|
|
||||||
'suffix': (124, 180, 228),
|
|
||||||
'file': (190, 228, 217),
|
|
||||||
'keyword': (217, 228, 254),
|
|
||||||
'fullmatch': (228, 124, 124),
|
|
||||||
'regex': (225, 228, 124),
|
|
||||||
'command': (228, 124, 124),
|
|
||||||
'message': (176, 150, 198),
|
|
||||||
'other': (228, 190, 191),
|
|
||||||
}
|
|
||||||
|
|
||||||
tag_text: Dict[str, str] = {
|
|
||||||
'prefix': '前缀',
|
|
||||||
'suffix': '后缀',
|
|
||||||
'file': '文件',
|
|
||||||
'keyword': '包含',
|
|
||||||
'fullmatch': '完全',
|
|
||||||
'regex': '正则',
|
|
||||||
'command': '命令',
|
|
||||||
'message': '消息',
|
|
||||||
'other': '其他',
|
|
||||||
}
|
|
||||||
|
|
||||||
tags: Dict[str, Optional[Image.Image]] = {
|
|
||||||
'prefix': None,
|
|
||||||
'suffix': None,
|
|
||||||
'file': None,
|
|
||||||
'keyword': None,
|
|
||||||
'fullmatch': None,
|
|
||||||
'regex': None,
|
|
||||||
'command': None,
|
|
||||||
'other': None,
|
|
||||||
'message': None,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_tag(tag_type: str) -> Image.Image:
|
|
||||||
cache = tags[tag_type]
|
|
||||||
if cache is not None:
|
|
||||||
return cache
|
|
||||||
text = tag_text[tag_type]
|
|
||||||
tag = Image.new('RGBA', (60, 40))
|
|
||||||
tag_draw = ImageDraw.Draw(tag)
|
|
||||||
tag_draw.rounded_rectangle((7, 5, 53, 35), 10, tag_color[tag_type])
|
|
||||||
tag_draw.text((30, 20), text, (62, 62, 62), core_font(22), 'mm')
|
|
||||||
tags[tag_type] = tag
|
|
||||||
return tag
|
|
||||||
|
|
||||||
|
|
||||||
def get_command_bg(command: str, tag_type: str):
|
|
||||||
img = Image.new('RGBA', (220, 40))
|
|
||||||
img_draw = ImageDraw.Draw(img)
|
|
||||||
img_draw.rounded_rectangle((6, 5, 160, 35), 10, (230, 202, 167))
|
|
||||||
img_draw.text((83, 20), command, (62, 62, 62), core_font(20), 'mm')
|
|
||||||
tag = get_tag(tag_type)
|
|
||||||
img.paste(tag, (160, 0), tag)
|
|
||||||
return img
|
|
||||||
|
|
||||||
|
|
||||||
def _c(data: Union[int, str, bool]) -> Tuple[int, int, int]:
|
|
||||||
gray_color = (184, 184, 184)
|
|
||||||
|
|
||||||
if isinstance(data, bool):
|
|
||||||
color = tag_color['prefix'] if data else gray_color
|
|
||||||
elif isinstance(data, str):
|
|
||||||
color = (
|
|
||||||
tag_color['prefix']
|
|
||||||
if data == 'ALL'
|
|
||||||
else tag_color['command'] if data == 'GROUP' else tag_color['file']
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
colors = list(tag_color.values())
|
|
||||||
if data <= len(colors) and data >= 0:
|
|
||||||
color = colors[data]
|
|
||||||
else:
|
|
||||||
color = tag_color['other']
|
|
||||||
return color
|
|
||||||
|
|
||||||
|
|
||||||
def _t(data: Union[int, str, bool]) -> str:
|
|
||||||
if isinstance(data, bool):
|
|
||||||
text = '开启' if data else '关闭'
|
|
||||||
elif isinstance(data, str):
|
|
||||||
text = (
|
|
||||||
'不限' if data == 'ALL' else '群聊' if data == 'GROUP' else '私聊'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
texts = [
|
|
||||||
'主人',
|
|
||||||
'超管',
|
|
||||||
'群主',
|
|
||||||
'管理',
|
|
||||||
'频管',
|
|
||||||
'子管',
|
|
||||||
'正常',
|
|
||||||
'低',
|
|
||||||
'黑',
|
|
||||||
]
|
|
||||||
if data <= len(texts) and data >= 0:
|
|
||||||
text = [
|
|
||||||
'主人',
|
|
||||||
'超管',
|
|
||||||
'群主',
|
|
||||||
'管理',
|
|
||||||
'频管',
|
|
||||||
'子管',
|
|
||||||
'正常',
|
|
||||||
'低',
|
|
||||||
'黑',
|
|
||||||
][data]
|
|
||||||
else:
|
|
||||||
text = '最低'
|
|
||||||
return text
|
|
||||||
|
|
||||||
|
|
||||||
def get_plugin_bg(plugin: Plugins, sv_list: List[SV]):
|
|
||||||
plugin_name = plugin.name
|
|
||||||
img_list: List[Image.Image] = []
|
|
||||||
|
|
||||||
for sv in sv_list:
|
|
||||||
sv_img = Image.new(
|
|
||||||
'RGBA',
|
|
||||||
(
|
|
||||||
900,
|
|
||||||
sv_title + ((len(sv.TL) + 3) // 4) * 40,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
sv_img_draw = ImageDraw.Draw(sv_img)
|
|
||||||
|
|
||||||
index = 0
|
|
||||||
for type in sv.TL:
|
|
||||||
for trigger_name in sv.TL[type]:
|
|
||||||
tg_img = get_command_bg(
|
|
||||||
trigger_name, sv.TL[type][trigger_name].type
|
|
||||||
)
|
|
||||||
sv_img.paste(
|
|
||||||
tg_img,
|
|
||||||
(6 + 220 * (index % 4), 67 + 40 * (index // 4)),
|
|
||||||
tg_img,
|
|
||||||
)
|
|
||||||
index += 1
|
|
||||||
index = 0
|
|
||||||
|
|
||||||
sv_img_draw.rounded_rectangle((15, 19, 25, 50), 10, (62, 62, 62))
|
|
||||||
sv_img_draw.text((45, 31), sv.name, (62, 62, 62), core_font(36), 'lm')
|
|
||||||
|
|
||||||
sv_img_draw.rounded_rectangle((710, 15, 760, 50), 10, _c(sv.enabled))
|
|
||||||
sv_img_draw.rounded_rectangle((770, 15, 820, 50), 10, _c(sv.pm))
|
|
||||||
sv_img_draw.rounded_rectangle((830, 15, 880, 50), 10, _c(sv.area))
|
|
||||||
|
|
||||||
sv_img_draw.text(
|
|
||||||
(735, 32), _t(sv.enabled), (62, 62, 62), core_font(22), 'mm'
|
|
||||||
)
|
|
||||||
sv_img_draw.text(
|
|
||||||
(795, 32), _t(sv.pm), (62, 62, 62), core_font(22), 'mm'
|
|
||||||
)
|
|
||||||
sv_img_draw.text(
|
|
||||||
(855, 32), _t(sv.area), (62, 62, 62), core_font(22), 'mm'
|
|
||||||
)
|
|
||||||
img_list.append(sv_img)
|
|
||||||
|
|
||||||
img = Image.new(
|
|
||||||
'RGBA',
|
|
||||||
(
|
|
||||||
900,
|
|
||||||
plugin_title + sum([i.size[1] for i in img_list]),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
img_draw = ImageDraw.Draw(img)
|
|
||||||
img_draw.rounded_rectangle((10, 26, 890, 76), 10, (230, 202, 167))
|
|
||||||
img_draw.text((450, 51), plugin_name, (62, 62, 62), core_font(42), 'mm')
|
|
||||||
|
|
||||||
temp = 0
|
|
||||||
for _img in img_list:
|
|
||||||
img.paste(_img, (0, 92 + temp), _img)
|
|
||||||
temp += _img.size[1]
|
|
||||||
|
|
||||||
return img
|
|
||||||
|
|
||||||
|
|
||||||
async def get_help_img() -> Image.Image:
|
|
||||||
from gsuid_core.sv import SL
|
|
||||||
|
|
||||||
content = SL.detail_lst
|
|
||||||
img_list: List[Image.Image] = []
|
|
||||||
for plugin in content:
|
|
||||||
plugin_img = get_plugin_bg(plugin, content[plugin])
|
|
||||||
img_list.append(plugin_img)
|
|
||||||
|
|
||||||
x = 900
|
|
||||||
y = 200 + sum([i.size[1] for i in img_list])
|
|
||||||
# img = await get_color_bg(x, y)
|
|
||||||
img = Image.new('RGBA', (x, y), (255, 255, 255))
|
|
||||||
title = Image.open(TEXT_PATH / 'title.png')
|
|
||||||
|
|
||||||
# white = Image.new('RGBA', img.size, (255, 255, 255, 120))
|
|
||||||
# img.paste(white, (0, 0), white)
|
|
||||||
img.paste(title, (0, 50), title)
|
|
||||||
|
|
||||||
temp = 0
|
|
||||||
for _img in img_list:
|
|
||||||
img.paste(_img, (0, 340 + temp), _img)
|
|
||||||
temp += _img.size[1]
|
|
||||||
|
|
||||||
img = img.convert('RGB')
|
|
||||||
img.save(
|
|
||||||
CORE_HELP_IMG,
|
|
||||||
format='JPEG',
|
|
||||||
quality=pic_quality,
|
|
||||||
subsampling=0,
|
|
||||||
)
|
|
||||||
|
|
||||||
return img
|
|
223
gsuid_core/help/draw_new_plugin_help.py
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
import random
|
||||||
|
from pathlib import Path
|
||||||
|
from copy import deepcopy
|
||||||
|
from typing import Dict, Literal, Optional
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
from gsuid_core.help.model import PluginHelp
|
||||||
|
from gsuid_core.data_store import get_res_path
|
||||||
|
from gsuid_core.utils.fonts.fonts import core_font
|
||||||
|
from gsuid_core.utils.image.convert import convert_img
|
||||||
|
from gsuid_core.utils.plugins_config.gs_config import pic_gen_config
|
||||||
|
from gsuid_core.utils.image.image_tools import (
|
||||||
|
crop_center_img,
|
||||||
|
draw_color_badge,
|
||||||
|
)
|
||||||
|
|
||||||
|
cache: Dict[str, int] = {}
|
||||||
|
ICON_PATH = Path(__file__).parent / 'new_icon'
|
||||||
|
TEXT_PATH = Path(__file__).parent / 'texture2d'
|
||||||
|
pic_quality: int = pic_gen_config.get_config('PicQuality').data
|
||||||
|
|
||||||
|
|
||||||
|
def find_icon(name: str, icon_path: Path = ICON_PATH):
|
||||||
|
for icon in icon_path.glob('*.png'):
|
||||||
|
if icon.stem == name:
|
||||||
|
_r = icon
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
for icon in icon_path.glob('*.png'):
|
||||||
|
if icon.stem in name:
|
||||||
|
_r = icon
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if (icon_path / '通用.png').exists():
|
||||||
|
_r = icon_path / '通用.png'
|
||||||
|
else:
|
||||||
|
_r = random.choice(list(icon_path.iterdir()))
|
||||||
|
return Image.open(_r)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_new_help(
|
||||||
|
plugin_name: str,
|
||||||
|
plugin_info: Dict[str, str],
|
||||||
|
plugin_icon: Image.Image,
|
||||||
|
plugin_help: Dict[str, PluginHelp],
|
||||||
|
plugin_prefix: str = '',
|
||||||
|
help_mode: Literal['dark', 'light'] = 'dark',
|
||||||
|
banner_bg: Optional[Image.Image] = None,
|
||||||
|
banner_sub_text: str = '💖且听风吟。',
|
||||||
|
help_bg: Optional[Image.Image] = None,
|
||||||
|
cag_bg: Optional[Image.Image] = None,
|
||||||
|
item_bg: Optional[Image.Image] = None,
|
||||||
|
icon_path: Path = ICON_PATH,
|
||||||
|
footer: Optional[Image.Image] = None,
|
||||||
|
enable_cache: bool = True,
|
||||||
|
):
|
||||||
|
help_path = get_res_path('help') / f'{plugin_name}.jpg'
|
||||||
|
|
||||||
|
if (
|
||||||
|
help_path.exists()
|
||||||
|
and plugin_name in cache
|
||||||
|
and cache[plugin_name]
|
||||||
|
and enable_cache
|
||||||
|
):
|
||||||
|
return await convert_img(Image.open(help_path))
|
||||||
|
|
||||||
|
if banner_bg is None:
|
||||||
|
banner_bg = Image.open(TEXT_PATH / 'banner_bg.jpg')
|
||||||
|
if help_bg is None:
|
||||||
|
help_bg = Image.open(TEXT_PATH / 'help_bg.jpg')
|
||||||
|
if cag_bg is None:
|
||||||
|
cag_bg = Image.open(TEXT_PATH / 'cag_bg.png')
|
||||||
|
if footer is None:
|
||||||
|
footer = Image.open(TEXT_PATH / f'footer_{help_mode}.png')
|
||||||
|
if item_bg is None:
|
||||||
|
item_bg = Image.open(TEXT_PATH / f'item_{help_mode}.png')
|
||||||
|
|
||||||
|
if help_mode == 'dark':
|
||||||
|
main_color = (255, 255, 255)
|
||||||
|
sub_color = (206, 206, 206)
|
||||||
|
else:
|
||||||
|
main_color = (0, 0, 0)
|
||||||
|
sub_color = (102, 102, 102)
|
||||||
|
|
||||||
|
banner_bg = banner_bg.convert('RGBA')
|
||||||
|
help_bg = help_bg.convert('RGBA')
|
||||||
|
cag_bg = cag_bg.convert('RGBA')
|
||||||
|
item_bg = item_bg.convert('RGBA')
|
||||||
|
footer = footer.convert('RGBA')
|
||||||
|
|
||||||
|
plugin_icon = plugin_icon.resize((128, 128))
|
||||||
|
|
||||||
|
# 准备计算整体帮助图大小
|
||||||
|
w, h = 1545, 300 + footer.height
|
||||||
|
|
||||||
|
cag_num = len(plugin_help)
|
||||||
|
h += cag_num * 100
|
||||||
|
for cag in plugin_help:
|
||||||
|
cag_data = plugin_help[cag]['data']
|
||||||
|
sv_num = len(cag_data)
|
||||||
|
h += (((sv_num - 1) // 3) + 1) * 175
|
||||||
|
|
||||||
|
# 基准图
|
||||||
|
img = crop_center_img(help_bg, w, h)
|
||||||
|
|
||||||
|
# 绘制banner
|
||||||
|
banner_bg.paste(plugin_icon, (89, 88), plugin_icon)
|
||||||
|
banner_draw = ImageDraw.Draw(banner_bg)
|
||||||
|
|
||||||
|
_banner_name = plugin_name + '帮助'
|
||||||
|
banner_draw.text(
|
||||||
|
(262, 128),
|
||||||
|
_banner_name,
|
||||||
|
main_color,
|
||||||
|
font=core_font(50),
|
||||||
|
anchor='lm',
|
||||||
|
)
|
||||||
|
banner_draw.text(
|
||||||
|
(262, 183),
|
||||||
|
banner_sub_text,
|
||||||
|
sub_color,
|
||||||
|
font=core_font(30),
|
||||||
|
anchor='lm',
|
||||||
|
)
|
||||||
|
x1, y1, x2, y2 = core_font(50).getbbox(_banner_name)
|
||||||
|
plugin_name_len = int(x2 - x1)
|
||||||
|
|
||||||
|
for key, value in plugin_info.items():
|
||||||
|
if value == 'any' or not value:
|
||||||
|
value = (252, 69, 69)
|
||||||
|
badge = draw_color_badge(
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
core_font(30),
|
||||||
|
(255, 255, 255),
|
||||||
|
)
|
||||||
|
banner_bg.paste(
|
||||||
|
badge,
|
||||||
|
(262 + plugin_name_len + 10, 128 - badge.height // 2),
|
||||||
|
badge,
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin_name_len += badge.width + 10
|
||||||
|
|
||||||
|
img.paste(banner_bg, (0, 0), banner_bg)
|
||||||
|
|
||||||
|
# 开始粘贴服务
|
||||||
|
hs = 0
|
||||||
|
for cag in plugin_help:
|
||||||
|
sv = plugin_help[cag]
|
||||||
|
cag_bar = deepcopy(cag_bg)
|
||||||
|
cag_desc = sv['desc']
|
||||||
|
cag_data = sv['data']
|
||||||
|
cag_draw = ImageDraw.Draw(cag_bar)
|
||||||
|
|
||||||
|
cag_draw.text(
|
||||||
|
(136, 50),
|
||||||
|
cag,
|
||||||
|
main_color,
|
||||||
|
font=core_font(45),
|
||||||
|
anchor='lm',
|
||||||
|
)
|
||||||
|
bbox = core_font(45).getbbox(cag)
|
||||||
|
cag_name_len = int(bbox[2] - bbox[0])
|
||||||
|
|
||||||
|
cag_draw.text(
|
||||||
|
(136 + cag_name_len + 15, 55),
|
||||||
|
cag_desc,
|
||||||
|
sub_color,
|
||||||
|
font=core_font(30),
|
||||||
|
anchor='lm',
|
||||||
|
)
|
||||||
|
img.paste(cag_bar, (0, 280 + hs), cag_bar)
|
||||||
|
|
||||||
|
for i, command in enumerate(cag_data):
|
||||||
|
command_name = command['name']
|
||||||
|
# command_desc = command['desc']
|
||||||
|
command_eg = command['eg']
|
||||||
|
command_bg = deepcopy(item_bg)
|
||||||
|
|
||||||
|
icon = find_icon(command_name, icon_path)
|
||||||
|
command_bg.paste(icon, (6, 12), icon)
|
||||||
|
|
||||||
|
command_draw = ImageDraw.Draw(command_bg)
|
||||||
|
|
||||||
|
command_draw.text(
|
||||||
|
(160, 67),
|
||||||
|
plugin_prefix + command_name,
|
||||||
|
main_color,
|
||||||
|
font=core_font(40),
|
||||||
|
anchor='lm',
|
||||||
|
)
|
||||||
|
|
||||||
|
command_draw.text(
|
||||||
|
(160, 116),
|
||||||
|
plugin_prefix + command_eg,
|
||||||
|
sub_color,
|
||||||
|
font=core_font(26),
|
||||||
|
anchor='lm',
|
||||||
|
)
|
||||||
|
|
||||||
|
x, y = 45 + (i % 3) * 490, 370 + (i // 3) * 175 + hs
|
||||||
|
img.paste(command_bg, (x, y), command_bg)
|
||||||
|
|
||||||
|
hs += (((len(cag_data) - 1) // 3) + 1) * 175 + 100
|
||||||
|
|
||||||
|
img.paste(
|
||||||
|
footer,
|
||||||
|
((w - footer.width) // 2, h - footer.height - 20),
|
||||||
|
footer,
|
||||||
|
)
|
||||||
|
|
||||||
|
img = img.convert('RGB')
|
||||||
|
img.save(
|
||||||
|
help_path,
|
||||||
|
'JPEG',
|
||||||
|
quality=pic_quality,
|
||||||
|
subsampling=0,
|
||||||
|
)
|
||||||
|
cache[plugin_name] = 1
|
||||||
|
|
||||||
|
return await convert_img(img)
|
BIN
gsuid_core/help/texture2d/banner_bg.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
gsuid_core/help/texture2d/bg.jpg
Normal file
After Width: | Height: | Size: 158 KiB |
BIN
gsuid_core/help/texture2d/cag_bg.png
Normal file
After Width: | Height: | Size: 888 B |
BIN
gsuid_core/help/texture2d/footer_dark.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
gsuid_core/help/texture2d/footer_light.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
gsuid_core/help/texture2d/item_dark.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
gsuid_core/help/texture2d/item_light.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 62 KiB |
@ -2,8 +2,6 @@ from gsuid_core.sv import SV
|
|||||||
from gsuid_core.bot import Bot
|
from gsuid_core.bot import Bot
|
||||||
from gsuid_core.models import Event
|
from gsuid_core.models import Event
|
||||||
from gsuid_core.logger import logger
|
from gsuid_core.logger import logger
|
||||||
from gsuid_core.utils.image.convert import convert_img
|
|
||||||
from gsuid_core.help.draw_help import CORE_HELP_IMG, get_help_img
|
|
||||||
|
|
||||||
sv_core_help_img = SV('Core帮助')
|
sv_core_help_img = SV('Core帮助')
|
||||||
|
|
||||||
@ -11,10 +9,4 @@ sv_core_help_img = SV('Core帮助')
|
|||||||
@sv_core_help_img.on_fullmatch(('core帮助', 'Core帮助'))
|
@sv_core_help_img.on_fullmatch(('core帮助', 'Core帮助'))
|
||||||
async def send_core_htlp_msg(bot: Bot, ev: Event):
|
async def send_core_htlp_msg(bot: Bot, ev: Event):
|
||||||
logger.info('[早柚核心] 开始执行[帮助图]')
|
logger.info('[早柚核心] 开始执行[帮助图]')
|
||||||
if CORE_HELP_IMG.exists():
|
await bot.send('该功能已删除...')
|
||||||
img = await convert_img(CORE_HELP_IMG)
|
|
||||||
else:
|
|
||||||
img = await get_help_img()
|
|
||||||
img = await convert_img(img)
|
|
||||||
logger.info('[早柚核心] 帮助图获取成功!')
|
|
||||||
await bot.send(img)
|
|
||||||
|
@ -11,5 +11,5 @@ AMBR_GCG_DETAIL = AMBR_BASE_URL + '/v2/chs/gcg/{}?vh=37F4'
|
|||||||
AMBR_MONSTER_LIST = AMBR_BASE_URL + '/v2/chs/monster?vh=37F4'
|
AMBR_MONSTER_LIST = AMBR_BASE_URL + '/v2/chs/monster?vh=37F4'
|
||||||
AMBR_ICON_URL = AMBR_BASE_URL + '/assets/UI'
|
AMBR_ICON_URL = AMBR_BASE_URL + '/assets/UI'
|
||||||
AMBR_MONSTER_ICON_URL = f'{AMBR_ICON_URL}/monster/'
|
AMBR_MONSTER_ICON_URL = f'{AMBR_ICON_URL}/monster/'
|
||||||
AMBR_DAILY_URL = AMBR_BASE_URL + '/v2/chs/dailyDungeon?vh=37F4'
|
AMBR_DAILY_URL = AMBR_BASE_URL + '/api/v2/chs/dailyDungeon?vh=37F4'
|
||||||
AMBR_UPGRADE_URL = AMBR_BASE_URL + '/v2/chs/upgrade?vh=40F3'
|
AMBR_UPGRADE_URL = AMBR_BASE_URL + '/api/v2/chs/upgrade?vh=40F3'
|
||||||
|
BIN
gsuid_core/utils/fonts/MiSans-Bold.ttf
Normal file
@ -2,7 +2,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from PIL import ImageFont
|
from PIL import ImageFont
|
||||||
|
|
||||||
FONT_ORIGIN_PATH = Path(__file__).parent / 'yuanshen_origin.ttf'
|
FONT_ORIGIN_PATH = Path(__file__).parent / 'MiSans-Bold.ttf'
|
||||||
|
|
||||||
|
|
||||||
def core_font(size: int) -> ImageFont.FreeTypeFont:
|
def core_font(size: int) -> ImageFont.FreeTypeFont:
|
||||||
|
@ -6,6 +6,7 @@ from typing import Tuple, Union, Optional
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from httpx import get
|
from httpx import get
|
||||||
|
from utils.fonts.fonts import core_font
|
||||||
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||||
|
|
||||||
from gsuid_core.models import Event
|
from gsuid_core.models import Event
|
||||||
@ -20,6 +21,31 @@ def get_div():
|
|||||||
return Image.open(TEXT_PATH / 'div.png')
|
return Image.open(TEXT_PATH / 'div.png')
|
||||||
|
|
||||||
|
|
||||||
|
def draw_color_badge(
|
||||||
|
text: str,
|
||||||
|
color: Union[Tuple[int, int, int], str] = (252, 69, 69),
|
||||||
|
font: ImageFont.FreeTypeFont = core_font(30),
|
||||||
|
font_color: Tuple[int, int, int] = (255, 255, 255),
|
||||||
|
):
|
||||||
|
x1, y1, x2, y2 = font.getbbox(text)
|
||||||
|
offset_x = int((x2 - x1) * 0.3)
|
||||||
|
offset_y = int((y2 - y1) * 0.5)
|
||||||
|
x3, y3, x4, y4 = x1 - offset_x, y1 - offset_y, x2 + offset_x, y2 + offset_y
|
||||||
|
w, h = int(x4 - x3), int(y4 - y3)
|
||||||
|
center_x, center_y = int(w // 2), int(h // 2)
|
||||||
|
img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw.rounded_rectangle((0, 0, w, h), fill=color, radius=20)
|
||||||
|
draw.text(
|
||||||
|
(center_x, center_y),
|
||||||
|
text,
|
||||||
|
font=font,
|
||||||
|
fill=font_color,
|
||||||
|
anchor='mm',
|
||||||
|
)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
def get_status_icon(status: Union[int, bool]) -> Image.Image:
|
def get_status_icon(status: Union[int, bool]) -> Image.Image:
|
||||||
if status:
|
if status:
|
||||||
img = Image.open(TEXT_PATH / 'yes.png')
|
img = Image.open(TEXT_PATH / 'yes.png')
|
||||||
@ -89,9 +115,9 @@ async def shift_image_hue(img: Image.Image, angle: float = 30) -> Image.Image:
|
|||||||
|
|
||||||
for y in range(img.height):
|
for y in range(img.height):
|
||||||
for x in range(img.width):
|
for x in range(img.width):
|
||||||
h, s, v = pixels[x, y]
|
h, s, v = pixels[x, y] # type: ignore
|
||||||
h = (h + hue_shift) % 360
|
h = (h + hue_shift) % 360
|
||||||
pixels[x, y] = (h, s, v)
|
pixels[x, y] = (h, s, v) # type: ignore
|
||||||
|
|
||||||
img = img.convert('RGBA')
|
img = img.convert('RGBA')
|
||||||
img.putalpha(alpha)
|
img.putalpha(alpha)
|
||||||
@ -394,7 +420,16 @@ class CustomizeImage:
|
|||||||
img = img.convert("RGBA")
|
img = img.convert("RGBA")
|
||||||
img = img.resize((1, 1), resample=0)
|
img = img.resize((1, 1), resample=0)
|
||||||
dominant_color = img.getpixel((0, 0))
|
dominant_color = img.getpixel((0, 0))
|
||||||
return dominant_color
|
if isinstance(dominant_color, float):
|
||||||
|
_dominant_color = tuple(
|
||||||
|
[int(dominant_color * 255) for _ in range(3)]
|
||||||
|
) # type: ignore
|
||||||
|
elif dominant_color is None or isinstance(dominant_color, int):
|
||||||
|
_dominant_color: Tuple[int, int, int] = (255, 255, 255)
|
||||||
|
else:
|
||||||
|
_dominant_color = dominant_color # type: ignore
|
||||||
|
|
||||||
|
return _dominant_color
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_bg_color(
|
def get_bg_color(
|
||||||
|