Image Compressor using ReactJS
Last Updated :
25 Jul, 2024
This article focuses on crafting an Interactive Feature-based Image Compressor utilizing the ReactJS library. Users can upload image files and adjust compression quality via a slider. Upon setting the compression quality and initiating compression, users can download the compressed image locally. Additionally, the application offers navigation for accessing Instructions and Compression History.
Output Preview: Let us have a look at how the final output will look like.

Prerequisites
Steps to create the React App:
Step 1: Create a React App
npx create-react-app image-compressor
Step 2: Navigate to the newly created project folder by executing the below command.
cd image-compressor
Step 3: Steps to install required modules
npm install react-bootstrap @fortawesome/react-fontawesome @fortawesome/free-solid-svg-icons
npm install image-conversion bootstrap
Project Structure:

The updated dependencies in package.json will look like this:
"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"bootstrap": "^5.3.2",
"image-conversion": "^2.1.1",
"react": "^18.2.0",
"react-bootstrap": "^2.9.1",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
Approach to create Image Compressor:
- The application is structured using React components like Buttons, NavBar, Modal, Spinner, etc., along with CSS for styling.
- Image upload triggers validation to ensure only image files can be compressed, with customization options for compression quality.
- Users can download compressed images and access features like viewing instructions and past compression history.
- The interface is organized with sections for navigation, image display/upload, compression controls, and a Reset Button for clearing uploaded files.
Example: Insert the below code in the App.js, Compressor.js, and Compressor.css file mentioned in the above directory structure.
CSS
/* Components/Compressor.css */
.center {
text-align: center !important;
}
.mainContainer {
margin: 0;
text-align: center;
}
@media (max-width: 768px) {
.mainContainer {
margin: 0;
}
}
.navbar {
z-index: 1041;
box-shadow: 0 4px 8px rgba(233, 12, 12, 0.2);
background-color: #fff78b !important;
padding: 20px;
}
.navbar-content {
color: green !important;
text-align: center !important;
font-weight: bold;
font-size: 24px;
text-transform: uppercase;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.help-icon,
.history-icon {
font-size: 24px;
cursor: pointer;
margin-right: 20px;
color: #000;
}
.help-icon:hover,
.history-icon:hover {
color: #3498db;
}
.help-container,
.history-container {
text-align: left;
padding: 10px;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 5px;
margin: 10px;
max-height: 200px;
overflow-y: auto;
}
.social-icons {
margin-right: 10px;
box-sizing: border-box;
width: 1.5em !important;
height: 1.5em !important;
color: #ecf0f1;
transition: color 0.3s;
}
.social-icons:hover {
color: #e74c3c;
}
.uploadCard {
width: 80%;
display: inline-block;
}
.image {
display: block;
max-width: 100%;
height: auto;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border: 1px solid #ecf0f1;
}
.upload-btn-wrapper {
position: relative;
overflow: hidden;
display: inline-block;
}
.btn {
border: none;
color: white;
padding: 10px 20px;
border-radius: 8px;
font-size: 20px;
font-weight: bold;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
}
.btn:hover {
background-color: #2980b9;
transform: scale(1.05);
}
.upload-btn-wrapper input[type="file"] {
font-size: 100px;
position: absolute;
left: 0;
top: 0;
opacity: 0;
}
#qualitySlider {
width: 100%;
padding: 0;
margin: 10px 0;
}
.btn.download-btn {
background-color: #2ecc71;
transition: background-color 0.3s;
}
.btn.download-btn:hover {
background-color: #27ae60;
}
.btn-reset {
border: none;
color: white;
background-color: #e74c3c;
padding: 10px 20px;
border-radius: 8px;
font-size: 20px;
font-weight: bold;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
margin-left: 20px;
}
.btn-reset:hover {
background-color: #c0392b;
transform: scale(1.05);
}
.compressed-message {
font-size: 24px;
font-weight: bold;
color: #2ecc71;
margin-top: 10px;
transition: color 0.3s;
}
.compressed-message:hover {
color: #27ae60;
}
.button-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
}
@media (max-width: 768px) {
.help-container,
.history-container {
width: 100%;
max-width: none;
}
}
JavaScript
//App.js
import React from 'react';
import './App.css';
import CompressorComp
from "./Components/Compressor";
import 'bootstrap/dist/css/bootstrap.css';
function App() {
return (
<CompressorComp />
);
}
export default App;
JavaScript
//Components/Compressor.js
import React,
{
useState, useEffect
} from 'react';
import {
Navbar, Card,
Spinner, Modal,
Button
} from 'react-bootstrap';
import { FontAwesomeIcon }
from '@fortawesome/react-fontawesome';
import {
faImage, faDownload,
faUpload, faImage as faImagePlaceholder,
faQuestionCircle,
faHistory
} from '@fortawesome/free-solid-svg-icons';
import './Compressor.css';
import { compress }
from 'image-conversion';
function CompressorComp() {
const [compressedLink, setCompressedLink] = useState('');
const [originalImage, setOriginalImage] = useState(null);
const [originalLink, setOriginalLink] = useState('');
const [uploadImage, setUploadImage] = useState(false);
const [outputFileName, setOutputFileName] = useState('');
const [compressionQuality, setCompressionQuality] = useState(0.8);
const [originalSize, setOriginalSize] = useState(0);
const [compressedSize, setCompressedSize] = useState(0);
const [isCompressed, setIsCompressed] = useState(false);
const [compressionInProgress, setCompressionInProgress] = useState(false);
const [loading, setLoading] = useState(false);
const [showHelp, setShowHelp] = useState(false);
const [showHistory, setShowHistory] = useState(false);
const [compressedHistory, setCompressedHistory] = useState([]);
const [showCompressedImage, setShowCompressedImage] = useState(false);
const [modalShow, setModalShow] = useState(false);
useEffect(() => {
if (originalImage) {
setCompressedLink('');
setCompressedSize(0);
setIsCompressed(false);
setShowCompressedImage(false);
}
}, [originalImage]);
async function uploadLink(event) {
const imageFile = event.target.files[0];
setOriginalLink(URL.createObjectURL(imageFile));
setOriginalImage(imageFile);
setOutputFileName(imageFile.name);
setUploadImage(true);
setOriginalSize(imageFile.size);
}
async function compressImage() {
if (!originalImage) {
alert('Please upload an image first.');
return;
}
try {
setCompressionInProgress(true);
setShowCompressedImage(false);
setLoading(true);
const compressedImage =
await compress(originalImage, {
quality: compressionQuality,
width: 800,
height: 800,
});
setCompressedLink(URL.createObjectURL(compressedImage));
setCompressedSize(compressedImage.size);
setIsCompressed(true);
setCompressedHistory(
[
...compressedHistory,
{
link: compressedLink,
name: outputFileName
}
]);
setTimeout(
() => {
setLoading(false);
setShowCompressedImage(true);
}, 2000);
} catch (error) {
console.error('Image compression failed:', error);
alert('Image compression failed. Please try again.');
} finally {
setCompressionInProgress(false);
}
}
function resetApp() {
setOriginalLink('');
setOriginalImage(null);
setUploadImage(false);
setOutputFileName('');
setCompressionQuality(0.8);
setOriginalSize(0);
setCompressedSize(0);
setIsCompressed(false);
setCompressedLink('');
setShowCompressedImage(false);
}
function toggleHelp() {
setShowHelp(!showHelp);
}
function toggleHistory() {
setShowHistory(!showHistory);
}
return (
<div className="mainContainer">
<Navbar className="navbar justify-content-between"
bg="lig" variant="dark">
<div>
<Navbar.Brand className="navbar-content">
<center>
<FontAwesomeIcon icon={faImage}
className="icon" />
GeeksforGeeks Image Compressor
</center>
</Navbar.Brand>
</div>
<div className="navbar-actions">
<FontAwesomeIcon icon={faQuestionCircle}
className="help-icon" onClick={toggleHelp} />
<FontAwesomeIcon icon={faHistory}
className="history-icon" onClick={toggleHistory} />
</div>
</Navbar>
{showHelp && (
<div className="help-container">
<p>Instructions:</p>
<ul>
<li>
Upload an image using
the "Upload a file" button.
</li>
<li>
Adjust the compression
quality using the slider.
</li>
<li>
Press the "Compress" button
to start the compression.
</li>
<li>
Download the compressed image
using the "Download" button.
</li>
</ul>
</div>
)}
{showHistory && (
<div className="history-container">
<p>Compressed History:</p>
<ul>
{
compressedHistory.map(
(item, index) => (
<li key={index}>
<a href={item.link}
download={item.name}>
{item.name}
</a>
</li>
))
}
</ul>
</div>
)}
<div className="row mt-5">
<div className="col-xl-3 col-lg-3
col-md-12 col-sm-12">
{uploadImage ? (
<Card.Img className="image"
variant="top" src={originalLink}
alt="Original Image" />
) : (
<Card.Img className="uploadCard"
variant="top" src={faUpload} alt="" />
)}
<div className="d-flex justify-content-center
upload-btn-wrapper">
<label htmlFor="uploadBtn"
className="btn btn-primary">
<FontAwesomeIcon icon={faUpload}
className="icon" />
Upload a file
</label>
<input
type="file"
id="uploadBtn"
accept="image/*"
className="mt-2 btn btn-primary w-75"
onChange={(event) => uploadLink(event)} />
</div>
</div>
<div
className="col-xl-6 col-lg-6
col-md-12 col-sm-12
d-flex justify-content-center
align-items-baseline">
<div>
{outputFileName ? (
<div>
<label htmlFor="qualitySlider">
Compression Quality:
</label>
<input
id="qualitySlider"
type="range"
min="0.1"
max="1"
step="0.1"
value={compressionQuality}
onChange={
(event) =>
setCompressionQuality(
parseFloat(event.target.value)
)
}
/>
<div className="text-center">
Original Size:
{
Math.round(originalSize / 1024)
} KB
<br />
Compressed Size:
{
Math.round(compressedSize / 1024)
} KB
</div>
<div className="text-center">
{isCompressed &&
!compressionInProgress && (
<div className="text-success
compressed-message">
Image compressed successfully!
</div>
)}
{
compressionInProgress &&
<div className="text-info">
Compressing image...
</div>
}
</div>
<div className="button-container">
{loading ? (
<div className="text-info">
Loading...
</div>
) : (
<button type="button"
className="btn btn-success"
onClick={compressImage}>
<FontAwesomeIcon icon={faImage}
className="icon" />
Compress
</button>
)}
<button type="button"
className="btn btn-danger ml-3"
onClick={resetApp}>
Reset
</button>
</div>
</div>
) : (
<></>
)}
</div>
</div>
<div className="col-xl-3 col-lg-3 col-md-12 col-sm-12">
{showCompressedImage ? (
<div>
<Card.Img
className="image"
variant="top"
src={compressedLink}
alt="Compressed Image"
onClick={() => setModalShow(true)}
style={{ cursor: 'pointer' }}
/>
<a href={compressedLink}
download={outputFileName}
className="mt-2 btn btn-success
w-75 download-btn">
<FontAwesomeIcon icon={faDownload}
className="icon" />
Download
</a>
<Modal show={modalShow}
onHide={
() =>
setModalShow(false)
} size="lg">
<Modal.Body className="text-center">
<Card.Img className="image"
variant="top" src={compressedLink}
alt="Compressed Image" />
</Modal.Body>
<Modal.Footer>
<Button variant="secondary"
onClick={
() => setModalShow(false)
}>
Close
</Button>
</Modal.Footer>
</Modal>
</div>
) : (
<div className="d-flex align-items-center
justify-content-center">
{
compressionInProgress &&
<Spinner animation="border" variant="primary" />
}
{
!uploadImage &&
!compressionInProgress && (
<FontAwesomeIcon icon={faImagePlaceholder}
className="icon" size="3x" />
)
}
</div>
)}
</div>
</div>
</div>
);
}
export default CompressorComp;
Steps to run the application:
npm start
Output: Type the following URL in the address bar http://localhost:3000/
Similar Reads
Image To PDF Converter using React
Image To PDF Converter using React is a web application that allows users to upload images and convert them into PDF documents. It uses React's state management and file handling capabilities to provide a user-friendly interface for image upload, display, deletion, and PDF generation. This applicati
4 min read
Create an Image Resizer and Compressor Using React
In this tutorial, we'll create an image resizer and compressor application using React. We search for different tools and websites on the internet to resize and compress the image. But, as a web developer, we can create our image resize and compressor using React. The application allows user to uplo
5 min read
ReactJS UI Ant Design Image Component
Ant Design Library has this component pre-built, and it is very easy to integrate as well. Image Component is used to provide a way to put images in our application that are Previewable. We can use the following approach in ReactJS to use the Ant Design Image Component. Image Props: alt: It is used
2 min read
React Rebass Image Component
React Rebass is a front-end framework that was designed keeping react in mind. In this article, we will know how to use Image Component in React Rebass. The Image is an important component that is required in each development. So to create an Image component, we can import the Rebass Image component
2 min read
Re-rendering Components in ReactJS
Re-rendering is an important concept in ReactJS as it determines how and when components update. Understanding the re-rendering process is essential for optimizing the performance of React applications. What is Re-rendering in ReactJS?In React, a re-render happens when a component's state or props c
5 min read
How to crop images in ReactJS ?
Image cropping is a common requirement in web applications, especially when dealing with user-generated content, photo editing, or image manipulation. ReactJS, being a popular JavaScript library for building user interfaces, provides various techniques and libraries that can be used to implement ima
3 min read
Paint App using ReactJS
In this article, we will be building a simple paint application that lets you draw just like in MS-Paint. Through this article, we will learn how to implement and work with canvas in React.js. Our app contains two sections, one for drawing and the other is a menu where the user can customize the bru
4 min read
Create a meme generator by using ReactJS
In this tutorial, weâll create a meme generator using ReactJS. In the meme generator, we have two text fields in which we enter the first text and last text. After writing the text when we click the Gen button, it creates a meme with an image and the text written on it. Preview Image: PrerequisiteTh
3 min read
How to create Image Slider in ReactJS ?
Image Slider is a dynamic web element that displays a collection of images and has a slider to switch between the Images. It is the most common feature to show image collection in web applications or mobile apps. Websites like Amazon.com, Flipkart.com, and many e-commerce sites use image sliders to
4 min read
ReactJS Onsen UI Icon Component
ReactJS Onsen-UI is a popular front-end library with a set of React components that are designed to developing HTML5 hybrid and mobile web apps in a beautiful and efficient way. Icon component is used to display the icons as icons are required for every application for UI purposes. We can use the fo
2 min read