diff --git a/Paimon_Info/draw_abyss_info.py b/Paimon_Info/draw_abyss_info.py index 4be5efb..78ee258 100644 --- a/Paimon_Info/draw_abyss_info.py +++ b/Paimon_Info/draw_abyss_info.py @@ -2,7 +2,7 @@ import datetime import os from PIL import Image, ImageDraw, ImageFont - +from pathlib import Path from utils import aiorequests from utils.message_util import MessageBuild from utils.file_handler import load_image @@ -111,27 +111,32 @@ async def draw_abyss_card(data, uid, floor_num): top_img.alpha_composite(role_img, (width, 165)) width += 150 defeat_rank = data['defeat_rank'][0] - defeat_rank_img = await aiorequests.get_img(url=defeat_rank['avatar_icon'], size=(60, 60), mode='RGBA') + avatar_img = Path() / 'data' / 'LittlePaimon' / 'res' / 'avatar_side' / defeat_rank['avatar_icon'].split('/')[-1] + defeat_rank_img = await aiorequests.get_img(url=defeat_rank['avatar_icon'], size=(60, 60), mode='RGBA', save_path=avatar_img) top_draw.text((160, 343), str(defeat_rank['value']), font=get_font(21), fill='white') top_img.alpha_composite(defeat_rank_img, (280, 320)) damage_rank = data['damage_rank'][0] - damage_rank_img = await aiorequests.get_img(url=damage_rank['avatar_icon'], size=(60, 60), mode='RGBA') + avatar_img = Path() / 'data' / 'LittlePaimon' / 'res' / 'avatar_side' / damage_rank['avatar_icon'].split('/')[-1] + damage_rank_img = await aiorequests.get_img(url=damage_rank['avatar_icon'], size=(60, 60), mode='RGBA', save_path=avatar_img) top_draw.text((495, 343), str(damage_rank['value']), font=get_font(21), fill='white') top_img.alpha_composite(damage_rank_img, (590, 320)) take_damage_rank = data['take_damage_rank'][0] - take_damage_rank_img = await aiorequests.get_img(url=take_damage_rank['avatar_icon'], size=(60, 60), mode='RGBA') + avatar_img = Path() / 'data' / 'LittlePaimon' / 'res' / 'avatar_side' / take_damage_rank['avatar_icon'].split('/')[-1] + take_damage_rank_img = await aiorequests.get_img(url=take_damage_rank['avatar_icon'], size=(60, 60), mode='RGBA', save_path=avatar_img) top_draw.text((180, 389), str(take_damage_rank['value']), font=get_font(21), fill='white') top_img.alpha_composite(take_damage_rank_img, (280, 365)) energy_skill_rank = data['energy_skill_rank'][0] - energy_skill_rank_img = await aiorequests.get_img(url=energy_skill_rank['avatar_icon'], size=(60, 60), mode='RGBA') + avatar_img = Path() / 'data' / 'LittlePaimon' / 'res' / 'avatar_side' / energy_skill_rank['avatar_icon'].split('/')[-1] + energy_skill_rank_img = await aiorequests.get_img(url=energy_skill_rank['avatar_icon'], size=(60, 60), mode='RGBA', save_path=avatar_img) top_draw.text((530, 389), str(energy_skill_rank['value']), font=get_font(21), fill='white') top_img.alpha_composite(energy_skill_rank_img, (590, 365)) normal_skill_rank = data['normal_skill_rank'][0] - normal_skill_rank_img = await aiorequests.get_img(url=normal_skill_rank['avatar_icon'], size=(60, 60), mode='RGBA') + avatar_img = Path() / 'data' / 'LittlePaimon' / 'res' / 'avatar_side' / normal_skill_rank['avatar_icon'].split('/')[-1] + normal_skill_rank_img = await aiorequests.get_img(url=normal_skill_rank['avatar_icon'], size=(60, 60), mode='RGBA', save_path=avatar_img) top_draw.text((195, 435), str(normal_skill_rank['value']), font=get_font(21), fill='white') top_img.alpha_composite(normal_skill_rank_img, (280, 410)) diff --git a/Paimon_Info/draw_daily_note.py b/Paimon_Info/draw_daily_note.py index 34c6d49..20664d2 100644 --- a/Paimon_Info/draw_daily_note.py +++ b/Paimon_Info/draw_daily_note.py @@ -5,6 +5,7 @@ import random import matplotlib.pyplot as plt from PIL import Image, ImageDraw, ImageFont +from pathlib import Path from utils import aiorequests from utils.message_util import MessageBuild from utils.file_handler import load_image @@ -121,7 +122,8 @@ async def draw_daily_note_card(data, uid): exp = data['expeditions'] i = 0 for role in exp: - role_avatar = await aiorequests.get_img(url=role['avatar_side_icon'], size=(135, 135), mode='RGBA') + role_avatar = Path() / 'data' / 'LittlePaimon' / 'res' / 'avatar_side' / role['avatar_side_icon'].split('/')[-1] + role_avatar = await aiorequests.get_img(url=role['avatar_side_icon'], size=(135, 135), mode='RGBA', save_path=role_avatar) bg_img.alpha_composite(role_avatar, (i * 200 + 168, 1537)) bg_img.alpha_composite(await draw_ring(1 - int(role['remained_time']) / 72000), (i * 201 + 101, 1490)) if role['status'] == 'Ongoing': @@ -147,7 +149,6 @@ async def draw_daily_note_card(data, uid): bg_draw.text((1408, 1588), last_finish_str, fill="#5680d2", font=get_font(60, '优设标题黑.ttf')) - role_img = load_image(os.path.join(res_path, 'emoticons', random.choice(os.listdir(os.path.join(res_path, 'emoticons')))), size=3.5, mode='RGBA') bg_img.alpha_composite(role_img, (1220, 200)) now = datetime.datetime.now().strftime('%m月%d日%H:%M') diff --git a/Paimon_Info/draw_player_card.py b/Paimon_Info/draw_player_card.py index 0c980a5..21e5ead 100644 --- a/Paimon_Info/draw_player_card.py +++ b/Paimon_Info/draw_player_card.py @@ -3,6 +3,7 @@ import os import random import re +from pathlib import Path from PIL import Image, ImageDraw, ImageFont from utils import aiorequests @@ -11,6 +12,18 @@ from utils.file_handler import load_image res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') +b = load_image(os.path.join(res_path, 'player_card', '角色卡底部.png')) +b_c = load_image(os.path.join(res_path, 'player_card', 'chara_botton.png')) +fetter = [] +for i in range(0, 11): + fetter.append(load_image(os.path.join(res_path, 'player_card', f'好感度{i}.png'))) +weapon_bg = [] +for i in range(1, 6): + weapon_bg.append(load_image(os.path.join(res_path, 'player_card', f'{i}星武器.png'))) +constellation = [] +for i in range(0, 7): + constellation.append(load_image(os.path.join(res_path, 'player_card', f'命之座{i}.png'))) + def get_font(size): return ImageFont.truetype(os.path.join(res_path, 'msyh.ttc'), size) @@ -31,22 +44,18 @@ async def get_chara_card(data): chara_card = Image.new("RGBA", (226, 313), (255, 255, 255, 255)) chara_img = load_image(os.path.join(res_path, 'role_card', f'{data["id"]}.png')) chara_card.alpha_composite(chara_img, (0, 0)) - b = load_image(os.path.join(res_path, 'player_card', 'chara_botton.png')) - chara_card.alpha_composite(b, (0, 236)) + chara_card.alpha_composite(b_c, (0, 236)) # 命座 if data['name'] != '埃洛伊': - actived_constellation_num = load_image( - os.path.join(res_path, 'player_card', f'命之座{data["actived_constellation_num"]}.png')) - chara_card.alpha_composite(actived_constellation_num, (155, 0)) + chara_card.alpha_composite(constellation[data["actived_constellation_num"]], (155, 0)) # 好感度 if data['name'] != '旅行者': - fetter = load_image(os.path.join(res_path, 'player_card', f'好感度{data["fetter"]}.png')) - chara_card.alpha_composite(fetter, (155, 166)) + chara_card.alpha_composite(fetter[data["fetter"]], (155, 166)) # 武器背景 - weapon_bg = load_image(os.path.join(res_path, 'player_card', f'{data["weapon"]["rarity"]}星武器.png')) - chara_card.alpha_composite(weapon_bg, (0, 227)) + chara_card.alpha_composite(weapon_bg[data["weapon"]["rarity"] - 1], (0, 227)) # 武器图标 - weapon_icon = await aiorequests.get_img(url=data['weapon']['icon'], size=(63, 63), mode='RGBA') + weapon_icon = Path() / 'data' / 'LittlePaimon' / 'res' / 'weapon' / data['weapon']['icon'].split('/')[-1] + weapon_icon = await aiorequests.get_img(url=data['weapon']['icon'], size=(63, 63), mode='RGBA', save_path=weapon_icon) chara_card.alpha_composite(weapon_icon, (0, 230)) # 等级信息 chara_draw = ImageDraw.Draw(chara_card) @@ -252,7 +261,6 @@ async def get_chara_card_long(data): chara_card = Image.new("RGBA", (226, 382), (255, 255, 255, 255)) chara_img = load_image(os.path.join(res_path, 'role_card', f'{data["id"]}.png')) chara_card.alpha_composite(chara_img, (0, 0)) - b = load_image(os.path.join(res_path, 'player_card', '角色卡底部.png')) chara_card.alpha_composite(b, (0, 282)) # 命座 if data['name'] != '埃洛伊': @@ -261,12 +269,11 @@ async def get_chara_card_long(data): chara_card.alpha_composite(actived_constellation_num, (155, 0)) # 好感度 if data['name'] != '旅行者': - fetter = load_image(os.path.join(res_path, 'player_card', f'好感度{data["fetter"]}.png')) - chara_card.alpha_composite(fetter, (155, 166)) + chara_card.alpha_composite(fetter[data['fetter']], (155, 166)) # 武器背景 - weapon_bg = load_image(os.path.join(res_path, 'player_card', f'{data["weapon"]["rarity"]}星武器.png')) - chara_card.alpha_composite(weapon_bg, (3, 288)) - weapon_icon = await aiorequests.get_img(url=data['weapon']['icon'], size=(62, 62), mode='RGBA') + chara_card.alpha_composite(weapon_bg[data["weapon"]["rarity"] - 1], (3, 288)) + weapon_icon = Path() / 'data' / 'LittlePaimon' / 'res' / 'weapon' / data['weapon']['icon'].split('/')[-1] + weapon_icon = await aiorequests.get_img(url=data['weapon']['icon'], size=(62, 62), mode='RGBA', save_path=weapon_icon) chara_card.alpha_composite(weapon_icon, (3, 291)) # 等级信息 chara_draw = ImageDraw.Draw(chara_card) @@ -330,7 +337,8 @@ shadow = load_image(os.path.join(res_path, 'other', 'shadow.png')) async def draw_reli_icon(data): base_icon = load_image(os.path.join(res_path, 'other', f'star{data["rarity"]}.png'), size=(80, 80)) - icon = await aiorequests.get_img(url=data["icon"], size=(80, 80), mode='RGBA') + icon = Path() / 'data' / 'LittlePaimon' / 'res' / 'reli' / data['icon'].split('/')[-1] + icon = await aiorequests.get_img(url=data["icon"], size=(80, 80), mode='RGBA', save_path=icon) base_icon.alpha_composite(icon, (0, 0)) base_icon.alpha_composite(shadow, (40, 60)) base_icon_draw = ImageDraw.Draw(base_icon) @@ -340,7 +348,8 @@ async def draw_reli_icon(data): async def draw_const_skill_icon(data, name): base_icon = load_image(os.path.join(res_path, 'other', '命座.png'), size=(65, 65)) - icon = await aiorequests.get_img(url=data["icon"], size=(65, 65), mode='RGBA') + icon = Path() / 'data' / 'LittlePaimon' / 'res' / 'skill' / data['icon'].split('/')[-1] + icon = await aiorequests.get_img(url=data["icon"], size=(65, 65), mode='RGBA', save_path=icon) base_icon.alpha_composite(icon, (0, 0)) if 'is_actived' in data and not data['is_actived']: unlock_icon = load_image(os.path.join(res_path, 'other', '命座未解锁.png'), size=(65, 65)) @@ -412,7 +421,8 @@ async def draw_chara_card(data, skill_data, chara_name, uid): # 武器 weapon_bg = load_image(os.path.join(res_path, 'other', f'star{character["weapon"]["rarity"]}.png'), size=(100, 100)) - weapon_icon = await aiorequests.get_img(url=character['weapon']['icon'], size=(100, 100), mode='RGBA') + weapon_icon = Path() / 'data' / 'LittlePaimon' / 'res' / 'weapon' / character['weapon']['icon'].split('/')[-1] + weapon_icon = await aiorequests.get_img(url=character['weapon']['icon'], size=(100, 100), mode='RGBA', save_path=weapon_icon) bg_img.alpha_composite(weapon_bg, (293, 175)) bg_img.alpha_composite(weapon_icon, (293, 175)) bg_img.alpha_composite(shadow.resize((50, 25)), (344, 250)) diff --git a/utils/aiorequests.py b/utils/aiorequests.py index 54d8a6f..8d7f1c0 100644 --- a/utils/aiorequests.py +++ b/utils/aiorequests.py @@ -66,7 +66,7 @@ async def get_img(url: str, params: Optional[Dict[str, Any]] = None, timeout: Optional[int] = 20, save_path: Optional[Union[str, Path]] = None, - size: Optional[Tuple[int, int]] = None, + size: Optional[Union[Tuple[int, int], float]] = None, mode: Optional[str] = None, crop: Optional[Tuple[int, int, int, int]] = None, **kwargs) -> Union[str, Image.Image]: @@ -83,51 +83,42 @@ async def get_img(url: str, :param mode: 图片模式,为空则不做修改 :param crop: 图片裁剪,为空则不做修改 """ - try: - async with httpx.AsyncClient() as client: - resp = await client.get(url, - headers=headers, - params=params, - timeout=timeout, - **kwargs) - resp = resp.read() - if b'error' in resp: - return 'No Such File' - img = Image.open(BytesIO(resp)) - if size: - img = img.resize(size, Image.ANTIALIAS) - if mode: - img = img.convert(mode) - if crop: - img = img.crop(crop) - if save_path: - if isinstance(save_path, str): - save_path = Path(save_path) - save_path.parent.mkdir(parents=True, exist_ok=True) - img.save(save_path) - return img - except SSLCertVerificationError: - async with httpx.AsyncClient() as client: - resp = await client.get(url.replace('https', 'http'), - headers=headers, - params=params, - timeout=timeout, - **kwargs) - resp = resp.read() - if b'error' in resp: - return 'No Such File' - img = Image.open(BytesIO(resp)) - if size: - img = img.resize(size, Image.ANTIALIAS) - if mode: - img = img.convert(mode) - if crop: - img = img.crop(crop) - if save_path: - if isinstance(save_path, str): - save_path = Path(save_path) - save_path.parent.mkdir(parents=True, exist_ok=True) - img.save(save_path) - return img - except Exception: - traceback.print_exc() + if save_path and Path(save_path).exists(): + img = Image.open(save_path) + else: + try: + async with httpx.AsyncClient() as client: + resp = await client.get(url, + headers=headers, + params=params, + timeout=timeout, + **kwargs) + resp = resp.read() + if b'error' in resp: + return 'No Such File' + img = Image.open(BytesIO(resp)) + except SSLCertVerificationError: + async with httpx.AsyncClient() as client: + resp = await client.get(url.replace('https', 'http'), + headers=headers, + params=params, + timeout=timeout, + **kwargs) + resp = resp.read() + if b'error' in resp: + return 'No Such File' + img = Image.open(BytesIO(resp)) + 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 mode: + img = img.convert(mode) + if crop: + img = img.crop(crop) + if save_path and not Path(save_path).exists(): + save_path = Path(save_path) + save_path.parent.mkdir(parents=True, exist_ok=True) + img.save(save_path) + return img diff --git a/utils/message_util.py b/utils/message_util.py index 39ca5a4..11d3321 100644 --- a/utils/message_util.py +++ b/utils/message_util.py @@ -28,11 +28,20 @@ class MessageBuild: ) -> MessageSegment: if isinstance(img, str) or isinstance(img, Path): img = load_image(path=img, size=size, mode=mode, crop=crop) + else: + 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) + if mode: + img = img.convert(mode) bio = BytesIO() img = img.convert(mode) img.save(bio, format='JPEG' if mode == 'RGB' else 'PNG', quality=quality) - img_b64 = 'base64://' + base64.b64encode(bio.getvalue()).decode() - return MessageSegment.image(img_b64) + return MessageSegment.image(bio) @classmethod async def StaticImage(cls, @@ -58,8 +67,7 @@ class MessageBuild: bio = BytesIO() img = img.convert(mode) img.save(bio, format='JPEG' if mode == 'RGB' else 'PNG', quality=quality) - img_b64 = 'base64://' + base64.b64encode(bio.getvalue()).decode() - return MessageSegment.image(img_b64) + return MessageSegment.image(bio) @classmethod def Text(cls, text: str) -> MessageSegment: