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-compression23# or45yarn 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-23cd .\Image-Compressor\45yarn start
After this is in your browser, you should be able to see this page
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() {23super();45this.state = {67compressed link:89"https://testersdock.com/wp-content/uploads/2017/09/file-upload-1280x640.png",1011originalImage: "",1213originalLink: "",1415clicked: false,1617uploadImage: false1819};2021}
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<input23type="file"45accept="image/*"67className="mt-2 btn btn-outline-warning w-75"89onChange={e => this.handle(e)}1011/>
Once we have uploaded an image the handle
method will be called
1handle = e => {23const imageFile = e.target.files[0];45this.setState({67originalLink: URL.createObjectURL(imageFile),89originalImage: imageFile,1011outputFileName: imageFile.name,1213uploadImage: true1415});1617};
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 ? (23<Card.Img45className="ht"67variant="top"89src={this.state.originalLink}1011></Card.Img>1213) : (1415<Card.Img1617className="ht"1819variant="top"2021src="https://testersdock.com/wp-content/uploads/2017/09/file-upload-1280x640.png"2223></Card.Img>2425)}
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 ? (23<Button45variant="primary"67onClick={e => this.click(e)}89>1011Compress1213</Button>1415) : (1617<></>1819)}
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 = {23maxSizeMB: 2,45maxWidthOrHeight: 800,67useWebWorker: true89};10111213if (options.maxSizeMB >= this.state.originalImage.size / 1024) {1415alert("Bring a bigger image");1617return 0;1819}20212223let output;2425imageCompression(this.state.originalImage, options).then(x => {2627output = x;28293031const downloadLink = URL.createObjectURL(output);3233this.setState({3435compressedLink: downloadLink3637});3839});40414243this.setState({ clicked: true });4445return 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) {23alert("Bring a bigger image");45return 0;67}
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 => {23output = x;4567const downloadLink = URL.createObjectURL(output);89this.setState({1011compressedLink: downloadLink1213});1415});
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>23{this.state.clicked ? (45<div className="d-flex justify-content-center">67<a89href={this.state.compressedLink}1011download={this.state.outputFileName}1213className="mt-2 btn btn-info w-75"1415>1617Download1819</a>2021</div>2223) : (2425<></>2627)}
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.