我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

上一章:OTT端技术赋能之前端收单能力建设 | 《优酷OTT互联网大屏前端技术实践》第四章>>>

下一章:不一样的烟火:记OTT端半屏互动能力建设 | 《优酷OTT互联网大屏前端技术实践》第六章>>>

点击免费下载
《优酷OTT互联网大屏前端技术实践》>>>

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

作者| 阿里巴巴文娱技术 罄天

一、背景

图片作为网页中的重要组成元素,广泛存在于各种站点中,有些站点中的图片内容已经远远超过了其他网页内容总和。如何高效的、快速的制作业务图片就被广泛的提出来。阿里有很多自动化图片生产平台,如海棠,鲁班等。

谈到自动化制图,主要有两种模式:
一是自动化模式:依赖于服务化能力包装,将核心制图能力进行抽取,任何三方通过直接调用服务能力即可完成图片的合成,此种模式完全自动化,无需任何人工干预即可制作出符合指定条件的业务图片;

二是半自动化模式:主要依赖于业务共性的提取与升华,将繁琐的重复的业务流程通过统一的范式来解决,或多或少的需要人工干预。人工干预一方面需要人力投入,另一方面意味着可以发挥人的主观创造性。成品图除了满足指定的共性外,也可以保证输出个性,这种个性与共性并存的方式不失为一种好的折中。

二、OTT自动化制图

1、OTT自动化制图的起源

以前,优酷OTT侧有自动化制图的雏形,主要依据前端提供制图的工具平台,并将OTT主要合作厂商坑位图配置信息进行固化,然后运营在工具平台上做相应的坑位图合成。此模式在一定程度上满足了运营的合图需求。

在2019年,OTT侧开始尝试自动化制图。深入自动化制图的目的也很明显,主要基于以下痛点:

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

1)内容源与成品沉淀

我们观察到,阿里集团开始大面积的做自动化制图的尝试,有影响力的包括鲁班系统。从OTT的业务场景出发,这些平台存在一些不足:比如,所生产物料的最终落地形式是一次性的,忽略了物料的源和产物最核心的内容价值。从渠道维度来讲,OTT侧坑位图具有高度的同质性,不仅包括内容源如节目,而且从产物的角度也如此。例如《爱我就别想太多》,某电视厂商对资源位有明确的要求,而且优酷等平台方也需要这一内容源,内容源的价值就应该被放大。另外,优酷需要将同一个成品图,投放到不同渠道上,如果能从产物角度做沉淀,成品图才能发挥最大价值。

2)场景单一

制图工具解决的问题非常有限,主要是节目图的制作。前文提到,从内容源到成品图都缺少相应沉淀,这使得自动化制图服务的场景单一,和当前平台能力相比有明显差距。

现阶段OTT自动化制图涵盖了节目图、轮播、专题、动图等常见的制图场景,并结合自动化与半自动化双轨模式。半自动化场景下可以充分发挥运营创造性,基于原材料做创新性尝试;在自动化场景下,直接对接专题轮播系统,使得依赖于特定模板的制图无需人工参与。更近一步,在大数据推荐上也有相应场景,比如依赖于客户端唯一标识实现个性化的专题类推荐,这使得自动化制图一改之前"自动化"包装的外表。

3)分发效率

平台建立之初,从素材源到成品的完整链路都在本地环境完成,依赖于工具平台下载的成品图对接给运营、第三方进行投放。严重依赖于运营的人力投入,分发效率低,其原因是从内容源到成品库,到最终的分发链路缺乏一致性,所以使得整个系统没有“活”起来。

所以从平台建立开始,我们就在探索一条"活"的完整链路。通过链路的升级,不仅能完成内容源、成品库的沉淀,也包括最终分发链路的升级,从而摆脱传统工具平台面临的点状而非面状链路。

4)TOB厂商

"巧妇难为无米之炊",在自动化制图场景下,所谓的“米”就是模板,模板的格式包括但不限于PSD、SKETCH等,也包括如SVG,比如海棠。“米”是最核心的内容,如果不能从特定的场景中提取内容共性,那么自动化制图领域下的效率提升就非常有限,因此共性才是最应该被重视的特征。
并且,这种共性不仅存在于单个内容提供商,也存在于提供商之间。

2、OTT自动化制图的模式

自动化制图的优势非常明显:

第一是链路的升级:通过自动化制图的流程,可将原来"线下讨论-UED设计-效果确认-开发使用图片"的一次性长链路,转化为"UED设计模板-运营制图-自动/半自动分发"的非一次性完整流程,缩短沟通成本。

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

第二,内容共享红利:基于系统设计的高质量毛料库,产品库可进一步沉淀,打通多方,减少任何三方重复设计的可能性,将内容价值从原来的一方扩展到整个合作方生态,形成完整的内容回流链路;

第三,分发链路的建设:基于系统设计的成品图无需任何人工对接,可直接输出到渠道三方或者对接任何系统。现有可行的尝试,如专题系统自动化,大数据的个性化推荐场景等,完成从内容生产到内容自动分发的一体化能力建设。

制图效率环节:在半自动化制图场景,站外投放时间可从原来周级缩短为小时级,计件的时间成本减低50%~60%。而在自动化制图场景,无需任何人工干预的方式,使得自动化制图能真正发挥价值。

二、OTT自建自动化制图平台

可能会有人问,阿里已经有鲁班系统等自动化制图平台,为什么优酷OTT要自建?

1、为什么考虑自建?

与鲁班系统服务的(侧重商品化属性)场景不同, OTT场景更侧重媒资属性。图片主体维度的偏差,使得很多原本在商品制图场景下的规则被打破。比如一个简单的元素缩放操作,常规是按照等比加移动的方式解决。但是在以人物为中心的场景,这可能并不合理。因为在以人为主体的场景中,所有模板的指定需要考虑“人物”,而非人物所在元素图片的缩放,简单的说就是人脸,否则可能面临着人物缩放不满足模板要求的场景。因此,我们需要更进一步引入算法或人工打标的新思路。而且,除了元素缩放的特有场景,其实这种区别还很多。比如特定场景的模糊效果、动图绘制、自动化能力输出等等,这种基于特定业务特性的需求海棠确实难以做到定制。

2、商品图使用海棠

除了生产媒资海报图以外,OTT业务也需要生产商品图。比如天猫魔盒:

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

在没有自建系统之前,所有天猫魔盒的图片生产全部依赖于海棠。设计师从海棠后台传入模板,然后基于此模板在海棠上做相应的坑位图。但自建系统后也慢慢尝试切回到自有系统,主要原因有两个:

第一,内容回流: OTT业务本身是一闭环系统,媒资图和商品图缺一不可。这使得内容隔离渐渐不被接受。内容回流到自有系统后可以做统一管理、分发,享受现有系统提供的能力;

第二,定制化能力:设计师的需求往往依据业务的迭代渐渐变化,渐进增强成为一个常态。因此,当自己的述求不被满足或者不会被满足后可能会渐渐的丧失信心,进而转向新的平台。而自建系统正好提供了这样一个契机。下图提供了一个基于多模板拼接的述求。任何模板可以随意拖进工作区,然后对模板元素加工并设置模板特性,比如模板间距等。

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

三、OTT自动化制图的流程

关于自动化制图我们是如何实现的?整体流程可以简化为下图:

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

1、模板解析与数据格式化

自动化制图的前提是内容的共性,共性点更近一步的提取,就是模板,模板格式包括但不限于PSD、SKETCH、SVG等。任意一张成品图都可以看做是基于某一种模板生产出来的,这张成品图由不同图层构成,这和Photoshop中的图层是同一个道理。比如以下示例图就包含了角标、文案卖点、主题、主角、蒙版,背景图等诸多图层。通过对不同图层的*组合、编辑,得到最终的成品图。

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

上面讲到模板是由不同的图层所描述的,更形象的,模板就是解析后得到的格式化数据,描述了模板中的元素信息,如位置、尺寸、数量等等。而成品图可以看做是基于这些约定(也可以看做是图纸)生产出来的最终元素。

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

上图就是对PSD的解析后获取到的模板缩略图。当然,正如前文所讲,解析后图片的存在形式也不再是图片本身,而是格式化的数据,一般是对应的JSON。该JSON包含了模板指定的所有元素信息:

const templateInfo = {
      "modelBase": {
        // 包括模板本身的信息,如尺寸等
      },
      "psdLayerInfoList": null,
      "person": [
        // 模板包含的主体个数,主体可以是人或者其他元素
        // 也包括主体的人脸信息等
      ],
      "bgPic": {
        //背景图
      },
      "themeGradientMask": [{
        //主题渐变
      }],
      "showNameH": [{
      }],
      "showNameV": [{
      }],
      "mMask": [{}],
      "mAppLogo": [{
      }],
      "mFontAppName": [{}]
 }

2、前端依据模板绘制流程

服务端做了统一的数据格式化后,给到前端的是格式化的数据,数据指定了模板包含的所有元素信息,前端基于该元素信息进行绘制。

1)分层绘制

HTML5页面中图层的概念大家应该已经很熟悉了。讲到HTML5的网页分层就需要深入理解Chrome渲染原理中的RenderObject,、RenderLayer、Graphiclayer等几棵树。

除了网页会分层以外,Canvas中绘制的元素也可以分层,分层绘制有很多优势。比如在游戏场景中,很多背景类的图层需要重绘的可能性远比动态元素,如障碍物低得多。因此,在每一帧的绘制行为中,可以绕过相应背景图的绘制,直接绘制当前场景变化的图层即可,这与Chrome网页分层要解决的问题是一样的。

class SmallMultiLayerCanvas {
  constructor(id) {
    this.id = id;
    this.canvas = document.getElementById(id);
    this.ctx2d = this.canvas.getContext('2d');
    this.layers = [];
  }
  static extend = function (defaults, options) {
    var extended = {}, prop;
    for (prop in defaults) {
      if (Object.prototype.hasOwnProperty.call(defaults, prop))
        extended[prop] = defaults[prop];
    }
    for (prop in options) {
      if (Object.prototype.hasOwnProperty.call(options, prop))
        extended[prop] = options[prop];
    }
    return extended;
  };
 // 添加图层
  addLayer(obj) {
    const layer = SmallCanvas.extend({
      id: Math.random().toString(36).substr(2, 5),
      show: true,
      render: function (canvas, ctx) { }
    }, obj);
    if (this.getLayer(layer.id) !== false) {
      return false;
    }
    this.layers.push(layer);
    return this;
  };
  //渲染所有图层
  render() {
    var canvas = this.canvas;
    var ctx = this.ctx2d;
    this.layers.forEach(function (item, index, array) {
      if (item.show)
        item.render(canvas, ctx);
    });
  };
  //获取一个图层
  getLayer(id) {
    var length = this.layers.length;
    for (var i = 0; i < length; i++) {
      if (this.layers[i].id === id)
        return this.layers[i];
    }
    return false;
  };
  // 移除一个图层
  removeLayer(id) {
    var length = this.layers.length;
    for (var i = 0; i < length; i++) {
      if (this.layers[i].id === id) {
        removed = this.layers[i];
        this.layers.splice(i, 1);
        return removed;
      }
    }
    return false;
  };
}

以上是一个简单的分层绘制的类,通过该类可以随意新增、移除、获取、渲染任意的图层。这也是很多复杂的多图层绘制框架的最核心思想,比如fabric.js或者konvajs。有了这样的图层管理框架,就可以根据服务端下发的格式化数据来绘制模板中指定的任意元素,以模板为图纸,生产出符合设计规定的核心产品。例如:

<canvas id="theCanvas" width="512" height="512"></canvas>

在该Canvas上,我们绘制出几个指定的图形看看效果如何:

const myCanvas = new SmallMultiLayerCanvas("theCanvas");
myCanvas.addLayer({
  id: 'background',
  render: function (canvas, ctx) {
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
  }
})
  .addLayer({
    id: 'squares',
    render: function (canvas, ctx) {
      ctx.fillStyle = "#E5E059";
      ctx.fillRect(50, 50, 150, 150);
      ctx.fillStyle = "#BDD358";
      ctx.fillRect(350, 75, 150, 150);
      ctx.fillStyle = "#E5625E";
      ctx.fillRect(50, 250, 100, 250);
    }
  })
  .addLayer({
    id: 'circles',
    render: function (canvas, ctx) {
      ctx.fillStyle = "#558B6E";
      ctx.beginPath();
      ctx.arc(75, 75, 80, 0, 2 * Math.PI);
      ctx.fill();
      ctx.beginPath();
      ctx.fillStyle = "#88A09E";
      ctx.arc(275, 275, 150, 0, 2 * Math.PI);
      ctx.fill();
      ctx.beginPath();
      ctx.fillStyle = "#704C5E";
      ctx.arc(450, 450, 50, 0, 2 * Math.PI);
      ctx.fill();
    }
  })
  .addLayer({
    id: 'triangles',
    render: function (canvas, ctx) {
      ctx.fillStyle = "#DAF7A6";
      ctx.beginPath();
      ctx.moveTo(120, 400);
      ctx.lineTo(250, 300);
      ctx.lineTo(300, 500);
      ctx.closePath();
      ctx.fill();

      ctx.fillStyle = "#FFC300";
      ctx.beginPath();
      ctx.moveTo(400, 100);
      ctx.lineTo(350, 300);
      ctx.lineTo(230, 200);
      ctx.closePath();
      ctx.fill();

      ctx.fillStyle = "#C70039";
      ctx.beginPath();
      ctx.moveTo(100, 100);
      ctx.lineTo(100, 300);
      ctx.lineTo(300, 300);
      ctx.closePath();
      ctx.fill();
    }
  });
myCanvas.render();

上面的代码通过链式调用在Canvas中添加了4个对象,id分别为background、squares、circles、triangles。而且每一个对象都有相应的render方法,该方法指定了元素本身在Canvas的上下文是如何绘制的。基于以上代码可以看到在Canvas中绘制的效果:

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

2)单量与批量模式实时渲染

本小节将讲述首轮绘制后如何基于用户输入做相应的更新。其实所有的半自动化绘图场景,运营不可能只根据某一个模板进行绘制,换句话说,多模板同时绘制的场景必须加以考量。

比如,大多数场景下,运营需要同时基于模板来绘制海信、康佳、歌华、LG的所有坑位图然后导出或者投放,进而摆脱每次只能单独绘制导出单模板的低效模式。因此基于多模板实时绘制渲染的方式就亟待解决。基于此,在半自动化绘制场景中,天生支持多模板实时渲染绘制的模式,正如下面的动图所示:

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

上图展示的是多模板实时修改的场景,也就是所谓的联动模式。但在未开启联动模式的场景下,所有的修改只针对单模板生效。因此在满足成品图共性的同时又保证了模板的个性。

3、数据统一存储在服务端

前面讲过,工具化平台的设计思路没法做到链路的完整串联,进而完成内容的回流,这在平台化的思路下是行不通的。平台化解决问题的思路是:从内容生产到内容消费的完整链路串联。

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

基于此,从输入到输出,到最终的分发都需要流动起来,这一切的前提都基于数据的存储,从输入源到输出结果。基于存储的结果,完成了从自动化生产,个性化等*推荐。

四、OTT蜂鸟制图场景的主要输出与输入

下图展示了制图平台在业务上所做的尝试,也总结了在支撑业务的同时,如何在技术上做范式的探索。

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

从1.0到2.0,是整个系统架构的升级。系统现有支持能力在OTT场景下已经逐渐完善起来。

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

1、技术侧主要输出

1)服务化的能力

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

服务化的能力是上面所述的解决问题范式的具体形式,而制图平台服务化的能力已经涵盖了包括:通用模板解析能力,图片合成服务化能力,素材服务化能力,统一分发能力等等。
a) 通用模板解析能力,不仅适用于制图场景的数据格式化,在智能化领域也有涉及;
b) 图片合成服务化能力,不仅可用于制图场景,对于动画合成场景也有渗透;
c) 至于素材的服务化,分发能力的联合在业务赋能的同时,也能谋求业务发展方向的新思路。

2)半自动化合图尝试

服务化能力将制图的触角做了极大的延展,但在半自动化的制图场景,依然需要探究新的制图范式。基于此,我们产出了自有的Canvas合图尝试,这与鲁班、海棠的模式有极大的差异。这条路没有太多的参考,很多问题需要自己去挖坑和填坑。

2、无人工自动化制图

自动化制图具有极大的吸引力,无需运营任何手动制图干预,直接在系统中选择相应的内容集合即可。因此,这种业务赋能尝试也被极大的重视起来。在OTT业务范围内比较成功的案例就是专题系统:

我在优酷OTT端做自动化制图 | 《优酷OTT互联网大屏前端技术实践》第五章

通过指定内容集合(scgid)以及相应的封面图生成规则就可生成相应的专题推荐内容,极大的节省了人力成本。

上一篇:《运维工程师成长之路》一2.2 小结


下一篇:OTT端性能优化建设之本地缓存设计 | 《优酷OTT互联网大屏前端技术实践》第七章