In this article, you will learn to compress an image in JavaScript and then upload it to Imgur. Similar to our previous guide on resizing images, and the one on drawing on images, you can accomplish everything with the HTML5 <canvas>
element and we will involve any external libraries for this.
Smartphones cameras have become increasingly accurate and enhanced their photo quality for years. Consequently, their file size has grown as well. Since the speed of the average network has not improved at the same pace, it is essential to compress the images before uploading them.
Compressing is about downscaling an image. In other words, you want to reduce either its size or quality or both. By doing so, you can avoid uploading large images, saving the end-user time and money.
Compressing an Image With <canvas>
You can clone the GitHub repository that supports this article with the following commands:
git clone https://github.com/Tonel/how-to-compress-an-image-in-javascript-imgly
Then, you can try the demo application by opening the index.html
file in your browser.
Otherwise, keep following this step-by-step tutorial and learn how to build the demo application.
1. Implementing the Compression Logic
You can compress an image by solely using the HTML <canvas>
element. This is a powerful image manipulation tool that allows you to achieve many results, as we have already explored in our blog.
Now, let’s delve into how to compress an image with canvas
:
function compressImage(imgToCompress, resizingFactor, quality) {
// resizing the image
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const originalWidth = imgToCompress.width;
const originalHeight = imgToCompress.height;
const canvasWidth = originalWidth * resizingFactor;
const canvasHeight = originalHeight * resizingFactor;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context.drawImage(
imgToCompress,
0,
0,
originalWidth * resizingFactor,
originalHeight * resizingFactor
);
// reducing the quality of the image
canvas.toBlob(
(blob) => {
if (blob) {
// showing the compressed image
resizedImage.src = URL.createObjectURL(resizedImageBlob);
}
},
"image/jpeg",
quality
);
}
This function is an extension of the resizeImage()
function defined in this article. So, follow the link to that tutorial to learn more about it.
What is new here are the last few lines, which take care of reducing the quality of the uploaded image based on the quality
parameter. As you can see, the last part of the compressImage()
is based on the toBlob()
function. This transforms the image stored in the canvas into a Blob
object and compresses it based on the last parameter passed to the function. This last parameter represents the quality of the target image file.
Just like resizingFactor
, quality
must contain a Number
between 0 and 1.
Also, since the toBlob()
function returns a Blob
object, you can store it in a global variable. Then, you can use the blob
object representing the compressed image file to upload it to your server. Let’s see how.
2. Uploading an Image to Imgur
First, you need an Imgur account. If you already have one, log in here. Otherwise, create a new account for free here.
Now, register an application here to have access to the Imgur API program. Fill out the form as follows:
Then, click on “Submit” and you should get access to this page.
Store your Client-ID
in a safe place. You will need it later.
Now, you have everything required to start uploading images to your Imgur application.
Uploading an image to Imgur in JavaScript is easy and can be achieved with just a bunch of lines of code, as below:
// compressedImageBlob represents the compressed image Blob to upload
const formdata = new FormData();
formdata.append("image", compressedImageBlob);
fetch("https://api.imgur.com/3/image/", {
method: "POST",
headers: {
Accept: "application/json",
Authorization: "Client-ID YOUR_CLIENT_ID"
},
body: formdata
}).then((response) => {
if (response?.status === 403) {
console.error("Unvalid Client-ID!");
} else if (response?.status === 200) {
// retrieving the URL of the image
// just uploaded to Imgur
response.json().then((jsonResponse) => {
console.log(`URL: ${jsonResponse.data?.link}`);
});
} else {
console.error(response);
}
});
Replace YOUR_CLIENT_ID
with the Client-ID
retrieved before, and you should now be able to use this snippet to upload your images to Imgur.
3. Putting It All Together
Now it is time to see the compressImage()
function in action through a simple example.
<!DOCTYPE html>
<html>
<body>
<h1>Compress and Resize an Image</h1>
<p>
Upload an image and compress it or use the following demo image
</p>
<input id="upload" type="file" accept="image/*" />
<div>
<h2>Original Image</h2>
<img
style="margin-top: 5px;"
id="originalImage"
src="demo.jpg"
crossorigin="anonymous"
/>
</div>
<div style="margin-top: 5px;">
<span>Resizing: </span>
<input type="range" min="1" max="100" value="80" id="resizingRange" />
</div>
<div style="margin-top: 5px; margin-left: 8px;">
<span>Quality: </span>
<input type="range" min="1" max="100" value="80" id="qualityRange" />
</div>
<h2>Compressed Image</h2>
<div><b>Size:</b> <span id="size"></span></div>
<img id="compressedImage" />
<div>
<button id="uploadButton">Upload to Imgur</button>
</div>
<script src="src/index.js"></script>
</body>
</html>
const fileInput = document.querySelector("#upload");
const originalImage = document.querySelector("#originalImage");
const compressedImage = document.querySelector("#compressedImage");
const resizingElement = document.querySelector("#resizingRange");
const qualityElement = document.querySelector("#qualityRange");
const uploadButton = document.querySelector("#uploadButton");
let compressedImageBlob;
let resizingFactor = 0.8;
let quality = 0.8;
// initializing the compressed image
compressImage(originalImage, resizingFactor, quality);
fileInput.addEventListener("change", async (e) => {
const [file] = fileInput.files;
// storing the original image
originalImage.src = await fileToDataUri(file);
// compressing the uplodaded image
originalImage.addEventListener("load", () => {
compressImage(originalImage, resizingFactor, quality);
});
return false;
});
resizingElement.oninput = (e) => {
resizingFactor = parseInt(e.target.value) / 100;
compressImage(originalImage, resizingFactor, quality);
};
qualityElement.oninput = (e) => {
quality = parseInt(e.target.value) / 100;
compressImage(originalImage, resizingFactor, quality);
};
uploadButton.onclick = () => {
// uploading the compressed image to
// Imgur (if present)
if (compressedImageBlob) {
const formdata = new FormData();
formdata.append("image", compressedImageBlob);
fetch("https://api.imgur.com/3/image/", {
method: "POST",
headers: {
Accept: "application/json",
Authorization: "Client-ID YOUR_CLIENT_ID"
},
body: formdata
}).then((response) => {
if (response?.status === 403) {
alert("Unvalid Client-ID!");
} else if (response?.status === 200) {
// retrieving the URL of the image
// just uploaded to Imgur
response.json().then((jsonResponse) => {
alert(`URL: ${jsonResponse.data?.link}`);
});
alert("Upload completed succesfully!");
} else {
console.error(response);
}
});
} else {
alert("Rezind and compressed image missing!");
}
};
function compressImage(imgToCompress, resizingFactor, quality) {
// showing the compressed image
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const originalWidth = imgToCompress.width;
const originalHeight = imgToCompress.height;
const canvasWidth = originalWidth * resizingFactor;
const canvasHeight = originalHeight * resizingFactor;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context.drawImage(
imgToCompress,
0,
0,
originalWidth * resizingFactor,
originalHeight * resizingFactor
);
// reducing the quality of the image
canvas.toBlob(
(blob) => {
if (blob) {
compressedImageBlob = blob;
compressedImage.src = URL.createObjectURL(compressedImageBlob);
document.querySelector("#size").innerHTML = bytesToSize(blob.size);
}
},
"image/jpeg",
quality
);
}
function fileToDataUri(field) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.addEventListener("load", () => {
resolve(reader.result);
});
reader.readAsDataURL(field);
});
}
// source: https://stackoverflow.com/a/18650828
function bytesToSize(bytes) {
var sizes = ["Bytes", "KB", "MB", "GB", "TB"];
if (bytes === 0) {
return "0 Byte";
}
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + " " + sizes[i];
}
The input
element allows users to upload an image. This is then passed to the compressImage()
function along with the resizingFactor
and quality
values retrieved from the respective range input
HTML elements. This function takes care of compressing the image, displaying it, and storing its Blob
representation to the global compressedImageBlob
variable. Finally, compressedImageBlob
is uploaded to Imgur when the “Upload to Imgur” button is clicked.
Notice that these two snippets are what allow you to implement the live example you can find at the beginning of the article.
Final Considerations
Compressing an image in Vanilla JavaScript is easy. You can achieve this with no extra libraries and in a dozen of lines of code. At the same time, the resizing part of the process relies on an image interpolation algorithm that changes according to the browser in use. This can lead to different results based on the end-user’s browser. Also, compressing while preserving quality is always tricky and can easily become a grueling goal to achieve.
If you want to avoid this stress, consider adopting a commercial and browser-consistent solution like PhotoEditorSDK. This library provides access to a wide set of tools that allow you to manipulate your images in many ways and with an advanced and easy-to-use UI.
Resizing an Image with PhotoEditor SDK
First, read this article from the official documentation to get started with PhotoEditorSDK
in HTML and JavaScript. Then, you can use the transform tool to resize your image, as shown below:
Check out this feature on the PhotoEditorSDK demo page.
Conclusion
In this article, we learned how to downscale an image in JavaScript before uploading it to your server. In detail, we resized and reduced the quality of an uploaded image before uploading it to Imgur. Everything was achieved by using only the HTML5 <canvas>
element. This is a powerful tool supported by most browsers that allows you to resize and change the quality of an image with just a few lines of code. On the other hand, this process may not be browser-consistent. That is why we also introduced a commercial and more reliable solution – such as PhotoEditorSDK.
Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on Twitter with any questions, comments, or suggestions. To stay in the loop with our latest articles and case studies, subscribe to our Newsletter.