背景介绍
参考链接:https://blog.csdn.net/Python_HUHU/article/details/139703289 点的背景颜色在开始修改;文字的颜色在最后修改。 文字内容可以修改。
python 代码
import tkinter as tk
import random
from math import sin, cos, pi, log
from PIL import Image, ImageDraw, ImageFont
width = 888
height = 500
heartx = width / 2
hearty = height / 2
side = 11
heartcolor = "pink"
class Heart :
def __init__ ( self, generate_frame= 20 ) :
self. _points = set ( )
self. _edge_diffusion_points = set ( )
self. _center_diffusion_points = set ( )
self. all_points = { }
self. build( 2000 )
self. generate_frame = generate_frame
for frame in range ( generate_frame) :
self. calc( frame)
def build ( self, number) :
for _ in range ( number) :
t = random. uniform( 0 , 2 * pi)
x, y = heart_function( t)
self. _points. add( ( x, y) )
for _x, _y in list ( self. _points) :
for _ in range ( 3 ) :
x, y = scatter_inside( _x, _y, 0.05 )
self. _edge_diffusion_points. add( ( x, y) )
point_list = list ( self. _points)
for _ in range ( 4000 ) :
x, y = random. choice( point_list)
x, y = scatter_inside( x, y, 0.17 )
self. _center_diffusion_points. add( ( x, y) )
@staticmethod
def calc_position ( x, y, ratio) :
force = 1 / ( ( ( x - heartx) ** 2 + ( y - hearty) ** 2 ) ** 0.520 )
dx = ratio * force * ( x - heartx) + random. randint( - 1 , 1 )
dy = ratio * force * ( y - hearty) + random. randint( - 1 , 1 )
return x - dx, y - dy
def calc ( self, generate_frame) :
ratio = 10 * curve( generate_frame / 10 * pi)
all_points = [ ]
for x, y in self. _points:
x, y = self. calc_position( x, y, ratio)
size = random. randint( 1 , 3 )
all_points. append( ( x, y, size) )
for x, y in self. _edge_diffusion_points:
x, y = self. calc_position( x, y, ratio)
size = random. randint( 1 , 2 )
all_points. append( ( x, y, size) )
for x, y in self. _center_diffusion_points:
x, y = self. calc_position( x, y, ratio)
size = random. randint( 1 , 2 )
all_points. append( ( x, y, size) )
self. all_points[ generate_frame] = all_points
def render ( self, draw, render_frame) :
for x, y, size in self. all_points[ render_frame % self. generate_frame] :
draw. rectangle( [ x, y, x + size, y + size] , fill= heartcolor)
def heart_function ( t, shrink_ratio: float = side) :
x = 16 * ( sin( t) ** 3 )
y = - ( 13 * cos( t) - 5 * cos( 2 * t) - 2 * cos( 3 * t) - cos( 4 * t) )
x *= shrink_ratio
y *= shrink_ratio
x += heartx
y += hearty
return int ( x) , int ( y)
def scatter_inside ( x, y, beta= 0.15 ) :
ratio_x = - beta * log( random. random( ) )
ratio_y = - beta * log( random. random( ) )
dx = ratio_x * ( x - heartx)
dy = ratio_y * ( y - hearty)
return x - dx, y - dy
def curve ( p) :
return 2 * ( 2 * sin( 4 * p) ) / ( 2 * pi)
def save_gif ( ) :
frames = [ ]
heart = Heart( )
for frame in range ( heart. generate_frame) :
img = Image. new( 'RGB' , ( width, height) , 'black' )
draw = ImageDraw. Draw( img)
heart. render( draw, frame)
text = "Miss ❤ U"
font = ImageFont. truetype( "./font/DejaVu-Sans.ttf" , 40 )
bbox = draw. textbbox( ( 0 , 0 ) , text, font= font)
text_width, text_height = bbox[ 2 ] - bbox[ 0 ] , bbox[ 3 ] - bbox[ 1 ]
text_x = ( width - text_width) / 2
text_y = ( height - text_height) / 2
draw. text( ( text_x, text_y) , text, font= font, fill= "gold" )
frames. append( img)
frames[ 0 ] . save( './result/1_2_3_heart_animation_with_text.gif' , save_all= True , append_images= frames[ 1 : ] , duration= 160 , loop= 0 )
if __name__ == '__main__' :
save_gif( )
绘制结果
进阶修改:周围环绕文字,修改背景颜色
import tkinter as tk
import random
from math import sin, cos, pi, log, atan2
from PIL import Image, ImageDraw, ImageFont
width = 666
height = 460
heartx = width / 2
hearty = height / 2
side = 11
heartcolor = "pink"
macaron_blue = "#A2C2E1"
cream_white = "#F5F5F5"
cyan_green = "#00FFFF"
class Heart :
def __init__ ( self, generate_frame= 20 ) :
self. _points = set ( )
self. _edge_diffusion_points = set ( )
self. _center_diffusion_points = set ( )
self. all_points = { }
self. build( 2000 )
self. generate_frame = generate_frame
for frame in range ( generate_frame) :
self. calc( frame)
def build ( self, number) :
for _ in range ( number) :
t = random. uniform( 0 , 2 * pi)
x, y = heart_function( t)
self. _points. add( ( x, y) )
for _x, _y in list ( self. _points) :
for _ in range ( 3 ) :
x, y = scatter_inside( _x, _y, 0.05 )
self. _edge_diffusion_points. add( ( x, y) )
point_list = list ( self. _points)
for _ in range ( 4000 ) :
x, y = random. choice( point_list)
x, y = scatter_inside( x, y, 0.17 )
self. _center_diffusion_points. add( ( x, y) )
@staticmethod
def calc_position ( x, y, ratio) :
force = 1 / ( ( ( x - heartx) ** 2 + ( y - hearty) ** 2 ) ** 0.520 )
dx = ratio * force * ( x - heartx) + random. randint( - 1 , 1 )
dy = ratio * force * ( y - hearty) + random. randint( - 1 , 1 )
return x - dx, y - dy
def calc ( self, generate_frame) :
ratio = 10 * curve( generate_frame / 10 * pi)
all_points = [ ]
for x, y in self. _points:
x, y = self. calc_position( x, y, ratio)
size = random. randint( 1 , 3 )
all_points. append( ( x, y, size) )
for x, y in self. _edge_diffusion_points:
x, y = self. calc_position( x, y, ratio)
size = random. randint( 1 , 2 )
all_points. append( ( x, y, size) )
for x, y in self. _center_diffusion_points:
x, y = self. calc_position( x, y, ratio)
size = random. randint( 1 , 2 )
all_points. append( ( x, y, size) )
self. all_points[ generate_frame] = all_points
def render ( self, draw, render_frame) :
for x, y, size in self. all_points[ render_frame % self. generate_frame] :
draw. rectangle( [ x, y, x + size, y + size] , fill= heartcolor)
def heart_function ( t, shrink_ratio: float = side) :
x = 16 * ( sin( t) ** 3 )
y = - ( 13 * cos( t) - 5 * cos( 2 * t) - 2 * cos( 3 * t) - cos( 4 * t) )
x *= shrink_ratio
y *= shrink_ratio
x += heartx
y += hearty
return int ( x) , int ( y)
def scatter_inside ( x, y, beta= 0.15 ) :
ratio_x = - beta * log( random. random( ) )
ratio_y = - beta * log( random. random( ) )
dx = ratio_x * ( x - heartx)
dy = ratio_y * ( y - hearty)
return x - dx, y - dy
def curve ( p) :
return 2 * ( 2 * sin( 4 * p) ) / ( 2 * pi)
def calculate_bounding_circle_radius ( ) :
max_distance = 0
for t in range ( 0 , 360 ) :
radian = t * pi / 180
x, y = heart_function( radian)
distance = ( ( x - heartx) ** 2 + ( y - hearty) ** 2 ) ** 0.5
if distance > max_distance:
max_distance = distance
return max_distance
def draw_text_on_circle ( draw, text, radius, font) :
char_angle = pi / len ( text)
for i, char in enumerate ( text) :
angle = i * char_angle - pi + 0.19
angle = angle * - 1
x = heartx + radius * cos( angle)
y = hearty + radius * sin( angle)
bbox = draw. textbbox( ( 0 , 0 ) , char, font= font)
text_width, text_height = bbox[ 2 ] - bbox[ 0 ] , bbox[ 3 ] - bbox[ 1 ]
draw. text( ( x - text_width / 2 , y - text_height / 2 ) , char, font= font, fill= cyan_green)
def save_gif ( ) :
frames = [ ]
heart = Heart( )
circle_radius = calculate_bounding_circle_radius( ) + 20
for frame in range ( heart. generate_frame) :
img = Image. new( 'RGB' , ( width, height) , macaron_blue)
draw = ImageDraw. Draw( img)
heart. render( draw, frame)
text = "爱 你 呦"
font = ImageFont. truetype( "./font/simsun.ttc" , 40 )
bbox = draw. textbbox( ( 0 , 0 ) , text, font= font)
text_width, text_height = bbox[ 2 ] - bbox[ 0 ] , bbox[ 3 ] - bbox[ 1 ]
text_x = ( width - text_width) / 2
text_y = ( height - text_height) / 2
draw. text( ( text_x, text_y) , text, font= font, fill= "gold" )
frames. append( img)
frames[ 0 ] . save( './result/1_2_3_heart_animation_with_text.gif' , save_all= True , append_images= frames[ 1 : ] , duration= 160 , loop= 0 )
if __name__ == '__main__' :
save_gif( )
生成结果
END