This Mediajam showcases how to transform an image to gif as a fadeout using cloudinary API's in combination with typescript Nextjs
Codesandbox
The final project can be viewed on Codesandbox.
You can find the full source code on my Github repository.
Project initialization and setup
Initiatilization of next js with typescript project
First, we initialize an empty next js project.
Using the commands below. The command will prompt you to name your project.
1npx create-next-app@latest --typescript23# or45yarn create next-app --typescript
Once initialization is complete you can confirm that the initial setup is complete by running.
1yarn dev23# OR45npm run dev
After running the above command visit localhost port 3000
Dependencies definitions and additions
html2canvas
cloudinary
gifshot
styled-components
1yarn add html2canvas23yarn add gifshot45yarn add cloudinary67yarn add styled-components
Additional setup for gifshot
Add the following line of code in the ./pages/api/decs.d.ts
file
To enable the import and export of the module within the project
1declare module "gifshot";
Development steps
Setup demonstration image in the public folder.
link the image to an image tag in the App class renderer
Retrieve the html image tag and convert the element to the canvas using the html2canvas library
Generate 6 other canvases (Due to storage constraints) while fading out the pixels in each canvas.
Take the generated list of canvases to convert them into data urls array
Combine the images to gif using gifshot library
Upload the generated video/gif to cloudinary for storage.
Display the generated fadeout/disintegration gif
link the image to an image tag in the App class renderer
1<Main>23<div className="inner">45{loading ? (67<div>Processing ... </div>89) : (1011<Image1213id="world"1415src={gif_image ? gif_image : `/goat.jpg`}1617alt=""1819/>2021)}2223<br />2425{url ? <div>{url}</div> : ""}2627{!loading && <button onClick={this.snap.bind(this)}>Snap</button>}2829</div>3031</Main>
Retrieve the html image tag and convert the element to the canvas using the html2canvas library
1// convert img tag to canvas23const canvas = await html2canvas(img as HTMLElement);45const ctx = canvas.getContext("2d");67if (!ctx) return;89// Getting image data from the canvas for pixel manipulation1011const image_data = ctx.getImageData(0, 0, canvas.width, canvas.height);1213if (!image_data) return;1415const pixel_arr = image_data.data;
Generate 6 other canvases while fading out the pixels in each canvas
1const image_data_array = this.createBlankImageArray(image_data);23//put pixel info to imageDataArray (Weighted Distributed)45for (let i = 0; i < pixel_arr.length; i++) {67const p = Math.floor((i / pixel_arr.length) * CANVAS_COUNT);891011const dist = Math.round(Math.random() * (CANVAS_COUNT - 1));12131415const a = image_data_array[dist];1617a[i] = pixel_arr[i];1819a[i + 1] = pixel_arr[i + 1];2021a[i + 2] = pixel_arr[i + 2];2223a[i + 3] = pixel_arr[i + 3];2425}
Take the generated list of canvases to convert them into data urls array
1// fadeout image list generation and mapping23const images = new Array(CANVAS_COUNT)45.fill(0)67.map((_, i) =>89this.createCanvasFromImageData(1011image_data_array[i],1213canvas.width,1415canvas.height1617).toDataURL()1819);
Combine the images into gifs using the gifshot library
1gifshot.createGIF(23{45images,67gifWidth: canvas.width,89gifHeight: canvas.height,1011numFrames: CANVAS_COUNT1213},1415(obj: any) => {1617if (obj.error) {1819console.log(obj.error);2021return;2223}2425console.log(obj.image);2627this.uploadVideoCloudinary(obj.image);2829this.setState({ gif_image: obj.image, loading: false });3031}3233);
Upload the generated video/gif to cloudinary for storage
This article will use cloudinary for media upload and storage. Use this link to access the cloudinary website and sign up or log in to receive your environment variables(Cloud name
, API Key
, and API Secret
). The mentioned variables will be found in your dashboard which should look like the below:
.
Create a file named .env
at the root of your project. The file is where we store our environment variables. Paste the following code into the file
1CLOUDINARY_NAME = ""2345CLOUDINARY_API_KEY = ""6789CLOUDINARY_API_SECRET= ""
Ensure to fill in the blanks with your respective environment variables then restart the project server for the project to update its env.
Head to the ./pages/api
directory and create a file named upload.tsx
. In the file, we will access the cloudinary API to upload our files and receive the cloudinary file URL.
Start by including the necessary imports
1import type { NextApiRequest, NextApiResponse } from 'next'23var cloudinary = require('cloudinary').v2
Integrate your environment variables with the API backend like below:
1cloudinary.config({23cloud_name: process.env.CLOUDINARY_NAME,45api_key: process.env.CLOUDINARY_API_KEY,67api_secret: process.env.CLOUDINARY_API_SECRET,89});
Since we are using typescript, we will include a type system to represent the type of value that will be used in our backend. In our case, the value will be a string.
1type Data = {23name: string45}
We can then introduce a handler function that receives a post request and processes response feedback for our front end.
1// https://rv7py.sse.codesandbox.io/23export default async function handler(45req: NextApiRequest,67res: NextApiResponse<Data>89) {1011if (req.method === "POST") {1213let fileStr: string = req.body.data;1415let uploadResponse: any;16171819try {2021uploadResponse = await cloudinary.uploader.upload_large(fileStr, {2223resource_type: "auto",2425chunk_size: 6000000,2627timeout: 600002829});3031console.log(uploadResponse);3233} catch (err) {3435console.log(err);3637}3839res.status(200).json({ name: "" + uploadResponse.secure_url });4041}4243}
The code above receives the request body and uploads it to cloudinary. It then captures the sent file's cloudinary URL and sends it back to the front end as a response.
That's it! we've completed our project backend.