開發Asset compute背景工作
asset compute背景工作是Asset compute專案的核心,因為提供自訂功能,可執行或協調對資產執行的工作,以建立新轉譯。
asset compute專案會自動產生簡易的背景工作,將資產的原始二進位檔複製到已命名的轉譯中,不需要進行任何轉換。 在本教學課程中,我們將修改此背景工作以製作更有趣的轉譯,以說明Asset compute背景工作的力量。
我們將建立Asset compute背景工作,此背景工作會產生新的水準影像轉譯,以模糊版本的資產遮蓋資產轉譯左側的空白空間。 最終轉譯的寬度、高度和模糊皆已引數化。
asset compute工作者引動過程的邏輯流程
asset compute背景工作在renditionCallback(...)
函式中實作Asset computeSDK背景工作API合約,其概念為:
- 輸入: AEM資產的原始二進位檔與處理設定檔引數
- 輸出: 要新增至AEM資產的一或多個轉譯
-
AEM Author服務會叫用Asset compute背景工作,提供資產的 (1a) 原始二進位檔(
source
引數),以及 (1b) 處理設定檔中定義的任何引數(rendition.instructions
引數)。 -
asset computeSDK會根據資產的原始二進位 (1a) 和任何引數 (1b),協調執行自訂Asset compute中繼資料背景工作程式的
renditionCallback(...)
函式,產生新的二進位轉譯。- 在本教學課程中,轉譯是在「處理中」建立的,這表示工作者會撰寫轉譯,不過來源二進位檔也可以傳送至其他Web服務API以產生轉譯。
-
asset compute背景工作會將新轉譯的二進位資料儲存至
rendition.path
。 -
寫入至
rendition.path
的二進位資料會透過Asset computeSDK傳輸至AEM Author Service,並公開為 (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() { ... }
開啟背景工作程式index.js
- 確保Asset compute專案在VS程式碼中開啟
- 導覽至
/actions/worker
資料夾 - 開啟
index.js
檔案
這是我們將在本教學課程中修改的Worker JavaScript檔案。
安裝並匯入支援的npm模組
asset compute專案是以Node.js為基礎,受益於健全的npm模組生態系統。 若要運用npm模組,我們必須先將模組安裝至Asset compute專案。
在此背景工作程式中,我們運用jimp,直接在Node.js程式碼中建立並操控轉譯影像。
-
在Asset compute專案的根目錄中開啟命令列(這可以透過 終端機>新終端機 在VS Code中完成)並執行命令:
code language-none $ npm install jimp
-
將
jimp
模組匯入背景工作程式程式碼,以便透過Jimp
JavaScript物件使用。
更新背景工作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
,如果未透過處理設定檔提供預設值,則會提供預設值。 請注意,從AEM as a Cloud Service處理設定檔叫用時,renditions.instructions
會以字串形式傳入,因此請確定它們已轉換為背景工作程式碼中的正確資料型別。
'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
。
開始處理轉譯之前,請檢查以確定所有引數在此背景中是否有效及受支援:
- 請確定
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背景工作必須同步完成其工作,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);
}
}
執行背景工作
現在Worker程式碼已完成,而且先前已在manifest.yml中註冊及設定,可以使用本機Asset compute開發工具執行以檢視結果。
-
從Asset compute專案的根目錄
-
執行
aio app run
-
等待Asset compute開發工具在新視窗中開啟
-
在 選取檔案…… 下拉式清單中,選取要處理的影像範例
- 選取要當作來源資產二進位檔使用的範例影像檔案
- 如果還沒有任何專案,請點選左側的 (+),然後上傳範例影像檔案,然後重新整理[開發工具]瀏覽器視窗
-
將
"name": "rendition.png"
更新為此背景工作,以產生透明PNG。- 請注意,此「name」引數僅用於開發工具,不應依賴。
code language-json { "renditions": [ { "worker": "...", "name": "rendition.png" } ] }
-
點選 執行 並等待轉譯產生
-
轉譯 區段會預覽產生的轉譯。 點選轉譯預覽以下載完整的轉譯
使用引數執行背景工作
若是透過「處理設定檔」設定傳入引數,您可在Asset compute開發工具中,藉由在轉譯引數JSON上提供索引鍵/值組來模擬這些引數。
例如,Jimp的
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
-
更新轉譯引數以自訂大小、對比和亮度。
code language-json { "renditions": [ { "worker": "...", "name": "rendition.png", "size": "450", "contrast": "0.30", "brightness": "0.15" } ] }
-
再次點選 執行
-
點選轉譯預覽以下載並檢閱產生的轉譯。 請注意它的尺寸,以及相較於預設轉譯,對比度和亮度是如何變更的。
-
將其他影像上傳到 Source檔案 下拉式清單,然後嘗試使用其他引數針對這些影像執行背景工作!
Github上的背景工作索引.js
Github上的最終index.js
位於: