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.

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" />
                            w3wiki 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;


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;
    }
  }


Steps to run the application:

npm start

Output: Type the following URL in the address bar http://localhost:3000/



Image Compressor using ReactJS

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.

Similar Reads

Prerequisites

React CSS JSX Function Components in React...

Steps to create the React App:

Step 1: Create a React App...

Project Structure:

...

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....