玩一下 imagemagick

imagemagick,在我这里大概有两大类用途:

  1. 没有 ps,下个 ps 贼大,怎么办?命令行修图吧。。。
  2. gif 加速(配合 ffmpeg)

不过这玩意那是相当复杂。。。以下是一些入门教程:

文档:

请注意,本文完成时所使用的 Imagemagick 版本为 7.0.10-48 Q16 x64 2020-12-10(windows),修复了 Imagemagick 无法直接将 mp4 转换为 gif 的问题,可通过 chocolatey 安装并通过 magick -version 查看版本;在 Linux 上还安装了老版本的 Imagemagick,版本为 6.9.10-23 Q16 x86_64 20190101,通过 ubuntu 19.10 的 apt 安装指令安装,可通过 convert -version 查询版本。

图像配字

适用场景:表情包制作(x

-gravity:文字位置,可选东西南北中(

-fill -stroke:文字颜色和边框

-pointsize:文字大小,必填

-kerning:文字间隔

-font:如果你要写中文的话。。。就得指定中文字体

-annotate:偏移,一般表情包的字也不会放最边边,还是要往中间偏点点~

1
magick .\0.jpg -gravity south -fill white -pointsize 400 -kerning 600  -stroke black -font 'SimSun-&-NSimSun' -annotate +0+150 '[内容]'   0_des.jpg

马赛克(伪)

后面的举例图有 nsfw 内容!我暂时还不知道怎么给图片打多边形马赛克 / 模糊。。。只能简单用白色多边形遮一下。

draw:后面跟的 polygon 是多边形的意思,要裁其他图形的话参考这里 draw。后面的参数是多边形的座标,具体座标挺多画图软件能查看的(比如 irfanview),甚至 magick 自带工具 display 命令都可以。后面座标就按单向连通图的顺序,顺时针逆时针都可以。

1
magick .\0raw.jpg -fill white  -draw 'polygon 342,2031 125,2274 330,2809 677,2851 652,2470' .\0.jpg

纠偏 + 裁剪

经常收壁纸,有的画集是有外框的,我有强迫症要把外框剪掉(而且有外框做壁纸也不好看)。另外,有的画集是扫描的,但扫描的时候没有彻底放正,导致剪裁的时候会发现有一点点歪。通常我会使用 photoshop 的透视剪裁来处理这类图片,不过这次 magick 有比较自动化的命令,来试试效果怎么样。

样张(不要吐槽这是张色图,我暂时懒得找又歪又有边框的图了,扫了一眼手机的图册就只有这张,而且这张图片和外框相接触的部分还带有一些彩边,非常适合检测算法的能力):

另外,下面的样图因为图床大小限制原因被我转成 jpg,但我操作的时候用的是原图 png。

方法 1:用 photoshop 裁剪工具(不纠偏)

手工裁剪,尽量保留最大方形可见面积,且几乎不容忍任何解析度较低的彩边。

最后得到 2427x3429 大小的图片。

方法2:用 photoshop 透视裁剪工具(顺便纠偏)

手工像素级裁剪,尽量保留最大方形可见面积,且几乎不容忍任何解析度较低的彩边。

最后得到 2441x3434 大小的图片。目前最标准和完美的结果,也是下面操作的基准目标。

方法3: 直接使用 magick 自动检测

-fuzz 模糊检测因子,越大容忍度越低,裁掉的内容也就越多

-border 边框最小尺寸

+repage 消除位移属性(可有可无)

-trim 进行裁剪

1
convert 005.png  -fuzz 73% -border 1x1 +repage -trim 005_magick1.png

显然裁少了一截。最后只得到 2410x3293 尺寸的图片。fuzz 参数也没有调整余地了,调小成 72 右上角的字就消不掉。右上角的字和头发颜色相仿似乎使 magick 识别出现了混乱。另外右下角还有显而易见没裁掉的白边。

加一个代表指定边框颜色的 -bordercolor 参数,fuzz 参数就要提高到 85。color 具体能填什么,参考这里:Color Name

1
convert 005.png -bordercolor '#ffffff' -fuzz 85% -border 1x1 +repage -trim 005_magick1.png

分辨率变成 2412x3294。问题依旧。

去掉 -boader 参数。fuzz 可以降低到 60 多,但此时裁掉的像素就太多。差出数量级,这里就不给数据了。

方法 4:自动旋转后使用 magick 检测拼接

-deskew 是自动倾斜校正参数。

1
convert 005.png -background white -deskew 40% 005_tem.png

然后

1
convert 005_tem.png  -fuzz 73% -border 1x1 +repage -trim +repage 005_magick2.png

分辨率变成 2412x3269。仍然不完美,但白边没那么明显了。另外我尝试过 -deskew 100% 这个参数,结果二次处理后白边更大,效果不好。

方法 5:magick 检测拼接,然后再自动旋转

1
2
3
convert 005.png  -fuzz 50% -border 1x1 +repage -trim +repage 005_tem.png   
convert 005_tem.png -background white -deskew 40% 005_tem2.png
convert 005_tem2.png -fuzz 73% -border 1x1 +repage -trim +repage 005_magick3.png

虽说分辨率甚至是图像和方法 4 出来的几乎都一模一样,不过 tem2 和 tem 两张图对比,后者有明显的纠偏痕迹了。但究竟是 magick3 trim 的时候又纠回来了还是之前的 trim 带了纠偏效果我就看不出来了。

方法6(magick 7 专用)

参考文章:Enhanced -trim operator

注意这里的 -define trim:percent-background=15%,含义和上面的 -fuzz 完全相反,越小裁掉的内容越多。

1
magick 005.png  -define trim:percent-background=15% -define trim:background-color='#ffffff' -trim 005_tem.png

分辨率 2440x3431。接近手工调整的结果了,但看起来还是有白边。特别是纠偏以后:

1
convert 005_tem.png  -background white -deskew 40%  005_tem1.png

尝试使用纯粹的 trim 方法(也就是方法 3),发现无论如何都剪不掉那些细小的白边。甚至把 -fuzz 参数调到 80 了,把图片上部剪掉一些了结果右侧的细小白边也还没被剪掉。

继续用本方法裁一遍

1
magick 005_tem1.png  -define trim:percent-background=15% -define trim:background-color='#ffffff' -trim 005_magick4.png

极限了,还是有肉眼可见的白边,但再把 -define trim 参数调小就又影响画面了。白边的大小,相比只纠偏以后的效果,勉强是可以接受的。此时分辨率为 2437x3429。

方法7:将白色边框中的多余的部分用 gui(画图 / ps)剪掉,再处理

既然纠偏和裁剪顺序定下来了,那我们顺便把命令也集成在一起。

看起来虽然剪掉了多余的部分让 -fuzz-define trim:percent-background 不需要那么高(低)就能识别出真正边框的大致轮廓;但要确定下具体轮廓,好像还是不行(意思是还是有白边),看起来应该是纠偏没有办法纠的太正?

-fuzz 下:

1
convert 0052.png   -deskew 40% -fuzz 70% -bordercolor white -border 1x1 +repage -trim 005_magick5.png

分辨率 2448x3434。这次本方法能剪出一个比较完整的图像而不会把头发的一部分都给当框削了。

-define trim:percent-background 下:

1
magick 0052.png  -define trim:percent-background=15% -define trim:background-color='#ffffff' -trim -background white -deskew 40% -define trim:percent-background=15% -define trim:background-color='#ffffff' -trim 005_magick6.png

分辨率 2439x3431。白边反而还比 -fuzz 那边要大了,效果还比没有用 gui 修改前的还差。。。(也许是我命令写的有问题,但我感觉就算命令写的没问题白框也削不掉)

方法 8:去除噪点

就这样放弃了吗?不!我又查到了一篇新的参考文章:Trimming exterior empty space with ImageMagick does not work on scanned documents,说是扫描件的噪点会干扰软件的判断。

那就试试先去噪点:

1
convert 0052.png -write MPR:source -morphology close rectangle:3x4 -morphology erode square    MPR:source -compose Lighten -composite -morphology erode square    MPR:source -composite -morphology erode square    MPR:source -composite -morphology erode square    MPR:source -composite -morphology erode square    MPR:source -composite -morphology erode square    MPR:source -composite -morphology erode square    MPR:source -composite -morphology erode square    MPR:source -composite -morphology erode square    MPR:source -composite 0053.png

再用 -fuzz。合起来的命令效果不如分开的,那就保险起见用分开的命令。-fuzz需要进一步调低。

1
2
convert 0053.png -background white -deskew 40% 005_tem.png
convert 005_tem.png -fuzz 50% -border 1x1 +repage -trim +repage 005_magick7.png

分辨率 2445x3434。仍有白边。

1
2
3
magick 0053.png  -define trim:percent-background=15% -define trim:background-color='#ffffff' -trim 005_tem.png
magick 005_tem.png -background white -deskew 40% 005_tem1.png
magick 005_tem1.png -define trim:percent-background=15% -define trim:background-color='#ffffff' -trim 005_magick8.png

分辨率 2737x3429,有白边。


结论:在这个时间点,不好用。

图像拼接

多张表情包合成(x

-append:竖着拼。如果是 +append 就是横着拼。

-resize:几张图中如果不是尺寸一致一定就会有的图长有的图短。这就要看个人考量了,比如要竖着拼的话,是把窄的图等比缩放到和宽得一样宽,还是把宽的图缩放到和最窄的一样窄,那就在要缩放的图后面加 -resizeresize 的参数是 长x宽,如果有其中一个参数不用改动可以留空,但是要保留 x 号。

1
convert a.jpg  b.jpg -resize 814x -append   0.jpg

tgs 转换与加速

tgs 是 telegram 内动态表情包的专用格式。telegram 内的表情包可以通过机器人 @Stickerdownloadbot 导出单张或批量导出一整个表情包系列的图片,对于静态图片 bot 会同时导出为包含三种不同格式内容的压缩包;但对于动态图片就只会导出为一个内含 tgs 格式文件的压缩包,后续就还需要通过以下方法进行转换才能在其他地方使用。

tgs 转换

lottie

桌面平台,python 里面一个叫 lottie 的包,建议在 Linux 下使用,windows 下安装繁琐;

linux:

1
2
3
4
5
pip3 install lottie
sudo pip3 install --upgrade pip
pip3 install cairosvg opencv-python
pip3 install lottie
lottie_convert.py 0.tgs 0.gif

windows:

参考https://weasyprint.readthedocs.io/en/stable/install.html#windows,先安装 tschoonj/GTK-for-Windows-Runtime-Environment-Installer

1
2
3
4
5
6
pip install cairosvg pillow
pip install opencv-python
python -m pip install --upgrade pip setuptools
python -m pip install WeasyPrint
pip3 install lottie
python lottie_convert.py 0.tgs 0.gif

shu

ios 上的 shu,美区有售。可将 tgs 批量导出为各种格式,如 webp、gif、pngs 等。

tgs-to-gif (12.14 更新)

上面两个软件,前者免费但容易出现各类错误,且安装繁琐;后者需要付费但效果尚可。

最近又出现一个新的 tgs 转换工具 ed-asriyan/tgs-to-gif,前面两个工具转换一些 tgs 会出现重影(经过测试不是下面我 gif 速度优化的锅,而是转换出来的帧里面本身就有重影的帧出现),这个工具基本解决了重影的问题,且大部分 gif 也不存在速度过慢的问题。缺点是转换出来的 gif 质量低于前面两个软件,且在 windows 的 irfanview 下播放会出现花屏现象,原因不明。

在 pc 和虚拟机上上使用建议借助 nodejs 安装;在国外 vps 上使用建议借助 docker 安装。

原因嘛,docker 方便但因为网络原因安装速度可能会很慢,docker 内部比较难上代理,docker 加速器在这里无效因为跑 docker 的时候我发现这个东西不仅拉镜像还在跑 apt;但 vps 上用 nodejs 还需要非 root 账号,因为本项目用到了 puppeteer,还不一定成功,我在两台 debian 的机子上都掉坑一台找不到 browser 另一台装不上 gifski,找不到 browser 那一回 nodejs 我用了 15,后面发现 15 不行;装不上 gifski 是因为 cargo 都装不上,掉进新坑用命令 rustup install stable 运行到一般就被 kill 了估计是内存都不够了,也不想划虚拟内存了,懒得爬出来了。

另外 nodejs 运行时的运行目录必须在项目内(但 tgs 文件不需要放在项目内),docker 不需要但写 tgs 文件夹路径的时候得写绝对路径,各有各的麻烦。

nodejs:

1
2
3
4
5
6
7
curl https://sh.rustup.rs -sSf | sh #并 ctrl+d
curl -sL https://deb.nodesource.com/setup_14.x | bash - #目前不支持15
apt-get install -y nodejs
cargo install gifski
git clone https://github.com/ed-asriyan/tgs-to-gif.git
cd tgs-to-gif
npm install

即可使用

1
2
3
4
#转换多个 tgs
node cli.js 0.tgs 1.tgs...
#转换整个文件夹
node cli.js /home/zbttl/tgs

docker:

1
2
3
git clone https://github.com/ed-asriyan/tgs-to-gif.git
cd tgs-to-gif
docker build -t tgs-to-gif .

即可使用

1
docker run --rm -v <文件夹绝对路径>:/source tgs-to-gif

(12 月 23 日更新) docker 版和 nodejs 效果居然不一样。。。。docker 版出来的效果需要加速,所以只推荐 nodejs 版。至于为什么效果会不一样。。。我猜测是因为 gifski 版本的原因,docker 里面 gifski 版本还是 0.10.4,我在实机中安装的版本已经是 1.22 了。但话说回来,issue 里面刚好就有个人吐槽长度宽度参数不生效 [The –height HEIGHT –width WIDTH don’t work #25](The –height HEIGHT –width WIDTH don’t work #25),作者给的意见是更换为 gifski 旧版。。。。另外一点,托之前忘记安装 gifski 的福,我看到了部分运行命令:

合着这质量还只有百分之 80。。。但我在项目中完全查不到这些个帧数质量啥的在哪调,所以没辙。

先说一下踩进去的坑,不想看的可以跳过下面这一段:

鉴坑扯淡

样张:

用 shu 转完后,发现发出去的图片在 qq 中播放速度相当慢 。

肯定是啥参数不对。。。查参数的软件,我一开始只记得查视频用的 mediainfo,打开一看,这玩意就不是用来看 gif 参数的。。。只有一个图像格式 87a 和我手上其他 gif 不同,其他 gif 是 89a(后来的后来经过调查,87a 和 89a 的差别,是 87a 是旧标准,不支持半透明参数)。不过还是尝试转一下吧。

检测 GIF 版本的方法,图片确实变成 89a 了,但是出现了严重的重影。。。

后续我用了各种类型的软件转换和测试,大概的测试结果如下图:

类型 张数 码率 fps tbr duration delay irfanview 5s(循环次) windowsqq 10s androidqq(10s) 张数/时间 张数/时间+delay
ps转视频再改回gif 11 1646 33.33 33.33 0.33 0.03 16 16 20 0.03 0.06
ezgif(从webp转换) 13 1691 20 20 0.65 0.05 7 13 15 0.05 0.1
23 2395 33.33 33.33 0.69 0.03 8 8 12 0.03 0.06
ezgif(加速) 23 3481 50 50 0.46 0.02 8 8 12 0.02 0.04
ps改帧数 12 646 14 28 0.84 0.07 6 15 11 0.07 0.14
ps改帧数改延迟 12 452 10 10 1.2 0.01 25 15 9 0.1 0.11
imageonline 23 716 10 10 2.3 0 15 4 4 0.1 0.1
  1. 上面这些转换方法转出来的图片都是没有重影的;

  2. 前面的这些参数来自 ffprobe 和 imagemagick 的 identify 工具,ffmpeg 的 tbr/duration 参数含义参考这里:What does the output of ffmpeg mean? tbr tbn tbc etc?

    FFmpeg中的时间戳有三种不同的时基。实际打印的 值是这些值的倒数,即1 / tbr,1 / tbn和1 / tbc。
    我认为tbn是AVStream中来自容器的时基 。它用于所有AVStream时间戳。
    tbc是AVCodecContext中用于特定流的编解码器的时基 。它用于所有AVCodecContext和相关时间戳。
    tbr是从视频流中推测出来的,它是用户在寻找视频帧速率时希望看到的值 ,只是有时由于场速率与帧速率的关系,它是预期值的两倍 。

    时基:确定帧定时的依据;avstream:音频/视频顺序数据;容器:可以包含音频/视频数据通道的文件格式,例如avi,mp4或mkv;

    我想他们选择报告TBR,是因为ffmpeg对帧率实际是最好的猜测。在许多容器上,fps字段(更具体地说AVStream.avg_frame_rate是)不可用,因此不能真正依靠它。

    以及:What is video timescale, timebase, or timestamp in ffmpeg?]

  3. 有的情况下帧数越高播放速度反而越慢,不同平台下同样的两种图片有可能速度表现完全相反。这跟 gif 下的 fps 定义和各软件对 gif 定义的理解有关;

  4. 综合比较 ps 转视频加速改回 gif 效果是最好的。(又是 ps,ps 万能)

另外,shu 也可以把 tgs 换成其他多种格式,但直接能动的就两种:gif 和 webp。上面我用 ezgif 讲 webp 转成 gif,发现速度大体正常,综合参数,我提出一个大胆的假设:应该蛮多软件不看 delay 而是直接以张数作为播放速度的依据。至于为什么不看延迟?可能跟所谓 gif 零延迟有关:

1
2
3
4
5
6
7
8
好吧,它们很重要,那又是什么呢?因为许多应用程序不喜欢它们,或者处理不当。他们认为“零延迟帧”是一件坏事,即使您出于某种原因故意将它们添加到动画中也是如此。
这是我了解或被告知“做错事”的应用程序的摘要...
金普 不会保存“零延迟帧”,它们总是向具有零时延的任何帧添加最小的时延。:-(

火狐 在这样的帧上会稍有非零的停顿。大概是这样,根本没有时间延迟的动画会耗尽所有计算机的CPU周期。但是firefox,如果动画的总显示时间为非零,则“ ”仍不能放松该限制。

IE浏览器 最小时间延迟为6厘秒,并且忽略小于此时间的任何延迟。
如果任何图像帧超出了第一帧设置的动画范围,Internet Explorer 8版本也会失败(立即重新启动循环)。我将其归类为主要错误。

因为 0 延迟可能报错,所以干脆就不用延迟来计算了。。。。

如同这篇文章:Top 10 Best GIF Speed Changers: How to Speed up or Slow down GIF Easily 给出的所有手段几乎都是在 gif 的 delay 参数上动手脚,而 delay 参数又似乎和 fps 挂钩(参考这里:Do 60 FPS GIF’s actually exist? Or is the maximum 50 FPS?),但如果软件不认可你的 delay 参数,那自然就没有用。那么 gif 就会按照 timebase,也就是 0.04s 一张这个速度进行播放。另外为什么说 delay 似乎和 fps 挂钩呢?因为 delay 设置为 2 和 3 的时候,ffprobe 显示帧数分别为 50fps 和 33.33fps。但!delay 设置为 1 的时候,ffprobe 又显示帧数只有 10fps。。。可能是因为触发了 ffprobe 的最小延迟机制(要求最小延迟为 2,只能显示 50fps)。其实不止 ffprobe,还有许多看图软件的最小延迟也设定为 2。如果 delay 写 1 的话 gif 显示速度反而会变慢。

本次转换的主要目的是 tgs 转换的 gif 在 qq 上播放较慢。不过后续测试发现是部分 gif 调整 delay 后播放速度没有改观;而本身 delay 较大的 gif 修改 delay 后明显感觉播放速度加快。至于那部分能够修改 delay 加速的 gif 有没有 delay 阈值我倒是没有认真进行过测试。但减少帧数是一定能奏效的(

另外除了重影,某些软件转换到 gif 过程中会导致背景从透明变为白色,这也是要解决的问题。

减少 gif 张数,我目前得知两种方法:

  1. 抽取关键帧(Image.n_frames),关键帧的概念参见:Pillow (PIL Fork) Documentation

    Image.n_frames: intThe number of frames in this image.This attribute is only defined by image plugins that support animated images. Plugins may leave this attributeundefined if they don’t support loading animated images, even if the given format supports animated images.Given that this attribute is not present for all images usegetattr(image, “n_frames”, 1)to checkthe number of frames that Pillow is aware of in an image regardless of its format

    但只对那些优化过的 gif 有用(优化过的 gif 是啥意思?参考压缩 gif 一文中的参考文章 3 gif modification)

  2. 转换成其他格式(比如视频)然后加速后再转回去。上面用 ps 处理过一次,但 ps 是个 gui,批量转换肯定不能用 ps。

另外,对于修改 delay,也建议使用 imagemagick 而不是那些原理不明的工具。

1
convert -delay 2 0.gif 0_change.gif

具体修改到什么程度可以参考以下两篇文章:

  1. Do 60 FPS GIF’s actually exist? Or is the maximum 50 FPS? 上面引用过了,另外这篇文章里面还有个「暴论」

    这意味着,对于100 FPS的图像速率,最小值为1(在大多数显示器上很难呈现…),对于50 FPS的图像速率,其下一个最小值为2,而对于下一个值为3图像速率为33.3 FPS。因此,完全不可能达到60 FPS。

    请注意,此扩展是针对少数几秒钟延迟的帧(最大延迟约为600秒),因此1/100秒的分辨率就足够了。这当然不是视频的意思,这就是为什么该字段编码延迟而不是帧速率的原因。

    制作视频GIF确实是对规范的滥用(即使现在如此普遍,以至于大多数人可能没有意识到这一点,就像大多数人没有意识到GIF和JPEG使用不同类型的压缩一样,并且应该被使用)在不同种类的图像上)。

  2. How to Change Animated GIF Speed

转换后听说还可能遭遇再次转回 mp4 出错的问题,可以参考这篇文章:(原)关于使用imagemagick将gif叠加到图片或者画布上的方法,以及疑难杂症(我一开始解决重影问题也是看得这篇文章,后面发现下面正文的参考文章中有更详细的理解,就是比较长)

除此之外还有很多神秘问题,比如转换后最后一帧和第一帧之间有停顿,闪屏,花屏等,某些问题可以看压缩 gif 一文中的参考文章 3 gif modification。


转换为 tgs 后可能会出现的问题

回到正题。总结一下 tgs 转换到 gif 后,要让转换的 gif 达到能看的级别,需要解决:

  1. 转换前动画速度过慢
  2. 转换后的重影
  3. 转换后透明度丢失

操作后建议用一些工具检测一下参数(比如 delay、张数等)

  1. ffprobe(ffmpeg 随附,可显示码率、tbr/duration、fps)

    1
    ffprobe 0.gif
  2. imagemagick 中的 identify 工具(magick7 以后的版本都要以 magick 命令打头)

    1
    (magick) identify 0.gif

    identify 主要用来看延迟的,那么可以修改一下命令:

    1
    identify -verbose 0.gif  | grep Delay

    或者用 identify 自身的通配符(参考:Percent Escape HandlingImagemagick GraphicsMagick image mean command

    1
    identify -format "%m:%f %wx%h %T\n" .\0.gif
  3. gif_anim_montage 脚本。可将每帧的形状,处理方式和延迟以顺序的方式集合到一张图片中。

    1
    ./gif_anim_montage 0.gif 0.jpg
  4. 查看视频 / gif 总帧数

    1
    ffprobe -v error -count_frames -select_streams v:0  -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 0.gif 

转换为 tgs 后对于动画速度较慢的处理方法

ps 转换加速法

就是我一开始说的方法,因为效果不错先放上来。

  1. 安装相同年度版本的 ps 和 media encoder,可能要装 pr(因为经过试验 2019 ps cc 无法唤起 2020 ps pr)

  2. 在 ps 中打开 gif,点击窗口 -> 时间轴

  3. 点击时间轴右下角的“转换为视频时间轴”按钮

  4. 点击“渲染视频”(转换为视频时间轴成功后这个按钮就在附近),渲染为有 alpha 通道的 quicktime 视频(否则透明背景就会强制被白的背景填充)。

  5. 打开导出的视频,点击时间轴上面的小箭头,调整至相应速度(比如加速两倍,调整为 200%)

    小箭头.jpg

  6. 文件->导出->存储为 web 可用格式,按自己的习惯调整参数即可。

    0.gif

    用命令 4 解析出来显示 23 张,和原视频相比没少?但用命令 3 解开就会发现实际上是实施了优化。虽然张数增多了,但实际大小应该是降低的。

ps 直接加速法

  1. 在 ps 中打开 gif,点击窗口 -> 时间轴
  2. 点击时间轴右下角的“转换为视频时间轴”按钮
  3. 点击时间轴窗口右上角,选择设置时间轴帧速率功能
  4. 降低帧率。然后修改延迟
  5. 导出即可

帧数减少的同时 delay 参数也会增加。另外这个方法其实没法准确控制最后获得的张数,要慢慢调,好处就是不用导出到视频。

webp 转换法

需要 imagemagick 7+

-coalesce:把 gif 每帧拆分出来

-set dispose background:让下一帧显示时先清空上一帧显示的所有内容(把上一帧被描绘的像素统统删成透明) 。不使用这个参数就会造成重影。也可以把这个参数写在输入文件的前面,并改成 -dispose background

1
magick  "(" 0.webp -coalesce ")"  -set dispose background -loop 0 ./0.gif

但在 windows 下最新版本好像可以直接转了。。。

1
magick 0.webp 0.gif

最后成品帧数只有 13。

借助 ffmpeg 转换加速

setpts=0.5*PTS:加速两倍

-vcodec qtrle:一个支持 argb(带透明通道)的编码。也可以换为 -vcodec png(rgba 编码,没有本质上区别)和 -vcodec rawvideo(体积很大,可能还要配合 -pix_fmt rgba

1
ffmpeg -i 0.gif -movflags faststart -vcodec qtrle -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -filter:v "setpts=0.5*PTS" 0.mov

然后使用 magick,-delay 需要用 ffprobe 查一下原 gif 的还原进去。不过光是 qq 用不管也可以。

1
convert -dispose background -quiet -delay 3 0.mov 0_change.gif

01.gif

如果遭遇最后一帧和第一帧直接有卡顿,需要加上 -deconstruct 参数。要注意使用此参数后动画速度可能进一步提高(原因不明),需要把 -delay 值拉大。

1
convert -dispose background -deconstruct -quiet -delay 5 0.mov 0_change.gif

此时输出的 gif 已经足够小,没有必要再使用优化参数进行优化(另一个原因是我使用 -layers optimize 参数后部分文件大小反而增加了)。