Python——制作表白神图

Python——制作表白神图

  • PIL制作表白图片
    • 前言
    • 解析
    • 总代码

PIL制作表白图片

前言

在网上看到了很多由文字构成的图片,感觉挺厉害的,so自己也来亲自上手试试。
先上个图叭,让大家康康什么是文字图(底色是白色,可能有点模糊)
Python——制作表白神图_第1张图片
放大看,可以按住Ctrl键用鼠标滑轮(全图是由love组成)

解析

首先要理解将图片转换成文字图的原理,才能更好的理解代码。
我们要做的就是先构造一块画布,将原图片取出每一像素的颜色,然后用相同颜色的文字取代该处的像素,最后将这些文字布局在画布上。

知道了原理,现在开始开工!!!

先用tkinter将界面布局好
Python——制作表白神图_第2张图片
因为需要用到pack和grid定位,所以需要生成两个frame

root = Tk()
root.title("making love image")
root.resizable(1,1)
root.geometry("400x600")

frame1 = Frame(root)
frame2 = Frame(root)
frame1.pack()
frame2.pack()

read_var = StringVar()
save_var = StringVar()
Label3 = Label(frame1,text = "文件路径:")
Label3.grid(row = 0,column = 0,pady = 10)
Label1 = Label(frame1,textvariable = read_var)
Label1.grid(row = 0,column = 1,pady = 30)
Label4 = Label(frame1,text = "保存路径:")
Label4.grid(row = 1,column = 0,pady = 10)
Label2 = Label(frame1,textvariable = save_var)
Label2.grid(row = 1,column = 1,pady = 30)

Button1 = Button(frame2,text = "选择图片",font = ("楷体",22),command = get_image)
Button2 = Button(frame2,text = "选择路径",font = ("楷体",22),command = save_image)
Button3 = Button(frame2,text = "开始生成",font = ("楷体",22),command = make_image)
Button1.pack(pady = 20)
Button2.pack(pady = 20)
Button3.pack(pady = 20)

接着是设置如何选取文件(一般选取文件路径都是这样的代码)
**注:**文件可以选取的类型只有以下代码提到的三种(jpg/png/gif)
文件类型是可以自己改的

def get_image():
    global IMGPATH      # 全局变量
    filenames = askopenfilenames(filetypes = (("jpg img","*.jpg"),("png img","*.png"),("gif img","*.gif")))     # 文件可选类型(jpg\png\gif)
    if len(filenames) > 0:
        fnlist = [fn for fn in filenames]
        fnstr = '\n'.join(fnlist)
        read_var.set(fnstr)
        IMGPATH = fnlist
    else:
        read_var.set("目前没有选择任何图片文件")

设置保存路径(利用asksavesfilename方法选取路径)
**注:**选取保存路径时需自己写文件名及后缀名

def save_image():
    global savepath     # 全局变量savepath
    savepath = tkinter.filedialog.asksaveasfilename()       # 返回保存路径
    save_var.set(savepath)		

设置生成图片过程

def make_image():
    global IMGPATH
    global savepath
    for imgpath in IMGPATH:		#IMGPATH是一个包含路径的字符串,imgpath才是真正的路径
        produce_image(imgpath,savepath)
    showinfo(title = '完成生成',message = f'保存路径为:{savepath}')      # 弹出消息框

以下才是本章的重点(如何转换)
首先打开所需文件,取出该图的像素组

img_raw = Image.open(img_path)      # 打开图片
img_array = img_raw.load()      # 加载图像的像素数组

生成一块画布,选取字体类型及文字大小
注:
将画布设置为可涂鸦,该画布的底色可以改变,不同的图用不同颜色的底色,会使转换后的图更为清晰
选择的文字字体类型(即’arial.ttf’)需在windows-font中存在----->不了解的可以看这里

    img_new = Image.new("RGB", img_raw.size, (255, 255, 255))       # 生成新画布
    draw = ImageDraw.Draw(img_new)      # 在新画布上可以画画
    font = ImageFont.truetype('arial.ttf', font_size)       # 选择字体类型和大小

设置文字生成器(即可以一直循环生成文字)
最好是去了解一下yield的用法

def character_generator(text):
    while True:
        for i in range(len(text)):
            yield text[i]

将文字按图片像素组分布在新的画布上

    for y in range(0, img_raw.size[1], font_size):
        for x in range(0, img_raw.size[0], font_size):
            draw.text((x, y), next(ch_gen), font=font, fill=img_array[x, y], direction=None)

总代码

# coding=utf-8

from tkinter import *
from tkinter.filedialog import askopenfilenames
import tkinter.filedialog
from tkinter.messagebox import showinfo
from PIL import Image,ImageDraw,ImageFont

root = Tk()
root.title("making love image")
root.resizable(1,1)
root.geometry("400x600")

frame1 = Frame(root)
frame2 = Frame(root)
frame1.pack()
frame2.pack()

read_var = StringVar()
save_var = StringVar()

IMGPATH = ""
savepath = ""

def get_image():
    global IMGPATH      # 全局变量
    filenames = askopenfilenames(filetypes = (("jpg img","*.jpg"),("png img","*.png"),("gif img","*.gif")))     # 文件可选类型
    if len(filenames) > 0:
        fnlist = [fn for fn in filenames]
        fnstr = '\n'.join(fnlist)
        read_var.set(fnstr)
        IMGPATH = fnlist
    else:
        read_var.set("目前没有选择任何图片文件")
        
def save_image():
    global savepath     # 全局变量savepath
    savepath = tkinter.filedialog.asksaveasfilename()       # 返回保存路径
    save_var.set(savepath)

def make_image():
    global IMGPATH
    global savepath
    for imgpath in IMGPATH:
        produce_image(imgpath,savepath)
    showinfo(title = '完成生成',message = f'保存路径为:{savepath}')      # 弹出消息框

def produce_image(img_path, savepath):

    font_size = 7       # 设置文字大小
    text = "love"       # 设置文字内容

    img_raw = Image.open(img_path)      
    img_array = img_raw.load()      

    img_new = Image.new("RGB", img_raw.size, (255, 255, 255))       
    draw = ImageDraw.Draw(img_new)      
    font = ImageFont.truetype('arial.ttf', font_size)      

    ch_gen = character_generator(text)

    for y in range(0, img_raw.size[1], font_size):
        for x in range(0, img_raw.size[0], font_size):

            draw.text((x, y), next(ch_gen), font=font, fill=img_array[x, y], direction=None)

    img_new.convert('RGB').save(savepath)       # 保存图片

def character_generator(text):
    while True:
        for i in range(len(text)):
            yield text[i]
            
Label3 = Label(frame1,text = "文件路径:")
Label3.grid(row = 0,column = 0,pady = 10)
Label1 = Label(frame1,textvariable = read_var)
Label1.grid(row = 0,column = 1,pady = 30)
Label4 = Label(frame1,text = "保存路径:")
Label4.grid(row = 1,column = 0,pady = 10)
Label2 = Label(frame1,textvariable = save_var)
Label2.grid(row = 1,column = 1,pady = 30)

Button1 = Button(frame2,text = "选择图片",font = ("楷体",22),command = get_image)
Button2 = Button(frame2,text = "选择路径",font = ("楷体",22),command = save_image)
Button3 = Button(frame2,text = "开始生成",font = ("楷体",22),command = make_image)
Button1.pack(pady = 20)
Button2.pack(pady = 20)
Button3.pack(pady = 20)

mainloop()

你可能感兴趣的:(python)