Res*_*ker 2 python canvas discord discord.py
我需要有关 discord.py 的帮助。我一直在用 python 创建一个机器人,所以我想用这个机器人制作一个画布个人资料卡。问题是,我在 google 中没有找到任何关于它的信息,只有 node.js。我不想重写我的机器人,我想制作一张个人资料卡,例如:juniperbot、mee6。请帮帮我吧!
我不知道jupiterbot,mee6但如果canvas意味着在文档中使用 Canvas进行图像操作,discord.js那么它仅用于生成图像,并且只是send()作为普通文件.png或.jpg.
Python 通常使用模块枕头来生成或修改图像。图像, ImageDraw , ImageFont
from discord.ext import commands
from discord import File
from PIL import Image, ImageDraw, ImageFont
import io
TOKEN = 'MY-TOKEN'
bot = commands.Bot(command_prefix='!')
@bot.command(name='canvas')
async def canvas(ctx, text=None):
IMAGE_WIDTH = 600
IMAGE_HEIGHT = 300
# create empty image 600x300
image = Image.new('RGB', (IMAGE_WIDTH, IMAGE_HEIGHT)) # RGB, RGBA (with alpha), L (grayscale), 1 (black & white)
# or load existing image
#image = Image.open('/home/furas/images/lenna.png')
# create object for drawing
draw = ImageDraw.Draw(image)
# draw red rectangle with green outline from point (50,50) to point (550,250) #(600-50, 300-50)
draw.rectangle([50, 50, IMAGE_WIDTH-50, IMAGE_HEIGHT-50], fill=(255,0,0), outline=(0,255,0))
# draw text in center
text = f'Hello {ctx.author.name}'
font = ImageFont.truetype('Arial.ttf', 30)
text_width, text_height = draw.textsize(text, font=font)
x = (IMAGE_WIDTH - text_width)//2
y = (IMAGE_HEIGHT - text_height)//2
draw.text( (x, y), text, fill=(0,0,255), font=font)
# create buffer
buffer = io.BytesIO()
# save PNG in buffer
image.save(buffer, format='PNG')
# move to beginning of buffer so `send()` it will read from beginning
buffer.seek(0)
# send image
await ctx.send(file=File(buffer, 'myimage.png'))
if __name__ == '__main__':
bot.run(TOKEN)
Run Code Online (Sandbox Code Playgroud)
结果:
编辑:添加用户头像的版本。
我还展示了如何从 url 读取图像并将其用作背景。但它只能读取一次——在开始时。
@bot.command(name='canvas')
async def canvas(ctx, text=None):
#print('\n'.join(dir(ctx)))
#print('\n'.join(dir(ctx.author)))
# --- create empty image ---
#IMAGE_WIDTH = 600
#IMAGE_HEIGHT = 300
# create empty image 600x300
#image = Image.new('RGB', (IMAGE_WIDTH, IMAGE_HEIGHT)) # RGB, RGBA (with alpha), L (grayscale), 1 (black & white)
# --- load image from local file ---
# or load existing image
#image = Image.open('/home/furas/Obrazy/images/lenna.png')
# --- load image from url ---
import urllib.request
url = 'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png?download'
response = urllib.request.urlopen(url)
image = Image.open(response) # it doesn't need `io.Bytes` because it `response` has method `read()`
print('size:', image.size)
#IMAGE_WIDTH, IMAGE_HEIGHT = image.size
IMAGE_WIDTH = image.size[0]
# --- draw on image ---
# create object for drawing
draw = ImageDraw.Draw(image)
# draw red rectangle with green outline from point (50,50) to point (550,250) #(600-50, 300-50)
draw.rectangle([50, 50, IMAGE_WIDTH-50, IMAGE_HEIGHT-50], fill=(255,0,0, 128), outline=(0,255,0))
# draw text in center
text = f'Hello {ctx.author.name}'
font = ImageFont.truetype('Arial.ttf', 30)
text_width, text_height = draw.textsize(text, font=font)
x = (IMAGE_WIDTH - text_width)//2
y = (IMAGE_HEIGHT - text_height)//2
draw.text( (x, y), text, fill=(0,0,255), font=font)
# --- avatar ---
#print('avatar:', ctx.author.avatar_url)
#print('avatar:', ctx.author.avatar_url_as(format='jpg'))
#print('avatar:', ctx.author.avatar_url_as(format='png'))
AVATAR_SIZE = 128
# get URL to avatar
# sometimes `size=` doesn't gives me image in expected size so later I use `resize()`
avatar_asset = ctx.author.avatar_url_as(format='jpg', size=AVATAR_SIZE)
# read JPG from server to buffer (file-like object)
buffer_avatar = io.BytesIO()
await avatar_asset.save(buffer_avatar)
buffer_avatar.seek(0)
# read JPG from buffer to Image
avatar_image = Image.open(buffer_avatar)
# resize it
avatar_image = avatar_image.resize((AVATAR_SIZE, AVATAR_SIZE)) #
x = 50 + 5
y = (IMAGE_HEIGHT-AVATAR_SIZE)//2 # center vertically
image.paste(avatar_image, (x, y))
# --- sending image ---
# create buffer
buffer_output = io.BytesIO()
# save PNG in buffer
image.save(buffer_output, format='PNG')
# move to beginning of buffer so `send()` it will read from beginning
buffer_output.seek(0)
# send image
await ctx.send(file=File(buffer_output, 'myimage.png'))
Run Code Online (Sandbox Code Playgroud)
结果:
编辑:使用新图像绘制透明矩形的示例和Image.alpha_composite()
Pillow doc:示例:绘制部分不透明文本
from discord.ext import commands
from discord import File
from PIL import Image, ImageDraw, ImageFont
import io
import urllib.request
TOKEN = 'MY-TOKEN'
bot = commands.Bot(command_prefix='!')
# read background image only once
url = 'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png?download'
response = urllib.request.urlopen(url)
background_image = Image.open(response) # it doesn't need `io.Bytes` because it `response` has method `read()`
background_image = background_image.convert('RGBA') # add channel ALPHA to draw transparent rectangle
@bot.command(name='canvas')
async def canvas(ctx, text=None):
AVATAR_SIZE = 128
# --- duplicate image ----
image = background_image.copy()
image_width, image_height = image.size
# --- draw on image ---
# create object for drawing
#draw = ImageDraw.Draw(image)
# draw red rectangle with alpha channel on new image (with the same size as original image)
rect_x0 = 20 # left marign
rect_y0 = 20 # top marign
rect_x1 = image_width - 20 # right margin
rect_y1 = 20 + AVATAR_SIZE - 1 # top margin + size of avatar
rect_width = rect_x1 - rect_x0
rect_height = rect_y1 - rect_y0
rectangle_image = Image.new('RGBA', (image_width, image_height))
rectangle_draw = ImageDraw.Draw(rectangle_image)
rectangle_draw.rectangle((rect_x0, rect_y0, rect_x1, rect_y1), fill=(255,0,0, 128))
# put rectangle on original image
image = Image.alpha_composite(image, rectangle_image)
# create object for drawing
draw = ImageDraw.Draw(image) # create new object for drawing after changing original `image`
# draw text in center
text = f'Hello {ctx.author.name}'
font = ImageFont.truetype('Arial.ttf', 30)
text_width, text_height = draw.textsize(text, font=font)
x = (rect_width - text_width - AVATAR_SIZE)//2 # skip avatar when center text
y = (rect_height - text_height)//2
x += rect_x0 + AVATAR_SIZE # skip avatar when center text
y += rect_y0
draw.text((x, y), text, fill=(0,0,255,255), font=font)
# --- avatar ---
# get URL to avatar
# sometimes `size=` doesn't gives me image in expected size so later I use `resize()`
avatar_asset = ctx.author.avatar_url_as(format='jpg', size=AVATAR_SIZE)
# read JPG from server to buffer (file-like object)
buffer_avatar = io.BytesIO()
await avatar_asset.save(buffer_avatar)
buffer_avatar.seek(0)
# read JPG from buffer to Image
avatar_image = Image.open(buffer_avatar)
# resize it
avatar_image = avatar_image.resize((AVATAR_SIZE, AVATAR_SIZE)) #
image.paste(avatar_image, (rect_x0, rect_y0))
# --- sending image ---
# create buffer
buffer_output = io.BytesIO()
# save PNG in buffer
image.save(buffer_output, format='PNG')
# move to beginning of buffer so `send()` it will read from beginning
buffer_output.seek(0)
# send image
await ctx.send(file=File(buffer_output, 'myimage.png'))
if __name__ == '__main__':
print('Running ... https://discord.com/channels/709507681441808385/709507681441808388')
bot.run(TOKEN)
Run Code Online (Sandbox Code Playgroud)
结果:
BTW:示例如何使用 alpha 通道创建圆形图像(创建圆形头像):
编辑:使用遮罩显示圆形头像的版本
# --- avatar ---
# get URL to avatar
# sometimes `size=` doesn't gives me image in expected size so later I use `resize()`
avatar_asset = ctx.author.avatar_url_as(format='jpg', size=AVATAR_SIZE)
# read JPG from server to buffer (file-like object)
buffer_avatar = io.BytesIO(await avatar_asset.read())
# buffer_avatar = io.BytesIO()
# await avatar_asset.save(buffer_avatar)
# buffer_avatar.seek(0)
# read JPG from buffer to Image
avatar_image = Image.open(buffer_avatar)
# resize it
avatar_image = avatar_image.resize((AVATAR_SIZE, AVATAR_SIZE)) #
circle_image = Image.new('L', (AVATAR_SIZE, AVATAR_SIZE))
circle_draw = ImageDraw.Draw(circle_image)
circle_draw.ellipse((0, 0, AVATAR_SIZE, AVATAR_SIZE), fill=255)
#avatar_image.putalpha(circle_image)
#avatar_image.show()
image.paste(avatar_image, (rect_x0, rect_y0), circle_image)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5181 次 |
| 最近记录: |