筆者在開發過程中,遇到了這樣的需求,需要將合成如下圖所示的分享圖,用戶可以點擊圖片保存分享,其中紅色框內的數據都是變化的
筆者在查閱資料後發現:阿里雲oss圖片可以添加水印對圖片進行處理,最多可支持三個圖片水印,所有的圖片都要求在同一個buket下,而筆者開發系統有拉取微信頭像地址,不是企業oss的buket,如果要使用還得上傳到buket,並且阿里雲oss圖片水印明確指出,不支持水印圖片內切圓,所以不滿足項目需求。
最後決定自己本地合成處理圖片,目前該版本未經高併發等專業測試,所以有很多不足之處,如果路過的你有更好的解決方案,希望能多多指教幫助成長。
我的做法是使用python 的PIL庫實現圖片的處理,在本地合成圖片後將圖片上傳至oss,然後用oss處理圖片圓角,以下爲相關處理方法
import requests
from PIL import Image, ImageFont, ImageDraw, ImageFilter
import qrcode
def download_image(url, name):
"""下載圖片到本地"""
r = requests.get(url)
with open(name, 'wb') as f:
f.write(r.content)
def circle_new(path):
"""頭像內切圓"""
ima = Image.open(path).convert("RGBA")
ima = ima.resize((72, 72))
r2 = 72
circle = Image.new('1', (r2, r2), 0)
draw = ImageDraw.Draw(circle)
draw.ellipse((0, 0, r2, r2), fill=(255))
alpha = Image.new('RGBA', (r2, r2), (255, 255, 255, 255))
alpha = alpha.convert("1")
alpha.paste(circle, (0, 0))
ima.putalpha(alpha) # 蒙層圖片
# ima.show()
# ima.save(r".\head.png")
return ima
def create_code(url, QRcenter=r".\QRcenter.jpg"):
“”合成二維碼“”“”
qr = qrcode.QRCode(
version=5, error_correction=qrcode.constants.ERROR_CORRECT_H, box_size=8, border=4)
qr.add_data(url)
qr.make(fit=True)
img = qr.make_image()
img = img.convert("RGBA")
icon = Image.open(QRcenter) # 這裏是二維碼中心的圖片
img_w, img_h = img.size
factor = 4
size_w = int(img_w / factor)
size_h = int(img_h / factor)
icon_w, icon_h = icon.size
if icon_w > size_w:
icon_w = size_w
if icon_h > size_h:
icon_h = size_h
icon = icon.resize((icon_w, icon_h), Image.ANTIALIAS)
w = int((img_w - icon_w) / 2)
h = int((img_h - icon_h) / 2)
icon = icon.convert("RGBA")
img.paste(icon, (w, h), icon)
# img.show() # 顯示圖片,可以通過save保存
return img
def image_tool(urlName=None, url=None, centerUrl=None, price=None, nickName=None, fontPath=None, logoPath=None,
coursePath=None, avatarPath=None):
target = Image.new('RGBA', (600, 696), "white")
# 頂部宣傳圖
box = (0, 0, 600, 439) # 區域
region = Image.open(coursePath)
region = region.convert("RGBA")
region = region.resize((600, 439))
# 企業logo
box1 = (0, 626, 600, 696)
region1 = Image.open(logoPath)
region1 = region1.convert("RGBA")
region1 = region1.resize((600, 70))
# 用戶頭像
box2 = (20, 530, 92, 602)
region2 = circle_new(avatarPath)
region2 = region2.resize((72, 72))
# 二維碼
box3 = (472, 461, 580, 569)
region3 = create_code(url, centerUrl)
region3 = region3.convert("RGBA")
region3 = region3.resize((108, 108))
# 粘貼圖片
target.paste(region, box)
target.paste(region1, box1)
target.paste(region2, box2)
target.paste(region3, box3)
# 寫入介紹
draw = ImageDraw.Draw(target)
font = ImageFont.truetype(fontPath, 30)
# (fl, il) = math.modf(price)
# priceList = [str(il), str(int(fl * 10))]
draw.text((20, 456), "成功邀請後,將獲得", "#333333", font)
draw.text((293, 456), str(price) + "元收益", "#FFCC33", font)
# 寫入暱稱
font1 = ImageFont.truetype(fontPath, 28)
draw.text((101, 546), nickName + "推薦", "#333333", font1)
# 寫入固定文字
font2 = ImageFont.truetype(fontPath, 24)
draw.text((478, 573), "掃碼購買", "#333333", font2)
x, y = target.size
p = Image.new('RGBA', target.size, (255, 255, 255))
p.paste(target, (0, 0, x, y), target)
# p.show()
p.save(urlName) # 保存圖片
def get_res_url(backgroundUrl, avatarBase64=None, courseBase64=None, price=None, nickName=None):
"""處理圖片圓角,註釋部分爲最先考慮的阿里雲水印寫法,有興趣的可以看一看"""
# text_Info1 = get_base64_txt("成功邀請後,將獲得")
# text_Info2 = get_base64_txt(str(price / 100) + "元收益")
# text_Info3 = get_base64_txt(nickName + "推薦")
# text_Info4 = get_base64_txt("掃碼購買")
resStr = backgroundUrl
resStr += "?x-oss-process=image/resize,w_600,h_696"
# resStr += "/watermark,image_" + logoBase64 + ",x_0,y_637"
resStr += "/watermark,image_" + avatarBase64 + ",x_508,y_94/rounded-corners,r_30"
# resStr += "/watermark,image_" + courseBase64 + ",x_0,y_0"
# resStr += "/watermark,type_d3F5LXplbmhlaQ,size_30,text_" + text_Info1 + ",color_333333,x_20,y_456"
# resStr += "/watermark,type_d3F5LXplbmhlaQ,size_30,text_" + text_Info2 + ",color_FFCC33,x_293,y_456"
# resStr += "/watermark,type_d3F5LXplbmhlaQ,size_28,text_" + text_Info3 + ",color_333333,x_101,y_546"
# resStr += "/watermark,type_d3F5LXplbmhlaQ,size_24,text_" + text_Info4 + ",color_333333,x_478,y_573"
return resStr
if __name__ == "__main__":
code_tool()
由於涉及大量的io操作,第一次分享圖片合成很慢,但是可以用數據庫記錄用戶的分享,如果一旦合成就數據庫記錄,第二次直接返回信息。但是這樣會出現的問題是,如果用戶修改信息或者分享的商品信息修改,那麼分享圖信息依然不會修改,這一點筆者目前還沒有想到很好的方法。
本地操作需要將圖片拉取到本地存儲,然後PIL才能操作圖片,所以會有圖片命名的處理,要求所有圖片不重名,並且圖片使用完後要將圖片刪除,不然圖片會存儲在服務器,導致服務器壓力。