Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.

Adobe photoshop action integration with aem asset instance

Avatar

Level 3

8/29/24

Hi all,

Working on aio app builder(asset compute worker) to integrate the Photoshop action api. I have the Photoshop action file which has to do the below actions

  1. Apply a Photoshop Action (supplied) that will:

    1. Convert Colour Profile – sRGB (layers)

    2. Deep Etch (Flattened Image) Single Layer Mask

    3. Clipping Path (post Deep Etch)

and want to save the output as 

  1. Layered PSD (non destructive to enable mask editing)

  2. JPG/PNG retaining clipping path

I have configured the processing profile to call the appbuilder worker code with the photoshop action file. I am getting the output rendition in the form of psd and png.. but i can able to see that psd rendition is not having the mask applied and png rendition is not having the transparent background. Getting background removed for both the psd and png rendition. When i check the same photoshop action file in the adobe photoshop, its working fine. my doubt is do we need to separate logic in the worker code. below is my piece of code. And i noticed the property of the asset in aem, it is showing the type as image/jpeg..

async function setupPhotoshopActionsOptions(client, instructions, files) {
if (!instructions || !instructions.photoshopActions) {
throw Error("Photoshop Action URL not provided");
}
let photoshopActions = instructions.photoshopActions;
let ext;
try {
ext = path.extname(photoshopActions).substring(1).toLowerCase();
} catch (err) {
console.log("Error extracting the file name");
}
if (!ext) {
const tempActionFilename = `${uuidv4()}_temp.atn`;
const aioLibActionFilename = `${uuidv4()}/photoshopActions.atn`;
await downloadFile(photoshopActions, tempActionFilename);
await files.copy(tempActionFilename, aioLibActionFilename, { localSrc: true });
photoshopActions = aioLibActionFilename;
}
const options = {
actions: [{
href: photoshopActions
}]
};
if (options && Array.isArray(options.actions) && instructions.photoshopActionsName) {
options.actions[0].actionName = instructions.photoshopActionsName;
}
return options;
}
exports.main = worker(async (source, rendition, params) => {
const { orgId, apiKey, accessToken } = getAuthorization(params);
let files = await Files.init();
const client = await sdk.init(orgId, apiKey, accessToken, files);
const fmt = rendition.instructions.fmt || "jpg";
const tempFilename = `${uuidv4()}/rendition.${fmt}`;
const options = await setupPhotoshopActionsOptions(client, rendition.instructions, files);
const result = await client.applyPhotoshopActions(source.url, tempFilename, options);
console.log('Response from Photoshop API', result);
if (result && result.outputs && result.outputs[0].status === 'failed') {
const errors = result.outputs[0].errors;
console.error('Photoshop API failed:', errors);
throw new Error(`Photoshop API failed: ${errors.code} ${errors.title}`);
}
console.log("Photoshop actions are successful:", rendition.path);
if (fmt === 'psd') {
try {
const psdTempFilename = `${uuidv4()}/rendition.psd`;
const psdOptions = {
...options,
outputType: "psd", // Request PSD output with layers intact
layers: true, // Ensure layers are retained
};
const result = await client.applyPhotoshopActions(source.url, psdTempFilename, psdOptions);
console.log("Photoshop API Result for PSD:", result);
if (result && result.outputs && result.outputs[0].status === 'failed') {
const errors = result.outputs[0].errors;
console.error('Photoshop API failed:', errors);
throw new Error(`Photoshop API failed: ${errors.code} ${errors.title}`);
}
await files.copy(psdTempFilename, rendition.path, { localDest: true });
await files.delete(psdTempFilename);
console.log("PSD rendition completed successfully");
} catch (error) {
console.error("Error processing PSD rendition:", error);
throw error;
}
} else if (fmt === 'png') {
try {
const pngTempFilename = `${uuidv4()}/rendition.png`;
const pngOptions = {
...options,
outputType: "png", // Ensure PNG output with transparency preserved
preserveTransparency: true // Explicitly state to preserve transparency
};
const result = await client.applyPhotoshopActions(source.url, pngTempFilename, pngOptions);
console.log("Photoshop API Result for PNG:", result);
if (result && result.outputs && result.outputs[0].status === 'failed') {
const errors = result.outputs[0].errors;
console.error('Photoshop API failed:', errors);
throw new Error(`Photoshop API failed: ${errors.code} ${errors.title}`);
}
await files.copy(pngTempFilename, rendition.path, { localDest: true });
await files.delete(pngTempFilename);
console.log("PNG rendition completed successfully");
} catch (error) {
console.error("Error processing PNG rendition:", error);
throw error;
}
} else {
try {
await files.copy(tempFilename, rendition.path, { localDest: true });
await files.delete(tempFilename);
console.log("JPG rendition completed successfully");
} catch (error) {
console.error("Error processing JPG rendition:", error);
throw error;
}
}
}. Its really helpful if you could help me to get a solution. Thanks in advance!
 
Regards,
Bhavani Bharanidharan
3 Comments

Avatar

Community Advisor

9/3/24

@BhavaniBharani Please try adding the following properties to your code:

 

  • retainMaskedArea: true: This might help in ensuring that the mask remains intact in the PSD output.
  • clippingPath: true: Added to the PNG rendition to ensure the clipping path is preserved.

I haven't tried this personally, but it could be worth the shot. Thanks!

 

Avatar

Administrator

9/4/24

@BhavaniBharani Did you find the suggestions helpful? Please let us know if you require more information. Otherwise, please mark the answer as correct for posterity. If you've discovered a solution yourself, we would appreciate it if you could share it with the community. Thank you!

Avatar

Hi  diksha_mishra,

 Tried the mentioned option, but not working as expected. I think i need to change the structure of the code were i need to call the photoshop api to save the output with mask and transparent background.

 https://developer.adobe.com/firefly-services/docs/photoshop/api/photoshop_actions/

 

but my doubt here is, do i need to directly call the photoshop api without calling the photoshop action function(to process the action file for the assets) or to make api call after the asset is processed against the photoshop action file.

 

Would be helpful if anyone knows how to use the above photoshop Api.

 

Thanks in advance!

 

Regards,

Bhavani Bharanidharan