用python制作文字特效

用pyton制作文字特效

先上两张效果图
在这里插入图片描述
在这里插入图片描述

基本结构

总结文字特效的特点是,每个文字独立运动,都符合同一个运动规律,但每个文字之间保持一个固定的时间差。每个字的运动可以分成三个部分,字体大小的变化、文字位置的变化、文字颜色(透明度)的变化。

# 把每个文字与它的三个运动结合为一个基本单位
def newTextMotion(char, posFunc, sizeFunc, colorFunc):
    tm={}
    tm['char']=char
    tm['posFunc']= posFunc
    tm['sizeFunc']= sizeFunc
    tm['colorFunc']= colorFunc
    return tm

文字动效的展示

在任意一个时间点上,获得文字的显示效果。

# 在指定的时间,计算文字的位置、大小、颜色等
def showText(img, textMotion, time):
    char= textMotion['char'] 
    pos= textMotion['posFunc'](time)
    size= textMotion['sizeFunc'](time)
    color= textMotion['colorFunc'](time)
    font= ImageFont.truetype(fontName, size)
    draw = ImageDraw.Draw(im=img)
    textSize= draw.textsize(text=char, font=font)
    tx= pos[0]- textSize[0]// 2
    ty= pos[1]- textSize[1]// 2
    draw.text(xy=(tx, ty), text=char, fill=color, font=font)

针对一组文字,形成一个列表,获取起每个时间点的显示图,作为一帧

def getTextFrame(tmList, time):
    textImg= Image.new('RGBA', (1280, 720))
    for tm in tmList:
        showText(textImg, tm, time) 
    return textImg

具体文字运动规律

下面看看这两种特效的具体运动规律。乍一看比较复杂,但拆分为三个运动后,其实每种都比较简单。以此为模块,读者可以自行制作更多的文字特效。

# 文字缩小
def makeTextShrink(char, toSize, toPos, toColor, offset, dur):
    def colorFunc(time):
        if time< offset:
            return (0,0,0,0)
        if time> offset+ dur:
            return toColor
        return toColor[:-1] + (50+ round((time-offset)/dur*200),)
    def sizeFunc(time):
        if time< offset:
            return toSize* 8
        if time> offset+ dur:
            return toSize
        return toSize*8 - round((time-offset)/dur* toSize*7.5)
    def posFunc(time):
        if time< offset:
            return (0,0)
        if time> offset+ dur:
            return toPos
        # return (toPos[0], round((time-offset)/dur*toPos[1]))
        return toPos
    return newTextMotion(char, posFunc, sizeFunc, colorFunc)

# 抛物线降落(有一个回弹效果)
def makeTextParaDrop(char, toSize, toPos, toColor, offset, dur):
    def colorFunc(time):
        if time< offset:
            return (0,0,0,0)
        if time> offset+ dur:
            return toColor
        return toColor[:-1] + (50+ round((time-offset)/dur*200),)
    def sizeFunc(time):
        if time< offset:
            return toSize
        if time> offset+ dur:
            return toSize
        return toSize
    def posFunc(time):
        if time< offset:
            return (toPos[0], 0)
        if time> offset+ dur:
            return toPos
        r= 0.75
        dur2= dur
        a= toPos[1]/(dur2* dur2* (1- 2* r))
        b= -2* a* dur2* r
        x= (time-offset)
        return (toPos[0], round(a* x* x+ b*x))
    # print(toPos)
    return newTextMotion(char, posFunc, sizeFunc, colorFunc)

整体设置与运行

对于一行文字,每个增加特效,并依次给予一个延时。

# 一行文字,给定所有参数,配置运动函数与延时
def getMotionList(text, fontSize, fontColor, startPos, fromTime, dur, func):
    tmList=[]
    inter= round(dur/ len(text))
    for i in range(len(text)):
        char= text[i]
        pos= (startPos[0]+ i* fontSize+ 10, startPos[1])
        color= fontColor
        # tm= makeTextDropMotion(char, fontSize, pos, color, 150*i)
        tm= func(char, fontSize, pos, color, fromTime+inter*i, dur)
        tmList.append(tm)
    return tmList
    

这里,将不同的文字特效函数作为参数传入即可,有比较好的扩展性。

最后是一个展示函数,用了imageio来制作gif图。这里注意两个地方,第一是展示时间应当是单文字运动时间的两倍。为了确保动感,当第一个文字到位时,最后一个文字恰好启动,所以时间是两倍的关系。
第二是制作GIF的延时应当与计算用的延时一致,这里都是50毫秒(20fps)。

def showTextDrop(text, startPos, func):
    fontSize= 50
    color=(255, 255,  0, 255)
    tmList= getMotionList(text, fontSize, color, startPos, 0, 1000, func)
    frames=[]
    outfilename='temp.gif'
    for i in range(0, 2000, 50):
        print(i)
        img= Image.new('RGB', (640, 360))
        # img= Image.open('back.png').resize((640, 360), Image.ANTIALIAS)
        # img = img.convert("RGB")   
        textImg= getTextFrame(tmList, i)
        r, g, b, a= textImg.split()
        img.paste(textImg, (0,0), mask= a)
        str1= 'tempAA.png'
        img.save(str1)
        im = imageio.imread(str1)
        frames.append(im)
    imageio.mimsave(outfilename, frames, 'GIF', duration=0.05) 
    
if __name__=='__main__':
    # showTextDrop('淡妆浓抹总相宜', (150,200), makeTextParaDrop)
    showTextDrop('淡妆浓抹总相宜', (150,200), makeTextDropMotion)

完整源代码

贴一下完整的代码。


from PIL import Image, ImageDraw, ImageFont
import imageio

fontName= r'.\happy1.ttf'

# 把每个文字与它的三个运动结合为一个基本单位
def newTextMotion(char, posFunc, sizeFunc, colorFunc):
    tm={}
    tm['char']=char
    tm['posFunc']= posFunc
    tm['sizeFunc']= sizeFunc
    tm['colorFunc']= colorFunc
    return tm

# 在指定的时间,计算文字的位置、大小、颜色等
def showText(img, textMotion, time):
    char= textMotion['char'] 
    pos= textMotion['posFunc'](time)
    size= textMotion['sizeFunc'](time)
    color= textMotion['colorFunc'](time)
    font= ImageFont.truetype(fontName, size)
    draw = ImageDraw.Draw(im=img)
    textSize= draw.textsize(text=char, font=font)
    tx= pos[0]- textSize[0]// 2
    ty= pos[1]- textSize[1]// 2
    draw.text(xy=(tx, ty), text=char, fill=color, font=font)

# 文字缩小
def makeTextShrink(char, toSize, toPos, toColor, offset, dur):
    def colorFunc(time):
        if time< offset:
            return (0,0,0,0)
        if time> offset+ dur:
            return toColor
        return toColor[:-1] + (50+ round((time-offset)/dur*200),)
    def sizeFunc(time):
        if time< offset:
            return toSize* 8
        if time> offset+ dur:
            return toSize
        return toSize*8 - round((time-offset)/dur* toSize*7.5)
    def posFunc(time):
        if time< offset:
            return (0,0)
        if time> offset+ dur:
            return toPos
        # return (toPos[0], round((time-offset)/dur*toPos[1]))
        return toPos
    return newTextMotion(char, posFunc, sizeFunc, colorFunc)

# 抛物线降落(有一个回弹效果)
def makeTextParaDrop(char, toSize, toPos, toColor, offset, dur):
    def colorFunc(time):
        if time< offset:
            return (0,0,0,0)
        if time> offset+ dur:
            return toColor
        return toColor[:-1] + (50+ round((time-offset)/dur*200),)
    def sizeFunc(time):
        if time< offset:
            return toSize
        if time> offset+ dur:
            return toSize
        return toSize
    def posFunc(time):
        if time< offset:
            return (toPos[0], 0)
        if time> offset+ dur:
            return toPos
        r= 0.75
        dur2= dur
        a= toPos[1]/(dur2* dur2* (1- 2* r))
        b= -2* a* dur2* r
        x= (time-offset)
        return (toPos[0], round(a* x* x+ b*x))
    # print(toPos)
    return newTextMotion(char, posFunc, sizeFunc, colorFunc)

def getTextFrame(tmList, time):
    textImg= Image.new('RGBA', (1280, 720))
    for tm in tmList:
        showText(textImg, tm, time) 
    return textImg

# 一行文字,给定所有参数,配置运动函数与延时
def getMotionList(text, fontSize, fontColor, startPos, fromTime, dur, func):
    tmList=[]
    inter= round(dur/ len(text))
    for i in range(len(text)):
        char= text[i]
        pos= (startPos[0]+ i* fontSize+ 10, startPos[1])
        color= fontColor
        # tm= makeTextDropMotion(char, fontSize, pos, color, 150*i)
        tm= func(char, fontSize, pos, color, fromTime+inter*i, dur)
        tmList.append(tm)
    return tmList

def showTextDrop(text, startPos, func):
    fontSize= 50
    color=(255, 255,  0, 255)
    tmList= getMotionList(text, fontSize, color, startPos, 0, 1000, func)
    frames=[]
    outfilename='temp.gif'
    for i in range(0, 2000, 50):
        print(i)
        img= Image.new('RGB', (640, 360))
        # img= Image.open('back.png').resize((640, 360), Image.ANTIALIAS)
        # img = img.convert("RGB")   
        textImg= getTextFrame(tmList, i)
        r, g, b, a= textImg.split()
        img.paste(textImg, (0,0), mask= a)
        str1= 'tempAA.png'
        img.save(str1)
        im = imageio.imread(str1)
        frames.append(im)
    # writeGif('temp.gif', frames, duration=0.1, subRectangles=False) #
    imageio.mimsave(outfilename, frames, 'GIF', duration=0.05) # 生成方式也差不

if __name__=='__main__':
    # showTextDrop('淡妆浓抹总相宜', (150,200), makeTextParaDrop)
    showTextDrop('淡妆浓抹总相宜', (150,200), makeTextDropMotion)


  • 10
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 可以使用Python编程语言和第三方库如Pygame或PyOpenGL来制作烟火特效。 Pygame是一个用于游戏开发的库,而PyOpenGL是一个用于3D图形编程的库。 这些库都可以帮助您在Python实现动画和图形,从而实现烟火特效。 ### 回答2: Python可以通过使用相关库和模块来制作烟火特效。以下是一个简单的实现示例: 首先,我们需要安装必要的库,如pygame和random。在终端中使用pip install pygame来安装pygame库。 接下来,创建一个新的Python脚本,并导入所需的库: ```python import pygame import random ``` 然后,设置屏幕的宽度和高度,并创建一个窗口: ```python width = 800 height = 600 screen = pygame.display.set_mode((width, height)) pygame.display.set_caption("Fireworks") ``` 在主循环中,我们可以设置一个变量来控制是否退出程序,并初始化一些必要的参数: ```python running = True # 初始化参数 particles = [] num_particles = 100 ``` 然后,我们可以创建一个粒子类来表示烟火中的单个粒子。每个粒子都有自己的坐标、速度和颜色: ```python class Particle: def __init__(self, x, y): self.x = x self.y = y self.vx = random.uniform(-1, 1) self.vy = random.uniform(-1, 1) self.color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) def update(self): self.x += self.vx self.y += self.vy self.vx *= 0.99 self.vy *= 0.99 def draw(self): pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), 2) ``` 在主循环中,我们可以使用循环来更新和绘制每个粒子: ```python while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False screen.fill((0, 0, 0)) # 生成新的粒子 if len(particles) < num_particles: particles.append(Particle(width/2, height)) for particle in particles: particle.update() particle.draw() pygame.display.flip() ``` 运行脚本,你将看到在窗口中生成具有烟花效果的粒子。你可以根据需要进行调整和改进,例如调整粒子的速度、颜色和数量,以及添加爆炸效果等。 这只是一个简单的示例,python提供了强大的库和工具可以用来创建各种各样的烟火特效。 ### 回答3: 要使用Python制作烟火特效,可以借助一些图形库和计算库来实现。 首先,可以使用Python中的图形库如Pygame或Turtle来创建一个窗口,作为烟火特效的画布。在画布上可以绘制各种形状的火花。 接下来,可以使用随机数来生成不同颜色和位置的火花。使用Python中的random模块来生成随机数,并应用到绘制的火花上。可以通过控制火花的位置、大小以及爆炸速度等参数,来让烟火特效看起来更加真实。 然后,使用循环来控制火花的爆炸效果。可以使用一系列的圆圈或者线条来模拟火花的爆炸效果。通过在每次循环迭代中更新火花的位置和大小,可以实现火花的流动和变化。 此外,可以利用渐变色或色彩过渡来增加火花特效的美感。可以使用Python中的色彩模块如colorsys或者PIL中的ImageDraw模块来实现颜色过渡效果。 最后,可以增加一些声音效果来完善烟火特效。可以使用Python中的声音库如pygame.mixer来添加爆炸声音,使整个烟火特效更加生动。 总之,使用Python制作烟火特效需要使用图形库、计算库和声音库等多种模块,并利用随机数、循环和颜色过渡等技巧来实现火花的绘制、爆炸和效果渲染等过程。通过合理组合这些技术和库,可以制作出逼真、华丽的烟火特效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

圣手书生肖让

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值