Firefly Expand Image API Tutorial
Generatively expand an image out beyond its edges with the Expand Image API
Overview
In this tutorial, imagine we are working on a marketing campaign at a Fortune 100 company, and we need to create differently sized image variations optimized for various social media platforms. In the past we had to manually resize images for each platform, which was time-consuming and error-prone. With Firefly's Expand Image API, we can automate this process and generate multiple variations of images with dimensions optimized for platforms like Instagram, Facebook, Twitter, and more.
Before diving into the code, let's preview the high-level steps:
- Define Target Dimensions: Each social media platform has specific image size requirements. We define these dimensions for the platforms we plan to target.
- Upload Source Image: Use Firefly's Upload API to upload your original image.
- Generate Image Variations: Use Firefly's Expand Image API to create resized variations of the image for each dimension.
Depending on your learning style, you may prefer to walk through this tutorial step-by-step or jump immediately to the full source code.
Prerequisites
This tutorial assumes you possess a Firefly Services Client ID and Client Secret. If you don't have these credentials, learn how to get them at the Adobe Developer Console page.
Set Up Your Environment
Before we begin this Node.js tutorial, run the following in a secure terminal:
Copied to your clipboardexport FIREFLY_SERVICES_CLIENT_ID=yourClientIdAsdf123export FIREFLY_SERVICES_CLIENT_SECRET=yourClientSecretAsdf123mkdir firefly-expand-image-api-tutorialcd firefly-expand-image-api-tutorialnpm init --ynpm install axios qstouch index.js
Download the Sample Image
Save this sample image to your project folder:
Define the Dimensions
First, let's define the image dimensions for each social media platform:
Copied to your clipboardconst SOCIAL_MEDIA_PLATFORMS = [{name: 'Instagram Post',width: 1080,height: 1080,},{name: 'Facebook Cover',width: 820,height: 312,},{name: 'Twitter Post',width: 1024,height: 512,}];
Upload the Source Image
Next, let's upload our source image using Firefly's Upload API. This image serves as the starting point for all variations.
Copied to your clipboardconst axios = require("axios");const fs = require('fs');async function uploadImage({ filePath, fileType, accessToken }) {let stream = fs.createReadStream(filePath);let stats = fs.statSync(filePath);let fileSizeInBytes = stats.size;const config = {method: 'post',url: 'https://firefly-api.adobe.io/v2/storage/image',headers: {'Authorization': `Bearer ${accessToken}`,'X-API-Key': process.env.FIREFLY_SERVICES_CLIENT_ID,'Content-Type': fileType,'Content-Length': fileSizeInBytes,},data: fileStream,maxContentLength: Infinity,maxBodyLength: Infinity,};const response = await axios(config);return response.data;}
On success, the response looks similar to this:
Copied to your clipboard{"images":[{"id": "510aabb4-e154-4a7b-bd2e-f492ee71c938"}]}
Generate Image Variations
Next, let's create a function that generates images for each social media platform with Firefly's Expand Image API. We use the axios
library to make HTTPs requests:
Copied to your clipboardconst axios = require('axios');async function genExpand({ imageId, width, height, accessToken }) {const body = {size: { width, height },image: {source: { uploadId: imageId }}}const config = {method: 'post',url: 'https://firefly-api.adobe.io/v3/images/expand',headers: {'X-Api-Key': process.env.FIREFLY_SERVICES_CLIENT_ID,'Authorization': `Bearer ${accessToken}`,'Content-Type': 'application/json',},data: JSON.stringify(body),};const response = await axios(config);return response.data;}
We can expand the image to fit each social media platform's optimized dimensions and log the URL of the generated image:
Copied to your clipboardasync function createSocialMediaRenditions(accessToken) {// Upload the source imagelet upload = await uploadImage('./expand-image-tutorial-source-image.webp', 'image/webp', accessToken);let sourceImageId = upload.images[0].id;// Iterate over each platform and generate renditionsfor (let platform of SOCIAL_MEDIA_PLATFORMS) {let result = await genExpand(sourceImageId,platform.width,platform.height,accessToken);console.log(`Generated image variation for ${platform.name} at ${result.outputs[0].image.url}`);}}
Full Example
You can review the prerequisites section to understand how to set up your environment prior to running this code. Note that this is an example only and is not production-ready and requires additional error handling, logging, security measures, and more before you can run it at scale in a live application.
Copied to your clipboardconst axios = require("axios");const qs = require("qs");const fs = require("fs");// Define social media platforms and their image dimensionsconst SOCIAL_MEDIA_PLATFORMS = [{name: "Instagram Post",width: 1080,height: 1080,},{name: "Facebook Cover",width: 820,height: 312,},{name: "Twitter Post",width: 1024,height: 512,},];(async () => {const accessToken = await retrieveAccessToken();await createSocialMediaRenditions(accessToken);})();async function retrieveAccessToken() {let data = qs.stringify({grant_type: "client_credentials",client_id: process.env.FIREFLY_SERVICES_CLIENT_ID,client_secret: process.env.FIREFLY_SERVICES_CLIENT_SECRET,scope:"openid,AdobeID,session,additional_info,read_organizations,firefly_api,ff_apis",});let config = {method: "post",maxBodyLength: Infinity,url: "https://ims-na1.adobelogin.com/ims/token/v3",headers: {"Content-Type": "application/x-www-form-urlencoded",},data: data,};try {const response = await axios.request(config);const { access_token } = response.data;return access_token;} catch (error) {console.log(error);}}async function uploadImage({ filePath, fileType, accessToken }) {const fileStream = fs.createReadStream(filePath);const fileStats = fs.statSync(filePath);const fileSizeInBytes = fileStats.size;const config = {method: "post",url: "https://firefly-api.adobe.io/v2/storage/image",headers: {Authorization: `Bearer ${accessToken}`,"X-API-Key": process.env.FIREFLY_SERVICES_CLIENT_ID,"Content-Type": fileType,"Content-Length": fileSizeInBytes,},data: fileStream,maxContentLength: Infinity,maxBodyLength: Infinity,};const response = await axios(config);return response.data;}async function genExpand({ imageId, width, height, accessToken }) {const body = {numVariations: 1,size: {width,height,},image: {source: {uploadId: imageId,},},};const config = {method: "post",url: "https://firefly-api.adobe.io/v3/images/expand",headers: {"X-Api-Key": process.env.FIREFLY_SERVICES_CLIENT_ID,Authorization: `Bearer ${accessToken}`,"Content-Type": "application/json",},data: body,};const response = await axios(config);return response.data;}async function createSocialMediaRenditions(accessToken) {// Upload the source imagelet upload = await uploadImage({filePath: "./expand-image-tutorial-source-image.webp",fileType: "image/webp",accessToken,});let sourceImageId = upload.images[0].id;// Loop over each platform and generate renditionsfor (const platform of SOCIAL_MEDIA_PLATFORMS) {let result = await genExpand({imageId: sourceImageId,width: platform.width,height: platform.height,accessToken,});console.log(`Generated rendition for ${platform.name} at ${result.outputs[0].image.url}`,);}}
We wrote this tutorial in CommmonJS in order to make it easy to get up and running with the code. If you'd prefer to use ES6 modules, convert the code by changing the require
statements to import
statements and then changing the file name from index.js
to index.mjs
.
Deepen Your Understanding
Now that you completed this tutorial, visit its API Reference to explore more advanced use cases to automate image generation with Firefly.