记得之前工作业务上有实现生成小程序分享海报的需求,但是相比小程序端canvas生成海报还是复杂的多,这里使用的是PIL来画图拼接,最后生成图片,最后保存在本地或者上传到云存储以便后续使用,具体看业务需求。
话不多说,这里使用的是python语言,以下为代码
import uuid
import json
import os
import requests
import config
import base64
from PIL import Image, ImageDraw, ImageFont
class PosterImage:
"""海报"""
qr_code_base_url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token='
def __init__(self, avatar, backdrop_path):
self.avatar = avatar
self.backdrop_path = backdrop_path
self.qr_code_url = self.qr_code_base_url + (你的access_token)
self.backdrop = Image.open(self.backdrop_path)
self.generate_copy_backdrop()
def get_qr_code(self, content: str):
"""生成二维码 pil对象"""
def get_stream(self, url, user_id, role, kwargs=None):
"""获取二维码字节码"""
json_data = {'scene': '',
'page': '',
'width': 280,
'auto_color': False,
'is_hyaline': False}
# 提交到微信地址
result = requests.post(url, json=json_data, timeout=3, verify=False)
self.stream = result.content
def get_avatar(self):
"""获取微信头像"""
self.stream = requests.get(url=self.avatar).content
def save_stream(self):
"""将流数据保存至本地文件内,返回文件名"""
prefix = uuid.uuid1().hex
file_name = f'{prefix}.png'
file_path = 'qr_code/' + file_name
import os
path = os.getcwd()+'/plugins/public/'
file_path = os.path.join(path, file_path)
with open(file_path, 'wb') as f:
f.write(self.stream)
return file_path
def open_material(self, path):
"""打开素材
qr_code:背景
qr_code:小程序页面二维码
"""
try:
self.material = Image.open(path)
return self.material
except(OSError, NameError):
print('OSError, Path:', path)
def generate_copy_backdrop(self):
"""生成背景图拷贝对象,对背景图的操作不会影响原对象"""
self.copy_backdrop = self.backdrop.copy().convert('RGB')
self.copy_backdrop_draw = ImageDraw.Draw(self.copy_backdrop)
def set_font(self, css_path: str = None, fill: tuple = (0, 0, 0), size: int = 36):
"""设定字体"""
import os
path = os.getcwd()
path = os.path.join(path, "static/Alibaba-PuHuiTi-Bold.ttf")
self.font = ImageFont.truetype(path, size=size)
self.font_fill = fill
def synthesis(self, img, x: float, y: float, size=None):
"""合成图片
:param img: pil对象
:param size: 图形尺寸
:param x: 横向坐标
:param y: 纵向坐标
"""
if size:
img = img.resize((size, size), Image.ANTIALIAS)
self.copy_backdrop.paste(img, (x, y))
def write(self, content, x: float, y: float):
"""写入内容,写入前可以通过self.set_font 设定字体
:param content: 文字内容
:param x: 横向坐标
:param y: 纵向坐标
"""
self.copy_backdrop_draw.text((x, y), text=content, fill=self.font_fill, font=self.font)
def create_post():
"""生成分享海报"""
import os
path = os.getcwd()
path = os.path.join(path, "static/backdrop.png")
poster_image = PosterImage(avatar=avatar, backdrop_path=path)
# 获取二维码/合成二维码
poster_image.get_stream(url=poster_image.qr_code_url, user_id=user_id, role=role)
poster_image.open_material(poster_image.save_stream())
poster_image.synthesis(poster_image.material, x=505, y=855, size=195)
# 获取微信头像/合成头像
if user.avatar:
poster_image.get_avatar()
poster_image.open_material(poster_image.save_stream())
poster_image.synthesis(poster_image.material, x=65, y=895, size=120)
# 获取昵称
if user.nickname:
poster_image.set_font()
poster_image.write(nickname, x=205, y=900)
filename = f'{uuid.uuid1().hex}.jpg'
path = os.getcwd()+'/plugins/public/'
poster_image_path = os.path.join(path, 'post_image/' + filename)
poster_image.copy_backdrop.save(poster_image_path)
# todo 将海报直传oss 或者保存本地
其实这段代码没有很复杂,只是将构建好的图像不断的合成,难点的话就是相对应的方法调用,还有代码里出现的很多x和y坐标,这个是你的图片元素的位置,你可以放置任意的图像进行合成,相当于不断的在一个画布上堆东西,api还是很丰富的,可以旋转,遮罩,放大缩小等。具体使用还需要你自己摸索。
版权属于:Jolly
本文链接:https://totoro.site/index.php/archives/94/
关于转载:原创文章,禁止转载