From c652dbc4f0deb4bf4900a7e4a4a6ca936209b550 Mon Sep 17 00:00:00 2001 From: cypas Date: Fri, 23 Feb 2024 23:14:40 +0800 Subject: [PATCH] =?UTF-8?q?pillow=E7=94=B19.5.0=E5=8D=87=E7=BA=A7=E4=B8=BA?= =?UTF-8?q?10.2.0=E8=BF=87=E7=A8=8B=E4=B8=AD=E9=80=82=E9=85=8D=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ttf.getsize函数弃用了只能使用ttf.getbbox,但传递language参数缺少libraqm.dll文件,此文件需要手动下载至python目录,过程过于繁琐,若不带language参数,计算出来的w和h值与之前版本偏差过大,很多显示特别是帮助和nso帮助全部会乱,暂时停止适配 --- nonebot_plugin_splatoon3_schedule/__init__.py | 100 +++++++++--------- nonebot_plugin_splatoon3_schedule/config.py | 14 +-- .../image/image_processer.py | 13 ++- .../image/image_processer_tools.py | 61 ++++++----- pyproject.toml | 4 +- test.py | 20 ++-- 6 files changed, 113 insertions(+), 99 deletions(-) diff --git a/nonebot_plugin_splatoon3_schedule/__init__.py b/nonebot_plugin_splatoon3_schedule/__init__.py index 5bfac60..56e4f74 100644 --- a/nonebot_plugin_splatoon3_schedule/__init__.py +++ b/nonebot_plugin_splatoon3_schedule/__init__.py @@ -68,8 +68,8 @@ push_job, ) -require("nonebot_plugin_apscheduler") -from nonebot_plugin_apscheduler import scheduler +# require("nonebot_plugin_apscheduler") +# from nonebot_plugin_apscheduler import scheduler __plugin_meta__ = PluginMetadata( name="splatoon3游戏日程查询", @@ -638,51 +638,51 @@ async def send_msg(bot: Bot, event: Event, msg: str | bytes): await bot.send(event, message=QQ_MsgSeg.image(url)) -@driver.on_startup -async def startup(): - """nb启动时事件""" - # 清空合成图片缓存表 - db_image.clean_image_temp() - # 初始化黑名单字典 - init_blacklist() - - -@driver.on_shutdown -async def shutdown(): - """nb关闭时事件""" - # 关闭数据库 - db_image.close() - db_control.close() - # 删除任务 - bots = nonebot.get_bots() - for k in bots.keys(): - job_id = f"sp3_schedule_push_job_{k}" - if scheduler.get_job(job_id): - scheduler.remove_job(job_id) - logger.info(f"remove job {job_id}!") - - -@driver.on_bot_connect -async def _(bot: Bot): - """bot接入时事件""" - bot_adapter = bot.adapter.get_name() - bot_id = bot.self_id - - # 防止bot重连时重复添加任务 - job_id = f"sp3_schedule_push_job_{bot_id}" - if scheduler.get_job(job_id): - scheduler.remove_job(job_id) - logger.info(f"remove job {job_id} first") - - scheduler.add_job( - push_job, - trigger="cron", - hour="0,2,4,6,8,10,12,14,16,18,20,22", - minute=1, - id=job_id, - args=[bot, bot_adapter, bot_id], - misfire_grace_time=60, - coalesce=True, - max_instances=1, - ) - logger.info(f"add job {job_id}") +# @driver.on_startup +# async def startup(): +# """nb启动时事件""" +# # 清空合成图片缓存表 +# db_image.clean_image_temp() +# # 初始化黑名单字典 +# init_blacklist() +# +# +# @driver.on_shutdown +# async def shutdown(): +# """nb关闭时事件""" +# # 关闭数据库 +# db_image.close() +# db_control.close() +# # 删除任务 +# bots = nonebot.get_bots() +# for k in bots.keys(): +# job_id = f"sp3_schedule_push_job_{k}" +# if scheduler.get_job(job_id): +# scheduler.remove_job(job_id) +# logger.info(f"remove job {job_id}!") +# +# +# @driver.on_bot_connect +# async def _(bot: Bot): +# """bot接入时事件""" +# bot_adapter = bot.adapter.get_name() +# bot_id = bot.self_id +# +# # 防止bot重连时重复添加任务 +# job_id = f"sp3_schedule_push_job_{bot_id}" +# if scheduler.get_job(job_id): +# scheduler.remove_job(job_id) +# logger.info(f"remove job {job_id} first") +# +# scheduler.add_job( +# push_job, +# trigger="cron", +# hour="0,2,4,6,8,10,12,14,16,18,20,22", +# minute=1, +# id=job_id, +# args=[bot, bot_adapter, bot_id], +# misfire_grace_time=60, +# coalesce=True, +# max_instances=1, +# ) +# logger.info(f"add job {job_id}") diff --git a/nonebot_plugin_splatoon3_schedule/config.py b/nonebot_plugin_splatoon3_schedule/config.py index 2c88255..4679be8 100644 --- a/nonebot_plugin_splatoon3_schedule/config.py +++ b/nonebot_plugin_splatoon3_schedule/config.py @@ -1,6 +1,6 @@ from typing import List, Union -from nonebot import get_driver, get_plugin_config +# from nonebot import get_driver, get_plugin_config from pydantic import BaseModel, validator @@ -31,10 +31,10 @@ class Config(BaseModel): # 本地测试时由于不启动 driver,需要将下面三行注释并取消再下面两行的注释 -driver = get_driver() -global_config = driver.config -plugin_config = get_plugin_config(Config) +# driver = get_driver() +# global_config = driver.config +# plugin_config = get_plugin_config(Config) -# driver = None -# global_config = None -# plugin_config = Config() +driver = None +global_config = None +plugin_config = Config() diff --git a/nonebot_plugin_splatoon3_schedule/image/image_processer.py b/nonebot_plugin_splatoon3_schedule/image/image_processer.py index b419042..5719508 100644 --- a/nonebot_plugin_splatoon3_schedule/image/image_processer.py +++ b/nonebot_plugin_splatoon3_schedule/image/image_processer.py @@ -125,7 +125,7 @@ def get_events(events: list): # 顶部活动标志(大号) pos_h += 20 game_mode_img_size = (80, 80) - game_mode_img = get_file("event_bg").resize(game_mode_img_size, Image.ANTIALIAS) + game_mode_img = get_file("event_bg").resize(game_mode_img_size, Image.LANCZOS) game_mode_img_pos = (20, pos_h) paste_with_a(image_background, game_mode_img, game_mode_img_pos) pos_h += game_mode_img_size[1] + 20 @@ -134,7 +134,8 @@ def get_events(events: list): drawer = ImageDraw.Draw(image_background) ttf = ImageFont.truetype(ttf_path_chinese, 40) main_title_pos = (game_mode_img_pos[0] + game_mode_img_size[0] + 20, game_mode_img_pos[1]) - main_title_size = ttf.getsize(main_title) + left, top, right, bottom = ttf.getbbox(text=main_title) + main_title_size = right - left, bottom - top drawer.text(main_title_pos, main_title, font=ttf, fill=(255, 255, 255)) # 绘制描述 desc = cht_event_data["desc"] @@ -424,7 +425,9 @@ def check_coop_fish(_time): for pos, val in enumerate(time): # 绘制时间文字 time_text_pos = (50, 5 + pos * 160) - time_text_size = font.getsize(val) + left, top, right, bottom = font.getbbox(text=val) + time_text_size = right - left, bottom - top + dr.text(time_text_pos, val, font=font, fill="#FFFFFF") if check_coop_fish(val): # 现在时间处于打工时间段内,绘制小鲑鱼 @@ -433,7 +436,7 @@ def check_coop_fish(_time): paste_with_a(coop_stage_bg, coop_fish_img, coop_fish_img_pos) for pos, val in enumerate(stage): # 绘制打工地图 - stage_bg = get_save_file(val).resize(stage_bg_size, Image.ANTIALIAS) + stage_bg = get_save_file(val).resize(stage_bg_size, Image.LANCZOS) stage_bg_pos = (500, 2 + 162 * pos) coop_stage_bg.paste(stage_bg, stage_bg_pos) @@ -451,7 +454,7 @@ def check_coop_fish(_time): # 绘制武器底图 weapon_bg_img = Image.new("RGBA", weapon_size, (30, 30, 30)) # 绘制武器图片 - weapon_image = get_save_file(val_weapon).resize(weapon_size, Image.ANTIALIAS) + weapon_image = get_save_file(val_weapon).resize(weapon_size, Image.LANCZOS) paste_with_a(weapon_bg_img, weapon_image, (0, 0)) coop_stage_bg.paste(weapon_bg_img, (120 * pos_weapon + 20, 60 + 160 * pos)) for pos, val in enumerate(boss): diff --git a/nonebot_plugin_splatoon3_schedule/image/image_processer_tools.py b/nonebot_plugin_splatoon3_schedule/image/image_processer_tools.py index 5cbd73b..6f8ea53 100644 --- a/nonebot_plugin_splatoon3_schedule/image/image_processer_tools.py +++ b/nonebot_plugin_splatoon3_schedule/image/image_processer_tools.py @@ -150,7 +150,8 @@ def add_long_text(_text, _text_width) -> [str]: line_space = 12 for i, line in enumerate(para): drawer.text((text_start_pos[0], (line_space + font_size) * i + text_start_pos[1]), line, font_color, ttf) - w, h = ttf.getsize(line) + left, top, right, bottom = ttf.getbbox(text=line) + w, h = right - left, bottom - top height += h + line_space # 取最长w if w > width: @@ -263,7 +264,8 @@ def paste_with_a(image_background, image_pasted, pos): def get_stage_name_bg(stage_name, font_size=24): """绘制 地图名称及文字底图""" ttf = ImageFont.truetype(ttf_path_chinese, font_size) - w, h = ttf.getsize(stage_name) + left, top, right, bottom = ttf.getbbox(text=stage_name) + w, h = right - left, bottom - top stage_name_bg_size = (w + 20, h + 10) # 新建画布 stage_name_bg = Image.new("RGBA", stage_name_bg_size, (34, 34, 34)) @@ -282,7 +284,8 @@ def get_translucent_name_bg( ): """绘制 半透明文字背景""" ttf = ImageFont.truetype(font_path, font_size) - w, h = ttf.getsize(text) + left, top, right, bottom = ttf.getbbox(text=text) + w, h = right - left, bottom - top # 文字背景 text_bg_size = (w + 20, h + line_height) text_bg = get_file("filleted_corner").resize(text_bg_size).convert("RGBA") @@ -305,10 +308,11 @@ def get_time_head_bg(time_head_bg_size, date_time, start_time, end_time): # 绘制开始,结束时间 文字居中绘制 ttf = ImageFont.truetype(ttf_path, 40) time_head_text = "{} {} - {}".format(date_time, start_time, end_time) - w, h = ttf.getsize(time_head_text) + left, top, right, bottom = ttf.getbbox(text=time_head_text) + w, h = right - left, bottom - top time_head_text_pos = ( (time_head_bg_size[0] - w) / 2, - (time_head_bg_size[1] - h) / 2 - 12, + (time_head_bg_size[1] - h) / 2 - 25, ) drawer = ImageDraw.Draw(time_head_bg) drawer.text(time_head_text_pos, time_head_text, font=ttf, fill=(255, 255)) @@ -358,8 +362,8 @@ def get_stage_card( # 绘制两张地图 # 计算尺寸,加载图片 stage_size = (int(img_size[0] * 0.48), int(img_size[1] * 0.7)) - image_left = get_save_file(stage1).resize(stage_size, Image.ANTIALIAS) - image_right = get_save_file(stage2).resize(stage_size, Image.ANTIALIAS) + image_left = get_save_file(stage1).resize(stage_size, Image.LANCZOS) + image_right = get_save_file(stage2).resize(stage_size, Image.LANCZOS) # 定义圆角 蒙版 image_alpha = circle_corner(image_left, radii=16) @@ -425,7 +429,7 @@ def get_stage_card( game_mode_text_pos = (blank_size[0] // 3, contest_mode_pos[1]) drawer.text(game_mode_text_pos, game_mode_text, font=ttf, fill=(255, 255, 255)) # 绘制游戏模式小图标 - game_mode_img = get_file(game_mode).resize((35, 35), Image.ANTIALIAS) + game_mode_img = get_file(game_mode).resize((35, 35), Image.LANCZOS) game_mode_img_pos = (game_mode_text_pos[0] - 40, game_mode_text_pos[1] + 10) paste_with_a(image_background, game_mode_img, game_mode_img_pos) # # 绘制开始,结束时间 @@ -464,19 +468,19 @@ def get_weapon_card(weapon: [WeaponData], weapon_card_bg_size, rgb, font_color): weapon_bg = change_image_alpha(weapon_bg, 80) # 主武器 main_image_bg = Image.new("RGBA", main_size, (30, 30, 30, 255)) - main_image = Image.open(io.BytesIO(v.image)).resize(main_size, Image.ANTIALIAS) + main_image = Image.open(io.BytesIO(v.image)).resize(main_size, Image.LANCZOS) main_image_bg_pos = ((weapon_bg_size[0] - main_size[0]) // 2, 10) # main_image = circle_corner(main_image, radii=16) # main_image_bg.paste(main_image, (0, 0)) # 副武器 sub_image_bg = Image.new("RGBA", sub_size, (60, 60, 60, 255)) - sub_image = Image.open(io.BytesIO(v.sub_image)).resize(sub_size, Image.ANTIALIAS) + sub_image = Image.open(io.BytesIO(v.sub_image)).resize(sub_size, Image.LANCZOS) sub_image_bg_pos = (main_image_bg_pos[0], main_image_bg_pos[1] + main_size[1] + 10) # sub_image = circle_corner(sub_image, radii=16) # sub_image_bg.paste(sub_image, (0, 0)) # 大招 special_image_bg = Image.new("RGBA", special_size, (30, 30, 30, 255)) - special_image = Image.open(io.BytesIO(v.special_image)).resize(special_size, Image.ANTIALIAS) + special_image = Image.open(io.BytesIO(v.special_image)).resize(special_size, Image.LANCZOS) special_image_bg_pos = (main_image_bg_pos[0] + main_size[0] - special_size[0], sub_image_bg_pos[1]) # special_image = circle_corner(special_image, radii=16) # special_image_bg.paste(special_image, (0, 0)) @@ -496,12 +500,13 @@ def get_weapon_card(weapon: [WeaponData], weapon_card_bg_size, rgb, font_color): font_size = 15 if len(weapon_zh_name) > 10: font_size = 14 - font = ImageFont.truetype(ttf_path_chinese, font_size) - zh_name_size = font.getsize(weapon_zh_name) + ttf = ImageFont.truetype(ttf_path_chinese, font_size) + left, top, right, bottom = ttf.getbbox(text=weapon_zh_name) + zh_name_size = right - left, bottom - top # 纯文字不带背景 实现方式 dr = ImageDraw.Draw(weapon_bg) zh_name_pos = ((weapon_bg_size[0] - zh_name_size[0]) // 2, weapon_bg_size[1] - zh_name_size[1] - 7) - dr.text(zh_name_pos, weapon_zh_name, font=font, fill=font_color) + dr.text(zh_name_pos, weapon_zh_name, font=ttf, fill=font_color) # 带背景文字 实现方式 # weapon_zh_name_bg = get_stage_name_bg(weapon_zh_name, font_size) # weapon_zh_name_bg_size = weapon_zh_name_bg.size @@ -557,7 +562,7 @@ def get_event_card(event, event_card_bg_size): # 绘制游戏模式小图标 game_mode_text = event["leagueMatchSetting"]["vsRule"]["rule"] game_mode_img_size = (35, 35) - game_mode_img = get_file(game_mode_text).resize(game_mode_img_size, Image.ANTIALIAS) + game_mode_img = get_file(game_mode_text).resize(game_mode_img_size, Image.LANCZOS) game_mode_img_pos = (20, pos_h) paste_with_a(event_card_bg, game_mode_img, game_mode_img_pos) # 绘制时间 @@ -593,7 +598,8 @@ def get_event_card(event, event_card_bg_size): elif time_converter(et) < now: text = "已结束" text_color = (165, 170, 163) - text_size = ttf.getsize(text) + left, top, right, bottom = ttf.getbbox(text=text) + text_size = right - left, bottom - top drawer.text( (transverse_line_pos_list[1][0] - text_size[0] - 10, time_text_pos[1]), text, @@ -606,7 +612,7 @@ def get_event_card(event, event_card_bg_size): def get_festival_team_card( - festival, card_bg_size: tuple, teams_list: [], area_title: str, font_path: str = ttf_path_chinese + festival, card_bg_size: tuple[int, int], teams_list: [], area_title: str, font_path: str = ttf_path_chinese ): """绘制 祭典组别卡片""" group_img_size = (1000, 390) @@ -676,7 +682,8 @@ def get_festival_team_card( drawer = ImageDraw.Draw(team_bg) # 绘制时间 - w, h = ttf.getsize(time_text) + left, top, right, bottom = ttf.getbbox(text=time_text) + w, h = right - left, bottom - top # 文字居中绘制 time_text_pos = ((card_bg_size[0] - w) / 2, group_card_pos[1] + rectangle_h + group_img_size[1] + 20) text_rgb = dict_bg_rgb["祭典时间-金黄"] @@ -730,7 +737,8 @@ def get_festival_result_card(card_bg_size: tuple, teams_list: [], font_path: str for v in range(5): # 绘制条目名称 text = list_item_names[v] - w, h = ttf.getsize(text) + left, top, right, bottom = ttf.getbbox(text=text) + w, h = right - left, bottom - top # 文字居中绘制 text_pos = (130 + (60 - w) // 2, pos_h + 5) drawer.text(text_pos, text, font=ttf, fill=(255, 255, 255)) @@ -746,11 +754,13 @@ def get_festival_result_card(card_bg_size: tuple, teams_list: [], font_path: str ttf_win = ImageFont.truetype(font_path, font_size) win_text_1 = win_team_name win_text_2 = " 获胜!" - w, h = ttf_win.getsize(win_text_1 + win_text_2) + left, top, right, bottom = ttf_win.getbbox(text=win_text_1 + win_text_2) + w, h = right - left, bottom - top text_1_pos = ((temp_card_size[0] - w) // 2, pos_h + 30) drawer.text(text_1_pos, win_text_1, font=ttf_win, fill=win_rgb) # 分开绘制队伍名和获胜 - w, h = ttf_win.getsize(win_text_1) + left, top, right, bottom = ttf_win.getbbox(text=win_text_1) + w, h = right - left, bottom - top text_2_pos = (text_1_pos[0] + w, text_1_pos[1]) drawer.text(text_2_pos, win_text_2, font=ttf_cn, fill=win_rgb) @@ -764,7 +774,7 @@ def get_festival_result_card(card_bg_size: tuple, teams_list: [], font_path: str def get_festival_result_item_card( - card_bg_size: tuple, teams_list: [dict], item_index: int, font_path: str = ttf_path_chinese + card_bg_size: tuple[int, int], teams_list: [dict], item_index: int, font_path: str = ttf_path_chinese ): """绘制 祭典条目结算卡片""" bg_rgb = dict_bg_rgb["祭典结算项目卡片"] @@ -803,7 +813,8 @@ def get_data(index: int, value: dict) -> (bool, str): if win: text_rgb = win_rgb # 绘制百分比 - w, h = ttf.getsize(percentage) + left, top, right, bottom = ttf.getbbox(text=percentage) + w, h = right - left, bottom - top # 文字居中绘制 text_pos = (65 + width_space * k, (card_bg_size[1] - h) // 2) drawer.text(text_pos, percentage, font=ttf, fill=text_rgb) @@ -899,9 +910,9 @@ def compress_image(image_bytes: bytes, kb=500, step=10, quality=50): # dr.line([(350, 210), (602, 210)], fill="#FFFFFF", width=4) # # 遍历进行贴图 # for i in range(4): -# image = get_weapon(weapon1[i]).resize(weapon_size, Image.ANTIALIAS) +# image = get_weapon(weapon1[i]).resize(weapon_size, Image.LANCZOS) # image_background.paste(image, ((160 * i + 5), 20)) -# image = get_weapon(weapon2[i]).resize(weapon_size, Image.ANTIALIAS) +# image = get_weapon(weapon2[i]).resize(weapon_size, Image.LANCZOS) # image_background.paste(image, ((160 * i + 5), 20 + 220)) # # return image_background diff --git a/pyproject.toml b/pyproject.toml index 8b310d5..dbb3004 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,8 +12,8 @@ beautifulsoup4="^4.12.2" cfscrape="^2.1.1" httpx="^0.24.1" nonebot2="^2.2.0" -pydantic = ">=1.10.0,<3.0.0,!=2.5.0,!=2.5.1" -Pillow="9.5.0" +pydantic = ">=2.0.1,<3.0.0,!=2.5.0,!=2.5.1" +Pillow="^10.2.0" urllib3="1.26.16" playwright = "^1.40.0" nonebot-adapter-onebot = "^2.4.1" diff --git a/test.py b/test.py index d5af509..9ed89a8 100644 --- a/test.py +++ b/test.py @@ -101,19 +101,19 @@ # img = get_save_temp_image(plain_text, func, num_list, contest_match, rule_match) # # 测试nonebot 对战 命令文本触发 -# plain_text = "全部图" +# plain_text = "图" # -# num_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] +# num_list = [0] # # num_list = list(set([int(x) for x in plain_text[:-2]])) # num_list.sort() # # # stage_mode = plain_text[-2:] # rule_match = None # contest_match = None -# # res = get_stages_image(num_list, contest_match, rule_match) -# func = get_stages_image -# img = get_save_temp_image(plain_text, func, num_list, contest_match, rule_match) -# # res.show() +# res = get_stages_image(num_list, contest_match, rule_match) +# # func = get_stages_image +# # img = get_save_temp_image(plain_text, func, num_list, contest_match, rule_match) +# res.show() # 测试新版随机武器 @@ -130,12 +130,12 @@ # res.show() # 测试帮助 -# res = get_help_image() -# res.show() +res = get_help_image() +res.show() # 测试nso帮助 -# res = get_nso_help_image() -# res.show() +res = get_nso_help_image() +res.show() # 测试重载武器数据