说话泡泡生成图片程序

"""说话泡泡生成程序,这是为了给turtle.py模块增加"说话"功能的一个测试程序。就是在角色的头顶右上方或左上方的那个说话泡泡。这是实时生成的一个图片。"""


from PIL import ImageFont,Image,ImageDraw,ImageOps 


def make_string2image(string,width_every_line,font,fontcolor,bgcolor):
    """把字符串分成一行一行相等的,然后转换图形对象"""   
    if len(string) < 8 :
        unuber = 1+(8 - len(string)) // 2  # 左右两边要补偿的空格数
        string = " " * unuber   + string + " "* unuber
    width = 0 
    strings = []
    s = ""
    for c in string:                     # 把string整理成相同像素宽度的行        
        if width <= width_every_line and c != '\n':
            s = s + c                    
            width += font.getsize(c)[0]        
        else:        
            strings.append(s)
            if c!='\n':
                s = c
            else:
                s = ""
            width = 0       
    strings.append(s)

    row_spacing = font.getsize(strings[0])[1] // 2 # 第一行的高度的一半做为行距
    total_width = width_every_line 
    total_height = row_spacing                     # 起始值
    points=[]                                      # Draw的每行起始坐标点
    minwidth = width_every_line
    maxwidth = width_every_line
    for s in strings:
        w = font.getsize(s)[0] 
        if w > maxwidth : maxwidth = w      # 最大宽宽字符串
        if w < minwidth : minwidth = w      # 最小宽度字符串长度
        h = font.getsize(s)[1]
        points.append((row_spacing*2,total_height))
        total_height += (h + row_spacing//2)         
    total_height +=   row_spacing
     
    if len(strings) == 1 :    
        total_width = row_spacing + minwidth + row_spacing * 3
        
    else:
        total_width = row_spacing + maxwidth + row_spacing * 3     
     
    im = Image.new("RGB", (total_width, total_height), bgcolor)
    
    draw = ImageDraw.Draw(im)

    index = 0
    for s in strings:
        x = points[index][0]
        y = points[index][1]
        draw.text((x, y), s, fontcolor, font=font)
        index = index + 1
    return im

def make_round_rectangle(width,height,radius,color):
    """画圆角矩形,圆角半径为radius"""
    width = width + 20
    height = height + 20
    im = Image.new("RGBA", (width, height), (255, 255, 255,0))
    draw = ImageDraw.Draw(im)
    
    box = (0,0,2*radius,2*radius)         # 左上角圆弧
    draw.arc(box,180,270,fill=color)

    points = (radius,0 ,width-radius,0)   # 上横线
    draw.line(points,fill=color)

    box = (width-2*radius,0,width,2*radius) # 右上角圆弧
    draw.arc(box,270,360,fill=color)

    points = (width-1,radius-8,width-1,height-radius+8) # 右边垂线
    draw.line(points,fill=color)
    
    
    box = (width-2*radius,height-2*radius,width,height) # 右下角圆弧
    draw.arc(box,0,90,fill=color)
    
    points = (width-radius+8,height-1,radius-8,height-1)    # 下横线
    draw.line(points,fill=color)
    
    box = (0,height-2*radius,2*radius,height) # 左下角圆弧
    draw.arc(box,90,180,fill=color)
    
    points = (0,height-radius,0,radius)
    draw.line(points,fill=color)    
    return im

def make_bubble_border(size,radius,bgcolor):
    """角色面向右方向时的说话泡泡(不含文字),圆角半径为radius,圆角矩形宽高为size,'把柄'的高度为1.5*radius(三角形)"""
    width,height = size                  # 图像的宽高width,height
    width = width + 20
    height = height + 20
    im = Image.new("RGBA", (width, height + 2*radius), (255, 255, 255,0))
    #im = Image.new("RGBA", (width, height + 2*radius), (0, 255, 0,255))
    
    draw = ImageDraw.Draw(im)
    
    box = (0,0,2*radius,2*radius)         # 左上角圆弧
    draw.pieslice(box,180,270,fill=bgcolor)

    points = (radius,0 ,width-radius,0)   # 上横线
    draw.line(points,fill=bgcolor)

    box = (width-2*radius,0,width,2*radius) # 右上角圆弧
    draw.pieslice(box,270,360,fill=bgcolor)

    points = (width-1,radius-8,width-1,height-radius+8) # 右边垂线
    draw.line(points,fill=bgcolor)    
    
    box = (width-2*radius,height-2*radius,width,height) # 右下角圆弧
    draw.pieslice(box,0,90,fill=bgcolor)
    
    points = (width-radius+8,height-1,radius-8+40,height-1)    # 下横线右
    draw.line(points,fill=bgcolor)

    points = (radius-8+40,height-1,radius//2,height + 1.5*radius-8,radius,height-1)    # 下三角(把柄)
    draw.polygon(points,fill=bgcolor)
    
    box = (0,height-2*radius,2*radius,height) # 左下角圆弧
    draw.pieslice(box,90,180,fill=bgcolor)
    
    points = (0,height-radius,0,radius)
    draw.line(points,fill=bgcolor)

    box = (radius,0,width-radius,radius)     # 上填充矩形
    draw.rectangle(box,fill=bgcolor)

    box = (0,radius,width,height-radius)     # 中填充矩形
    draw.rectangle(box,fill=bgcolor)

    box = (radius,height-radius,width-radius,height)     # 下填充矩形
    draw.rectangle(box,fill=bgcolor)
    
    return im    

 
def make_say_bubble(string,imagewidth,fontfile,fontsize,fontcolor,bgcolor,radius):
    """生成说话泡泡,带字的,参数说明:string:句子,imagewidth,每行无间距总宽度(并不是每行宽度),fontfile:ttf或ttc字体文件
       ,fontsize:字体大小,fontcolor:三元组字体颜色,bgcolor:三元组背景颜色,radius:圆角矩形的半径。
    """
    font = ImageFont.truetype(fontfile,fontsize)                    # 字体对象
    image = make_string2image(string,imagewidth,font,fontcolor,bgcolor)     # 字符串拆分成等分行,转换成图像,image.size是它的宽高
    frame_right = make_bubble_border(image.size,radius,bgcolor)# 生成角色面向右说话的泡泡框架
    frame_left = ImageOps.mirror(frame_right)                       # 生成角色面向左说话的泡泡框架
    frame_right.paste(image,box = (10,10))                          # 把转换成图像的文字贴到frame_right上
    frame_left.paste(image,box = (10,10))
    return frame_left,frame_right


string = r"""1角色面向右方向时的说话泡泡(不含文字),圆角半径为radius,圆角矩形宽高为size,'把柄'的高度为1.5*radius(三角形)
请用A4纸、以双倍行距单面打印或誊抄,字迹务必清晰。

Please type or write clearly in double spacing on one side of A4 paper only.
,交易务必使用担保平台,防止上当受骗)"""
imagewidth = 200
fontfile = "simhei.ttf"
fontsize = 14
fontcolor = (23,23,23)
bgcolor = (240,240,240)
radius = 30
left,right = make_say_bubble(string,imagewidth,fontfile,fontsize,fontcolor,bgcolor,radius)
left.save("logoleft.png")
right.save("logoright.png")