Nonebot2插件:逝世表情包(2)
前言已经说倦了.jpg
总之本文是对商店插件的拙劣模仿,不要在意复杂的语法使用,有问题可以直接说教我
广告
好像nb2热度下来了,总之招租(0.water之言
这篇文章依旧是实现简单的表情包,大概是下面这三个
日向麻麻是404群的光
喜报:账号被风控
草图
1.实现
i.喜报
这里是板子
经常放代码是不是有水博客的嫌疑
import nonebot
from nonebot.rule import *
from nonebot import on_command
from nonebot import *
from nonebot.adapters.onebot.v11 import Bot, Event, MessageEvent, GroupMessageEvent
from nonebot.adapters.onebot.v11.message import Message
import PIL
from PIL import Image, ImageDraw, ImageFont
async def handle_rule(bot: Bot, event: Event) -> bool:
with open("src/plugins/群名单.txt", encoding='utf-8') as file:
white_block = []
for line in file:
line = line.strip()
line = re.split("[ |#]", line)
white_block.append(line[0])
try:
whatever, group_id, user_id = event.get_session_id().split('_') # 获取当前群聊id,发起人id,返回的格式为group_groupid_userid
except: # 如果上面报错了,意味着发起的是私聊,返回格式为userid
group_id = None
user_id = event.get_session_id()
if group_id in white_block:
return True
else:
return False
xi_bao = on_command("喜报", rule=handle_rule, priority=50)
@xi_bao.handle()
async def xi_bao_handle(bot: Bot, event: Event):
receive_text = str(event.get_message()).replace('/喜报', '').split()[0] # 获取需要生成的文字
为了生成看起来像样的喜报,我们考虑红色字体加个橙底阴影,实现方式为在预计生成字体的位置上偏移1到3个像素生成同样大小的橙色文字,最后再生成红色文字覆盖再上面,这样就做出了阴影效果
接着是考虑文字过长的换行效果,为了满足喜报该有的
大概需要了解就这些吧,其他代码里再注释
import PIL
from PIL import Image,ImageDraw,ImageFont
# 生成阴影文字函数
def text_border(draw, x, y, font, shadowcolor, fillcolor, text):
# draw thicker
for ax in range(1, 5):
for ay in range(1, 5):
draw.text(((x + ax - 2), (y + ay - 2)), text, font=font,
fill=shadowcolor) # 在不同方向上生成同样大小的橙色文字(shadowcolor),可以按自己的需求改
# now draw the text over it
draw.text((x, y), text, font=font, fill=fillcolor) # 最后覆盖
receive_text = str(event.get_message()).replace('/喜报', '').split()[0] # 获取需要生成的文字
user_pic = Image.open(f"模板地址")
# 添加文字,根据长度自行适配三种大小
draw = ImageDraw.Draw(user_pic)
limit_len = 0
# utf-8下的汉字3字节,英文1字节,这个范围是按照文字不会超过图片边界和最好的显示算的(懒得适配更多了,字体也不大了),如果有其他的想法自行计算
if len(receive_text.encode('utf-8')) < 57:
font = ImageFont.truetype("simhei", 80)
limit_len = 18
elif len(receive_text.encode('utf-8')) < 73:
limit_len = 24
font = ImageFont.truetype("simhei", 70)
elif len(receive_text.encode('utf-8')) < 82:
limit_len = 27
font = ImageFont.truetype("simhei", 60)
else:
await xi_bao.finish(Message(f"字数超过限制"))
word = receive_text
w, h = font.getsize(word)
if len(receive_text.encode('utf-8')) > limit_len: # 换行处理,每行的字节数按照前面的分类定
# 参数:位置、文本、填充、字体
n = 0
i = 0
len_str = 0
text_list = ['']
while n < len(receive_text):
if len_str + len(receive_text[n].encode('utf-8')) > limit_len:
text_list.append('')
i += 1
len_str = 0
else:
len_str += len(receive_text[n].encode('utf-8'))
text_list[i] += receive_text[n]
n += 1
i += 1
for k in range(i):
text_border(draw, (600 - font.getsize(text_list[k])[0]) / 2,
int(200 / i) / 2 + (80 + int(200 / i) * k) + 20 * (k), font, 'orange', 'red', text_list[k])
# 这里的位置也是自己算的,感觉比较好看
else: # 只用显示一行
text_border(draw, (600 - w) / 2, (450 - h) / 2, font, 'orange', 'red', word)
user_pic.save(f"你打算保存的地址")
await xi_bao.finish(
Message(
f"[CQ:image,file=file:///地址,id=40000]"))
样例:头图
ii.没有美貌
同样的这里是板子
总之实现方式和上面大差不差,为了尽可能像字幕也是用了一样的白底黑阴影的实现方式,对于过长的字体换行也是差不多的设计
懒得分段了,实现方式大差不差了
import nonebot
from nonebot.rule import *
from nonebot import on_command
from nonebot import *
from nonebot.adapters.onebot.v11 import Bot, Event, MessageEvent, GroupMessageEvent
from nonebot.adapters.onebot.v11.message import Message
import PIL
from PIL import Image, ImageDraw, ImageFont
async def handle_rule(bot: Bot, event: Event) -> bool:
with open("src/plugins/群名单.txt", encoding='utf-8') as file:
white_block = []
for line in file:
line = line.strip()
line = re.split("[ |#]", line)
white_block.append(line[0])
try:
whatever, group_id, user_id = event.get_session_id().split('_') # 获取当前群聊id,发起人id,返回的格式为group_groupid_userid
except: # 如果上面报错了,意味着发起的是私聊,返回格式为userid
group_id = None
user_id = event.get_session_id()
if group_id in white_block or group_id == None:
return True
else:
return False
lmtb = on_command("如果", rule=handle_rule, priority=50)
def text_border(draw, x, y, font, shadowcolor, fillcolor, text):
# draw thicker border
for ax in range(1, 5):
for ay in range(1, 5):
draw.text(((x + ax - 2), (y + ay - 2)), text, font=font, fill=shadowcolor)
# now draw the text over it
draw.text((x, y), text, font=font, fill=fillcolor)
@lmtb.handle()
async def lmtb_handle(bot: Bot, event: Event):
try:
whatever, group_id, user_id = event.get_session_id().split('_') # 获取当前群聊id,发起人id,返回的格式为group_groupid_userid
data = await bot.call_api('get_group_member_list', **{
'group_id': int(group_id)
})
except: # 如果上面报错了,意味着发起的是私聊,返回格式为userid
group_id = None
user_id = event.get_session_id()
rtext = str(event.get_message()).replace(' ', '').split('/如果')
receive_text = "如果" + rtext[1] + "的话" # 这个表情包原版就是如果xxx的话,嗯,忘记了
if receive_text == "":
await lmtb.finish(Message(f"似乎什么都没有输入呢"))
if len(receive_text.encode('utf-8')) > 147: # 这个表情包最好就两行
await lmtb.finish(Message(f"字数超过限制了"))
user_pic = Image.open(f"你模板的地址")
# 添加文字
draw = ImageDraw.Draw(user_pic)
font = ImageFont.truetype("simhei", 25) # 实际上显示出来的效果还是不能很靠近原版,因为懒全用的自带字库,可以考虑自己调换
word = receive_text
# 参数:位置、文本、填充、字体
if len(receive_text.encode('utf-8')) > 49: # 一样的换行处理
n = 0
i = 0
len_str = 0
text_list = ['']
while n < len(receive_text):
if len_str + len(receive_text[n].encode('utf-8')) > 49:
text_list.append('')
i += 1
len_str = 0
else:
len_str += len(receive_text[n].encode('utf-8'))
text_list[i] += receive_text[n]
n += 1
for k in range(i + 1):
text_border(draw, 23, 257 - (i - k) * 32, font, 'black', 'white', text_list[k])
# 这个位置的x最好不改吧,比较符合。y是大概移动得出来的,总之多试试?
else:
text_border(draw, 23, 257, font, 'black', 'white', word)
user_pic.save(f"生成的表情包存放地址")
await lmtb.finish(
Message(f"[CQ:image,file=file:///表情包地址,id=40000]"))
示例:头图
iii.为了你,继续打工
还是板子
实现思路大概为获取用户头像,新建一块和模板一样大小的白色画布,依次把用户头像和模板粘贴上去就形成了表情包
需要的注意的点为用户头像需要改变大小并旋转最后放到指定位置,同时模板对于放头像的位置设置了透明,粘贴时需要把alpha通道作为mask传入
没啥好分段的
import nonebot
import requests
from nonebot.rule import *
from nonebot import *
from nonebot.plugin import on_keyword
from nonebot.adapters.onebot.v11 import Bot, Event, MessageEvent, GroupMessageEvent
from nonebot.adapters.onebot.v11.message import Message
import re
import PIL
from PIL import Image, ImageDraw, ImageFont
async def handle_rule(bot: Bot, event: Event) -> bool:
with open("src/plugins/群名单.txt", encoding='utf-8') as file:
white_block = []
for line in file:
line = line.strip()
line = re.split("[ |#]", line)
white_block.append(line[0])
try:
whatever, group_id, user_id = event.get_session_id().split('_') # 仔细想想这里用isinstance(event,GroupMessageEvent)会好点,但需要接受群聊id干脆摆烂了
except: # 如果上面报错了,意味着发起的是私聊,返回格式为userid
group_id = None
user_id = event.get_session_id()
if group_id in white_block or group_id == None:
return True
else:
return False
bk_work = on_command("回去工作", rule=handle_rule, priority=50)
@bk_work.handle()
async def bk_work_handle(bot:Bot,event:Event):
msg = event.get_message()
user_id = ''
for i in msg:
if i.type=='at':
user_id = i.data['qq']
msg = event.get_plaintext()
msg = msg.replace('/回去工作','').split()
if user_id == '' :
if msg[0].isnumeric():
user_id = msg[0]
else:
await bk_work.finish(Message(f"指令输入错误,请输入QQ号或@号主"))
# 上面是获取用户的@或者输入QQ号
url1 =f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=640" # QQ高清头像api
pic_file = requests.get(url1)
open(f"用户头像保存地址", "wb").write(pic_file.content)
original_img = Image.open("板子地址")
user_img = Image.open("用户头像地址")
user_img = user_img.resize((220, 310)) # 这个是抄的petpet里面的,按着来吧
user_img = user_img.rotate(25,expand=True) # 同上,expand用于适配(拉伸)旋转后的图像
meme = Image.new("RGBA", size=original_img.size, color='white')
meme.paste(user_img, (56, 32)) # petpet里的位置,也是固定实现效果最好的位置
meme.paste(original_img, mask=original_img) # 把alpha通道作为mask
meme.save("表情包保存地址")
await bk_work.finish(Message(f"[CQ:image,file=file:///表情包保存地址,id=40000]"))
示例:头图
2.问题及其他
- 字体的适配可能不是很好,最好自己改成需要的
- 换行的实现比较粗暴,不知道有没有更好地实现方式
- 写挺丑
- 请多多star Mq佬的petpet和memes插件