如何将对象从 Javascript (Adobe CEP) 传递给 Adob​​e ExtendScript?

How do I pass an object to Adobe ExtendScript from Javascript (Adobe CEP)?

我正在使用 Adobe CEP (it lets developers create windowed extensions for Adobe CC products). The bulk of my code is modern JavaScript (the platform uses Chromium 57, Node.js 7.7.4). However, in order to access the DOM, I need to write some functions in Adobe ExtendScript 并从普通 JS 执行它们。唯一的方法是使用他们提供的 csInterface.evalScript(script, callback) 执行脚本。 script 必须是一个字符串,在我的例子中是一个转换为字符串的函数调用。 我希望能够通过 evalScript 将对象传入和传出 ExtendScript,但是 evalScript 只需要 return 一个字符串。

目前,我将每个对象 属性 作为其自己的参数传递。这很笨重,但很管用。

虽然我的第一个是 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() 很好,并且在我正在处理的文档中出现了一个椭圆。但是,通过串联执行一个 script/calling 函数感觉非常 错误 。所以总而言之,

  1. 我想要一些(更简洁的)方法将 dataObject 转换为字符串并通过 evalScript()
  2. 将其传递给 drawCircle()
  3. 并且我想从 drawCircle() return dataObject 并将其作为对象接收回来。目前,returning 对象只会导致 "[object Object]" 作为 return 值。

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 相同的文件夹中

Link to Indiscripts ExtendScript JSON module

然后将其与 #include 'json.jsx';(或 //@include 'json.jsx' 以避免 linter 错误)一起包含在您的 jsx 顶部。这将添加一个 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) 中对此进行了测试。