How To Manipulate an Image With Jimp in React

Let's get started with Jimp in React. Easily alter images with a few lines of code.


5 min read
How To Manipulate an Image With Jimp in React

In this article, you will learn how to use jimp in React to perform the most common image processing operations. As you are about to learn, this popular JavaScript library allows you to effortlessly manipulate an image with a few lines of code.

What is Jimp?

Jimp stands for JavaScript Image Manipulation Program, and it is one of the most popular open-source image processing libraries, with more than one million weekly downloads. As stated on the official GitHub page, Jimp is a Promise-based library that relies entirely on Vanilla JavaScript. This means that it has no native or external dependencies, as you can verify here. This makes it more reliable and lightweight.

Jimp comes with several functions that allows you to transform your images in endless ways. Particularly, it includes the resize(), blur(), crop(), rotate() functions and many others. At the time of writing, these are image formats supported by Jimp:

Let’s now see how to use the Jimp transformation functions.

Prerequisites

This is the list of prerequisites you need to make the React applications using Jimp we are about to build works:

You can add jimp to your project’s dependencies by launching the following command:

npm install jimp

Now, you have everything required to start getting your hands dirty with Jimp in React.

Basic Image Processing in Jimp

All the Jimp usage examples presented below share the same logic. So, let’s address it immediately.

Specifically, this is what a basic JimpDemo component looks like:

import Jimp from "jimp";
import { useEffect, useState } from "react";

export function JimpDemo({ imageUrl }) {
  const [jimpImage, setJimpImage] = useState(undefined);
  const [image, setImage] = useState(undefined);
  const [transformedImage, setTransformedImage] = useState(undefined);
  
  // loading an image every time imageUrl changes
  useEffect(() => {
    const loadImage = async () => {
      // generating the Jimp data structure
      // loading an image from an URL
      const jimpImage = await Jimp.read(imageUrl);
      setJimpImage(jimpImage);
      
      // transforming jimpImage into its Base64 representation
      // and storing it
      const image = await jimpImage.getBase64Async(Jimp.MIME_JPEG);
      setImage(image);
    };
    
    loadImage();
  }, [imageUrl]);
  
  // generating the transformed image
  // as soon as the Jimp data structure is ready
  useEffect(() => {
    if (jimpImage) {
      const transformImage = async () => {        
        // performing the Jimp image processing operation 
        // on jimpImage...
        
        // e.g. jimpImage.crop(100, 100)
        
        // storing the transformed image
        // in Base64 format
        const transformedImage = await jimpImage.getBase64Async(Jimp.MIME_JPEG);
        setTransformedImage(transformedImage);
      };
      
      transformImage();
    }
  }, [jimpImage, height, width]);
  
  return image && jimpImage ? (
    <>
      <h1>Original Image</h1>
      <img className="originalImage" src={image} alt="Original" />
      <h1>Transformed Image</h1>
      <img
        className="transformedImage"
        src={transformedImage}
        alt="Transformed"
      />
    </>
  ) : (
    <>Loading...</>
  );
}

First, the imageUrl prop value storing the URL to the image you want to transform is used to generate a Jimp data structure. This happens in the first useEffect() function when launching Jimp.read(). This function takes the path to a file or a URL and returns a Promise with the Jimp data structure you call the manipulation functions on. Also, the Base64 representation of the original image is stored to be able to show it in the HTML <img> tag.

Keep in mind that the function passed to useEffect() should not be async. This is why an internal async function was defined and then called instead.

Then, the second useEffect() function is called as soon as jimpImage is initialized and takes care of performing the transformation function on the original image. Again, the Base64 representation of the transformed image is saved.

Finally, both the original and transformed images are rendered by the component. As you can imagine, what will change in the following examples will be the Jimp image transform function called, which might also require extra props.

Cropping an image

The Jimp crop() function crops an image at a given point to a given size.

jimpImage.crop(x, y, width, height)
  • x: the x coordinate to crop from
  • y: the y coordinate to crop from
  • width: the width of the crop region
  • height: the height of the crop region

See it in action in the live example below:

Resizing an image

The Jimp resize() function resizes an image to set width and height using a 2-pass bilinear algorithm.

jimpImage.resize(width, height)
  • width: the width to resize the image
  • height: the height to resize the image to

See it in action in the live example below:

Rotating an image

The Jimp rotate() function rotates an image clockwise by a number of degrees. Note that the width and height of the image will be resized accordingly by default.

jimpImage.rotate(degrees)
  • degrees: the number of degrees to rotate the image by

See it in action in the live example below:

Filtering an image

Although Jimp does not come with a single filtering function, it offers several functions to achieve the desired results. For example, you can implement an image filtering feature by harnessing the blur(), color(), dither(), normalize(), or threshold() functions.

Let’s see some of them in action in the live demo below:

Jimp vs PhotoEditor SDK

Undoubtedly, Jimp is a powerful tool. It's an amazingly lightweight and simple library that offers so many image manipulations. On the other hand, achieving complex results requiring multiple manipulations to be performed on the end user's needs could become challenging. In detail, this would require an advanced, robust, reliable, and easy-to-use UI that only a commercial solution such as IMG.LY’s PhotoEditor SDK can offer.

photo-editor-sdk-photoeditor-for-web

You could build such a UI yourself on top of Jimp, but this would take a lot of time and effort. This is especially true if you want to implement a general-purpose application, such as an image processing application. For limited and specific tasks without any user interaction, Jimp is the ideal solution.

Also, now you can take a look at the CreativeEditor SDK which is a more advanced API solution and obvious alternative to Jimp! The fresh new release of the CreativeEditor SDK has an updated asset library and APIs, basically a great place to start tinkering around with it.

Conclusion

Today we learned about the jimp JavaScript library, its dependencies, how it works, and how to use it in React real-world scenarios. Specifically, this npm library comes with several image manipulation functions that can be used with a few lines of code. However, building a complex image editing application on top of it would require an entire UI, and you might want to avoid spending time on it. In this case, you should look into a more advanced, fully-featured, and ready-to-use solution – such as PhotoEditorSDK.

Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on Twitter with any questions, comments, or suggestions.


To stay in the loop with our latest articles and case studies, subscribe to our Newsletter.

GO TOP