开发Asset compute工作人员

asset compute工作进程是Asset compute项目的核心,因为它提供自定义功能,该功能执行或协调对资源执行的工作以创建新演绎版。

asset compute项目会自动生成一个简单的工作程序,该程序无需进行任何转换即会将资源的原始二进制文件复制到命名演绎版中。 在本教程中,我们将修改此工作程序,使其成为一个更有趣的演绎版,以说明Asset compute工作程序的强大功能。

我们将创建一个Asset compute工作程序,该工作程序会生成一个新的水平图像演绎版,通过模糊版本的资源来覆盖资源演绎版左侧的空白区域。 最终演绎版的宽度、高度和模糊已进行参数化。

asset compute工作进程调用的逻辑流程

asset compute工作程序在实施Asset computeSDK工作程序API合同时,位于 renditionCallback(...) 函数,其概念为:

  • 输入: AEM资产的原始二进制文件和处理配置文件参数
  • 输出: 要添加到AEM资源的一个或多个演绎版

asset compute工作进程逻辑流

  1. AEM Author服务调用Asset compute工作进程,提供资源的 (1a) 原始二进制文件(source 参数),和 (1b) 处理配置文件中定义的任何参数(rendition.instructions 参数)。

  2. asset computeSDK可协调自定义Asset compute元数据工作进程的 renditionCallback(...) 函数,根据资产的原始二进制文件生成新的二进制文件演绎版 (1a) 和任何参数 (1b).

    • 在本教程中,将创建演绎版“进行中”,这意味着工作进程构成演绎版,但源二进制文件也可以发送到其他Web服务API来生成演绎版。
  3. asset compute工作程序会将新演绎版的二进制数据保存到 rendition.path.

  4. 写入的二进制数据 rendition.path 通过Asset computeSDK传输到AEM创作服务,并公开为 (4a) 文本呈现版本和 (4b) 保留到资产的元数据节点。

上图阐明了Asset compute面向开发人员的顾虑以及用于Asset compute工作程序调用的逻辑流程。 好奇的是, asset compute执行的内部详细信息 可用,但只能依赖公共Asset computeSDK API合同。

工人的解剖学

所有Asset compute工作人员遵循相同的基本结构和输入/输出合同。

'use strict';

// Any npm module imports used by the worker
const { worker, SourceCorruptError } = require('@adobe/asset-compute-sdk');
const fs = require('fs').promises;

/**
Exports the worker implemented by a custom rendition callback function, which parametrizes the input/output contract for the worker.
 + `source` represents the asset's original binary used as the input for the worker.
 + `rendition` represents the worker's output, which is the creation of a new asset rendition.
 + `params` are optional parameters, which map to additional key/value pairs, including a sub `auth` object that contains Adobe I/O access credentials.
**/
exports.main = worker(async (source, rendition, params) => {
    // Perform any necessary source (input) checks
    const stats = await fs.stat(source.path);
    if (stats.size === 0) {
        // Throw appropriate errors whenever an erring condition is met
        throw new SourceCorruptError('source file is empty');
    }

    // Access any custom parameters provided via the Processing Profile configuration
    let param1 = rendition.instructions.exampleParam;

    /**
    Perform all work needed to transform the source into the rendition.

    The source data can be accessed:
        + In the worker via a file available at `source.path`
        + Or via a presigned GET URL at `source.url`
    **/
    if (success) {
        // A successful worker must write some data back to `renditions.path`.
        // This example performs a trivial 1:1 copy of the source binary to the rendition
        await fs.copyFile(source.path, rendition.path);
    } else {
        // Upon failure an Asset Compute Error (exported by @adobe/asset-compute-commons) should be thrown.
        throw new GenericError("An error occurred!", "example-worker");
    }
});

/**
Optionally create helper classes or functions the worker's rendition callback function invokes to help organize code.

Code shared across workers, or to complex to be managed in a single file, can be broken out across supporting JavaScript files in the project and imported normally into the worker.
**/
function customHelperFunctions() { ... }

打开worker index.js

自动生成的index.js

  1. 确保在VS代码中打开Asset compute项目
  2. 导航至 /actions/worker 文件夹
  3. 打开 index.js 文件

这是我们将在本教程中修改的工作JavaScript文件。

安装和导入支持npm的模块

由于Asset compute项目基于Node.js,因此其强大的 npm模块生态系统. 要利用npm模块,我们必须首先将其安装到我们的Asset compute项目中。

对于此员工,我们利用 jimp 直接在Node.js代码中创建和处理演绎版图像。

WARNING
asset compute并非支持所有用于资产处理的npm模块。 不支持依赖存在应用程序(如ImageMagick或其他依赖操作系统的库)的npm模块。 最好限制为仅使用JavaScript npm模块。
  1. 在Asset compute项目的根目录中打开命令行(这可以在VS Code中完成,方法是 “终端”>“新建终端”)并执行命令:

    code language-none
    $ npm install jimp
    
  2. 导入 jimp 模块导入到工作线程代码中,以便可以通过 Jimp javascript对象。
    更新 require 位于工作人员工作流程顶部的指令 index.js 导入 Jimp 对象来自 jimp 模块:

    code language-javascript
    'use strict';
    
    const Jimp = require('jimp');
    const { worker, SourceCorruptError } = require('@adobe/asset-compute-sdk');
    const fs = require('fs').promises;
    
    exports.main = worker(async (source, rendition, params) => {
        // Check handle a corrupt input source
        const stats = await fs.stat(source.path);
        if (stats.size === 0) {
            throw new SourceCorruptError('source file is empty');
        }
    
        // Do work here
    });
    

读取参数

asset compute工作进程可以读入参数,这些参数可以通过处理在AEMas a Cloud Service创作服务中定义的用户档案来传入。 这些参数通过 rendition.instructions 对象。

可以通过访问来读取这些内容 rendition.instructions.<parameterName> 在工作人员代码中。

下面我们将阅读可配置呈现的 SIZEBRIGHTNESSCONTRAST,如果没有通过处理配置文件提供默认值,则提供默认值。 请注意 renditions.instructions 在从AEMas a Cloud Service处理配置文件调用时,将作为字符串传递,因此请确保将这些类型转换为工作人员代码中的正确数据类型。

'use strict';

const Jimp = require('jimp');
const { worker, SourceCorruptError } = require('@adobe/asset-compute-sdk');
const fs = require('fs').promises;

exports.main = worker(async (source, rendition, params) => {
    const stats = await fs.stat(source.path);
    if (stats.size === 0) {
        throw new SourceCorruptError('source file is empty');
    }

    // Read in parameters and set defaults if parameters are provided
    // Processing Profiles pass in instructions as Strings, so make sure to parse to correct data types
    const SIZE = parseInt(rendition.instructions.size) || 800;
    const CONTRAST = parseFloat(rendition.instructions.contrast) || 0;
    const BRIGHTNESS = parseFloat(rendition.instructions.brightness) || 0;

    // Do work here
}

抛出错误 errors

asset compute工作程序可能会遇到导致错误的情况。 AdobeAsset computeSDK提供 一组预定义错误 遇到此类情况时可以抛出的标记。 如果没有特定的错误类型, GenericError 可使用,或特定自定义 ClientErrors 可以定义。

在开始处理演绎版之前,请检查以确保所有参数在此工作程序的上下文中有效并受支持:

  • 确保的演绎版指令参数 SIZECONTRAST、和 BRIGHTNESS 有效。 如果不存在,则引发自定义错误 RenditionInstructionsError.
    • 自定义 RenditionInstructionsError 扩展的类 ClientError 在该文件底部定义。 在以下情况下,使用特定的自定义错误会很有用 编写测试 对于工作人员。
'use strict';

const Jimp = require('jimp');
// Import the Asset Compute SDK provided `ClientError`
const { worker, SourceCorruptError, ClientError } = require('@adobe/asset-compute-sdk');
const fs = require('fs').promises;

exports.main = worker(async (source, rendition, params) => {
    const stats = await fs.stat(source.path);
    if (stats.size === 0) {
        throw new SourceCorruptError('source file is empty');
    }

    // Read in parameters and set defaults if parameters are provided
    const SIZE = parseInt(rendition.instructions.size) || 800;
    const CONTRAST = parseFloat(rendition.instructions.contrast) || 0;
    const BRIGHTNESS = parseFloat(rendition.instructions.brightness) || 0;

    if (SIZE <= 10 || SIZE >= 10000) {
        // Ensure size is within allowable bounds
        throw new RenditionInstructionsError("'size' must be between 10 and 1,0000");
    } else if (CONTRAST <= -1 || CONTRAST >= 1) {
        // Ensure contrast is valid value
        throw new RenditionInstructionsError("'contrast' must between -1 and 1");
    } else if (BRIGHTNESS <= -1 || BRIGHTNESS >= 1) {
        // Ensure contrast is valid value
        throw new RenditionInstructionsError("'brightness' must between -1 and 1");
    }

    // Do work here
}

// Create a new ClientError to handle invalid rendition.instructions values
class RenditionInstructionsError extends ClientError {
    constructor(message) {
        // Provide a:
        // + message: describing the nature of this erring condition
        // + name: the name of the error; usually same as class name
        // + reason: a short, searchable, unique error token that identifies this error
        super(message, "RenditionInstructionsError", "rendition_instructions_error");

        // Capture the strack trace
        Error.captureStackTrace(this, RenditionInstructionsError);
    }
}

创建节目

通过读取、净化和验证参数,写入代码以生成演绎版。 用于生成演绎版的伪代码如下所示:

  1. 新建 renditionImage 画布,按通过指定的方形尺寸 size 参数。

  2. 创建 image 源资产的二进制文件中的对象

  3. 使用 Jimp 库转换图像:

    • 将原始图像裁切为居中的正方形
    • 从“平方”图像的中心剪切一个圆
    • 缩放以适合由定义的尺寸 SIZE 参数值
    • 根据以下内容调整对比度 CONTRAST 参数值
    • 根据 BRIGHTNESS 参数值
  4. 放置转换后的 image 到中间 renditionImage 具有透明背景

  5. 写下作文, renditionImagerendition.path 因此,它可以保存回AEM作为资源演绎版。

此代码采用 Jimp API 执行这些图像转换。

asset compute工作人员必须同步完成工作,并且 rendition.path 必须完全回写到工作线程的 renditionCallback 完成。 这要求使用同步调用异步函数 await 运算符。 如果您不熟悉JavaScript异步函数以及如何使其以同步方式执行,请熟悉 JavaScript的等待运算符.

完成的工作人员 index.js 应当如下所示:

'use strict';

const Jimp = require('jimp');
const { worker, SourceCorruptError, ClientError } = require('@adobe/asset-compute-sdk');
const fs = require('fs').promises;

exports.main = worker(async (source, rendition, params) => {
    const stats = await fs.stat(source.path);
    if (stats.size === 0) {
        throw new SourceCorruptError('source file is empty');
    }

    // Read/parse and validate parameters
    const SIZE = parseInt(rendition.instructions.size) || 800;
    const CONTRAST = parseFloat(rendition.instructions.contrast) || 0;
    const BRIGHTNESS = parseFloat(rendition.instructions.brightness) || 0;

    if (SIZE <= 10 || SIZE >= 10000) {
        throw new RenditionInstructionsError("'size' must be between 10 and 1,0000");
    } else if (CONTRAST <= -1 || CONTRAST >= 1) {
        throw new RenditionInstructionsError("'contrast' must between -1 and 1");
    } else if (BRIGHTNESS <= -1 || BRIGHTNESS >= 1) {
        throw new RenditionInstructionsError("'brightness' must between -1 and 1");
    }

    // Create target rendition image
    let renditionImage =  new Jimp(SIZE, SIZE, 0x0);

    // Read and perform transformations on the source binary image
    let image = await Jimp.read(source.path);

    // Crop a circle from the source asset, and then apply contrast and brightness
    image.crop(
            image.bitmap.width < image.bitmap.height ? 0 : (image.bitmap.width - image.bitmap.height) / 2,
            image.bitmap.width < image.bitmap.height ? (image.bitmap.height - image.bitmap.width) / 2 : 0,
            image.bitmap.width < image.bitmap.height ? image.bitmap.width : image.bitmap.height,
            image.bitmap.width < image.bitmap.height ? image.bitmap.width : image.bitmap.height
        )
        .circle()
        .scaleToFit(SIZE, SIZE)
        .contrast(CONTRAST)
        .brightness(BRIGHTNESS);

    // Place the transformed image onto the transparent renditionImage to save as PNG
    renditionImage.composite(image, 0, 0)

    // Write the final transformed image to the asset's rendition
    await renditionImage.writeAsync(rendition.path);
});

// Custom error used for renditions.instructions parameter checking
class RenditionInstructionsError extends ClientError {
    constructor(message) {
        super(message, "RenditionInstructionsError", "rendition_instructions_error");
        Error.captureStackTrace(this, RenditionInstructionsError);
    }
}

运行辅助进程

现在,工作线程代码已经完成,并且之前已在中注册和配置 manifest.yml,可使用本地Asset compute开发工具执行该操作以查看结果。

  1. 从Asset compute项目的根目录

  2. 执行 aio app run

  3. 等待Asset compute开发工具在新窗口中打开

  4. 选择文件…… 下拉列表,选择要处理的示例图像

    • 选择用作源资产二进制文件的示例图像文件
    • 如果尚不存在任何内容,请点按 (+) 左侧,然后上传 示例图像 文件,并刷新开发工具浏览器窗口
  5. 更新 "name": "rendition.png" 作为此工作,生成透明的PNG。

    • 请注意,此“name”参数仅用于开发工具,不应依赖。
    code language-json
    {
        "renditions": [
            {
                "worker": "...",
                "name": "rendition.png"
            }
        ]
    }
    
  6. 点按 运行 并等待节目生成

  7. 节目 部分预览生成的解释。 点按演绎版预览以下载完整演绎版

    默认PNG演绎版

使用参数运行辅助进程

通过在Asset compute开发工具中提供参数(通过处理配置文件配置传入)作为演绎版参数JSON上的键/值对,可以模拟这些参数。

WARNING
在本地开发期间,当值作为Cloud Service处理配置文件作为字符串从AEM传入时,可以使用各种数据类型传入,因此,请确保根据需要解析正确的数据类型。
例如, Jimp's crop(width, height) 函数要求其参数 int的。如果 parseInt(rendition.instructions.size) 不会解析为int,然后调用 jimp.crop(SIZE, SIZE) 由于参数的“String”类型不兼容,因此失败。

我们的代码接受以下参数:

  • size 定义演绎版的大小(高度和宽度为整数)
  • contrast 定义对比度调整,必须介于–1和1之间,为浮动
  • brightness 定义明亮调整,必须介于–1和1之间,为浮动

这些内容在工作程序中读取 index.js 通过:

  • const SIZE = parseInt(rendition.instructions.size) || 800
  • const CONTRAST = parseFloat(rendition.instructions.contrast) || 0
  • const BRIGHTNESS = parseFloat(rendition.instructions.brightness) || 0
  1. 更新节目参数以自定义大小、对比度和亮度。

    code language-json
    {
        "renditions": [
            {
                "worker": "...",
                "name": "rendition.png",
                "size": "450",
                "contrast": "0.30",
                "brightness": "0.15"
            }
        ]
    }
    
  2. 点按 运行 再次

  3. 点按演绎版预览以下载并查看生成的演绎版。 请注意其尺寸以及对比度和亮度与默认演绎版相比的变化。

    参数化的PNG演绎版

  4. 将其他图像上传到 源文件 下拉框中,尝试使用不同的参数对其运行工作程序!

Github上的Worker index.js

最终的 index.js 可在Github上获取,网址为:

疑难解答

recommendation-more-help
4859a77c-7971-4ac9-8f5c-4260823c6f69