開發Asset compute背景工作
asset compute背景工作是Asset compute專案的核心,因為提供自訂功能,可執行或協調對資產執行的工作,以建立新轉譯。
asset compute專案會自動產生簡易的背景工作,將資產的原始二進位檔複製到已命名的轉譯中,不需要進行任何轉換。 在本教學課程中,我們將修改此背景工作以製作更有趣的轉譯,以說明Asset compute背景工作的力量。
我們將建立Asset compute背景工作,此背景工作會產生新的水準影像轉譯,以模糊版本的資產遮蓋資產轉譯左側的空白空間。 最終轉譯的寬度、高度和模糊皆已引數化。
asset compute工作者引動過程的邏輯流程
asset compute背景工作程式會在中實施Asset computeSDK背景工作API合約 renditionCallback(...)
函式,其概念為:
- 輸入: AEM資產的原始二進位檔和處理設定檔引數
- 輸出: 要新增至AEM資產的一或多個轉譯
-
AEM作者服務會叫用Asset compute背景工作,提供資產的 (1a) 原始二進位(
source
引數),和 (1b) 處理設定檔中定義的任何引數(rendition.instructions
引數)。 -
asset computeSDK會協調自訂Asset compute中繼資料背景工作程式的執行
renditionCallback(...)
函式,根據資產的原始二進位檔產生新的二進位轉譯 (1a) 和任何引數 (1b).- 在本教學課程中,轉譯是在「處理中」建立的,這表示工作者會撰寫轉譯,不過來源二進位檔也可以傳送至其他Web服務API以產生轉譯。
-
asset compute背景工作會將新轉譯的二進位資料儲存至
rendition.path
. -
寫入的二進位資料
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() { ... }
開啟背景工作程式index.js
- 確保Asset compute專案在VS程式碼中開啟
- 導覽至
/actions/worker
資料夾 - 開啟
index.js
檔案
這是我們將在本教學課程中修改的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物件。
更新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>
在背景工作程式碼中。
我們將在此閱讀可設定轉譯的 SIZE
, BRIGHTNESS
和 CONTRAST
,若未透過處理設定檔提供預設值,則會提供此值。 請注意 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
可定義。
開始處理轉譯之前,請檢查以確定所有引數在此背景中是否有效及受支援:
- 確定下列專案的轉譯指令引數:
SIZE
,CONTRAST
、和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);
}
}
建立轉譯
透過讀取、淨化及驗證的引數,會寫入程式碼以產生轉譯。 產生轉譯的偽程式碼如下:
-
建立新的
renditionImage
以方塊尺寸表示的畫布,指定透過size
引數。 -
建立
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);
}
}
執行背景工作
現在背景工作程式碼已完成,且先前已在中註冊及設定 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)
失敗,因為引數是不相容的「字串」型別。我們的程式碼接受下列的引數:
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" } ] }
-
點選 執行 再次
-
點選轉譯預覽以下載並檢閱產生的轉譯。 請注意它的尺寸,以及相較於預設轉譯,對比度和亮度是如何變更的。
-
上傳其他影像至 來源檔案 下拉式清單,然後嘗試使用不同的引數對其執行背景工作!
Github上的背景工作索引.js
最終的 index.js
可在Github上取得,網址為: