疯狂的转换器GIF'ok为电报的动画贴纸

而不是一千个字...


xZibit也很高兴,因为这里将GIF插入到贴纸中,然后插入到KDPV的GIF中!

现在介绍实现细节。

一切始于在Telegram开发人员的聊天中讨论即将推出的功能:

Bohdan Horbeshko,[04/04/19 20:21]嗯,但是该漫游器可能只会接受gif,然后进行转换... |维塔利[07/04/19 20:22]从gif到杰森?我会看的:)))| Bohdan Horbeshko,[04.07.19 20:22]为什么不呢? JSON中有一个PlayCanvas模型编辑器。 |维塔利,[04/04/19 8:23 p.m。],gif怎么样?逐像素导出? :) | Bohdan Horbeshko,[04/04/19 20:24]当然,IT界已经看到并且不会容忍这种扭曲。

一个男人说-一个男人做到了! Pillow和svgwrite的第一个原型是在一天之内完成的,该原型将GIF解析为像素并将其转换为带有SVG预览的矢量正方形。

有趣的事开始了……

他们说JSON是一种开放格式。


到现在为止,使用Telegram中的格式,他们一直在欺骗。 支持GIF动画-实际上,它们已转换为MP4视频。 支持贴纸-将它们上传到PNG,但转换为WebP。 这次一切都更加诚实:在入口处,然后在出口处。

对于动画贴纸,Telegram不使用GIF,视频,甚至不使用某些公认的矢量图形格式,例如SVG,或者上帝禁止克苏鲁! -快闪 它使用一种新的格式,这种格式出现在Airbnb-Lottie的机翼之下。 到目前为止,他在移动开发人员中享有一定的声誉,但是由于Telegram的支持,它可能会越来越受欢迎。

本质上,Lottie文件是JSON序列化的Adobe After Effects项目,可最大程度地利用此程序的所有功能。 遗憾的是,有了显示器, 一切都变得不那么乐观了 。 尽管有很多现成的“官方”库可用于渲染Lottie,但仅适用于Telegram涵盖的平台:Android,iOS,Qt和Web-所有格式中仅部分实现了该格式。 Telegram走得更远,并限制了受支持功能列表,并以其自身的格式“出现”,这与通常的Lottie不同,仅在于打包在GZip和"tgs": 1参数中"tgs": 1 。 我想我知道Denis Popov现在在哪里工作! :-)

而且,如果针对不同平台的库文档一切都很好,那么,a,至少无法找到关于格式设备的某些描述-仅在lottie-web来源中找到JSON格式。 为了理解格式的一般概念,我不得不在现有动画中进行修改。 实际文件与方案之间也存在差异:特别是在类型4的层中 ,根据方案,嵌套对象存储在"it"属性中-但是,在实际文件中,密钥称为"shapes" ,而"it"不起作用。

格式的细微差别:

  • 文件由图层组成。 与GIF不同,这里的每一层可以有任意的显示开始和结束时间。 可以对图层应用各种变换(更确切地说, 这是必要的 ):缩放,旋转,更改透明度等。 图层甚至可以是三维的(禁止电报)。
  • 一层由“形状”组成。 它们有很多类型,有些不能在Telegram中使用。 实际上,要显示一个图层,它应该包括三种形状:路径(在完成的动画中,通常是"sh"类型-贝塞尔曲线;到目前为止,转换器仅使用"rc"类型-矩形),填充( "fl"类型)和变换(输入"tr" )。
  • 您甚至可以包括栅格元素,创建文本图层,以及通过表达式在图层和形状参数之间建立关系。 Telegram也禁止所有这些好东西。

第一个问题从这里直接产生: 冗余 。 尽管最近已将转换参数的默认值添加到JSON方案中,但是它们未在库中实现。 因此,明确要求他们仍然是必要的。

看来这根本不是问题吗? 即使是简单的GZip,也可以很好地压缩公然重复的数据,并且1 MB的原始JSON神奇地变成了几十个千字节,悄悄地爬升到所述的64 kB限制。 在那里!

我加载了,这意味着胖乎乎的动画会在Telegram中平静地显示抽奖网站-在这里,代替模糊的有条件的美丽像素艺术,静态的模糊外观是这样的:



这是什么?! 但是事实证明,解压缩的数据显然有1 MB的未指定限制 。 Telegram团队的代表迅速确认了这一点,并宣布将限制增加到2 MB。

即使解决了这些问题,旧版Telegram的用户也无法访问超过1 MB的未压缩数据且不包含转换的标签。 因此,将来可能必须遵守这些限制。

透明度很重要。


枕头和OpenCV一起可以称为Python中图像处理的行业标准。 此外,它在GIF功能方面也非常清晰:它支持索引颜色并可以访问调色板。 它支持将像素图转换为NumPy数组,这对于生产处理很重要。 甚至收集颜色统计信息! 但是也有缺点:

  1. 没有获得透明颜色索引的记录方法。 作为临时解决方案,我不得不假设透明色是最常见的,但是在实际的GIF中,情况并非总是如此。
  2. 帧之间有延迟的相同之处:枕头仅将帧本身作为图像序列提供,而没有有关延迟的信息。
  3. 有时,部分帧会错误地叠加。

因此,我不得不寻找替代品。 gif2numpy模块充当它。 它针对GIF功能进行了“锐化”处理,可以访问图像和单个帧(包括GCE)的所有技术属性。 因此,他解决了读取延迟的问题。

事实证明,透明度根本不支持gif2numpy:颜色立即转换为三个通道,其位深度以字节为单位,而无需考虑位深度和保存颜色索引。 幸运的是,该模块包含一个文件,因此不难将其包含在项目中,并通过保留颜色#FE00FE保持透明来#FE00FE进行修改。

部分框架问题并非微不足道。 gif2numpy 尝试将这样的帧覆盖在前一帧上,但是它不检查overlay参数,这就是为什么总是不能得出正确结果的原因。 为了不弄乱标记, --unoptimize使用带有--unoptimize键的gifsicle初步图像处理-将部分帧转换为完整帧。 同时,这导致他们使用全局调色板,从而消除了在使用自己的框架调色板时分别处理透明颜色的需要。

用力挤压我


正方形是不错的选择,但是在这样的限制下,您需要表现出更多的想象力,否则,即使是微型GIF也不会“爬行”到Telegram中。

首先使用类似于RLE的方法 :将水平相邻的相同颜色的正方形合并为一个矩形。

接下来是利用Lottie功能。 由于每一层都有一个任意的开始和结束时间,因此您可以应用一种视频编解码器早已使用的技术,部分用于GIF本身:可以将保留在同一位置几帧的正方形合并为一层,在此期间显示更改其他几个。 到目前为止,仅对成对的相邻层实施。

发展计划


可以在这里大量应用的想法:

  • 识别任何大小的单色区域。 您可以将它们分成一组矩形,为此,有一个很好的算法 。 也建议将它们转换为轮廓,但是由于需要在Lottie中指示Bezier曲线的所有点而被遮盖了-在某些情况下,矩形可能更有益。
  • 识别运动。 同样,该技术早已在视频编解码器中使用。 如果同一轮廓不会改变帧与帧的形状,而只是改变坐标-而不是将其复制到多个图层上,而是将其放置在具有变换的一层上。
  • 识别一个区域与另一个区域的“覆盖”。 一个例子:

     ...... .O..O. ...... .OOOO. ...... 

    不同颜色的像素叠加在一种颜色的矩形上。 不必将这个矩形分解为一堆小矩形,也可以将其转换为复杂形状的轮廓,而无需将其覆盖在整个矩形的顶部。
  • 曲线和椭圆的矢量化,渐变的识别。 这会破坏像素的魅力,但会提高某些GIF的可压缩性几个数量级。 我保证,甚至在古老的“ Koloboks”中也有渐变! :D
  • 有损压缩。 首先,消除抖动,即使在过于平滑的图像中,也不会妨碍色彩的适度。 前面提到的文章可能会解决这个问题。

参考文献


Source: https://habr.com/ru/post/zh-CN460411/


All Articles