python PIL分享圖片合成

筆者在開發過程中,遇到了這樣的需求,需要將合成如下圖所示的分享圖,用戶可以點擊圖片保存分享,其中紅色框內的數據都是變化的
其中紅色框內的數據都是變化的,二維碼攜帶用戶和商品信息
筆者在查閱資料後發現:阿里雲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才能操作圖片,所以會有圖片命名的處理,要求所有圖片不重名,並且圖片使用完後要將圖片刪除,不然圖片會存儲在服務器,導致服務器壓力。

綜上考慮:其實分享圖合成如果只包含少部分信息,那麼阿里雲是最好的選擇,只需要轉碼拼接就行了。但是如果出現內切圓這樣的需求就處理不了了,可以嘗試get圖片到本地再上傳到自身buket下,或者註冊時直接存儲圓形頭像,但是處理都比較麻煩。如果你有更好的解決方法,希望留言互相學習,謝謝~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章