Automatically Turn Images Into Slideshow Video Using Node.js

Automatically Turn Images Into Slideshow Video Using Node.js

A basic slideshow is a sequence of still images that change at regular time intervals. With modern video editing software, you can go beyond the classical definition by adding motion effects and transitions to capture your audience's interest.

The possibilities with video slideshows are infinite. They are perfectly suited for storytelling, showcasing a product, highlighting aspects of physical locations (real estate tours, venues, etc), step-by-step tutorials, or different albums such as personal or event photography.

One of the most common effects you can add to your video slideshows is the Ken Burns effect - a simple, elegant transition effect that gives the illusion of motion on static images by zooming and panning around an image.

In this article, we'll go through the basics of creating video slideshows using Node.js, Shotstack cloud video editing API, and add effects to keep the viewers engaged.

Prerequisites

Shotstack API

Shotstack.io is a video-editing API that makes it easy to programmatically edit and render multiple videos in the cloud. As rendering videos is a CPU-intensive process, we will be using Shotstack's cloud infrastructure for efficiency. Sign up to the free Shotstack developer account to get started.

Node.js

Node.js is a powerful JavaScript runtime. We'll be using Node.js for this automation.

Getting started

git clone https://github.com/shotstack/node-demos.git

Install the dependencies including the Shotstack Node.js video editor SDK:

npm install

Set your API key as an environment variable (Linux/Mac):

export SHOTSTACK_KEY=your_key_here

or, if using Windows:

set SHOTSTACK_KEY=your_key_here

Replace your_key_here with your provided sandbox API key which is free for testing and development.

Creating a simple video slideshow using code

We are going to generate the slideshow video below using Node.js and the built-in video editing API functionality.

First, open the file examples/images.js from the demo project. This simple Node.js script takes an array of images, loops through them to create a video clip, and prepares a JSON payload. Finally, the payload is sent to the Shotstack API to be rendered.

We will use the Shotstack Node.js SDK which helps us configure the API client and interact with the API features using models, getter, and setter functions.

Configure the API client

The first few lines set up the client with the API URL and key, making sure the SHOTSTACK_KEY was set correctly in the previous step.

const Shotstack = require('shotstack-sdk');

const defaultClient = Shotstack.ApiClient.instance;
const DeveloperKey = defaultClient.authentications['DeveloperKey'];
const api = new Shotstack.EditApi();

let apiUrl = 'https://api.shotstack.io/stage';

if (!process.env.SHOTSTACK_KEY) {
    console.log('API Key is required. Set using: export SHOTSTACK_KEY=your_key_here');
    process.exit(1);
}

if (process.env.SHOTSTACK_HOST) {
    apiUrl = process.env.SHOTSTACK_HOST;
}

defaultClient.basePath = apiUrl;
DeveloperKey.apiKey = process.env.SHOTSTACK_KEY;

Defining the slideshow images

We need to define an array of images to use in our slideshow, the images need to be hosted somewhere online and be accessible via a public or signed URL. For this tutorial we are using some photos we downloaded from the Pexels stock photo library.

Basic config

We will now define an empty array holder for our clips, in Shotstack a clip defines the type of asset, when it starts playing and how long it plays for:

let clips = [];

We need to control the duration of each slide and the time when it starts. We'll set default duration to 1.5 seconds.

let start = 0;
const length = 1.5;

Adding audio to the slideshow

A stunning slideshow should not miss an audio track - it can be music you like, some specific sounds that help the visuals, or even a voice-over. We use the SDK's Shotstack.Soundtrack model to set the audio file URL and a fadeInFadeOut volume effect.

let soundtrack = new Shotstack.Soundtrack;
soundtrack
    .setSrc('https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/music/gangsta.mp3')
    .setEffect('fadeInFadeOut');

Creating video clips from each image

Let's now use our images to create clips. We will iterate over the image array and create clips, defining the start time, length, and default effect. We use the Shotstack.ImageAsset model to set the image URL and the Shotstack. Clip model to create the clip playback properties and add them to our clips array we set up earlier.

images.forEach((image) => {
    let imageAsset = new Shotstack.ImageAsset;
    imageAsset
        .setSrc(image);

    let clip = new Shotstack.Clip;
    clip
        .setAsset(imageAsset)
        .setStart(start)
        .setLength(length)
        .setEffect('zoomIn');

    start = start + length;
    clips.push(clip);
});

Each slide starts immediately after the previous one ends. For the first image we default the start to 0 so it starts playing right away. We then add the length which we defined as 1.5 seconds, so each image will appear in the video for that duration.

Here is the full list of motion effects you can use to enhance your video slideshows:

  • zoomIn - slow zoom in
  • zoomOut - slow zoom out
  • slideLeft - slow slide (pan) left
  • slideRight - slow slide (pan) right
  • slideUp - slow slide (pan) up
  • slideDown - slow slide (pan) down

Adding the clips to the timeline

Shotstack API uses a timeline, which is like a container for multiple video clips which play over time. The timeline contains tracks that allow us to layer clips over one another.

In our case, the clips we just created are added to a track and then we add the track to the timeline, along with the soundtrack. We use the Shotstack.Track from the SDK and the Shotstack.Timeline:

let track = new Shotstack.Track;
track
    .setClips(clips);

let timeline = new Shotstack.Timeline;
timeline
    .setBackground('#000000')
    .setSoundtrack(soundtrack)
    .setTracks([track]);

Configuring the output video

Finally, we configure the output format and add the timeline and output to create an edit. Using the SDK again we use the Shotstack. Output and Shotstack.Edit models.

let output = new Shotstack.Output;
output
    .setFormat('mp4')
    .setResolution('sd')
    .setFps(30);

let edit = new Shotstack.Edit;
edit
    .setTimeline(timeline)
    .setOutput(output);

Sending the edit to the Shotstack API

The final step in our script is to send the data to the video editing API for processing and rendering. The Shotstack SDK takes care of converting our objects to JSON, adding our key to the request header, and sending everything to the API.

api.postRender(edit).then((data) => {
    let message = data.response.message;
    let id = data.response.id

    console.log(message + '\n');
    console.log('>> Now check the progress of your render by running:');
    console.log('>> node examples/status.js ' + id);

}, (error) => {
    console.error('Request failed: ', error);
    process.exit(1);
});

Running the script

To run the script use the node command from the root folder of the project:

node examples/images.js

If the render request is successful, the API will return the rendered id which we can use to retrieve the status of the render.

For this, you can run a different script included in our sample repo:

node examples/status.js {renderId}

Replace {renderId} with the ID returned from the first command.

Re-run the status.js script every 4-5 seconds until either a video URL is returned or there is an error message.

Recreating the Ken Burns effect using code

If you want to have a Ken Burns-style effect with the random transitions between the slides, we can define an array to hold the pool of effects we want to use and use a randomizer function.

You can add the code below before defining the image constant:

const effects = ['zoomIn', 'zoomOut', 'slideLeft', 'slideRight', 'slideUp', 'slideDown'];

const getRandomEffect = () => {
    return effects[Math.floor(Math.random() * effects.length)]
}

const images = [
    ...
]

All we need to do is replace the zoomIn effect in the clip creation code with the call to the getRandomEffect method.

images.forEach((image) => {
    let imageAsset = new Shotstack.ImageAsset;
    imageAsset
        .setSrc(image);

    let clip = new Shotstack.Clip;
    clip
        .setAsset(imageAsset)
        .setStart(start)
        .setLength(length)
        .setEffect(getRandomEffect());

    start = start + length;
    clips.push(clip);
});

Our randomized Ken Burns-style slideshow video will look something like the video below.

Controlling the motion effect for each image

If you want to have more control over each of the slides, you can configure the duration and effect individually when defining the images constant and using an array of objects instead:

const images = [
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-712850.jpeg',
        length: 2,
        effect: 'zoomIn'
    },
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-867452.jpeg',
        length: 5,
        effect: 'slideLeft'
    },
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-752036.jpeg',
        length: 1.5,
        effect: 'slideDown'
    },
    {
        src: 'https://s3-ap-southeast-2.amazonaws.com/shotstack-assets/examples/images/pexels/pexels-photo-572487.jpeg',
        length: 2,
        effect: 'slideRight'
    }
];

We now need to alter the clip creation code; we'll ignore the default length constant we defined in the first part and instead, use the value defined for each object in the array:

images.forEach((image) => {
    let imageAsset = new Shotstack.ImageAsset;
    imageAsset
        .setSrc(image.src);

    let clip = new Shotstack.Clip;
    clip
        .setAsset(imageAsset)
        .setStart(start)
        .setLength(image.length)
        .setEffect(image.effect);

    start = start + image.length;
    clips.push(clip);
});

Our final programmatically generated slideshow video looks like below.

Final thoughts

I hope this tutorial gave a basic understanding of how you can automate video generation with code.

The same demo code is also available in PHP and Ruby.

You can now get even more creative and add luma matte transitions to each slide or even cut the video to the beat of the soundtrack, the sky is the limit.

You can also build out from this example and create an entire application that uses images from different sources such as user-uploaded images or user-generated content, image scraping, or integrating with an image hosting service like Google Photos, Google Drive, DropBox, or Microsoft OneDrive.

Follow me to learn more about programmable media. You can start with our resources to learn more about programmable videos. Sign up for free to start building today!