mirror of
https://github.com/xuthus83/LittlePaimon.git
synced 2025-04-12 23:29:37 +08:00
✨ 优化帮助图
显示,增加图片资源缓存
配置项
This commit is contained in:
parent
584ee1aa80
commit
0546be70c8
@ -8,6 +8,8 @@ class ConfigModel(BaseModel):
|
|||||||
CookieWeb_url: str = Field('http://127.0.0.1:13579/LittlePaimon/cookie', alias='CookieWeb地址')
|
CookieWeb_url: str = Field('http://127.0.0.1:13579/LittlePaimon/cookie', alias='CookieWeb地址')
|
||||||
qrcode_bind_use_url: bool = Field(False, alias='绑定二维码以链接形式发送')
|
qrcode_bind_use_url: bool = Field(False, alias='绑定二维码以链接形式发送')
|
||||||
|
|
||||||
|
img_use_cache: bool = Field(True, alias='图片资源缓存开关')
|
||||||
|
|
||||||
sim_gacha_cd_group: int = Field(30, alias='模拟抽卡群冷却')
|
sim_gacha_cd_group: int = Field(30, alias='模拟抽卡群冷却')
|
||||||
sim_gacha_cd_member: int = Field(60, alias='模拟抽卡群员冷却')
|
sim_gacha_cd_member: int = Field(60, alias='模拟抽卡群员冷却')
|
||||||
sim_gacha_max: int = Field(5, alias='模拟抽卡单次最多十连数')
|
sim_gacha_max: int = Field(5, alias='模拟抽卡单次最多十连数')
|
||||||
|
@ -2,8 +2,7 @@ import asyncio
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from LittlePaimon.database import GenshinVoice
|
from LittlePaimon.database import GenshinVoice
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ import pytz
|
|||||||
from nonebot import get_bot
|
from nonebot import get_bot
|
||||||
|
|
||||||
from LittlePaimon.database import AbyssInfo
|
from LittlePaimon.database import AbyssInfo
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, get_qq_avatar, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm, get_qq_avatar
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from LittlePaimon.utils.requests import aiorequests
|
from LittlePaimon.utils.requests import aiorequests
|
||||||
|
@ -3,8 +3,7 @@ import datetime
|
|||||||
|
|
||||||
from LittlePaimon.database import AbyssInfo
|
from LittlePaimon.database import AbyssInfo
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ from typing import List
|
|||||||
|
|
||||||
from LittlePaimon.database import Character, LastQuery
|
from LittlePaimon.database import Character, LastQuery
|
||||||
from LittlePaimon.utils.alias import get_chara_icon
|
from LittlePaimon.utils.alias import get_chara_icon
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from .api import get_team_rate
|
from .api import get_team_rate
|
||||||
|
@ -2,8 +2,7 @@ import math
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from enum import IntEnum, auto
|
from enum import IntEnum, auto
|
||||||
|
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage
|
|
||||||
from LittlePaimon.utils.image import font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ import math
|
|||||||
import random
|
import random
|
||||||
from typing import Tuple, List, Optional
|
from typing import Tuple, List, Optional
|
||||||
|
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, get_qq_avatar, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, get_qq_avatar, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from .models import GachaLogInfo, FiveStarItem, FourStarItem
|
from .models import GachaLogInfo, FiveStarItem, FourStarItem
|
||||||
|
@ -5,9 +5,8 @@ from typing import List
|
|||||||
|
|
||||||
from LittlePaimon.database import Character, PlayerInfo, Player
|
from LittlePaimon.database import Character, PlayerInfo, Player
|
||||||
from LittlePaimon.utils.alias import get_chara_icon
|
from LittlePaimon.utils.alias import get_chara_icon
|
||||||
from LittlePaimon.utils.files import load_image
|
|
||||||
from LittlePaimon.utils.genshin import GenshinTools
|
from LittlePaimon.utils.genshin import GenshinTools
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from .draw_player_card import get_avatar, draw_weapon_icon
|
from .draw_player_card import get_avatar, draw_weapon_icon
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import math
|
import math
|
||||||
|
|
||||||
from LittlePaimon.database import Character
|
from LittlePaimon.database import Character
|
||||||
from LittlePaimon.utils.files import load_image
|
|
||||||
from LittlePaimon.utils.genshin import GenshinTools
|
from LittlePaimon.utils.genshin import GenshinTools
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from LittlePaimon.utils.requests import aiorequests
|
from LittlePaimon.utils.requests import aiorequests
|
||||||
|
@ -2,9 +2,8 @@ from nonebot import logger
|
|||||||
|
|
||||||
from LittlePaimon.database import Character
|
from LittlePaimon.database import Character
|
||||||
from LittlePaimon.utils.alias import get_chara_icon
|
from LittlePaimon.utils.alias import get_chara_icon
|
||||||
from LittlePaimon.utils.files import load_image
|
|
||||||
from LittlePaimon.utils.genshin import GenshinTools
|
from LittlePaimon.utils.genshin import GenshinTools
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import ENKA_RES, RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import ENKA_RES, RESOURCE_BASE_PATH
|
||||||
from .damage_cal import get_role_dmg
|
from .damage_cal import get_role_dmg
|
||||||
|
@ -3,8 +3,7 @@ from typing import List, Tuple, Optional
|
|||||||
|
|
||||||
from LittlePaimon.database import PlayerInfo, Character, PlayerWorldInfo, Weapon, Player
|
from LittlePaimon.database import PlayerInfo, Character, PlayerWorldInfo, Weapon, Player
|
||||||
from LittlePaimon.utils.alias import get_chara_icon
|
from LittlePaimon.utils.alias import get_chara_icon
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, get_qq_avatar, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, get_qq_avatar, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ import math
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from LittlePaimon.utils.requests import aiorequests
|
from LittlePaimon.utils.requests import aiorequests
|
||||||
|
@ -3,8 +3,8 @@ from pathlib import Path
|
|||||||
|
|
||||||
from LittlePaimon.database import Character, LastQuery
|
from LittlePaimon.database import Character, LastQuery
|
||||||
from LittlePaimon.utils import scheduler
|
from LittlePaimon.utils import scheduler
|
||||||
from LittlePaimon.utils.files import save_json, load_json, load_image
|
from LittlePaimon.utils.files import save_json, load_json
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from LittlePaimon.utils.requests import aiorequests
|
from LittlePaimon.utils.requests import aiorequests
|
||||||
|
@ -4,8 +4,7 @@ from typing import List
|
|||||||
from PIL import Image, ImageFile, ImageOps
|
from PIL import Image, ImageFile, ImageOps
|
||||||
|
|
||||||
from LittlePaimon.utils import logger
|
from LittlePaimon.utils import logger
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
from LittlePaimon.utils.requests import aiorequests
|
from LittlePaimon.utils.requests import aiorequests
|
||||||
|
@ -3,8 +3,7 @@ from typing import List
|
|||||||
|
|
||||||
from LittlePaimon import __version__
|
from LittlePaimon import __version__
|
||||||
from LittlePaimon.config import PluginInfo
|
from LittlePaimon.config import PluginInfo
|
||||||
from LittlePaimon.utils.files import load_image
|
from LittlePaimon.utils.image import PMImage, font_manager as fm, load_image
|
||||||
from LittlePaimon.utils.image import PMImage, font_manager as fm
|
|
||||||
from LittlePaimon.utils.message import MessageBuild
|
from LittlePaimon.utils.message import MessageBuild
|
||||||
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
from LittlePaimon.utils.path import RESOURCE_BASE_PATH
|
||||||
|
|
||||||
@ -47,22 +46,22 @@ async def draw_help(plugin_list: List[PluginInfo]):
|
|||||||
plugin_line = PMImage(orange_line)
|
plugin_line = PMImage(orange_line)
|
||||||
plugin_name_bg = PMImage(orange_name_bg)
|
plugin_name_bg = PMImage(orange_name_bg)
|
||||||
matcher_card = PMImage(orange_bord)
|
matcher_card = PMImage(orange_bord)
|
||||||
name_length = img.text_length(plugin.name, fm.get('SourceHanSerifCN-Bold.otf', 30))
|
plugin_name = plugin.name.replace('\n', '')
|
||||||
|
name_length = img.text_length(plugin_name, fm.get('SourceHanSerifCN-Bold.otf', 30))
|
||||||
await img.paste(plugin_line, (40, height_now))
|
await img.paste(plugin_line, (40, height_now))
|
||||||
await plugin_name_bg.stretch((23, plugin_name_bg.width - 36), int(name_length), 'width')
|
await plugin_name_bg.stretch((23, plugin_name_bg.width - 36), int(name_length), 'width')
|
||||||
await img.paste(plugin_name_bg, (40, height_now))
|
await img.paste(plugin_name_bg, (40, height_now))
|
||||||
await img.text(plugin.name, 63, height_now + 5, fm.get('SourceHanSerifCN-Bold.otf', 30), 'white')
|
await img.text(plugin_name, 63, height_now + 5, fm.get('SourceHanSerifCN-Bold.otf', 30), 'white')
|
||||||
height_now += plugin_line.height + 11
|
height_now += plugin_line.height + 11
|
||||||
if plugin.matchers:
|
if plugin.matchers and (matchers := [matcher for matcher in plugin.matchers if matcher.pm_show and (matcher.pm_usage or matcher.pm_name)]):
|
||||||
matchers = [matcher for matcher in plugin.matchers if matcher.pm_show and matcher.pm_usage]
|
|
||||||
matcher_groups = [matchers[i:i + 3] for i in range(0, len(matchers), 3)]
|
matcher_groups = [matchers[i:i + 3] for i in range(0, len(matchers), 3)]
|
||||||
for matcher_group in matcher_groups:
|
for matcher_group in matcher_groups:
|
||||||
max_length = max(len(matcher.pm_description) if matcher.pm_description else 0 for matcher in matcher_group)
|
max_length = max(len(matcher.pm_description.replace('\n', '')) if matcher.pm_description else 0 for matcher in matcher_group)
|
||||||
max_height = math.ceil(max_length / 16) * 22 + 40
|
max_height = math.ceil(max_length / 16) * 22 + 40
|
||||||
await matcher_card.stretch((5, matcher_card.height - 5), max_height, 'height')
|
await matcher_card.stretch((5, matcher_card.height - 5), max_height, 'height')
|
||||||
for matcher in matcher_group:
|
for matcher in matcher_group:
|
||||||
await img.paste(matcher_card, (40 + 336 * matcher_group.index(matcher), height_now))
|
await img.paste(matcher_card, (40 + 336 * matcher_group.index(matcher), height_now))
|
||||||
await img.text(matcher.pm_usage, 40 + 336 * matcher_group.index(matcher) + 15, height_now + 10, fm.get('SourceHanSansCN-Bold.otf', 24), 'black')
|
await img.text(matcher.pm_usage or matcher.pm_name, 40 + 336 * matcher_group.index(matcher) + 15, height_now + 10, fm.get('SourceHanSansCN-Bold.otf', 24), 'black')
|
||||||
if matcher.pm_description:
|
if matcher.pm_description:
|
||||||
await img.text_box(matcher.pm_description.replace('\n', '^'), (40 + 336 * matcher_group.index(matcher) + 10, 40 + 336 * matcher_group.index(matcher) + matcher_card.width - 22),
|
await img.text_box(matcher.pm_description.replace('\n', '^'), (40 + 336 * matcher_group.index(matcher) + 10, 40 + 336 * matcher_group.index(matcher) + matcher_card.width - 22),
|
||||||
(height_now + 44, height_now + max_height - 10), fm.get('SourceHanSansCN-Bold.otf', 18), '#40342d')
|
(height_now + 44, height_now + max_height - 10), fm.get('SourceHanSansCN-Bold.otf', 18), '#40342d')
|
||||||
|
@ -4,7 +4,7 @@ from nonebot import get_driver
|
|||||||
from .logger import logger
|
from .logger import logger
|
||||||
from .scheduler import scheduler
|
from .scheduler import scheduler
|
||||||
|
|
||||||
__version__ = '3.0.2'
|
__version__ = '3.0.3'
|
||||||
|
|
||||||
DRIVER = get_driver()
|
DRIVER = get_driver()
|
||||||
try:
|
try:
|
||||||
|
@ -4,60 +4,15 @@ except ImportError:
|
|||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from ssl import SSLCertVerificationError
|
from ssl import SSLCertVerificationError
|
||||||
from typing import Union, Optional, Tuple, Dict
|
from typing import Union
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import tqdm.asyncio
|
import tqdm.asyncio
|
||||||
from PIL import Image
|
|
||||||
from ruamel import yaml
|
from ruamel import yaml
|
||||||
|
|
||||||
from .requests import aiorequests
|
from .requests import aiorequests
|
||||||
|
|
||||||
|
|
||||||
cache_image: Dict[str, any] = {}
|
|
||||||
headers = {
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'}
|
|
||||||
|
|
||||||
|
|
||||||
async def load_image(
|
|
||||||
path: Union[Path, str],
|
|
||||||
*,
|
|
||||||
size: Optional[Union[Tuple[int, int], float]] = None,
|
|
||||||
crop: Optional[Tuple[int, int, int, int]] = None,
|
|
||||||
mode: Optional[str] = None,
|
|
||||||
) -> Image.Image:
|
|
||||||
"""
|
|
||||||
读取图像,并预处理
|
|
||||||
:param path: 图片路径
|
|
||||||
:param size: 预处理尺寸
|
|
||||||
:param crop: 预处理裁剪大小
|
|
||||||
:param mode: 预处理图像模式
|
|
||||||
:return: 图像对象
|
|
||||||
"""
|
|
||||||
if str(path) in cache_image:
|
|
||||||
img = cache_image[str(path)]
|
|
||||||
else:
|
|
||||||
if path.exists():
|
|
||||||
img = Image.open(path)
|
|
||||||
elif path.name.startswith(('UI_', 'Skill_')):
|
|
||||||
img = await aiorequests.download_icon(path.name, headers=headers, save_path=path, follow_redirects=True)
|
|
||||||
if img is None or isinstance(img, str):
|
|
||||||
return Image.new('RGBA', size=size or (50, 50), color=(0, 0, 0, 0))
|
|
||||||
else:
|
|
||||||
raise FileNotFoundError(f'{path} not found')
|
|
||||||
cache_image[str(path)] = img
|
|
||||||
if mode:
|
|
||||||
img = img.convert(mode)
|
|
||||||
if size:
|
|
||||||
if isinstance(size, float):
|
|
||||||
img = img.resize((int(img.size[0] * size), int(img.size[1] * size)), Image.ANTIALIAS)
|
|
||||||
elif isinstance(size, tuple):
|
|
||||||
img = img.resize(size, Image.ANTIALIAS)
|
|
||||||
if crop:
|
|
||||||
img = img.crop(crop)
|
|
||||||
return img
|
|
||||||
|
|
||||||
|
|
||||||
def load_json(path: Union[Path, str], encoding: str = 'utf-8'):
|
def load_json(path: Union[Path, str], encoding: str = 'utf-8'):
|
||||||
"""
|
"""
|
||||||
读取本地json文件,返回文件数据。
|
读取本地json文件,返回文件数据。
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Tuple, Union, Literal, List
|
from typing import Tuple, Union, Literal, List, Optional, Dict
|
||||||
|
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
||||||
from nonebot.utils import run_sync
|
from nonebot.utils import run_sync
|
||||||
|
|
||||||
|
from LittlePaimon.config import config
|
||||||
from .path import FONTS_PATH
|
from .path import FONTS_PATH
|
||||||
from .requests import aiorequests
|
from .requests import aiorequests
|
||||||
|
|
||||||
@ -22,17 +23,14 @@ class PMImage:
|
|||||||
mode: str = 'RGBA'
|
mode: str = 'RGBA'
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
初始化图像,优先读取image参数,如无则新建图像
|
初始化图像,优先读取image参数,如无则新建图像
|
||||||
:param image: PIL对象或图像路径
|
:param image: PIL对象或图像路径
|
||||||
:param size: 图像大小
|
:param size: 图像大小
|
||||||
:param color: 图像颜色
|
:param color: 图像颜色
|
||||||
:param mode: 图像模式
|
:param mode: 图像模式
|
||||||
"""
|
"""
|
||||||
if image:
|
if image:
|
||||||
if isinstance(image, Path):
|
self.image = Image.open(image) if isinstance(image, Path) else image.copy()
|
||||||
self.image = Image.open(image)
|
|
||||||
else:
|
|
||||||
self.image = image.copy()
|
|
||||||
else:
|
else:
|
||||||
if mode == 'RGB':
|
if mode == 'RGB':
|
||||||
color = (color[0], color[1], color[2])
|
color = (color[0], color[1], color[2])
|
||||||
@ -68,8 +66,7 @@ class PMImage:
|
|||||||
def save(self, path: Union[str, Path], **kwargs):
|
def save(self, path: Union[str, Path], **kwargs):
|
||||||
"""
|
"""
|
||||||
保存图像
|
保存图像
|
||||||
:param path: 保存路径
|
:param path: 保存路径
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.image.save(path, **kwargs)
|
self.image.save(path, **kwargs)
|
||||||
|
|
||||||
@ -84,7 +81,7 @@ class PMImage:
|
|||||||
def copy(self) -> "PMImage":
|
def copy(self) -> "PMImage":
|
||||||
"""
|
"""
|
||||||
返回一个本对象的复制
|
返回一个本对象的复制
|
||||||
:return: PMImage
|
:return: PMImage
|
||||||
"""
|
"""
|
||||||
return PMImage(self.image.copy())
|
return PMImage(self.image.copy())
|
||||||
|
|
||||||
@ -117,7 +114,7 @@ class PMImage:
|
|||||||
def resize(self, size: Union[float, Tuple[int, int]]):
|
def resize(self, size: Union[float, Tuple[int, int]]):
|
||||||
"""
|
"""
|
||||||
缩放图片
|
缩放图片
|
||||||
:param size: 缩放大小/区域
|
:param size: 缩放大小/区域
|
||||||
"""
|
"""
|
||||||
if isinstance(size, (float, int)):
|
if isinstance(size, (float, int)):
|
||||||
self.image = self.image.resize((int(self.width * size), int(self.height * size)), Image.Resampling.LANCZOS)
|
self.image = self.image.resize((int(self.width * size), int(self.height * size)), Image.Resampling.LANCZOS)
|
||||||
@ -129,7 +126,7 @@ class PMImage:
|
|||||||
def crop(self, box: Tuple[int, int, int, int]):
|
def crop(self, box: Tuple[int, int, int, int]):
|
||||||
"""
|
"""
|
||||||
裁剪图像
|
裁剪图像
|
||||||
:param box: 目标区域
|
:param box: 目标区域
|
||||||
"""
|
"""
|
||||||
self.image = self.image.crop(box)
|
self.image = self.image.crop(box)
|
||||||
self.draw = ImageDraw.Draw(self.image)
|
self.draw = ImageDraw.Draw(self.image)
|
||||||
@ -138,8 +135,8 @@ class PMImage:
|
|||||||
def rotate(self, angle: float, expand: bool = False, **kwargs):
|
def rotate(self, angle: float, expand: bool = False, **kwargs):
|
||||||
"""
|
"""
|
||||||
旋转图像
|
旋转图像
|
||||||
:param angle: 角度
|
:param angle: 角度
|
||||||
:param expand: expand
|
:param expand: expand
|
||||||
"""
|
"""
|
||||||
self.image.rotate(angle, resample=Image.BICUBIC, expand=expand, **kwargs)
|
self.image.rotate(angle, resample=Image.BICUBIC, expand=expand, **kwargs)
|
||||||
self.draw = ImageDraw.Draw(self.image)
|
self.draw = ImageDraw.Draw(self.image)
|
||||||
@ -152,9 +149,9 @@ class PMImage:
|
|||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
粘贴图像
|
粘贴图像
|
||||||
:param image: 图像
|
:param image: 图像
|
||||||
:param pos: 位置
|
:param pos: 位置
|
||||||
:param alpha: 是否透明
|
:param alpha: 是否透明
|
||||||
"""
|
"""
|
||||||
if image is None:
|
if image is None:
|
||||||
return
|
return
|
||||||
@ -178,12 +175,12 @@ class PMImage:
|
|||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
写文本
|
写文本
|
||||||
:param text: 文本
|
:param text: 文本
|
||||||
:param width: 位置横坐标
|
:param width: 位置横坐标
|
||||||
:param height: 位置纵坐标
|
:param height: 位置纵坐标
|
||||||
:param font: 字体
|
:param font: 字体
|
||||||
:param color: 颜色
|
:param color: 颜色
|
||||||
:param align: 对齐类型
|
:param align: 对齐类型
|
||||||
"""
|
"""
|
||||||
if align == 'left':
|
if align == 'left':
|
||||||
if isinstance(width, tuple):
|
if isinstance(width, tuple):
|
||||||
@ -235,7 +232,6 @@ class PMImage:
|
|||||||
else:
|
else:
|
||||||
width_now += c_length
|
width_now += c_length
|
||||||
|
|
||||||
|
|
||||||
@run_sync
|
@run_sync
|
||||||
def stretch(self,
|
def stretch(self,
|
||||||
pos: Tuple[int, int],
|
pos: Tuple[int, int],
|
||||||
@ -243,9 +239,9 @@ class PMImage:
|
|||||||
type: Literal['width', 'height'] = 'height'):
|
type: Literal['width', 'height'] = 'height'):
|
||||||
"""
|
"""
|
||||||
将某一部分进行拉伸
|
将某一部分进行拉伸
|
||||||
:param pos: 拉伸的部分
|
:param pos: 拉伸的部分
|
||||||
:param length: 拉伸的目标长/宽度
|
:param length: 拉伸的目标长/宽度
|
||||||
:param type: 拉伸方向,width:横向, height: 竖向
|
:param type: 拉伸方向,width:横向, height: 竖向
|
||||||
"""
|
"""
|
||||||
if pos[0] <= 0:
|
if pos[0] <= 0:
|
||||||
raise ValueError('起始轴必须大于等于0')
|
raise ValueError('起始轴必须大于等于0')
|
||||||
@ -295,9 +291,9 @@ class PMImage:
|
|||||||
width: int = 1):
|
width: int = 1):
|
||||||
"""
|
"""
|
||||||
绘制矩形
|
绘制矩形
|
||||||
:param pos: 位置
|
:param pos: 位置
|
||||||
:param color: 颜色
|
:param color: 颜色
|
||||||
:param width: 宽度
|
:param width: 宽度
|
||||||
"""
|
"""
|
||||||
self.draw.rectangle(pos, color, width=width)
|
self.draw.rectangle(pos, color, width=width)
|
||||||
|
|
||||||
@ -309,10 +305,10 @@ class PMImage:
|
|||||||
width: int = 1):
|
width: int = 1):
|
||||||
"""
|
"""
|
||||||
绘制圆角矩形
|
绘制圆角矩形
|
||||||
:param pos: 圆角矩形的位置
|
:param pos: 圆角矩形的位置
|
||||||
:param radius: 半径
|
:param radius: 半径
|
||||||
:param color: 颜色
|
:param color: 颜色
|
||||||
:param width: 宽度
|
:param width: 宽度
|
||||||
"""
|
"""
|
||||||
self.convert("RGBA")
|
self.convert("RGBA")
|
||||||
self.draw.rounded_rectangle(xy=pos, radius=radius, fill=color, width=width)
|
self.draw.rounded_rectangle(xy=pos, radius=radius, fill=color, width=width)
|
||||||
@ -326,15 +322,16 @@ class PMImage:
|
|||||||
angles: List[Literal['ul', 'ur', 'll', 'lr']] = None):
|
angles: List[Literal['ul', 'ur', 'll', 'lr']] = None):
|
||||||
"""
|
"""
|
||||||
选择最多4个角绘制圆角矩形
|
选择最多4个角绘制圆角矩形
|
||||||
:param pos: 左上角起点坐标
|
:param pos: 左上角起点坐标
|
||||||
:param size: 矩形大小
|
:param size: 矩形大小
|
||||||
:param radius: 半径
|
:param radius: 半径
|
||||||
:param color: 颜色
|
:param color: 颜色
|
||||||
:param angles: 角列表
|
:param angles: 角列表
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.draw.rectangle((pos[0] + radius / 2, pos[1], pos[0] + size[0] - (radius / 2), pos[1] + size[1]), fill=color)
|
self.draw.rectangle((pos[0] + radius / 2, pos[1], pos[0] + size[0] - (radius / 2), pos[1] + size[1]),
|
||||||
self.draw.rectangle((pos[0], pos[1] + radius / 2, pos[0] + size[0], pos[1] + size[1] - (radius / 2)), fill=color)
|
fill=color)
|
||||||
|
self.draw.rectangle((pos[0], pos[1] + radius / 2, pos[0] + size[0], pos[1] + size[1] - (radius / 2)),
|
||||||
|
fill=color)
|
||||||
angle_pos = {
|
angle_pos = {
|
||||||
'ul': (pos[0], pos[1], pos[0] + radius, pos[1] + radius),
|
'ul': (pos[0], pos[1], pos[0] + radius, pos[1] + radius),
|
||||||
'ur': (pos[0] + size[0] - radius, pos[1], pos[0] + size[0], pos[1] + radius),
|
'ur': (pos[0] + size[0] - radius, pos[1], pos[0] + size[0], pos[1] + radius),
|
||||||
@ -355,11 +352,10 @@ class PMImage:
|
|||||||
width: int = 1):
|
width: int = 1):
|
||||||
"""
|
"""
|
||||||
画线
|
画线
|
||||||
:param begin: 起始点
|
:param begin: 起始点
|
||||||
:param end: 终点
|
:param end: 终点
|
||||||
:param color: 颜色
|
:param color: 颜色
|
||||||
:param width: 宽度
|
:param width: 宽度
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self.draw.line(begin + end, fill=color, width=width)
|
self.draw.line(begin + end, fill=color, width=width)
|
||||||
|
|
||||||
@ -375,13 +371,13 @@ class PMImage:
|
|||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
画百分比圆环
|
画百分比圆环
|
||||||
:param size: 圆环大小
|
:param size: 圆环大小
|
||||||
:param pos: 圆环位置
|
:param pos: 圆环位置
|
||||||
:param width: 圆环宽度
|
:param width: 圆环宽度
|
||||||
:param percent: 百分比
|
:param percent: 百分比
|
||||||
:param colors: 颜色
|
:param colors: 颜色
|
||||||
:param startangle: 角度
|
:param startangle: 角度
|
||||||
:param transparent: 是否透明
|
:param transparent: 是否透明
|
||||||
"""
|
"""
|
||||||
if isinstance(percent, float):
|
if isinstance(percent, float):
|
||||||
if percent < 0 or percent > 1:
|
if percent < 0 or percent > 1:
|
||||||
@ -449,7 +445,7 @@ class PMImage:
|
|||||||
def to_rounded_corner(self, radii: int = 30):
|
def to_rounded_corner(self, radii: int = 30):
|
||||||
"""
|
"""
|
||||||
将图片变为圆角
|
将图片变为圆角
|
||||||
:param radii: 半径
|
:param radii: 半径
|
||||||
"""
|
"""
|
||||||
circle = Image.new("L", (radii * 2, radii * 2), 0)
|
circle = Image.new("L", (radii * 2, radii * 2), 0)
|
||||||
draw = ImageDraw.Draw(circle)
|
draw = ImageDraw.Draw(circle)
|
||||||
@ -468,12 +464,12 @@ class PMImage:
|
|||||||
|
|
||||||
@run_sync
|
@run_sync
|
||||||
def add_border(self, border_size: int = 10, color: Union[str, Tuple[int, int, int, int]] = 'black',
|
def add_border(self, border_size: int = 10, color: Union[str, Tuple[int, int, int, int]] = 'black',
|
||||||
shape: str = 'rectangle'):
|
shape: Literal['rectangle', 'circle'] = 'rectangle'):
|
||||||
"""
|
"""
|
||||||
给图片添加边框
|
给图片添加边框
|
||||||
:param border_size: 边框宽度
|
:param border_size: 边框宽度
|
||||||
:param color: 边框颜色
|
:param color: 边框颜色
|
||||||
:param shape: 边框形状,rectangle或circle
|
:param shape: 边框形状,rectangle或circle
|
||||||
"""
|
"""
|
||||||
self.convert("RGBA")
|
self.convert("RGBA")
|
||||||
if shape == 'circle':
|
if shape == 'circle':
|
||||||
@ -502,9 +498,9 @@ class FontManager:
|
|||||||
def get(self, font_name: str = 'hywh.ttf', size: int = 25, variation: str = None) -> ImageFont.ImageFont:
|
def get(self, font_name: str = 'hywh.ttf', size: int = 25, variation: str = None) -> ImageFont.ImageFont:
|
||||||
"""
|
"""
|
||||||
获取字体,如果已在缓存中,则直接返回
|
获取字体,如果已在缓存中,则直接返回
|
||||||
:param font_name: 字体名称
|
:param font_name: 字体名称
|
||||||
:param size: 字体大小
|
:param size: 字体大小
|
||||||
:param variation: 字体变体
|
:param variation: 字体变体
|
||||||
"""
|
"""
|
||||||
if 'ttf' not in font_name and 'ttc' not in font_name and 'otf' not in font_name:
|
if 'ttf' not in font_name and 'ttc' not in font_name and 'otf' not in font_name:
|
||||||
font_name += '.ttf'
|
font_name += '.ttf'
|
||||||
@ -524,6 +520,50 @@ class FontManager:
|
|||||||
|
|
||||||
font_manager = FontManager()
|
font_manager = FontManager()
|
||||||
|
|
||||||
|
cache_image: Dict[str, any] = {}
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'}
|
||||||
|
|
||||||
|
|
||||||
|
async def load_image(
|
||||||
|
path: Union[Path, str],
|
||||||
|
*,
|
||||||
|
size: Optional[Union[Tuple[int, int], float]] = None,
|
||||||
|
crop: Optional[Tuple[int, int, int, int]] = None,
|
||||||
|
mode: Optional[str] = None,
|
||||||
|
) -> Image.Image:
|
||||||
|
"""
|
||||||
|
读取图像,并预处理
|
||||||
|
:param path: 图片路径
|
||||||
|
:param size: 预处理尺寸
|
||||||
|
:param crop: 预处理裁剪大小
|
||||||
|
:param mode: 预处理图像模式
|
||||||
|
:return: 图像对象
|
||||||
|
"""
|
||||||
|
if config.img_use_cache and str(path) in cache_image:
|
||||||
|
img = cache_image[str(path)]
|
||||||
|
else:
|
||||||
|
if path.exists():
|
||||||
|
img = Image.open(path)
|
||||||
|
elif path.name.startswith(('UI_', 'Skill_')):
|
||||||
|
img = await aiorequests.download_icon(path.name, headers=headers, save_path=path, follow_redirects=True)
|
||||||
|
if img is None or isinstance(img, str):
|
||||||
|
return Image.new('RGBA', size=size or (50, 50), color=(0, 0, 0, 0))
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError(f'{path} not found')
|
||||||
|
if config.img_use_cache:
|
||||||
|
cache_image[str(path)] = img
|
||||||
|
if mode:
|
||||||
|
img = img.convert(mode)
|
||||||
|
if size:
|
||||||
|
if isinstance(size, float):
|
||||||
|
img = img.resize((int(img.size[0] * size), int(img.size[1] * size)), Image.ANTIALIAS)
|
||||||
|
elif isinstance(size, tuple):
|
||||||
|
img = img.resize(size, Image.ANTIALIAS)
|
||||||
|
if crop:
|
||||||
|
img = img.crop(crop)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
async def get_qq_avatar(qid: str) -> PMImage:
|
async def get_qq_avatar(qid: str) -> PMImage:
|
||||||
"""
|
"""
|
||||||
|
@ -16,9 +16,8 @@ from nonebot.typing import T_State
|
|||||||
from LittlePaimon.database import LastQuery, PrivateCookie, Player, PlayerAlias
|
from LittlePaimon.database import LastQuery, PrivateCookie, Player, PlayerAlias
|
||||||
from . import NICKNAME
|
from . import NICKNAME
|
||||||
from .alias import get_match_alias
|
from .alias import get_match_alias
|
||||||
from .files import load_image
|
|
||||||
from .filter import filter_msg
|
from .filter import filter_msg
|
||||||
from .image import PMImage
|
from .image import PMImage, load_image
|
||||||
from .requests import aiorequests
|
from .requests import aiorequests
|
||||||
from .typing import CHARACTERS, MALE_CHARACTERS, FEMALE_CHARACTERS, GIRL_CHARACTERS, BOY_CHARACTERS, \
|
from .typing import CHARACTERS, MALE_CHARACTERS, FEMALE_CHARACTERS, GIRL_CHARACTERS, BOY_CHARACTERS, \
|
||||||
LOLI_CHARACTERS
|
LOLI_CHARACTERS
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from amis import Action, Divider, Form, InputText, LevelEnum, Page, PageSchema, Switch, Remark, InputNumber, InputTime, InputTimeRange, Alert, Editor, \
|
from amis import Action, Divider, Form, InputText, LevelEnum, Page, PageSchema, Switch, Remark, InputNumber, InputTime, \
|
||||||
|
InputTimeRange, Alert, Editor, \
|
||||||
Select
|
Select
|
||||||
|
|
||||||
action_button = [Action(label='保存', level=LevelEnum.success, type='submit'),
|
action_button = [Action(label='保存', level=LevelEnum.success, type='submit'),
|
||||||
@ -65,7 +66,8 @@ cookie_web_form = Form(
|
|||||||
label='Web端token密钥',
|
label='Web端token密钥',
|
||||||
name='Web端token密钥',
|
name='Web端token密钥',
|
||||||
value='${Web端token密钥}',
|
value='${Web端token密钥}',
|
||||||
labelRemark=Remark(shape='circle', content='用于对Web端身份认证的token进行加密,为32位字符串,请不要保持为默认密钥,务必进行修改,修改后重启生效')
|
labelRemark=Remark(shape='circle',
|
||||||
|
content='用于对Web端身份认证的token进行加密,为32位字符串,请不要保持为默认密钥,务必进行修改,修改后重启生效')
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
actions=action_button
|
actions=action_button
|
||||||
@ -180,7 +182,7 @@ ssbq_form = Form(
|
|||||||
name='实时便签停止检查时间段',
|
name='实时便签停止检查时间段',
|
||||||
value='${实时便签停止检查时间段}',
|
value='${实时便签停止检查时间段}',
|
||||||
labelRemark=Remark(shape='circle',
|
labelRemark=Remark(shape='circle',
|
||||||
content='在这段时间(例如深夜)不进行实时便签检查,注意开始时间不要晚于结束时间,不然会有问题'),
|
content='在这段时间(例如深夜)不进行实时便签检查,注意开始时间不要晚于结束时间,不然会有问题'),
|
||||||
timeFormat='HH',
|
timeFormat='HH',
|
||||||
format='HH',
|
format='HH',
|
||||||
inputFormat='HH时'
|
inputFormat='HH时'
|
||||||
@ -277,6 +279,15 @@ other_form = Form(
|
|||||||
api='/LittlePaimon/api/set_config',
|
api='/LittlePaimon/api/set_config',
|
||||||
visibleOn='${select == 7}',
|
visibleOn='${select == 7}',
|
||||||
body=[
|
body=[
|
||||||
|
Switch(
|
||||||
|
label='图片资源缓存',
|
||||||
|
name='图片资源缓存开关',
|
||||||
|
value='${图片资源缓存开关}',
|
||||||
|
labelRemark=Remark(shape='circle',
|
||||||
|
content='开启时,会将制图所需的图片资源加载到内存中进行缓存,以提高制图速度,如果机器内存较小,建议关闭'),
|
||||||
|
onText='开启',
|
||||||
|
offText='关闭'
|
||||||
|
),
|
||||||
Switch(
|
Switch(
|
||||||
label='网页截图权限',
|
label='网页截图权限',
|
||||||
name='启用网页截图权限',
|
name='启用网页截图权限',
|
||||||
@ -306,7 +317,8 @@ other_form = Form(
|
|||||||
label='github资源地址',
|
label='github资源地址',
|
||||||
name='github资源地址',
|
name='github资源地址',
|
||||||
value='${github资源地址}',
|
value='${github资源地址}',
|
||||||
labelRemark=Remark(shape='circle', content='本bot部分资源托管在github,如果下载缓慢或无法正常访问,可以尝试更换地址,或者添加你自己的代理地址,注意最后要有/'),
|
labelRemark=Remark(shape='circle',
|
||||||
|
content='本bot部分资源托管在github,如果下载缓慢或无法正常访问,可以尝试更换地址,或者添加你自己的代理地址,注意最后要有/'),
|
||||||
creatable=True,
|
creatable=True,
|
||||||
options=[
|
options=[
|
||||||
{
|
{
|
||||||
@ -403,4 +415,6 @@ select = Select(label='选择配置类',
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
page = PageSchema(url='/bot_config/configs', icon='fa fa-wrench', label='配置项管理',
|
page = PageSchema(url='/bot_config/configs', icon='fa fa-wrench', label='配置项管理',
|
||||||
schema=Page(title='配置项管理', initApi='/LittlePaimon/api/get_config', body=[select, cookie_web_form, sim_gacha_form, auto_mys_form, ssbq_form, ys_form, notice_form, other_form, nonebot_form]))
|
schema=Page(title='配置项管理', initApi='/LittlePaimon/api/get_config',
|
||||||
|
body=[select, cookie_web_form, sim_gacha_form, auto_mys_form, ssbq_form, ys_form,
|
||||||
|
notice_form, other_form, nonebot_form]))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user