DEV Community

EHSAN.
EHSAN.

Posted on • Originally published at your-codes.vercel.app

Create your own 📷 image compressor & to webp convertor using HTML, CSS, JavaScript from scratch 🚀

Effortless Image Compression and Conversion to .webp Format Using Pure HTML, CSS, and JavaScript 🚀 | your-ehsan | your-codes

Introducing a new image compressor and resizer: Reduce your image sizes without compromising quality. This Image Resizer & Compressor can resize and compress any image and it can also convert any Image to .webp. It means this is also any image to .webp convertor 🎉.

Images are an essential component of websites, blogs, and social media platforms. However, large images can slow down your website's loading time, leading to a poor user experience. This is where image compression and resizing come in - they allow you to reduce the size of your images without compromising on their quality. In this blog post, we introduce a new image compressor and resizer that will help you achieve just that.

What is an image compressor and resizer?

An image compressor and resizer is a tool that allows you to reduce the file size of your images without compromising on their quality. It achieves this by using various compression algorithms that remove unnecessary data from the image file while maintaining its visual integrity. A resizer, on the other hand, allows you to change the dimensions of your image while maintaining its aspect ratio.

Easy to use: Simply upload your image, choose the compression level resize it if you wish, and download the compressed image.

Customizable: Our tool allows you to choose the compression level that suits your needs. You can choose between high, medium, and low compression levels depending on your requirements.

Faster loading times: Compressing and resizing your images will reduce their file size, making them load faster on your website or social media platform.

Improved user experience: Faster loading times mean a better user experience for your visitors.

Reduced storage space: Compressing your images will also help you save storage space on your device or server.

Better SEO: Faster loading times can also improve your website's search engine ranking.

Let's start building

First of all, let's create an index.html file in the root of our project's folder. Then paste this code into the index.html file.


<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="IE=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>@your-ehsan | JS — Image_resizer & Compressor</title>
      <link
        rel="shortcut icon"
        href="https://github.com/your-ehsan.png"
        type="image/x-icon"
      />
    </head>
    <body>
      <div class="wrapper">
        <div id="UploadBox" class="upload-box">
          <input id="FileInput" type="file" accept="image/*" alt="" />
          <img hidden id="SelectedIMG" src="" alt="" />
          <i>
            <svg
              id="InputSVG"
              xmlns="http://www.w3.org/2000/svg"
              class="InputSVG"
              viewBox="0 0 640 512"
            >
              <path
                d="M144 480C64.5 480 0 415.5 0 336c0-62.8 40.2-116.2 96.2-135.9c-.1-2.7-.2-5.4-.2-8.1c0-88.4 71.6-160 160-160c59.3 0 111 32.2 138.7 80.2C409.9 102 428.3 96 448 96c53 0 96 43 96 96c0 12.2-2.3 23.8-6.4 34.6C596 238.4 640 290.1 640 352c0 70.7-57.3 128-128 128H144zm79-217c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l39-39V392c0 13.3 10.7 24 24 24s24-10.7 24-24V257.9l39 39c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-80-80c-9.4-9.4-24.6-9.4-33.9 0l-80 80z"
              />
            </svg>
          </i>
          <p class="InputText">Browse file to Upload</p>
        </div>
        <div class="content">
          <div class="row sizes">
            <div class="column width">
              <label for=""> width </label>
              <input type="number" name="" id="WidthInput" />
            </div>
            <div class="column height">
              <label for=""> height </label>
              <input type="number" name="" id="HeightInput" />
            </div>
          </div>
          <div class="row checkboxes">
            <div class="column ratio">
              <input type="checkbox" name="" id="ratio" checked />
              <label for="ratio">Lock aspect ratio</label>
            </div>
            <div class="column quality">
              <input type="checkbox" name="" id="quality" checked />
              <label for="quality">Reduce Quality</label>
            </div>
          </div>
          <button id="DownloadBtn" accesskey="d" class="download-btn">
            Download
          </button>
        </div>
      </div>
    </body>
  </html>
Enter fullscreen mode Exit fullscreen mode

After that you have to give your code some beauty, I am giving your HTML some beauty. For that, you have to create a new *.css *file with the name *style.css *and then link that stylesheet with your HTML file by adding this line between your head tag ->

like this one
<!-- ... rest of the other code -->
<head>
  <link rel="stylesheet" src="./style.css"/>
</head>
<!-- ... other code  -->
Enter fullscreen mode Exit fullscreen mode

after creating your stylesheet file and then linking it with your HTML file you have to add some style code in your style.css file.


@font-face {
  font-family: "Ubuntu";
  src: url("https://fonts.googleapis.com/css2?family=Ubuntu:wght@300&display=swap");
}  
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Ubuntu", sans-serif;
}
body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: #833ab4;
  background: -moz-linear-gradient(
    204deg,
    #833ab4de 0%,
    #1d70fdde 62%,
    #45fcdb93 100%
  );
  background: -webkit-linear-gradient(
    204deg,
    #833ab4de 0%,
    #1d70fdde 62%,
    #45fcdb93 100%
  );
  background: linear-gradient(
    204deg,
    #833ab4de 0%,
    #1d70fdde 62%,
    #45fcdb93 100%
  );
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#833ab4",endColorstr="#45fcdb",GradientType=1);
}
.wrapper {
  width: 450px;
  height: 280px;
  overflow: hidden;
  padding: 30px;
  background: #fff;
  border-radius: 12px;
  transition: 0.5s ease-out;
}
.active {
  height: max-content;
}
.wrapper .upload-box {
  height: 225px;
  display: flex;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  flex-direction: column;
  border: 2px dashed #696969;
}
.upload-box p {
  font-size: 1.2rem;
  margin-top: 20px;
  color: #696969;
}
.upload-box img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  border-radius: 8px;
  border: 6px;
}
.upload-box i {
  width: 30%;
  fill: #696969;
  object-fit: cover;
  object-position: center;
  border-radius: 8px;
  border: 6px;
}
.wrapper .content {
  margin-top: 30px;
}
.content .row {
  display: flex;
  justify-content: space-around;
}
.row .column label {
  font-size: 1.2rem;
  font-stretch: condensed;
  margin: 0 10px;
}
#FileInput {
  width: 100%;
  height: 100%;
  display: none;
}
.sizes .column input {
  width: 100%;
  height: 50px;
  outline: none;
  margin-top: 8px;
  padding: 0 16px;
  font-size: 1.2rem;
  font-weight: bold;
  color: #363bb6;
  border-radius: 6px;
  border: 1px solid #7c7db6;
}
.sizes .column input:focus {
  padding: 0 16px;
  border: 2px solid #5f5f5f;
}
.content .checkboxes {
  margin-top: 20px;
}
.checkboxes .column {
  display: flex;
  align-items: center;
}
.checkboxes .column input {
  width: 18px;
  height: 18px;
  accent-color: #7c7db6;
}
.content .download-btn {
  width: 100%;
  transition: all 0.5s ease-in-out;
  color: #fff;
  outline: none;
  border: none;
  cursor: pointer;
  font-size: 1.2rem;
  border-radius: 6px;
  padding: 16px 0;
  margin: 30px 0 10px;
  background: cadetblue;
  background: rgb(131, 58, 180);
  background: -moz-linear-gradient(
    94deg,
    #833ab4de 0%,
    #1d70fdde 62%,
    #45fcdb93 100%
  );
  background: -webkit-linear-gradient(
    94deg,
    #833ab4de 0%,
    #1d70fdde 62%,
    #45fcdb93 100%
  );
  background: linear-gradient(
    94deg,
    #833ab4de 0%,
    #1d70fdde 62%,
    #45fcdb93 100%
  );
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#833ab4",endColorstr="#45fcdb",GradientType=1);
  text-transform: capitalize;
}
.content .download-btn:active {
  background: #833ab4;
  background: -moz-linear-gradient(
    189deg,
    #833ab4de 19%,
    #1d70fdde 71%,
    #45fcdb93 100%
  );
  background: -webkit-linear-gradient(
    189deg,
    #833ab4de 19%,
    #1d70fdde 71%,
    #45fcdb93 100%
  );
  background: linear-gradient(
    189deg,
    #833ab4de 19%,
    #1d70fdde 71%,
    #45fcdb93 100%
  );
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#833ab4",endColorstr="#45fcdb",GradientType=1);
}
.hidden {
  display: none;
}
@media (min-width: 375px) {
  .wrapper {
    width: 350px;
    height: 250px;
    padding: 15px;
  }
  .active {
    height: max-content;
  }
  .row .column label {
    font-size: 0.8rem;
    text-transform: capitalize;
  }
  .checkboxes .column input {
    width: 12px;
    height: 12px;
  }
  .sizes .column input {
    height: 40px;
    margin-top: 8px;
    padding: 0 12px;
    font-size: 1rem;
  }
}

Enter fullscreen mode Exit fullscreen mode

after adding and linking this stylesheet with the HTML file that I provided earlier you noticed that the image compressor is still look like the actual one.

we are not done yet, we also need to add some logic 💡 using the JavaScript code. so that we can make our project useable.

let's start writing JS code.

first create main.js file with your *html *file like you did with *css *before. then link it with your html file by adding this snippet after <body></body> tag like this.

💡 remember this script tag should be within you <html></html> tag.

<!-- ... rest of the code -->
<script src="./main.js" rel="text/script"/>
<!-- rest of the code ... -->

Enter fullscreen mode Exit fullscreen mode

Before continuing please confirm that your html file and *main.js *files are linked then write this code in your JS file

Gathering Magical Tools (DOM Elements):

// Gathering magical tools from the wizard's wand (DOM)
let FileInput = document.querySelector("#FileInput"),
  WidthInput = document.querySelector("#WidthInput"),
  HeightInput = document.querySelector("#HeightInput"),
  ratio = document.querySelector("#ratio"),
  quality = document.querySelector("#quality"),
  SelectedIMG = document.querySelector("#SelectedIMG"),
  UploadBox = document.querySelector("#UploadBox"),
  InputText = document.querySelector(".InputText"),
  DownloadBtn = document.querySelector("#DownloadBtn");

Enter fullscreen mode Exit fullscreen mode

This part finds and stores different elements (like buttons, switches, and containers) from the HTML document. Each element is found using its unique ID or class name.

Storing Original Image Ratio:

let OgImageRatio;

// Function to load a selected picture
const loadFile = (e) => {
  const file = e.target.files[0];
  if (!file) return;
  SelectedIMG.src = URL.createObjectURL(file);
  SelectedIMG.addEventListener("load", () => {
    SelectedIMG.removeAttribute("hidden");
    document.querySelector("#InputSVG").classList = "hidden";
    InputText.className = "hidden";
    WidthInput.value = SelectedIMG.naturalWidth;
    HeightInput.value = SelectedIMG.naturalHeight;
    OgImageRatio = SelectedIMG.naturalWidth / SelectedIMG.naturalHeight;
    document.querySelector(".wrapper").classList.add("active");
  });
};

Enter fullscreen mode Exit fullscreen mode

When a picture is selected, this code calculates the original image ratio and stores it for later use. It also sets up the selected image for display.

Adjusting Width and Height:

WidthInput.addEventListener("keyup", () => {
  const height = ratio.checked
    ? WidthInput.value / OgImageRatio
    : HeightInput.value;
  HeightInput.value = Math.floor(height);
});

HeightInput.addEventListener("keyup", () => {
  const width = ratio.checked
    ? HeightInput.value * OgImageRatio
    : WidthInput.value;
  WidthInput.value = Math.floor(width);
});

Enter fullscreen mode Exit fullscreen mode

These parts dynamically adjust the width and height inputs based on user actions (typing). The aspect ratio can be locked or unlocked using the 'ratio' checkbox.

Resizing and Downloading the Image:

function ResizeandDownload() {
  // Creating magical canvas and link elements
  const canvas = document.createElement("canvas");
  const a = document.createElement("a");
  const ctx = canvas.getContext("2d");

  canvas.width = WidthInput.value;
  canvas.height = HeightInput.value;

  // Checking if image quality should be reduced
  const imgQuality = quality.checked ? 0.2 || 0.5 : 1.0;

  // Drawing the selected image on the canvas
  ctx.drawImage(SelectedIMG, 0, 0, canvas.width, canvas.height);

  // Creating a magical link to download the image in .webp format
  a.href = canvas.toDataURL("image/webp", imgQuality);
  a.download = `@your-ehsan_${new Date().getTime()}`; // Naming the downloaded file
  a.click(); // Initiating the magical download
}

// Starting the resizing and download process when the magical word is clicked
DownloadBtn.addEventListener("click", ResizeandDownload);

Enter fullscreen mode Exit fullscreen mode

This section creates a canvas, draws the selected image on it, and then converts it to a .webp format before initiating the download when the "Download" button is clicked.

Additional Triggers and Actions:

// Loading the selected picture when a picture is chosen
FileInput.addEventListener("change", loadFile);

// Triggering the treasure chest (file input) when the upload box is clicked
UploadBox.addEventListener("click", () => FileInput.click());
Enter fullscreen mode Exit fullscreen mode

These parts listen for events: 'change' for the file input to load the picture and 'click' for the upload box to trigger the file input when clicked.

This detailed breakdown explains how each part of the JavaScript code contributes to the functionality of the image resizer and compressor tool.

after adding all these lines step by step your image-compressor may be completed yet and working fine. if not then add here's the complete JS file that you may need to check.

Complete main.js file

// Gathering magical tools from the wizard's wand (DOM)
let FileInput = document.querySelector("#FileInput"), // Treasure chest for pictures
  WidthInput = document.querySelector("#WidthInput"), // Button to adjust width
  HeightInput = document.querySelector("#HeightInput"), // Button to adjust height
  ratio = document.querySelector("#ratio"), // Switch for aspect ratio
  quality = document.querySelector("#quality"), // Switch for image quality
  SelectedIMG = document.querySelector("#SelectedIMG"), // Picture frame
  UploadBox = document.querySelector("#UploadBox"), // Door to pick pictures
  InputText = document.querySelector(".InputText"), // Special text for interaction
  DownloadBtn = document.querySelector("#DownloadBtn"); // Secret word to start magic

let OgImageRatio; // Variable to store original image ratio

// Function to load a selected picture
const loadFile = (e) => {
  const file = e.target.files[0]; // Picking the selected picture
  if (!file) return; // If no picture is selected, stop here
  SelectedIMG.src = URL.createObjectURL(file); // Show the selected picture in the picture frame
  SelectedIMG.addEventListener("load", () => { // When the picture is loaded:
    SelectedIMG.removeAttribute("hidden"); // Show the picture
    document.querySelector("#InputSVG").classList = "hidden"; // Hide the upload icon
    InputText.className = "hidden"; // Hide the upload text
    WidthInput.value = SelectedIMG.naturalWidth; // Get the picture's width
    HeightInput.value = SelectedIMG.naturalHeight; // Get the picture's height
    OgImageRatio = SelectedIMG.naturalWidth / SelectedIMG.naturalHeight; // Calculate the original image ratio
    document.querySelector(".wrapper").classList.add("active"); // Activate the magical wrapper
  });
};

// Adjusting height based on width input
WidthInput.addEventListener("keyup", () => {
  const height = ratio.checked // Checking if aspect ratio should be kept
    ? WidthInput.value / OgImageRatio // If yes, calculate height based on width and original ratio
    : HeightInput.value; // If no, keep the existing height value
  HeightInput.value = Math.floor(height); // Set the calculated or existing height
});

// Adjusting width based on height input
HeightInput.addEventListener("keyup", () => {
  const width = ratio.checked // Checking if aspect ratio should be kept
    ? HeightInput.value * OgImageRatio // If yes, calculate width based on height and original ratio
    : WidthInput.value; // If no, keep the existing width value
  WidthInput.value = Math.floor(width); // Set the calculated or existing width
});

// Function to resize and download the image
function ResizeandDownload() {
  const canvas = document.createElement("canvas"); // Creating a magical canvas
  const a = document.createElement("a"); // Creating a magical link
  const ctx = canvas.getContext("2d"); // Getting magical painting powers from the canvas

  canvas.width = WidthInput.value; // Setting canvas width
  canvas.height = HeightInput.value; // Setting canvas height

  const imgQuality = quality.checked ? 0.2 || 0.5 : 1.0; // Checking if image quality should be reduced

  ctx.drawImage(SelectedIMG, 0, 0, canvas.width, canvas.height); // Drawing the selected image on the canvas
  a.href = canvas.toDataURL("image/webp", imgQuality); // Creating a magical link to download the image in .webp format
  a.download = `@your-ehsan_${new Date().getTime()}`; // Naming the downloaded file with a magical name
  a.click(); // Initiating the magical download
}

// Starting the resizing and download process when the magical word is clicked
DownloadBtn.addEventListener("click", ResizeandDownload);

// Loading the selected picture when a picture is chosen
FileInput.addEventListener("change", loadFile);

// Triggering the treasure chest (file input) when the upload box is clicked
UploadBox.addEventListener("click", () => FileInput.click());

Enter fullscreen mode Exit fullscreen mode

I also added extra comments in every point, So that this may be easy for you to understand. 💖

Top comments (2)

Collapse
 
ashutosh_dev profile image
Ashutosh_dev

Try to attach some demo link.

Collapse
 
your-ehsan profile image
EHSAN.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.