如何从 Javascript (Adobe CEP) 向 Adobe ExtendScript 传递对象?

3
我正在使用Adobe CEP(它允许开发人员为Adobe CC产品创建窗口扩展)。我的大部分代码是现代JavaScript(该平台使用Chromium 57、Node.js 7.7.4)。然而,为了访问DOM,我需要在Adobe ExtendScript中编写一些函数,并从普通JS中执行它们。唯一的方法是使用他们提供的csInterface.evalScript(script, callback)来执行脚本。script必须是一个字符串,在我的情况下是将函数调用转换为字符串。我想能够通过evalScript传递对象到ExtendScript并返回,但evalScript只接受和返回字符串。

目前,我正在将每个对象属性作为自己的参数传递。这很笨重,但它可以工作。

我的第一个想法是使用 JSON.stringify(),但不幸的是 ExtendScript 是 ECMAScript 3 的方言,这意味着不支持 JSON.parse()
我不能只是将对象参数连接到脚本函数调用中,因为那么字符串将评估为 foo([object Object])
我看到有像 eval()/uneval()Object.toSource() 这样的函数,但这些在 Chromium 中不受支持。
下面是一个类似于我当前方法的示例: functions.js(ES3/ExtendScript)
function drawCircle(x, y, name) {
    // pick a layer
    var layer = app.activeDocument.layers[0];

    var diameter = 10;
    var top = y + diameter / 2;
    var left = x - diameter / 2;

    // draw ellipse in layer
    var circle = layer.pathItems.ellipse(top, left, diameter, diameter);

    circle.name = name;
    circle.filled = true;

    return true;
}

app.js(ES6)

const csInterface = new CSInterface();    // provided by Adobe
async function circle() {
    const dataObject = {x: 10, y: 10, name: 'Hello world!'};

    // the script to call
    // evaluates to drawCircle(10,10,'Hello world!');
    const script = "drawCircle(" + dataObject.x + "," + dataObject.y + ",'" + dataObject.name + "');";

    return new Promise((resolve, reject) => {
        csInterface.evalScript(script, (result) => {
            resolve(result);
        });
    });
}

如预期,circle() 成功调用了 drawCircle(),并且在我正在工作的文档中出现了一个椭圆。然而,通过连接字符串来执行脚本/调用函数感觉非常不对劲。所以总结一下:
  1. 我想要一种更好的方法将 dataObject 转换为字符串,并通过 evalScript() 将其传递给 drawCircle()
  2. 我想要从 drawCircle() 返回 dataObject 并将其作为对象接收回来。目前,返回一个对象只会得到 "[object Object]" 作为返回值。
1个回答

8

Javascript -> ExtendScript

将对象从Javascript传递到ExtendScript的唯一方式是使用JSON.stringify()发送JSON字符串。

是的,你说得没错,没有JSON.parse()支持,然而你也不需要

你仍然可以发送序列化后的对象,并且它将作为一个对象到达ExtendScript。

const dataObject = {x: 10, y: 10, name: 'Hello world!'};
const script = "drawCircle(" + JSON.stringify(dataObject) + ")";

然后在ExtendScript中,您可以通过以下方式轻松完成此操作:

function drawCircle(obj) {
  var layer = app.activeDocument.layers[0];

  var radius = 10;
  var top = obj.y + 5;
  var left = obj.x - 5;

  var circle = layer.pathItems.ellipse(top, left, radius, radius);

  circle.name = obj.name;
  circle.filled = true;

  return true;
}

ExtendScript -> Javascript

将此ExtendScript模块复制到与您的jsx文件相同的文件夹中。

链接至 Indiscripts ExtendScript JSON 模块

然后在jsx文件顶部使用#include 'json.jsx'; (或者//@include 'json.jsx'避免linter错误)引入它。这将添加一个名为JSON的全局函数,提供两种方法:JSON.eval()JSON.lave()

我们需要的方法是lave(),它允许您将对象转换为Javascript格式的字符串。可以认为它是JSON.stringify()的更友好版本。

function drawCircle(obj) {
  var layer = app.activeDocument.layers[0];

  var radius = 10;
  var top = obj.y + 5;
  var left = obj.x - 5;

  // draw ellipse in layer
  var circle = layer.pathItems.ellipse(top, left, radius, radius);

  circle.name = obj.name;
  circle.filled = true;

  return JSON.lave(circle);
}

接着在 JavaScript 中,你可以再次解析为对象:

const dataObject = {x: 10, y: 10, name: 'Hello world!'};
const script = "drawCircle(" + JSON.stringify(dataObject) + ")";

csInterface.evalScript(script, (result) => {
  console.log(JSON.parse(result));
});

我已测试过此功能在最新的CEP运行时版本(v9)中可用。

1
谢谢,我之前不知道可以直接传递字符串化的对象!我还找到了一个更通用的JSON polyfill。这两种方法都会修改$.global,所以我必须重新启动Illustrator来清除JSON.stringify(),然后才能使用JSON.lave() - Jason Weinzierl
如果您在发送的字符串中有特殊字符,您需要对它们进行“转义”。如果您只使用decodeURIComponent,它将无法覆盖某些字符。尤其是如果您需要支持旧版本,比如 Premiere 2019...(我知道escape已被弃用) - Guntram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接