导读
在上一篇文章中,我们揭秘了如何将「动效描述翻译为动效代码」——从Lottie导出CSS/Animated代码。本文,我们将探讨动效平台中的「多种序列帧格式自动转换」功能,实现设计与研发工作流的解耦,减少兼容性处理的工作量。
一、项目背景
在项目开发过程中,对序列帧动效进行格式转换的主要目的是提高动效的兼容性和性能。不同的动效格式(如APNG、AVIF、WEBP等)在浏览器支持、文件大小、加载速度等方面有差异。通过序列帧转换,研发同学可以根据使用场景,选择合适的格式,确保动效在不同平台上的流畅展示。此外,序列帧动效可以被转换成更高效的格式(如AVIF或WEBP)能显著减小文件大小,提升加载速度,优化页面性能和提升用户的体验。
以往,动效交付方式存在两个主要问题:一是研发同学在使用不同类型的序列帧动效时,必须依赖设计同学使用AE等工具进行格式转换;二是研发同学在实际应用动效时,往往需要根据不同的使用场景和展示效果编写复杂的兼容性处理逻辑。这两个环节都存在冗余的工作量,影响了效率。
为了优化这些流程,我们在动效平台上提供多种序列帧格式自动转换的功能,实现设计与研发工作流的解耦,降低彼此间的依赖。同时,平台确保导出的动效能够直接被研发同学使用,从而减少兼容性处理的工作量。
现在,动效平台通过接入公司内部平台提供的序列帧素材转换能力,从动效交付到导出,再到实际使用,为前端开发提供了最佳的使用方式。本文将重点介绍动效平台在序列帧动效格式转换方面的能力和流程。
二、序列帧格式概述
动效平台支持多种序列帧动效导出格式:
其中导出动图包含APNG、WEBP 和 AVIF 三种动效格式。
同一个序列帧动效,如:
在平台中导出不同动效格式的产物参数如下:
在选择项目中的动效格式时,我们可以结合序列帧动效的特点和适用场景来做出合适的选择。以下是常用序列帧的特点:
Lottie 序列帧图片
好处:可以使用 Lottie 的官方库进行播放,可以跨平台播放,可以保证一致性,规避其他方案各种编解码、不同环境支持不同文件格式等问题。例如客户端内置了Lottie Runtime,可以直接播放Lottie版的序列帧
坏处:体积大(图片没有压缩,也没有视频等的压缩算法),一般不太推荐使用
动图
-
APNG
- 好处:适合对清晰度、还原度有极高要求的场合,清晰度比视频高,且一般不会失真
- 坏处:体积比视频大,内存占用比视频高
-
WEBP
- 好处:压缩效率高,文件较小,支持透明和动画,适合 Web 和 KRN 动效
- 坏处:在大压缩时可能失真,部分旧浏览器不支持
-
AVIF
- 好处:压缩效率更高,色彩表现更好,适合需要高质量和小文件的动效
- 坏处:浏览器支持较少,编码和解码性能要求高
-
视频分为普通视频和透明视频,如果不需要透明通道的情况(例如下层元素不需要被漏出),可以选择普通视频,否则选择透明视频,透明视频占用内存会比普通视频更多。
好处:相比 APNG 体积更小,一般情况下是序列帧动效的首选
坏处:可能会出现低清晰度或者颜色失真的情况;多个video标签可能会产生额外的内存开销
适用场景
结合几种序列帧动效的优缺点,可以总结出各自的适用场景:
如果是有强烈跨平台需求,且对一致性要求比较高,同时对动效体积限制不大的情况下,推荐使用 lottie;
尺寸、帧数不大的情况
- 比如一些小icon、挂件、banner等,考虑到video标签本身会有内存开销,推荐使用APNG;
- 如果做好了前端动图的动态兼容能力,可以配合 WEBP 和 AVIF 格式使用。
尺寸、帧数比较大的情况
- 如果不需要透明通道,例如是层级最底下的主KV的氛围动效,建议使用普通视频;
- 如果需要透明通道的,例如弹出的某个氛围动效弹窗,因为需要透出底部的其他UI内容,建议使用透明视频。
序列帧动效种类繁多,上述场景只是一个概述,实际业务中需要结合具体使用场景进行综合考虑。动效平台赋能业务的核心原则主要体现在以下两点:
- 提供多端覆盖常用场景的序列帧动效格式转换能力;
- 减少 Web 端使用动图或序列帧动效时,前端开发需要在多个格式之间反复处理和判断运行时环境的冗余工作量和心智负担。
针对第一点,目前我们已支持多种格式的转换能力,涵盖 Web、React Native (RN) 及客户端等多个平台;针对第二点,我们提供了最优动图格式的动态匹配能力,能够根据运行时环境自动选择最佳格式,减少前端开发在不同格式间切换的复杂度。
接下来,我们将介绍这两部分功能。
三、序列帧格式转化能力
目前,动效平台提供了序列帧格式转换能力,支持将序列帧文件转换为多种格式,包括Lottie、APNG、WEBP、AVIF、视频以及透明视频。平台不仅允许用户直接上传序列帧文件进行格式转换,还能对平台中管理的序列帧动效资源进行格式转换导出为即用的动效组件。这一能力显著减少了之前提到的沟通成本,使得研发团队能够直接对设计团队提供的序列帧资源进行操作,快速转换成所需的格式,进一步提高了工作效率。
序列帧格式转换能力的结构如下图所示:
对于格式转换我们的链路流程是:
trans-server服务
trans-server转换服务是一个基于Node的中间层服务,专门负责处理动效平台的序列帧转换能力的后端服务。其主要功能包括:
- 提供平台客户端使用的动效资源上传、转换和获取接口;
- 对资源转换参数进行二次处理,创建素材转换任务和调度任务,调用动效格式转换RPC资源转换服务;
- 管理动效转换过程中的动效资源,利用redis缓存提高动效转换效率。
动效文件
动效平台在导出动效时,支持直接下载或通过CLI工具将动效文件集成到项目中。现在,在平台已经为 Web端 和 RN 端研发同学提供了开箱即用的解决方案,转换并导出的动效文件可以直接使用,已经实现了从转换到导出再到Runtime的完整流程,确保动效能够顺利集成。客户端研发也在平台上直接获取转换后的动效资源。
导出动效文件包括如下内容:
- 不同格式的动效源文件
- runtime 运行时使用的配置文件,文件信息包含动效的基本配置,引用对应格式的动效文件
- 用 runtime 封装的前端vue组件,研发同学直接引用该组件即可展示对应的动效
四、最优动图格式动态匹配
在使用 APNG 格式的动效时,可以与 WEBP 和 AVIF 格式配合使用,但这需要前端处理不同动图格式的兼容性。
为此,我们为web端设计了一个优化方案,以便在支持多种序列帧格式转换后,自动匹配最优动图格式。该方案通过在生产阶段将序列帧转换为APNG、 WebP 和 AVIF 三种格式,并在前端运行时根据环境动态选择最优格式进行展示,从而优化动图动效的展示效果,节省带宽并降低成本。
批量转换
为了支持序列帧资源同时转出多种格式的动效,提升转换链路的功能,现对相关服务进行升级,具体内容如下:
转换服务提供多资源转换接口,支持上传单个序列帧动效文件,创建一个转换组任务。每个组任务下可以对应多个不同格式的资源转换子任务,并进行绑定。用户可以通过该接口批量提交不同格式的动效转换需求,实现多格式的同时转换。
转换服务提供组任务查询接口,用户可以通过组任务ID,查询该组任务下所有子任务的状态和资源信息。此接口能够提供详细的任务进度、转换结果及资源输出信息,方便用户实时查询多个子任务的执行情况。
动效平台侧支持生成多动图格式的组件使用配置文件,并提供多种动效文件下载方式供使用者选择。使用者可通过平台将动效文件下载到本地,或通过CLI工具,在项目中通过命令导入所需的动效文件,满足不同开发场景的需求。
Runtime侧进行改造,新增多动图格式的使用方式,确保各动效格式在不同系统版本间的展示兼容性。经过改造后,Runtime能够自动适配并正确展示不同格式的动效文件,在多个平台和设备上实现一致的显示效果。
运行时动图匹配
通过以上链路,能够实现在平台上导出序列帧转动图动效时,导出含有 APNG、WEBP 和 AVIF 资源的动效文件,接下需要对运行时的展示逻辑进行改造,实现在运行时阶段动态匹配展示最优的动图格式。
<picture>和<source>
在前端展示最优动图格式时,可以利用 HTML 中的 <picture> 和 <source> 标签来实现动态匹配。
<picture> 标签可以让我们根据不同的格式和浏览器支持情况,选择合适的资源进行展示。通过在 <picture> 内部使用多个 <source> 标签,可以针对不同的浏览器和设备支持动态加载最适合的动图格式(如 APNG、WEBP 或 AVIF)。
在 <picture> 中,多个 <source> 标签可以根据条件(如浏览器支持的格式、图像尺寸等)提供不同的动图格式。每个 <source> 标签会包含一个 srcset 属性和一个 type 属性,type 用来指定图片格式,而 srcset 用来指定对应格式的动图资源路径。
<picture>
<!-- AVIF 格式优先 -->
<source srcset="path/to/animated-image.avif" type="image/avif">
<!-- WEBP 格式备用 -->
<source srcset="path/to/animated-image.webp" type="image/webp">
<!-- APNG 格式作为最后备选 -->
<source srcset="path/to/animated-image.apng" type="image/apng">
<!-- 默认使用 APNG 格式 -->
<img src="path/to/animated-image.apng" alt="动效展示">
</picture>
runtime改造
runtime 是动效平台通用便捷型动效播放工具。通过基本统一的 API 使用动效平台导出的动效资源,无需关心动效具体实现,统一调用方式,简化开发流程。可以把runtime 理解成一个通用api 封装层,屏蔽底层细节,提供DOM容器加上配置数据即可播放,使开发更关注于通用方法的调用播放动效。
为了支持动图动态匹配,我们需要在runtime中支持通过<picture>和<source>来动图的展示动图。
export function mountConvertibleImage(instance: InternalInstance<ApngConvertibleImageExportConfig>) {
const picture = document.createElement('picture');
const sources = [
{
srcset: instance.config.entrySrc!,
type: 'image/apng',
},
];
if (
instance.config.extraData.convertible === true ||
(Array.isArray(instance.config.extraData.convertible) && instance.config.extraData.convertible.includes('webp'))
) {
sources.unshift({
srcset: instance.config.extraData.entrySrcWebp!,
type: 'image/webp',
});
}
if (
instance.config.extraData.convertible === true ||
(Array.isArray(instance.config.extraData.convertible) && instance.config.extraData.convertible.includes('avif'))
) {
// source 是按顺序加载格式,最优先的插入到最前面
sources.unshift({
srcset: instance.config.extraData.entrySrcAvif!,
type: 'image/avif',
});
}
const sourcesElemMap = sources.map((source) => {
const sourceElem = document.createElement('source');
ensureLayout(instance, sourceElem);
sourceElem.type = source.type;
sourceElem.srcset = sources.filter((item) => item.type === sourceElem.type)[0].srcset;
picture.appendChild(sourceElem);
return sourceElem;
});
const img = document.createElement('img');
picture.appendChild(img);
instance.wrapper.appendChild(picture);
assignInstance(instance, {
getBaseInstance: () => picture,
load: async () => {
const loader = loadPicture(instance, sourcesElemMap, sources, img);
loader
.then(() => {
triggerEvents(instance, 'loaded');
})
.catch((e) => {
triggerEvents(instance, 'error', new ResourceError(e));
});
return loader;
},
play: async () => {
sourcesElemMap.forEach((elemItem) => {
elemItem.srcset = sources.filter((source) => source.type === elemItem.type)[0].srcset;
});
img.src = instance.config.entrySrc!;
triggerEvents(instance, 'play');
},
destroy: () => {
picture.parentNode?.removeChild(picture);
},
});
return instance;
}
动效配置文件新增配置项
最后再对导出的动效文件中的配置文件进行修改,确保在导出动态匹配的动图文件时,runtime 能够结合配置内容引用到具体的动效资源。
import entrySrc from './assets/effect.png';
import entrySrcWebp from './assets/effect.webp';
import entrySrcAvif from './assets/effect.avif';
export default Object.seal({
type: 'apng' as const,
entrySrc,
extraData: {
/**
* 以下为新增的动图展示配置项。
*/
convertible: true,
entrySrcAvif,
entrySrcWebp,
},
});
五、总结
以上内容介绍了不同序列帧格式动效的特点及适用场景,同时也阐述了动效平台在序列帧格式转换方面的支持能力,并支持了针对研发提效和提升收益的动图格式动态匹配的能力。
接下来,本系列文章的下一篇,将会为大家带来序列帧多格式转换服务的详细介绍,敬请期待!