Asset Compute ワーカーの開発
Asset Compute ワーカーは、Asset Compute プロジェクトの中核となり、アセットで実行された作業を実行(編成)して新しいレンディションを作成するカスタム機能を提供します。
Asset Compute プロジェクトは、アセットの元のバイナリを名前付きのレンディションに変換せずにコピーする、単純なワーカーを自動生成します。このチュートリアルでは、このワーカーを変更して、より興味深いレンディションを作成し、Asset Compute ワーカーの力を説明します。
新しい水平方向の画像レンディションを生成するアセットコンピューティングワーカーを作成します。アセットレンディションの左右の空きスペースを、アセットのぼかしたバージョンで埋めます。最終的なレンディションの幅、高さ、ぼかしがパラメーター化されます。
Asset Compute ワーカー呼び出しの論理フロー
Asset Compute ワーカーは、Asset Compute SDK ワーカー API コントラクトを renditionCallback(...) 関数で実装します。この関数は、概念的には次のようなものになります。
- 入力: AEM アセットのオリジナルバイナリパラメーターと処理プロファイルパラメーター
- 出力: AEM Asset に追加する 1 つ以上のレンディション
-
AEM オーサーサービスが Asset Compute ワーカーを呼び出し、アセットの (1a) オリジナルバイナリ(
sourceパラメーター)と、(1b)処理プロファイルで定義されているパラメーター(rendition.instructionsパラメーター)を渡します。 -
Asset Compute SDK がカスタム Asset Compute メタデータワーカーの
renditionCallback(...)関数の実行を調整し、アセットのバイナリ (1a) および任意のパラメーター (1b) に基づいて、新しいバイナリレンディションを生成します。- このチュートリアルでは、レンディションが「処理中」に作成されます。つまり、ワーカーはレンディションを構成しますが、ソースバイナリを他の web サービス API に送信して、レンディションを生成することもできます。
-
Asset Compute ワーカーが新しいレンディションのバイナリデータを
rendition.pathに保存します。 -
rendition.pathに書き込まれた XMP(XML)データが、Asset Compute SDK を通じて AEM オーサーサービスに転送され、そこで (4a) テキストレンディションとして公開され、(4b)アセットのメタデータノードに保存されます。
上の図は、Asset Compute 開発者に関する懸念事項と、Asset Compute ワーカー呼び出しへの論理的な流れを示しています。興味深い事に 内部での Asset Compute 実行の詳細が使用できますが、依存できるのはパブリック Asset Compute SDK 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() { ... }
ワーカー index.js を開く
- VS Code で Asset Compute プロジェクトが開いていることを確認します。
/actions/workerフォルダーに移動します。index.jsファイルを開きます。
これは、このチュートリアルで変更するワーカー JavaScript ファイルです。
サポートする npm モジュールのインストールと読み込み
Node.js ベースの Asset Compute プロジェクトは、堅牢な npm モジュールエコシステムです。npm モジュールを活用するには、まずモジュールを Asset Compute プロジェクトにインストールする必要があります。
このワーカーでは、jimp を利用して、Node.js コード内で直接レンディションイメージを作成および操作します。
-
Asset Compute プロジェクトのルートでコマンドラインを開きます(VS Code では、ターミナル/新しいターミナル)をクリックし、次のコマンドを実行します。
code language-none $ npm install jimp -
jimpモジュールをワーカーコードに読み込んで、JimpJavaScript オブジェクトによって使用できるようにします。
ワーカーのindex.jsの上部にあるrequireディレクティブを更新して、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 ワーカーは、AEM as a Cloud Service オーサーサービスで定義された処理プロファイル経由で渡すことができるパラメーターを読み取ることができます。パラメーターは、rendition.instructions オブジェクトを介してワーカーに渡されます。
これらは、ワーカーコードの rendition.instructions.<parameterName> にアクセスすることで読み取ることができます。
ここでは、設定可能なレンディションの SIZE、BRIGHTNESS、および CONTRAST を読み取り、処理プロファイル経由で何も指定されていない場合はデフォルト値を提供します。renditions.instructions は、AEM as 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 ワーカーで、エラーとなる状況が発生する場合があります。このような状況が発生した場合に、Adobe Asset Compute SDK が提供する事前定義済みのエラーのスイートをスローすることができます。特定のエラータイプが適用されない場合、GenericError を使用するか、特定のカスタム ClientErrors を定義できます。
レンディションの処理を開始する前に、このワーカーのコンテキストで、次のすべてのパラメーターが有効でサポートされていることを確認します。
SIZE、CONTRASTおよびBRIGHTNESSのレンディション命令パラメーターが有効であることを確認します。有効でない場合は、カスタムエラーRenditionInstructionsErrorをスローします。ClientErrorを拡張するカスタムRenditionInstructionsErrorクラスは、このファイルの末尾で定義します。特定のカスタムエラーを使用すると、ワーカーのテストの記述に便利です。
'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);
}
}
プロジェクトの作成
パラメーターを読み込み、不要部分を削除し検証したら、レンディションを生成するコードを記述します。レンディション生成の擬似コードを次に示します。
-
sizeパラメーターで指定した正方形の寸法で、新しいrenditionImageキャンバスを作成します。 -
ソースアセットのバイナリから
imageオブジェクトを作成します。 -
Jimp ライブラリを使用して、次のように画像を変換します。
- 元の画像を中央の位置で正方形に切り抜き
- 正方形に切り抜いた画像の中心から円を切り取り
SIZEパラメーター値で定義された寸法内に収まるように拡大・縮小CONTRASTパラメーター値に基づいてコントラストを調整BRIGHTNESSパラメーター値に基づいて明るさを調整
-
変換された
imageを、背景が透明なrenditionImageの中央に配置します。 -
構成された
renditionImageをrendition.pathに記述し、アセットレンディションとして AEM に保存できるようにします。
このコードでは、Jimp API を使用してこれらの画像変換を実行します。
Asset Compute ワーカーは同期的に作業を完了する必要があり、ワーカーの renditionCallback が完了する前に rendition.path を完全に書き込む必要があります。そのためには、await 演算子を使用して非同期の呼び出しを同期させる必要があります。JavaScript の非同期関数と、それらを同期的に実行する方法について詳しくない場合は、JavaScript の await 演算子について理解しておいてください。
完成したワーカー 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 開発ツールを使用して実行し、結果を確認できます。
-
Asset Compute プロジェクトのルートから
-
aio app runを実行します -
Asset Compute 開発ツールが新しいウィンドウで開くのを待ちます
-
「ファイルを選択」ドロップダウンで、処理するサンプル画像を選択します
- ソースアセットバイナリとして使用するサンプル画像ファイルを選択します
- 何も存在しない場合は、左側の (+) をタップし、サンプル画像ファイルをアップロードして、開発ツールブラウザーウィンドウを更新します
-
このワーカーとして
"name": "rendition.png"を更新し、透明な PNG を生成します。- この「name」パラメーターは開発ツールにのみ使用されるものなので、このパラメーターに依存しないでください。
code language-json { "renditions": [ { "worker": "...", "name": "rendition.png" } ] } -
「実行」をタップして、レンディションが生成されるのを待ちます。
-
この「レンディション」セクションには、生成されたレンディションのプレビューが表示されます。レンディションのプレビューをタップして、レンディション全体をダウンロード
パラメータを指定してワーカーを実行
処理プロファイル設定を通じて渡されるパラメーターは、レンディションパラメーター JSON でキーと値のペアとして指定することで、Asset Compute 開発ツールでシミュレートできます。
例えば、Jimp の
crop(width, height) 関数は、int 型のパラメーターが必要です。parseInt(rendition.instructions.size) が int に解析されない場合、パラメーターが「文字列」型と互換性がないので、jimp.crop(SIZE, SIZE) の呼び出しは失敗します。アドビのコードは次のパラメーターを受け入れます。
sizeはレンディションのサイズを定義します(高さと幅を整数で指定します)。contrastはコントラストの調整を定義します。-1 ~ 1 の範囲の浮動小数点として指定する必要があります。brightnessは明るさの調整を定義します。-1 ~ 1 の範囲の浮動小数点として指定する必要があります。
これらは次を経由して、ワーカー index.js で読み込まれます。
const SIZE = parseInt(rendition.instructions.size) || 800const CONTRAST = parseFloat(rendition.instructions.contrast) || 0const BRIGHTNESS = parseFloat(rendition.instructions.brightness) || 0
-
レンディションパラメーターを更新して、サイズ、コントラストおよび明るさをカスタマイズします。
code language-json { "renditions": [ { "worker": "...", "name": "rendition.png", "size": "450", "contrast": "0.30", "brightness": "0.15" } ] } -
「実行」をもう一度タップします。
-
レンディションのプレビューをタップし、生成されたレンディションをダウンロードして確認します。その寸法と、デフォルトのレンディションと比べてコントラストや明るさがどのように変更されたかに注目してください。
-
他の画像を ソースファイル ドロップダウンにアップロードし、別のパラメーターを指定してワーカーを実行してみてください。
Github のワーカー index.js
最終的な index.js は、GitHub で次の場所から入手できます。