Image Compression Using React.js

Banner for a MediaJam post

Eugene Musebe

Images draw attention, trigger emotions, and improve the user experience of your website. Image compression involves the reduction of the size of your image so that it takes less space on the hard drive and for better search engine optimization when it comes to websites e.g., 2MB to 440kbs. The image still retains its physical properties. We are going to use React to compress our images.

In this demo, we are going to explore how we can achieve this.

Codesandbox

The final version of this project can be viewed on Codesandbox.

Github

Check out the complete source code in this GitHub Repository.

Pre-requisites

To effectively follow along through this article you are required to have:

  • React.js basic skills

  • Basic knowledge of HTML

  • Knowledge of Javascript

  • Some knowledge of Bootstrap

Introduction

In this demo, we are going to use the browser-image-compression package to compress our images from a high-resolution image to a low-resolution image. You can read more about this package by clicking this link.

browser-image-compression is a module used to compress jpeg and png images by reducing resolution or storage size before uploading to the server to save bandwidth.

you can install it via npm or yarn

1npm install browser-image-compression
2
3# or
4
5yarn add browser-image-compression

Then import it into your components

1import imageCompression from "browser-image-compression";

Sample Project Setup

In this article, I will need you to clone the project from GitHub

1git clone https://github.com/musebe/-Image-Compressor-
2
3cd .\Image-Compressor\
4
5yarn start

After this is in your browser, you should be able to see this page

img.png

Usage

Let's now examine the ImageCompressor.js component to understand how the browser-image-compression package works.

Configuring the Component's State

Since this is a class component we are able to store the state for our component.

1constructor() {
2
3super();
4
5this.state = {
6
7compressed link:
8
9"https://testersdock.com/wp-content/uploads/2017/09/file-upload-1280x640.png",
10
11originalImage: "",
12
13originalLink: "",
14
15clicked: false,
16
17uploadImage: false
18
19};
20
21}

The compressed link will store the image link of the compressed image and the original image and the original link will store the values of the original image and original link respectively. The clicked and upload image store a boolean value that is false by default and changes to true when a button is clicked and when an image is uploaded.

Handling the Uploaded Image

When the Image is uploaded we want to change the state of our Component. To do this we are going to call the setState method since we just don't change the state of the component directly.

1<input
2
3type="file"
4
5accept="image/*"
6
7className="mt-2 btn btn-outline-warning w-75"
8
9onChange={e => this.handle(e)}
10
11/>

Once we have uploaded an image the handle method will be called

1handle = e => {
2
3const imageFile = e.target.files[0];
4
5this.setState({
6
7originalLink: URL.createObjectURL(imageFile),
8
9originalImage: imageFile,
10
11outputFileName: imageFile.name,
12
13uploadImage: true
14
15});
16
17};

event.target.files allows you to access a list of uploaded files. We can then get the first file since we process an image at a time using e.target.files[0]. To change the state we use setState to set the originalLink, originalImage, output filename, and upload image state as shown above.

URL.createObjectURL() is a static method that creates a string containing a URL representing the object given in the parameter.

User interface

We will use the shorthand for the if-else statement, ternary operator to change the user interface of our application when the user has not uploaded an image and he/she has uploaded an image.

1{this.state.uploadImage ? (
2
3<Card.Img
4
5className="ht"
6
7variant="top"
8
9src={this.state.originalLink}
10
11></Card.Img>
12
13) : (
14
15<Card.Img
16
17className="ht"
18
19variant="top"
20
21src="https://testersdock.com/wp-content/uploads/2017/09/file-upload-1280x640.png"
22
23></Card.Img>
24
25)}

If the state upload image is true it would replace the image the link of the Card Image with the originalLink which the state changed upon uploading. Otherwise, the Card Image link will be hard coded as shown above.

It is only after an image has been uploaded that we will see the compress button.

1{this.state.outputFileName ? (
2
3<Button
4
5variant="primary"
6
7onClick={e => this.click(e)}
8
9>
10
11Compress
12
13</Button>
14
15) : (
16
17<></>
18
19)}

When the image is not uploaded we don't have the state outputFileName hence we don't see the compress button. This state is set only after uploading hence returning the compress button.

Compressing the Uploaded Image

1const options = {
2
3maxSizeMB: 2,
4
5maxWidthOrHeight: 800,
6
7useWebWorker: true
8
9};
10
11
12
13if (options.maxSizeMB >= this.state.originalImage.size / 1024) {
14
15alert("Bring a bigger image");
16
17return 0;
18
19}
20
21
22
23let output;
24
25imageCompression(this.state.originalImage, options).then(x => {
26
27output = x;
28
29
30
31const downloadLink = URL.createObjectURL(output);
32
33this.setState({
34
35compressedLink: downloadLink
36
37});
38
39});
40
41
42
43this.setState({ clicked: true });
44
45return 1;

To prevent the user to upload an image less than 2mb we will check whether the maxSizeMB is greater than or equal to the originalImage size.

1if (options.maxSizeMB >= this.state.originalImage.size / 1024) {
2
3alert("Bring a bigger image");
4
5return 0;
6
7}

imageCompression() is a method that takes two parameters: the originalImage and the options.

We will have a promise in which when its state is fulfilled, that is the imageCompression() returns an object x, compressed image for our case. We will then create an Image URL for the compressed Image using the URL.createObjectURL(). We will also change the compressed link-state Compressed Image URL as shown below using setState.

1imageCompression(this.state.originalImage, options).then(x => {
2
3output = x;
4
5
6
7const downloadLink = URL.createObjectURL(output);
8
9this.setState({
10
11compressedLink: downloadLink
12
13});
14
15});

Downloading the Compressed Image

Lastly, we'll need to download the compressed image and compare it with the original image whether they are of different sizes.

1<Card.Img variant="top" src={this.state.compressedLink}></Card.Img>
2
3{this.state.clicked ? (
4
5<div className="d-flex justify-content-center">
6
7<a
8
9href={this.state.compressedLink}
10
11download={this.state.outputFileName}
12
13className="mt-2 btn btn-info w-75"
14
15>
16
17Download
18
19</a>
20
21</div>
22
23) : (
24
25<></>
26
27)}

Once the download button is clicked we'll get the link of the compressed Image from our component's state and then use it in the <a> href attribute. You will also need to add the download attribute to the anchor tag which will take the outputFileName.

Conclusion

In this article, we learned how we can compress images based on their sizes offline using React and the browser-image-compression package without losing the physical properties.

Eugene Musebe

Software Developer

I’m a full-stack software developer, content creator, and tech community builder based in Nairobi, Kenya. I am addicted to learning new technologies and loves working with like-minded people.