优化图片生成速度

This commit is contained in:
CMHopeSunshine 2022-06-01 12:59:03 +08:00
parent d92913772c
commit cc92c655a7
5 changed files with 95 additions and 80 deletions

View File

@ -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))

View File

@ -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')

View File

@ -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))

View File

@ -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

View File

@ -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: