This repository has been archived by the owner on Sep 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 36
/
__init__.py
169 lines (140 loc) · 4.64 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
from PIL import Image as IMG
from PIL import ImageOps
from moviepy.editor import ImageSequenceClip as imageclip
import numpy
import aiohttp
from io import BytesIO
import os
from graia.application import GraiaMiraiApplication
from graia.saya import Saya, Channel
from graia.saya.builtins.broadcast.schema import ListenerSchema
from graia.application.event.messages import *
from graia.application.message.chain import MessageChain
from graia.application.message.elements.internal import At
from graia.application.message.elements.internal import Image
from graia.application.event.messages import Group
from graia.application.exceptions import AccountMuted
# 插件信息
__name__ = "PetPet"
__description__ = "生成摸头gif"
__author__ = "SAGIRI-kawaii"
__usage__ = "在群内发送 摸@目标 即可"
saya = Saya.current()
channel = Channel.current()
channel.name(__name__)
channel.description(f"{__description__}\n使用方法:{__usage__}")
channel.author(__author__)
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def petpet_generator(app: GraiaMiraiApplication, message: MessageChain, group: Group):
message_text = message.asDisplay()
if message.has(At) and message_text.startswith("摸") or message_text.startswith("摸 "):
if not os.path.exists("./modules/PetPet/temp"):
os.mkdir("./modules/PetPet/temp")
await petpet(message.get(At)[0].target)
try:
await app.sendGroupMessage(
group,
MessageChain.create([
Image.fromLocalFile(f"./modules/PetPet/temp/tempPetPet-{message.get(At)[0].target}.gif")
])
)
except AccountMuted:
pass
frame_spec = [
(27, 31, 86, 90),
(22, 36, 91, 90),
(18, 41, 95, 90),
(22, 41, 91, 91),
(27, 28, 86, 91)
]
squish_factor = [
(0, 0, 0, 0),
(-7, 22, 8, 0),
(-8, 30, 9, 6),
(-3, 21, 5, 9),
(0, 0, 0, 0)
]
squish_translation_factor = [0, 20, 34, 21, 0]
frames = tuple([f'./modules/PetPet/PetPetFrames/frame{i}.png' for i in range(5)])
async def save_gif(gif_frames, dest, fps=10):
"""生成 gif
将输入的帧数据合并成视频并输出为 gif
参数
gif_frames: list<numpy.ndarray>
为每一帧的数据
dest: str
为输出路径
fps: int, float
为输出 gif 每秒显示的帧数
返回
None
但是会输出一个符合参数的 gif
"""
clip = imageclip(gif_frames, fps=fps)
clip.write_gif(dest) # 使用 imageio
clip.close()
# 生成函数(非数学意味)
async def make_frame(avatar, i, squish=0, flip=False):
"""生成帧
将输入的头像转变为参数指定的帧,以供 make_gif() 处理
参数
avatar: PIL.Image.Image
为头像
i: int
为指定帧数
squish: float
为一个 [0, 1] 之间的数,为挤压量
flip: bool
为是否横向反转头像
返回
numpy.ndarray
为处理完的帧的数据
"""
# 读入位置
spec = list(frame_spec[i])
# 将位置添加偏移量
for j, s in enumerate(spec):
spec[j] = int(s + squish_factor[i][j] * squish)
# 读取手
hand = IMG.open(frames[i])
# 反转
if flip:
avatar = ImageOps.mirror(avatar)
# 将头像放缩成所需大小
avatar = avatar.resize((int((spec[2] - spec[0]) * 1.2), int((spec[3] - spec[1]) * 1.2)), IMG.ANTIALIAS)
# 并贴到空图像上
gif_frame = IMG.new('RGB', (112, 112), (255, 255, 255))
gif_frame.paste(avatar, (spec[0], spec[1]))
# 将手覆盖(包括偏移量)
gif_frame.paste(hand, (0, int(squish * squish_translation_factor[i])), hand)
# 返回
return numpy.array(gif_frame)
async def petpet(member_id, flip=False, squish=0, fps=20) -> None:
"""生成PetPet
将输入的头像生成为所需的 PetPet 并输出
参数
path: str
为头像路径
flip: bool
为是否横向反转头像
squish: float
为一个 [0, 1] 之间的数,为挤压量
fps: int
为输出 gif 每秒显示的帧数
返回
bool
但是会输出一个符合参数的 gif
"""
url = f'http://q1.qlogo.cn/g?b=qq&nk={str(member_id)}&s=640'
gif_frames = []
# 打开头像
# avatar = Image.open(path)
async with aiohttp.ClientSession() as session:
async with session.get(url=url) as resp:
img_content = await resp.read()
avatar = IMG.open(BytesIO(img_content))
# 生成每一帧
for i in range(5):
gif_frames.append(await make_frame(avatar, i, squish=squish, flip=flip))
# 输出
await save_gif(gif_frames, f'./modules/PetPet/temp/tempPetPet-{member_id}.gif', fps=fps)