Desarrollo de un trabajador de Asset compute
Los assets computes de trabajo son el núcleo de un proyecto de Asset compute, ya que proporcionan una funcionalidad personalizada que organiza el trabajo realizado en un recurso para crear una nueva representación.
El proyecto de Asset compute genera automáticamente un programa de trabajo simple que copia el archivo binario original del recurso en una representación con nombre, sin ninguna transformación. En este tutorial modificaremos este trabajador para crear una representación más interesante, para ilustrar el poder de los trabajadores de la Asset compute.
Crearemos un asistente de Asset compute que genera una nueva representación de imagen horizontal que cubre el espacio vacío a la izquierda y a la derecha de la representación del recurso con una versión borrosa. La anchura, altura y desenfoque de la representación final se parametriza.
Flujo lógico de una invocación de trabajador de Asset compute
Los trabajadores de asset compute implementan el contrato de API de trabajo del SDK de Asset compute, en el renditionCallback(...)
función, que conceptualmente es:
- Entrada: AEM Parámetros binarios y de perfil de procesamiento originales de un recurso de
- Salida: AEM Una o más representaciones para agregar al recurso de la
-
AEM El servicio de autor de la invoca al trabajador de Asset compute, proporcionando el (1 bis) binario original (
source
), y (1 ter) cualquier parámetro definido en el perfil de procesamiento (rendition.instructions
parámetro). -
El SDK de Asset compute organiza la ejecución del trabajo de metadatos de Asset compute personalizado
renditionCallback(...)
función, generando una nueva representación binaria, basada en el binario original del recurso (1 bis) y cualquier parámetro (1 ter).- En este tutorial, la representación se crea "en proceso", lo que significa que el trabajador compone la representación, pero el binario de origen se puede enviar a otras API de servicio web para la generación de representaciones también.
-
El trabajador de Asset compute guarda los datos binarios de la nueva representación en
rendition.path
. -
Los datos binarios escritos en
rendition.path
se transporta mediante el SDK de Asset compute AEM al servicio de autor de la aplicación y se expone como (4 bis) una representación de texto y (4 ter) persistió en el nodo de metadatos del recurso.
El diagrama anterior articula las preocupaciones del desarrollador de la Asset compute y el flujo lógico para la invocación del trabajador de la Asset compute. Para los curiosos, la detalles internos de la ejecución de la Asset compute están disponibles, pero solo se puede depender de los contratos de API del SDK de Asset compute pública.
Anatomía de un trabajador
Todos los trabajadores de la Asset compute siguen la misma estructura básica y contrato de entrada/salida.
'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() { ... }
Abrir el archivo index.js de trabajador
- Asegúrese de que el proyecto de Asset compute esté abierto en el código VS
- Vaya a
/actions/worker
carpeta - Abra el
index.js
archivo
Este es el archivo JavaScript de trabajo que modificaremos en este tutorial.
Instalación e importación de módulos npm compatibles
Al estar basados en Node.js, los proyectos de Asset compute se benefician de lo robusto ecosistema de módulo npm. Para aprovechar los módulos npm, primero debemos instalarlos en nuestro proyecto de Asset compute.
En este trabajador, aprovechamos el saltar para crear y manipular la imagen de representación directamente en el código de Node.js.
-
Abra la línea de comandos en la raíz del proyecto de Asset compute (esto se puede hacer en VS Code mediante ). Terminal > Nuevo terminal) y ejecute el comando:
code language-none $ npm install jimp
-
Importe el
jimp
en el código de trabajador para que se pueda utilizar mediante elJimp
Objeto JavaScript.
Actualice elrequire
directivas en la parte superior de laindex.js
para importar elJimp
objeto de lajimp
módulo: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 });
Leer parámetros
Los trabajadores de asset compute AEM pueden leer parámetros que se pueden pasar a través de los perfiles de procesamiento definidos en el servicio de creación as a Cloud Service de. Los parámetros se pasan al trabajador a través de rendition.instructions
objeto.
Se pueden leer accediendo a rendition.instructions.<parameterName>
en el código de trabajador.
Aquí vamos a leer en la representación configurable de SIZE
, BRIGHTNESS
y CONTRAST
, proporcionando valores predeterminados si no se ha proporcionado ninguno a través del perfil de procesamiento. Tenga en cuenta que renditions.instructions
AEM se pasan como cadenas cuando se invocan desde perfiles de procesamiento as a Cloud Service, por lo que debe asegurarse de que se transforman en los tipos de datos correctos en el código de trabajo.
'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
}
Generación de errores errors
Los trabajadores de asset compute pueden encontrar situaciones que resulten en errores. El SDK de Asset compute de Adobe proporciona un conjunto de errores predefinidos que se pueden generar cuando se encuentran este tipo de situaciones. Si no se aplica ningún tipo de error específico, la variable GenericError
se puede utilizar o una personalización específica ClientErrors
se puede definir.
Antes de comenzar a procesar la representación, asegúrese de que todos los parámetros son válidos y compatibles en el contexto de este trabajador:
- Asegúrese de que los parámetros de instrucción de representación para
SIZE
,CONTRAST
, yBRIGHTNESS
son válidos. Si no, genera un error personalizadoRenditionInstructionsError
.- Una personalización
RenditionInstructionsError
clase que extiendeClientError
se define en la parte inferior de este archivo. El uso de un error personalizado específico resulta útil cuando escribir pruebas para el trabajador.
- Una personalización
'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);
}
}
Creación de la representación
Con los parámetros leídos, saneados y validados, el código se escribe para generar la representación. El pseudocódigo para la generación de representaciones es el siguiente:
-
Crear un nuevo
renditionImage
lienzo en dimensiones cuadradas especificadas mediante la variablesize
parámetro. -
Crear un
image
del binario del recurso de origen -
Utilice el Jimp para transformar la imagen:
- Recortar la imagen original en un cuadrado centrado
- Cortar un círculo desde el centro de la imagen al cuadrado
- Escalar para que se ajuste a las dimensiones definidas por el
SIZE
valor de parámetro - Ajuste el contraste en función de
CONTRAST
valor de parámetro - Ajuste el brillo en función del
BRIGHTNESS
valor de parámetro
-
Coloque el transformado
image
en el centro delrenditionImage
con fondo transparente -
Escriba el compuesto,
renditionImage
hastarendition.path
AEM para que pueda guardarse de nuevo en la pantalla como una representación de recursos.
Este código emplea el API de Jimp para realizar estas transformaciones de imagen.
Los trabajadores de asset compute deben finalizar su trabajo sincrónicamente y el rendition.path
debe estar completamente escrito en antes de la renditionCallback
completa. Esto requiere que las llamadas a funciones asincrónicas se realicen de forma sincrónica mediante await
operador. Si no está familiarizado con las funciones asincrónicas de JavaScript y con cómo hacer que se ejecuten de forma sincrónica, familiarícese con Operador de espera de JavaScript.
El trabajador terminado index.js
debería tener un aspecto similar al siguiente:
'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);
}
}
Ejecución del trabajador
Ahora que el código de trabajador está completo y se registró y configuró anteriormente en manifest.yml, se puede ejecutar utilizando la herramienta de desarrollo de Assets computes local para ver los resultados.
-
Desde la raíz del proyecto de Asset compute
-
Ejecutar
aio app run
-
Espere a que la herramienta de desarrollo de Assets computes se abra en una nueva ventana
-
En el Seleccionar un archivo… , seleccione una imagen de muestra para procesar
- Seleccione un archivo de imagen de muestra para utilizarlo como binario del recurso de origen
- Si todavía no existe, pulse el botón (+) a la izquierda y cargue un imagen de muestra y actualice la ventana del explorador de Herramientas de desarrollo
-
Actualizar
"name": "rendition.png"
como este trabajador para generar un PNG transparente.- Tenga en cuenta que este parámetro "name" solo se utiliza para la herramienta de desarrollo y no debe depender de.
code language-json { "renditions": [ { "worker": "...", "name": "rendition.png" } ] }
-
Tocar Ejecutar y espere a que se genere la representación
-
El Representaciones previsualiza la representación generada. Pulse la vista previa de la representación para descargar la representación completa
Ejecutar el trabajador con parámetros
Los parámetros, pasados a través de configuraciones de Perfil de procesamiento, se pueden simular en las herramientas de desarrollo de Assets computes proporcionándolos como pares clave/valor en el parámetro de representación JSON.
Por ejemplo, el de Jimp
crop(width, height)
requiere que sus parámetros sean int
Es… If parseInt(rendition.instructions.size)
no se analiza en un int y, a continuación, se llama a jimp.crop(SIZE, SIZE)
falla porque los parámetros son de tipo "cadena" incompatible.Nuestro código acepta parámetros para:
size
define el tamaño de la representación (altura y anchura como números enteros)contrast
define el ajuste de contraste, debe estar entre -1 y 1, como flotantebrightness
define el ajuste brillante, debe estar entre -1 y 1, como flotante
Se leen en el trabajador index.js
mediante:
const SIZE = parseInt(rendition.instructions.size) || 800
const CONTRAST = parseFloat(rendition.instructions.contrast) || 0
const BRIGHTNESS = parseFloat(rendition.instructions.brightness) || 0
-
Actualice los parámetros de representación para personalizar el tamaño, el contraste y el brillo.
code language-json { "renditions": [ { "worker": "...", "name": "rendition.png", "size": "450", "contrast": "0.30", "brightness": "0.15" } ] }
-
Tocar Ejecutar de nuevo
-
Pulse la vista previa de la representación para descargar y revisar la representación generada. Observe sus dimensiones y cómo se han cambiado el contraste y el brillo en comparación con la representación predeterminada.
-
Cargar otras imágenes en Archivo de origen y pruebe a ejecutar el trabajador con parámetros diferentes.
Worker index.js en Github
La final index.js
está disponible en Github en: