asset compute 작업자 개발

Asset compute 작업자는 에셋에서 새 렌디션을 만들기 위해 수행한 작업을 수행하거나 조정하는 사용자 지정 기능을 제공하는 Asset compute 프로젝트의 핵심입니다.

asset compute 프로젝트는 아무런 변형 없이 에셋의 원본 바이너리를 명명된 렌디션으로 복사하는 간단한 작업자를 자동으로 생성합니다. 이 튜토리얼에서는 Asset compute 작업자의 기능을 보여주기 위해 보다 흥미로운 렌디션을 만들기 위해 이 작업자를 수정합니다.

asset compute 작업자를 만들어 에셋 렌디션의 왼쪽과 오른쪽에 있는 빈 공간과 흐릿한 버전의 에셋을 포함하는 새 가로 이미지 렌디션을 생성합니다. 최종 렌디션의 너비, 높이 및 흐림 효과는 매개 변수화됩니다.

asset compute 작업자 호출의 논리 흐름

Asset compute 작업자는 개념적으로 다음과 같은 renditionCallback(...) 함수에서 Asset compute SDK 작업자 API 계약을 구현합니다.

  • 입력: AEM 자산의 원본 이진 및 처리 프로필 매개 변수입니다.
  • 출력: AEM 에셋에 추가할 하나 이상의 렌디션

Asset compute 작업자 논리 흐름

  1. AEM 작성자 서비스는 Asset compute 작업자를 호출하여 자산의 (1a) 원본 이진(source 매개 변수) 및 처리 프로필에 정의된 모든 매개 변수(rendition.instructions 매개 변수)를 (1b) ​합니다.

  2. asset compute SDK는 사용자 지정 Asset compute 메타데이터 작업자의 renditionCallback(...) 함수 실행을 조정하고 자산의 원본 이진 (1a) 및 모든 매개 변수 (1b) ​을(를) 기반으로 새 이진 렌디션을 생성합니다.

    • 이 자습서에서는 렌디션이 "처리 중"으로 작성됩니다. 즉, 작업자가 렌디션을 작성하지만 소스 바이너리를 다른 웹 서비스 API로 전송하여 렌디션을 생성할 수도 있습니다.
  3. asset compute 작업자가 새 렌디션의 이진 데이터를 rendition.path에 저장합니다.

  4. rendition.path에 기록된 이진 데이터는 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 열기

자동으로 생성된 index.js

  1. asset compute 프로젝트가 VS 코드에서 열려 있는지 확인합니다.
  2. /actions/worker 폴더로 이동
  3. index.js 파일 열기

이 파일은 이 자습서에서 수정할 작업자 JavaScript 파일입니다.

지원 npm 모듈 설치 및 가져오기

Node.js를 기반으로 하는 Asset compute 프로젝트는 강력한 npm 모듈 에코시스템의 혜택을 받습니다. npm 모듈을 활용하려면 먼저 Asset compute 프로젝트에 설치해야 합니다.

이 작업자에서는 jmp을(를) 활용하여 Node.js 코드에서 직접 렌디션 이미지를 만들고 조작합니다.

WARNING
에셋 조작을 위한 모든 npm 모듈이 Asset Compute에서 지원되는 것은 아닙니다. ImageMagick 또는 기타 OS 종속 라이브러리와 같은 애플리케이션의 존재 여부에 의존하는 npm 모듈은 지원되지 않습니다. JavaScript 전용 npm 모듈 사용으로 제한하는 것이 가장 좋습니다.
  1. asset compute 프로젝트의 루트에서 명령줄을 열고(터미널 > 새 터미널 ​을 통해 VS 코드에서 수행할 수 있음) 명령을 실행합니다.

    code language-none
    $ npm install jimp
    
  2. Jimp JavaScript 개체를 통해 사용할 수 있도록 jimp 모듈을 작업자 코드로 가져옵니다.
    jimp 모듈에서 Jimp 개체를 가져오려면 작업자 index.js의 맨 위에 있는 require 지시문을 업데이트하십시오.

    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, BRIGHTNESSCONTRAST을(를) 읽으며, 처리 프로필을 통해 제공된 기본값이 없는 경우 기본값을 제공합니다. 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, CONTRASTBRIGHTNESS에 대한 렌디션 명령 매개 변수가 유효한지 확인하십시오. 그렇지 않으면 사용자 지정 오류 RenditionInstructionsError을(를) throw합니다.
    • 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);
    }
}

렌디션 만들기

매개 변수를 읽고, 정리하고, 유효성을 검사하면 렌디션을 생성하기 위한 코드가 작성됩니다. 렌디션 생성을 위한 의사 코드는 다음과 같습니다.

  1. size 매개 변수를 통해 지정된 정사각형 차원에서 새 renditionImage 캔버스를 만듭니다.

  2. 원본 자산의 바이너리에서 image 개체 만들기

  3. Jimp 라이브러리를 사용하여 이미지를 변환합니다.

    • 원본 이미지를 가운데 사각형으로 자르기
    • "사각형" 이미지의 가운데에서 원을 자릅니다
    • SIZE 매개 변수 값으로 정의된 차원에 맞게 크기 조정
    • CONTRAST 매개 변수 값을 기준으로 대비 조정
    • BRIGHTNESS 매개 변수 값을 기준으로 밝기 조정
  4. 변환된 image을(를) 배경이 투명한 renditionImage의 가운데에 배치합니다.

  5. 자산 렌디션으로 AEM에 다시 저장할 수 있도록 작성된 renditionImage을(를) rendition.path에 작성하십시오.

이 코드는 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 개발 도구를 사용하여 이 코드를 실행할 수 있습니다.

  1. asset compute 프로젝트의 루트에서

  2. aio app run 실행

  3. asset compute 개발 도구가 새 창에서 열릴 때까지 대기

  4. 파일 선택… 드롭다운에서 처리할 샘플 이미지를 선택합니다.

    • 소스 자산 바이너리로 사용할 샘플 이미지 파일 선택
    • 아직 존재하지 않는 경우 왼쪽의 (+) ​을(를) 탭하고 샘플 이미지 파일을 업로드한 다음 개발 도구 브라우저 창을 새로 고치십시오
  5. 이 작업자로 "name": "rendition.png"을(를) 업데이트하여 투명 PNG를 생성합니다.

    • 이 "name" 매개 변수는 개발 도구에만 사용되며 를 사용하지 않아야 합니다.
    code language-json
    {
        "renditions": [
            {
                "worker": "...",
                "name": "rendition.png"
            }
        ]
    }
    
  6. 실행 ​을 누르고 렌디션이 생성될 때까지 기다립니다.

  7. 렌디션 섹션에서 생성된 렌디션을 미리 봅니다. 렌디션 미리 보기를 탭하여 전체 렌디션 다운로드

    기본 PNG 렌디션

매개 변수를 사용하여 작업자 실행

처리 프로필 구성을 통해 전달된 매개 변수는 렌디션 매개 변수 JSON에서 키/값 쌍으로 제공하여 Asset compute 개발 도구에서 시뮬레이션할 수 있습니다.

WARNING
로컬 개발 중에 AEM에서 문자열로 Cloud Service 처리 프로필로 전달될 때 다양한 데이터 유형을 사용하여 값을 전달할 수 있으므로 필요한 경우 올바른 데이터 유형을 구문 분석해야 합니다.
예를 들어 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
  1. 렌디션 매개 변수를 업데이트하여 크기, 대비 및 밝기를 사용자 지정합니다.

    code language-json
    {
        "renditions": [
            {
                "worker": "...",
                "name": "rendition.png",
                "size": "450",
                "contrast": "0.30",
                "brightness": "0.15"
            }
        ]
    }
    
  2. 실행 ​을 다시 탭

  3. 렌디션 미리 보기를 탭하여 생성된 렌디션을 다운로드하고 검토합니다. 해당 차원과 대비 및 밝기가 기본 렌디션과 비교하여 어떻게 변경되었는지 확인합니다.

    매개 변수가 있는 PNG 렌디션

  4. 다른 이미지를 Source 파일 드롭다운에 업로드하고 다른 매개 변수로 작업자를 실행해 보십시오.

Github의 작업자 index.js

최종 index.js은(는) Github의 다음 위치에서 사용할 수 있습니다.

문제 해결

recommendation-more-help
4859a77c-7971-4ac9-8f5c-4260823c6f69