Create your own 📷 image compressor & to webp convertor using HTML, CSS, JavaScript from scratch 🚀
EHSAN.
Posted on September 7, 2024
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>
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 -->
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;
}
}
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 ... -->
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");
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");
});
};
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);
});
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);
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());
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());
I also added extra comments in every point, So that this may be easy for you to understand. 💖
Posted on September 7, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.