前两天一个做宝爸的朋友问我,他想给娃做一个“PR出生365天”的视频,就是那种数字从0开始滚动到365的动画,问我能不能用程序搞定,我一听,这不就是咱Go语言的拿手好戏嘛,说实话,这种数字滚动的效果,很多人第一反应是“得用前端JavaScript吧”,但如果你手里正好有个Go的项目,或者你想在服务端生成视频帧,那完全可以用Go整一个出来,咱今天就把这事儿掰扯清楚。
数字滚动的核心:不是动画,是帧
很多人一上来就搜“滚动动画库”,其实走偏了,数字滚动的本质是什么?是在每一帧画面上画出不同的数字,比如你想要1秒30帧的动画,总共跑2秒,那就是60帧,第1帧画0,第2帧画6(假设你要从0滚到365,每帧加6左右),就这么一路画到第60帧画365。
这里头有个关键点:数字的字体、大小、位置、颜色必须固定不变,变的只有数字本身,这样才能形成“滚动”的视觉错觉,如果你用Go搞这个,实际上是在做一张一张的图片,然后合成视频,常用的库有golang.org/x/image/font处理字体,加上ffmpeg合成视频。
第一步:准备数字图片素材
你不需要搞什么花里胡哨的3D滚动,咱就老老实实画数字,用Go生成一张图,上面写个数字,核心代码就几行:

package main
import (
"image"
"image/color"
"image/draw"
"image/png"
"log"
"os"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
"golang.org/x/image/math/fixed"
)
func drawNumber(num int, width, height int) *image.RGBA {
img := image.NewRGBA(image.Rect(0, 0, width, height))
draw.Draw(img, img.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src)
point := fixed.Point26_6{
X: fixed.Int26_6(width / 2 * 64), // 水平居中
Y: fixed.Int26_6(height/2*64 + 32), // 垂直居中,32是字体偏移
}
d := &font.Drawer{
Dst: img,
Src: image.NewUniform(color.Black),
Face: basicfont.Face7x13,
Dot: point,
}
d.DrawString(fmt.Sprintf("%d", num))
return img
}
这样每一帧数字就生成了。但我得说实话:basicfont.Face7x13这字体太丑,就7x13像素,像80年代计算器,如果你想效果好一点,得加载个TTF字体文件,比如用golang.org/x/image/font/opentype,我踩过坑,建议大家直接用系统字体,比如微软雅黑或者思源黑体,不用自己去调像素。
第二步:生成365帧图片
从0到365,总共366帧(因为含0),但是你要不要真生成366张图?看情况,如果你的视频是30帧/秒,跑365个数只需要约12秒,但0到365的步长是1,那每一帧只跳一个数,看起来很平缓。如果你想要更“滚动”的感觉,把步长调大,比如每帧跳5个数,这样数字跳得快,视觉上就像在滚动了。
我一般这么算:
| 参数 | 值 | 说明 |
|---|---|---|
| 起始数字 | 0 | |
| 结束数字 | 365 | |
| 总帧数 | 73 | 每帧跳5个数 |
| 帧率 | 24 fps | 约3秒跑完 |
| 总时长 | 73/24 ≈ 3秒 | 节奏刚好 |
代码里加个循环,每一帧文件名按顺序命名,比如frame_001.png、frame_002.png。
for i := 0; i <= 365; i += 5 {
img := drawNumber(i, 1920, 1080)
filename := fmt.Sprintf("frame_%03d.png", i/5)
f, _ := os.Create(filename)
png.Encode(f, img)
f.Close()
}
第三步:合成视频,这里有个坑
Go本身不直接生成视频文件(除非你用github.com/3d0c/gmf这种FFmpeg绑定库),更省事的办法是:生成图片序列后,用FFmpeg命令行合成,你在Go里可以调用os/exec执行:
cmd := exec.Command("ffmpeg",
"-framerate", "24",
"-i", "frame_%03d.png",
"-c:v", "libx264",
"-pix_fmt", "yuv420p",
"birthday_365.mp4",
)
cmd.Run()
敲黑板:这里如果你的数字图片尺寸不是16:9,最好先统一尺寸,不然压缩出来会有黑边,我就吃过这个亏,生成的1920x1080图片,结果FFmpeg默认加了个16:9的裁剪,数字都歪了,解决办法是加参数-vf "scale=1920:1080,setsar=1"。
优化:让数字真正“滚动”起来
前面生成的其实是静态数字跳变,不算滚动,真正的数字滚动应该像老式机械码表那样,数字从上往下翻,如果你想要这种效果,那就得在每帧里画多个数字的重叠渐变。
比如第1帧显示“0”在底部,上方是半个“1”;第2帧显示“1”在中间,上方是半个“2”……这个用Go做就有点费劲了,因为你得手动算每个数字的垂直偏移和透明度,我试过一种取巧的办法:不画单个数字,画一竖排数字,然后通过裁剪显示不同部分,比如生成一张长条图,从上到下写着0、6、12、18……365,然后每一帧只取这个长条图的一部分,往上移动几个像素,这样就是真正的“滚动”了。
代码思路:
// 先生成一个长条图,所有数字竖着排
longImageHeight := (365/5 + 1) * singleHeight
longImg := image.NewRGBA(image.Rect(0, 0, width, longImageHeight))
for i, num := 0, 0; num <= 365; i, num = i+1, num+5 {
drawSingleNumber(longImg, num, 0, i*singleHeight)
}
// 每一帧裁剪不同的y起始位置
for frame := 0; frame < totalFrames; frame++ {
yOffset := frame * stepPixel
subImg := longImg.SubImage(image.Rect(0, yOffset, width, yOffset+height))
// 保存subImg为帧
}
这个方法的好处是,数字之间没有跳变,像真的在滚动。缺点呢? 长条图可能超级大,365个数,每个数字高度100像素,那就是36500像素高,一张PNG可能几十MB,不过对于现代电脑,内存撑得住。
实际做出来的效果怎么样?
我给我朋友做了一版,白色背景,黑色数字,字体用的思源黑体粗体,数字大小占了画面三分之一。结果发朋友圈被不少人问“怎么做的”,但是说实话,回看的时候发现一个问题:数字滚动的速度太快了,不到3秒就跑完,观众根本来不及看清数字的变化,更别说感受“365天”这个含义了,所以后来我改了策略:前100帧慢慢滚(每帧加1),中间100帧正常滚(每帧加3),最后165帧变成逐帧跳(每帧加1),这样最后阶段有个“冲刺”的感觉,这算是我自己踩了个坑,分享给大家。
如果你只是想做一条短视频,不是非得用Go,用Premiere Pro里的“基本图形”面板,建一个文本图层,打上数字表达式,效果更快,但如果你像我一样喜欢用程序控制一切,或者你要批量生成100个宝宝的视频,那Go绝对是性价比最高的选择——跑一次脚本,躺平等视频出来,多省心。
工具选对了,代码也就几十行,最有意思的部分其实是调参数,看数字以什么速度滚动最舒服,那个过程像是给视频调“呼吸节奏”,下次你要是想给自家宝贝做个这样的视频,不妨从今天说的这几个步骤入手,遇到卡住的地方,回看下字体加载那部分——八成是字体路径写错了。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://www.hljbesthome.com/fnagchan/1125.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《用 Go 语言做个PR出生365天数字滚动特效?这事儿真没那么玄乎》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:前两天一个做宝爸的朋友问我,他想给娃做一个“PR出生365天”的视频,就是那种数字从0开始滚动到365的动画,问我能不能用程序搞定,我一...