Adobe 系列扩展介绍

avatar
阿里巴巴 前端委员会智能化小组 @阿里巴巴

文/波本

前言


当下我们在许多的日常工作设计过程中,接触最频繁的就属 Adobe 公司旗下的几类设计工具产品了,相关数据显示,其旗下的 PS 市场份额达到了图像处理软件行业的 90%。

在业务高速发展的同时,Adobe 面向社区开发者的扩展应用开发生态技术也一直在不断演进,从最早时期的 C++ 以及操作系统特定的开发 SDK 演变为目前开发者所熟悉的网页开发技术栈,本篇文章就带你走进当下 Adobe 系列产品的扩展应用以及脚本是如何开发的。

CEP

CEP 全称为 Common Extensibility Platform,目前是用来开发 Adobe 系列产品中的扩展插件,你在 Adobe 系列软件内部看到的第三方的面板(插件),基本上都是这套技术实现的。这类扩展的技术栈是纯 Web 体系(HTML/CSS/Javascript/Node),它的前身叫做 CSXS 扩展,自 Adobe CC 系列发布后更名为 CEP。

开发套件

既然作为一个 Web 开发技术,跟 Web 应用配套的应用脚手架、构建、预览、打包等能力也是必不可少的,开源社区里也有人专门整理了这些配套的集合,你可以直接上手开发自己的 CEP 应用。

应用场景

那么具体它可以用来做什么呢?这里面的想象空间很大,CEP 可以像 Web 一样自定义出来一个三方面板,意味着你可以在这里做许多跟浏览器里一样的事情。因此本篇文章不展开讨论 Web 部分的面板研发,更多的是关注在 Adobe 系列产品工具本身跟 CEP 的结合点,对于 CEP 本身的 Web 开发你可以在它们的开源项目里找到更多的资料。

举以下两个简单的例子:操作处理自动化与图层数据导出应用。

  • 操作处理自动化:CEP 可以在 AI 里面对不同的文件做自动的预置动作处理,比如批量处理矢量文件等。
  • 图层数据导出应用:CEP 可以访问到 PS 里面具体的图层数据,从而将其进行结构化的数据处理、导出。


可以看到,一方面我们可以在日常设计工作中通过扩展能力帮设计师做一些批量自动化的事情,另一方面我们也可以结合图层数据本身做一些效率方面的应用。而这里面都会涉及到 Adobe 产品宿主本身的数据包括图层处理、产品菜单功能等,对于此类能力,Adobe 也给我们提供了几种不同的脚本能力让我们进行 touch :AppleScript(Mac)、VBScript(Windows)、Javascript(Mac/Windows)。作为前端,我们当然会选择熟悉的 Javascript,Adobe 又称它为 ExtendScript,下面我们就重点介绍下。

ExtendScript

ExtendScript 是一个比较特殊版本的 Javascript,它是在 ECMAScript3(吐槽下太老了)的基础上增加了 E4X、跨平台文件系统、多国语言、引用、用户行为操作交互、内置 $ 访问应用相关数据等额外功能。

跟 CEP 扩展应用的定位不同,ExtendScript 更多的只是作为一个在 Adobe 产品中可运行的脚本,你可以脱离 CEP 单独加载一份该脚本文件来做许多事情,直接在『文件 - 脚本 - 浏览』路径中导入一份 .jsx 文件即可运行。

开发调试

Adobe 提供了 ExtendScript ToolKit CC 这个专门的 IDE 来做开发和调试,它可以应用在不同的设计工具环境中。

image.png

特性

正如刚刚所说的,ExtendScript 真正的魅力在于它的一些特殊特性,比如访问处理图层数据、绘制一个交互 UI 窗口、执行动作等等。

绘制窗口

在 Adobe 里,你也可以通过脚本来绘制一些 Adobe 内置的用户交互窗口界面,这些脚本在 ExtendScript 里我们称之为 ScriptUI,我们可以纯粹使用代码来编写由各种控件组成的图形化界面。

var res = "dialog { text: 'Add Element', properties: {resizable: false} ,   \
  p: Panel { text: 'Element', alignment: ['fill', 'fill'], orientation: 'row', s:  StaticText { text: 'Name:' }, elName: EditText { alignment: ['fill', 'fill']} }, \
  topGP: Group { orientation: 'row', alignChildren: ['fill', 'fill'] ,\
    attGp: Panel { text: 'Attributes', orientaiton: 'column', \
      topRow: Group { alignment:  ['fill', 'fill'], alignChildren: ['left', 'center'], \
        aLabel: StaticText { text: 'Attribute Name:'} , \
        attribName: EditText { text: '', preferredSize: [100, 20] }, \
        addAttBtn: Button { text: 'Add', preferredSize: [45, 23] } \
      },\
      bottomRow: Group { orientation: 'row', alignChildren: 'left', \
        attribList: DropDownList { } , attribVal: EditText {preferredSize: [100, 20] }, attribValBtn: Button { text: 'Set', minimumSize: [40, 23]}\
      } \
    }, \
    attGp2: Panel { text: 'Text', orientaiton: 'column', dText: EditText { properties:{multiline:true}, preferredSize:  [200, 70], multiline: true } } \
  }, \
  elementGp: Panel {text: 'Element String', alignment: ['fill', 'fill'], alignChildren: ['fill', 'fill'], \
    eText: EditText { text: '', characters: 40, preferredSize: [200, 50], properties: { multiline: true} }, \
  } ,\
  btnGp: Group { okBtn: Button {text: 'OK' }, cancelBtn: Button {text: 'Cancel' } \
  } }";

var d = new Window(res);  
d.show()

image.png
你可以将上述代码保存为一个 demo.jsx 文件,在 Adobe 的产品里比如 PS 通过『文件 - 脚本 - 浏览』导入该脚本直接运行。

图层数据交互

在类似 Photoshop 这样的产品里,我们还可以通过 ExtendScript 访问到里面图层的数据,进而可以获取到不同类型的图层各个属性特征的数据。

var layer = app.activeDocument.activeLayer;

// 图层坐标位置信息
alert(layer.bounds);
// 图层类型
alert(layer.typename);
// 图层名称
alert(layer.name);

上述代码通过导入运行后将会弹出图层的一些基本信息,当然,在不同宿主(AE/PS/AI)里图层的信息数据结构也大都不同,ExtendScript 能直接通过全局 app 变量访问到图层实体之后(layer),通过 layer 的属性和方法访问到的数据也是有限的,大部分情况下还是需要通过动作事件来获取到更多的数据内容,比如获取文本类型图层的字体、大小、行高等样式属性等等。

事件通信

Adobe 系列产品里,很多宿主(比如 Photoshop)的操作和状态变化都是以事件形式进行消息通信的,我们也可以在 ExtendScript 里面进行事件的发送和监听。比如我们在 PS 里面将一段字符串写入到粘贴板:

function copyToClipboard(json) {
  var data = charIDToTypeID('TxtD');
  var dataToClipboardStr = stringIDToTypeID('textToClipboard');
  var desc = new ActionDescriptor();
  desc.putString(data, json);
  executeAction(dataToClipboardStr, desc, DialogModes.NO);
}

copyToClipboard('demo');


可以看到,我们向宿主发送了一个字符串类型为 textToClipboard 的事件,将其转换为一个事件 ID 发送到执行队列中进行执行,事实上,Adobe 内部许多操作以及数据获取都是通过类似的事件名来进行交互的。

局限性

当然,因为受限于 ECMAScript 3,原生的环境不支持目前我们所熟悉的一些开发特性,比如 JSON、数组的一些原生方法等等,我们需要通过类似 #include "./includes/json.jsx" 这样的方式来注入这类 polyfill。

End

本篇文章的目的更多是带大家了解目前设计产品市场份额 top 的 Adobe 系列产品扩展开发,从 CEP 到 ExtendScript,我们能做许多可以帮助优化日常工作流的事情,或者发掘更有创造性的应用。在后续的文章里,我们将具体深入到 imgcook CEP 插件和 ExtendScript,解析 imgcook 是如何提取 PS 里的图层数据、数据处理以及数据导出的。最后附上扩展开发中所需要的资料: