背景介绍
参考链接: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_framefor 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 - dydef 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_pointsdef 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_ratioy *= shrink_ratiox += heartxy += heartyreturn 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 - dydef 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, ImageFontwidth = 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_framefor 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 - dydef 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_pointsdef 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_ratioy *= shrink_ratiox += heartxy += heartyreturn 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 - dydef 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 = distancereturn 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