项目新需求,需要在后端进行图片合成,合成方式为“背景图+二维码+长文本”
在网上查了很多有关python图片合成的资料,大多使用的pygame和PIL,在这里我使用的是python3.5下的PIL分支pillow
国内网站对于如何处理长文本换行的问题,很少有讨论,在此将我的解决方案分享出来
本方案的基本思想是:
创建一个可以自适应变化大小的独立图层,
将整个长文本写进去,
分析图层的大小是否能够放入到背景图中,
如果不能就裁剪文本内容,再重复这一步骤,
from PIL import Image,ImageDraw,ImageFont
import qrcode
import pygame
backMode = { #背景图属性,我的背景图上需要添加一个二维码和多个文本框
"back_url":"timg.jpg",
"size":(550,363),
"QR":{ #二维码属性
"frame":(130,130), #大小
"position":(380,200), #位置
},
"text":[{ #文本框属性
"size":25, #字号
"ttf":"FZXBSJW.TTF", #字体
"color":"", #颜色
"position":(20,40),
"frame":(300,20),
},{
"size":25,
"ttf":"FZXBSJW.TTF",
"color":"",
"position":(20,80),
"frame":(300,20),
},{
"size":25,
"ttf":"FZXBSJW.TTF",
"color":"",
"position":(20,120),
"frame":(300,20),
},{
"size":25,
"ttf":"FZXBSJW.TTF",
"color":"",
"position":(20,160),
"frame":(300,20),
},],
}
def make_QR(content, sizeW = 0, sizeH = 0):#创建二维码
qr = qrcode.QRCode(version=3, box_size=3, border=1, error_correction=qrcode.constants.ERROR_CORRECT_H)
qr.add_data(content)
qr.make(fit=True)
img = qr.make_image()
if sizeW == 0 and sizeH == 0:
return img
w, h = img.size
if sizeW < w or sizeH < h:
return None
img = img.resize((sizeW,sizeH),Image.ANTIALIAS)
return img
def com_pic(topimg, backimg, position):#合并图片
nodeA = position
w, h = topimg.size
nodeB = (position[0]+w, position[1]+h)
backimg.paste(topimg, (nodeA[0], nodeA[1], nodeB[0], nodeB[1]))
return backimg
def write_line(backimg ,text, tmode):#给单个文本框填充数据
myfont = ImageFont.truetype(tmode["ttf"],size=tmode["size"])
draw = ImageDraw.Draw(backimg)
tend = len(text)
while True:
text_size = draw.textsize(text[:tend], font=myfont) #文本图层的尺寸
#print(text_size)
if text_size[0] <= tmode["frame"][0]:
break
else:
tend -= 1 #文本太长,调整文本长度
draw.text((tmode["position"][0], tmode["position"][1]), text[:tend], font=myfont)
return backimg, tend
def write_text(img , text, tmodeList):#写文本
tlist = text.split("\n")
mnum = 0
draw = ImageDraw.Draw(img)
for t in tlist:
tbegin = 0
tend = len(t)
while True:
img, tend = write_line(img, t[tbegin:tend], tmodeList[mnum])
mnum += 1
if tbegin + tend == len(t) or mnum == len(tmodeList):
break
else:
tbegin = tbegin + tend
tend = len(t)
if mnum == len(tmodeList):
break
return img
def make_pic(mode, text, url):
img = Image.open(mode["back_url"])#读取背景图片
QR_res = make_QR(url, mode["QR"]["frame"][0], mode["QR"]["frame"][1])#创建二维码
img = com_pic(QR_res, img, mode["QR"]["position"])#合成1
img = write_text(img, text, mode["text"])#写文本
img.save('A.PNG', quality=100)
make_pic(backMode, "晚风窃笑街角 需要为一堆落叶放哨\n冷的月色\n铺垫整场你礼貌的揭晓 不爱我就拉倒", "http://bd.kuwo.cn/yinyue/41230185")
exit()
下面是我使用的原图和生成效果,以及需要注意的内容