Per docs/plugin-audit-report.md (plugins normalized to Trigger(handlers) → Service(services) → Model(repository/models) + utils): - Split monolithic __init__.py into handlers/services/utils across dailywife, deer_pipe, dice, galgame_card, helldivers_tools, huoziyinshua, learning_chat, makeaquote, mc_server_status, ncm_saying, picfinder_take, picstatus, random_jm_code, regif, steam_info, video_analysis, group_tools - Move static assets under res/: deer_pipe font/img, makeaquote font, helldivers img/templates, huoziyinshua HuoZiYinShua - Add config.py + register_config_items to ncm_saying, random_jm_code, group_tools; learning_chat unified config bridge - Remove deprecated: voice_trans plugin, bf_bot/test.py, dead code in dailywife/deer_pipe, empty dirs, debug scripts under helldivers temp - Disable brash_general_supercredits_tools (stub comment only) - bot.py: optional stdout/stderr redirect to log file for Web log viewer, force ANSI colorize on non-TTY sinks - Move runtime data (jm_code.json) out of plugin dir into hexi/data - Docs: plugin-audit-report.md; README reflects removed plugins Co-Authored-By: Claude <noreply@anthropic.com>
88 lines
3.3 KiB
Python
88 lines
3.3 KiB
Python
"""打卡记鹿 —— 渲染工具(utils 层)。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import calendar
|
|
import os
|
|
import random
|
|
from collections import Counter
|
|
from datetime import datetime, timedelta
|
|
|
|
from nonebot.log import logger
|
|
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
|
|
|
from ..repository import get_records
|
|
|
|
# 资源统一放插件 res/ 下
|
|
filepath = os.path.join(os.path.dirname(os.path.dirname(__file__)), "res").replace("\\", "/")
|
|
|
|
|
|
async def draw_calendar_grid_image(uid, year, month):
|
|
first_weekday, num_days = calendar.monthrange(year, month)
|
|
first_weekday = (first_weekday + 1) % 7
|
|
cell_size = 50
|
|
cell_padding = 5
|
|
num_rows = (num_days + first_weekday + 6) // 7 + 1
|
|
image_width = 7 * (cell_size + cell_padding) - cell_padding
|
|
image_height = num_rows * (cell_size + cell_padding) - cell_padding
|
|
img = Image.new("RGBA", (image_width, image_height), "white")
|
|
draw = ImageDraw.Draw(img)
|
|
font_path = filepath + "/font/SourceHanSansCN-Medium.otf"
|
|
logger.debug(f"打卡字体路径: {font_path}")
|
|
font_normal = ImageFont.truetype(font=font_path, size=18)
|
|
font_large = ImageFont.truetype(font=font_path, size=24)
|
|
for i in range(7):
|
|
x = i * (cell_size + cell_padding)
|
|
draw.line([(x, 55), (x, image_height)], fill="black", width=1)
|
|
for j in range(0, image_height + cell_size, cell_size + cell_padding):
|
|
draw.line([(0, j), (image_width, j)], fill="black", width=1)
|
|
deer_pipe_path = filepath + "/img/deer_pipe.jpg"
|
|
deer_pipe_img = Image.open(deer_pipe_path)
|
|
deer_pipe_img = deer_pipe_img.resize((54, 50))
|
|
title = f"{month}月打卡记鹿"
|
|
text_length = draw.textlength(text=title, font=font_large)
|
|
img_xy = (int(((image_width - text_length + 55) / 2) - 55), 5)
|
|
title_pos = ((image_width - text_length + 55) / 2, 10)
|
|
img.paste(deer_pipe_img, img_xy)
|
|
draw.text(title_pos, title, fill="black", font=font_large)
|
|
day_counts = Counter(await get_records(uid))
|
|
date = datetime(year, month, 1)
|
|
for day in range(1, num_days + 1):
|
|
weekday = (first_weekday + day - 1) % 7
|
|
row = (first_weekday + day - 1) // 7 + 1
|
|
x = weekday * (cell_size + cell_padding) + cell_padding
|
|
y = row * (cell_size + cell_padding) + cell_padding
|
|
img.paste(deer_pipe_img, (x - 4, y))
|
|
draw.text((x + 20, y - 2), f"{str(day)}", fill="black", font=font_normal)
|
|
for i in range(day_counts.get(day, 0)):
|
|
im = get_random_right()
|
|
img = image_paste(im, img, (x - 4 + i * 10, y))
|
|
img = ImageOps.expand(img, border=5, fill="black")
|
|
img = ImageOps.expand(img, border=5, fill="white")
|
|
return img
|
|
|
|
|
|
selected_images = []
|
|
|
|
|
|
def get_random_right():
|
|
global selected_images
|
|
path = filepath + "/img/right"
|
|
im_name = [name for name in os.listdir(path) if name not in selected_images]
|
|
if not im_name:
|
|
selected_images = []
|
|
im_name = os.listdir(path)
|
|
index = random.randint(0, len(im_name) - 1)
|
|
im = im_name[index]
|
|
selected_images.append(im)
|
|
im_path = os.path.join(path, im)
|
|
im_file = Image.open(im_path)
|
|
im_file = im_file.resize((50, 50))
|
|
return im_file
|
|
|
|
|
|
def image_paste(paste_image, under_image, pos):
|
|
r, g, b, alpha = paste_image.split()
|
|
under_image.paste(paste_image, pos, alpha)
|
|
return under_image
|