I processi di lavoro di Asset compute costituiscono il nucleo di un progetto di Asset compute in quanto forniscono funzionalità personalizzate che eseguono o orchestrano il lavoro eseguito su una risorsa per creare un nuovo rendering.
Il progetto di Asset compute genera automaticamente un processo di lavoro semplice che copia il binario originale della risorsa in un rendering denominato, senza alcuna trasformazione. In questa esercitazione modificheremo questo processo di lavoro per creare una rappresentazione più interessante, per illustrare il potere dei lavoratori Asset compute.
Verrà creato un processo di lavoro di Asset compute che genera un nuovo rendering orizzontale dell’immagine, che copre lo spazio vuoto a sinistra e a destra del rendering della risorsa con una versione sfocata della risorsa. La larghezza, l'altezza e la sfocatura del rendering finale sono parametrizzate.
I dipendenti di Asset compute implementano il contratto Asset compute SDK worker API nel renditionCallback(...)
funzione concettualmente:
Il servizio di authoring di AEM richiama il processo di lavoro Asset compute, fornendo l’ (1 bis) binario originale (source
), e 1 ter) eventuali parametri definiti nel profilo di elaborazione (rendition.instructions
).
L'SDK di Asset compute orchestra l'esecuzione del processo di lavoro dei metadati di Asset compute personalizzati renditionCallback(...)
generare una nuova rappresentazione binaria basata sul binario originale della risorsa (1 bis) e qualsiasi parametro 1 ter).
Il processo di lavoro Asset compute salva i dati binari del nuovo rendering in rendition.path
.
Dati binari scritti in rendition.path
viene trasportato tramite Asset compute SDK a AEM Author Service ed esposto come 4 bis) una rappresentazione testuale e 4 ter) persistita nel nodo di metadati della risorsa.
Il diagramma riportato sopra descrive le preoccupazioni rivolte agli sviluppatori di Asset compute e il flusso logico verso la chiamata del lavoratore Asset compute. Per i curiosi, il dettagli interni sull'esecuzione degli Asset compute sono disponibili, ma solo i contratti API SDK per Asset compute pubblici possono essere dipendenti.
Tutti i lavoratori Asset compute seguono la stessa struttura di base e lo stesso contratto di input/output.
'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() { ... }
/actions/worker
cartellaindex.js
fileQuesto è il file JavaScript di lavoro che modificheremo in questa esercitazione.
Essendo basati su Node.js, i progetti di Asset compute beneficiano del ecosistema del modulo npm. Per sfruttare i moduli npm, dobbiamo prima installarli nel nostro progetto Asset compute.
In questo lavoratore, sfruttiamo il scintillare per creare e manipolare l'immagine di rendering direttamente nel codice Node.js.
Non tutti i moduli npm per la manipolazione delle risorse sono supportati da Asset compute. I moduli npm che si basano sull'esistenza di applicazioni come ImageMagick o altre librerie dipendenti dal sistema operativo non sono supportati. È consigliabile limitare l’utilizzo di moduli npm solo JavaScript.
Apri la riga di comando nella directory principale del progetto di Asset compute (questa operazione può essere eseguita in Codice VS tramite Terminale > Nuovo terminale) ed esegui il comando:
$ npm install jimp
Importa jimp
nel codice del lavoratore in modo che possa essere utilizzato tramite il Jimp
Oggetto JavaScript.
Aggiorna require
direttive in cima alla index.js
per importare Jimp
dell'oggetto jimp
modulo:
'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
});
I processi di lavoro di Asset compute possono leggere i parametri che possono essere trasmessi tramite Profili di elaborazione definiti AEM servizio Author as a Cloud Service. I parametri vengono trasmessi al processo di lavoro tramite il rendition.instructions
oggetto.
Queste possono essere lette accedendo a rendition.instructions.<parameterName>
nel codice lavoratore.
Qui si legge nel rendering configurabile SIZE
, BRIGHTNESS
e CONTRAST
, fornendo valori predefiniti se non ne è stato fornito alcuno tramite il profilo di elaborazione. Tieni presente che renditions.instructions
vengono passate come stringhe quando vengono richiamate da AEM profili di elaborazione as a Cloud Service, in modo che vengano trasformate nei tipi di dati corretti nel codice del processo di lavoro.
'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
}
I lavoratori Asset compute possono trovarsi in situazioni che generano errori. L’SDK per Asset compute di Adobe fornisce una suite di errori predefiniti che possono essere lanciati quando si verificano situazioni del genere. Se non si applica un tipo di errore specifico, la GenericError
può essere utilizzato o personalizzato ClientErrors
può essere definito.
Prima di iniziare a elaborare il rendering, controlla che tutti i parametri siano validi e supportati nel contesto di questo processo di lavoro:
SIZE
, CONTRAST
e BRIGHTNESS
sono validi. In caso contrario, genera un errore personalizzato RenditionInstructionsError
.
RenditionInstructionsError
classe che si estende ClientError
è definito in fondo a questo file. L'utilizzo di un errore personalizzato specifico è utile quando prove di scrittura per il lavoratore.'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);
}
}
Con i parametri letti, igienizzati e convalidati, il codice viene scritto per generare il rendering. Lo pseudo codice per la generazione del rendering è il seguente:
renditionImage
tela in dimensioni quadrate specificate tramite size
parametro .image
oggetto dal binario della risorsa di origineSIZE
valore parametroCONTRAST
valore parametroBRIGHTNESS
valore parametroimage
nel centro del renditionImage
che ha uno sfondo trasparenterenditionImage
a rendition.path
in modo che possa essere salvato nuovamente in AEM come rendering di una risorsa.Questo codice utilizza il API di Jimp per eseguire queste trasformazioni immagine.
I lavoratori Asset compute devono finire il lavoro in modo sincrono e il rendition.path
deve essere riscritto completamente prima del renditionCallback
completo. Ciò richiede che le chiamate alle funzioni asincrone siano effettuate in modo sincrono utilizzando il await
operatore. Se non hai familiarità con le funzioni asincrone di JavaScript e con come eseguirle in modo sincrono, acquisisci familiarità con Operatore di attesa di JavaScript.
Il lavoratore finito index.js
dovrebbe essere simile a:
'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);
}
}
Ora che il codice del lavoratore è completo ed è stato precedentemente registrato e configurato nel manifest.yml, può essere eseguito utilizzando lo strumento di sviluppo Asset compute locale per visualizzare i risultati.
Dalla directory principale del progetto Asset compute
Esegui aio app run
Attendi l'apertura dello strumento di sviluppo di Asset compute in una nuova finestra
In Seleziona un file… a discesa, seleziona un’immagine di esempio da elaborare
Aggiorna "name": "rendition.png"
come questo lavoratore per generare un PNG trasparente.
{
"renditions": [
{
"worker": "...",
"name": "rendition.png"
}
]
}
Tocca Esegui e attendere che il rendering venga generato
La Rendering visualizza in anteprima il rendering generato. Tocca l’anteprima del rendering per scaricare il rendering completo
I parametri passati tramite le configurazioni del profilo di elaborazione possono essere simulati in Asset compute Development Tools fornendo loro come coppie chiave/valore sul parametro di rendering JSON.
Durante lo sviluppo locale, i valori possono essere passati utilizzando vari tipi di dati, quando passati da AEM come profili di elaborazione del Cloud Service come stringhe, quindi assicurati che i tipi di dati corretti siano analizzati se necessario.
Ad esempio, Jimp crop(width, height)
la funzione richiede che i relativi parametri siano int
S. Se parseInt(rendition.instructions.size)
non viene analizzato in un valore int, quindi la chiamata a jimp.crop(SIZE, SIZE)
non riesce perché i parametri sono di tipo "String" incompatibile.
Il nostro codice accetta parametri per:
size
definisce le dimensioni del rendering (altezza e larghezza come numeri interi)contrast
definisce la regolazione del contrasto, deve essere compresa tra -1 e 1, come floatsbrightness
definisce la regolazione luminosa, deve essere compresa tra -1 e 1, come galleggiantiQueste vengono lette nel lavoratore index.js
tramite:
const SIZE = parseInt(rendition.instructions.size) || 800
const CONTRAST = parseFloat(rendition.instructions.contrast) || 0
const BRIGHTNESS = parseFloat(rendition.instructions.brightness) || 0
Aggiorna i parametri di rendering per personalizzare le dimensioni, il contrasto e la luminosità.
{
"renditions": [
{
"worker": "...",
"name": "rendition.png",
"size": "450",
"contrast": "0.30",
"brightness": "0.15"
}
]
}
Tocca Esegui di nuovo
Tocca l’anteprima del rendering per scaricare e rivedere il rendering generato. Nota le dimensioni e come sono stati modificati il contrasto e la luminosità rispetto al rendering predefinito.
Carica altre immagini in File di origine a discesa, e prova a eseguire il processo di lavoro rispetto a loro con parametri diversi!
Il finale index.js
è disponibile su Github all’indirizzo: