How to Resize an Image Before Upload with Client-Side JavaScript
In a document-scanning web app, image resizing is useful as it can correct the proportion of scanned documents and increase the DPI of document images to meet printing requirements.
In this article, we are going to talk about how to resize an image with JavaScript. One way is using Canvas and the other is using Dynamic Web TWAIN, a document-scanning SDK.
What you’ll build: A client-side image resizer that lets users pick a target resolution (including document presets like A4 and ID Card at various DPIs) and resize images in the browser using either the HTML5 Canvas API or Dynamsoft Dynamic Web TWAIN.
Key Takeaways
- JavaScript can resize images entirely client-side before upload using the Canvas API’s
drawImage()method, eliminating server round-trips. - Dynamic Web TWAIN’s
ChangeImageSizemethod supports batch resizing of high-resolution document images with selectable interpolation algorithms (nearest neighbour, bilinear, bicubic, best quality). - Preset resolution targets based on standard document sizes (A4, ID Card) and DPI values simplify resizing for common document-scanning workflows.
- Canvas resizing is fast for single images; Dynamic Web TWAIN is better suited for high-volume or quality-sensitive document processing.
Common Developer Questions
- How do I resize an image before uploading it to a server using client-side JavaScript?
- What is the best interpolation method for resizing scanned document images without losing quality?
- How can I batch resize multiple document images in the browser?
Prerequisites
To follow along, you need:
- A modern web browser (Chrome, Firefox, Edge, or Safari).
- A text editor or IDE.
- To use Dynamic Web TWAIN, get a 30-day free trial license.
Build an HTML5 Page for Client-Side Image Resizing
Create a new HTML5 page with the following template and then let’s add the image resizing function to it.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Resize an Image with JavaScript</title>
<style>
</style>
</head>
<body>
<div class="home">
<h2>Rotate an Image</h2>
<button id="resizeButton">Resize</button>
</div>
<script>
</script>
</body>
</html>
Step 1: Set the Desired Output Resolution
-
Add two
inputelements for specifying the resolution and a checkbox to enable keeping the aspect.HTML:
<style> input[type=number] { max-width: 50px; } </style> <label> Width: <input type="number" onfocus="this.oldvalue = this.value;" id="widthInput"> </label> <label> Height: <input type="number" onfocus="this.oldvalue = this.value;" id="heightInput"> </label> <label> Keep aspect: <input type="checkbox" id="keepAspectCheckbox"> </label>JavaScript:
let widthInput = document.getElementById("widthInput"); let heightInput = document.getElementById("heightInput"); widthInput.addEventListener("change",function(e){ if (document.getElementById("keepAspectCheckbox").checked) { syncSize(widthInput.oldvalue,heightInput.oldvalue,widthInput.value,undefined); } this.oldvalue = this.value; }) heightInput.addEventListener("change",function(e){ if (document.getElementById("keepAspectCheckbox").checked) { syncSize(widthInput.oldvalue,heightInput.oldvalue,undefined,heightInput.value); } this.oldvalue = this.value; }) function syncSize(oldWidth, oldHeight, newWidth, newHeight){ if (oldWidth && oldHeight) { const ratio = parseInt(oldWidth)/parseInt(oldHeight); if (newWidth) { newHeight = newWidth/ratio; heightInput.value = parseInt(newHeight); heightInput.oldvalue = heightInput.value; }else if (newHeight) { newWidth = newHeight * ratio; widthInput.value = parseInt(newWidth); widthInput.oldvalue = widthInput.value; } } } -
Add a
selectelement to use preset resolutions.Documents usually have a fixed size like A4 (8.268 x 11.693 in) and ID Card (3.375 x 2.125 in). We can calculate the resolutions based on different DPIs and add them as presets. For example, the resolution for an A4 document in 300 DPI should be 8.268 * 300 x 11.693 * 300 = 2480 x 3508.
HTML:
<label> Preset resolutions: <select id="presetSelect"> <option value="2480x3508">A4 300 DPI</option> <option value="1654x2339">A4 200 DPI</option> <option value="827x1169">A4 100 DPI</option> <option value="1013x638">ID Card 300 DPI</option> <option value="676x425">ID Card 200 DPI</option> <option value="338x213">ID Card 100 DPI</option> </select> </label>JavaScript:
document.getElementById("presetSelect").selectedIndex = -1; document.getElementById("presetSelect").addEventListener("change",async function(e){ usePreset(); }) function usePreset(){ let presetSelect = document.getElementById("presetSelect"); if (presetSelect.selectedIndex != -1) { let selectedOption = presetSelect.selectedOptions[0]; widthInput.value = selectedOption.value.split("x")[0]; heightInput.value = selectedOption.value.split("x")[1]; presetSelect.selectedIndex = -1; } }
Step 2: Load an Image File from the User’s Device
Add an input element for selecting files and use a button element to trigger it. The image file will be loaded into two image elements, one for displaying the resized result and one for storing the original image.
Fill the width and height inputs with the image’s original values.
HTML:
<button id="loadFileButton">Load a File</button>
<input style="display:none;" type="file" id="file" onchange="loadImageFromFile();" accept=".jpg,.jpeg,.png,.bmp" />
<div class="imageContainer">
<img id="image"/>
<img id="imageHidden"/>
</div>
<style>
.imageContainer {
overflow: auto;
}
#imageHidden {
display: none;
}
</style>
JavaScript:
function loadImageFromFile(){
let fileInput = document.getElementById("file");
let files = fileInput.files;
if (files.length == 0) {
return;
}
let file = files[0];
fileReader = new FileReader();
fileReader.onload = function(e){
document.getElementById("image").src = e.target.result;
document.getElementById("imageHidden").onload = function(){
widthInput.value = document.getElementById("imageHidden").naturalWidth;
heightInput.value = document.getElementById("imageHidden").naturalHeight;
widthInput.oldvalue = widthInput.value;
heightInput.oldvalue = heightInput.value;
}
document.getElementById("imageHidden").src = e.target.result;
};
fileReader.onerror = function () {
console.warn('oops, something went wrong.');
};
fileReader.readAsDataURL(file);
}
Step 3: Resize the Image Using the Canvas API
-
Add a
canvaselement to the document.<style> #canvasHidden { display: none; } </style> <canvas id="canvasHidden"></canvas> -
Set the canvas’s size according to the resolution specified.
const canvas = document.getElementById("canvasHidden"); canvas.width = widthInput.value; canvas.height = heightInput.value; -
Get the context of the canvas to perform actions.
const ctx = canvas.getContext("2d"); -
Draw the image onto the canvas.
const imageHidden = document.getElementById("imageHidden"); ctx.drawImage(imageHidden, 0, 0, imageHidden.naturalWidth, imageHidden.naturalHeight,0,0,canvas.width,canvas.height); -
Display the resized image.
document.getElementById("image").src = canvas.toDataURL();
Step 4: Resize Document Images with Dynamic Web TWAIN
Dynamic Web TWAIN is a document scanning SDK making it possible to scan documents in the browser. It provides various image processing methods. We can use its ChangeImageSize method to resize an image.
The advantage of using it is that it can be used to batch process a large volume of images as the processing is done using a native process.
Here are the steps to use it:
-
Include Dynamic Web TWAIN in the page.
<script src="https://unpkg.com/dwt@18.4.2/dist/dynamsoft.webtwain.min.js"></script> -
Initialize an instance of Web TWAIN and use it to resize the image. You can apply for its license here.
let DWObject; Dynamsoft.DWT.AutoLoad = false; Dynamsoft.DWT.ProductKey = "LICENSE-KEY"; Dynamsoft.DWT.ResourcesPath = "https://unpkg.com/dwt@18.4.2/dist"; async function resizeImageWithWebTWAIN(){ if (!DWObject) { await initDWT(); } DWObject.RemoveAllImages(); let file = document.getElementById("file").files[0]; let buffer = await file.arrayBuffer(); DWObject.LoadImageFromBinary(buffer, function(){ const method = document.getElementById("interpolationMethodSelect").selectedOptions[0].value; DWObject.ChangeImageSize(0,widthInput.value,heightInput.value,method, function(){ document.getElementById("image").src = DWObject.GetImageURL(0); }, function(errorCode, errorString){ console.log(errorString); }); }, function(errorCode, errorString){ console.log(errorString); }) } function initDWT(){ return new Promise((resolve, reject) => { const title = document.querySelector("h2").innerText; document.querySelector("h2").innerText = "Loading Dynamic Web TWAIN..."; Dynamsoft.DWT.CreateDWTObjectEx( { WebTwainId: 'dwtcontrol' }, function(obj) { DWObject = obj; document.querySelector("h2").innerText = title; resolve(); }, function(err) { console.log(err); document.querySelector("h2").innerText = "Failed to load Dynamic Web TWAIN"; reject(err); } ); }) } -
New pixels have to be added during resizing which is called interpolation. Dynamic Web TWAIN provides several algorithms to do this.
A
selectelement is added for this.<div class="dwtcontrols"> <label> Interpolation Method: <select id="interpolationMethodSelect"> <option value="1">Nearest Neighbour</option> <option value="2">Bilinear</option> <option value="3">Bicubic</option> <option value="5" selected>Best Quality</option> </select> </label> </div>
Common Issues and Edge Cases
- Canvas produces blurry results on large downscales. When shrinking an image by more than 50%, a single
drawImagecall can produce noticeable aliasing. A common workaround is to resize in multiple steps (halving dimensions each pass) before the final draw. canvas.toDataURL()defaults to PNG, which can be very large. If file size matters, pass"image/jpeg"and a quality parameter (e.g.,canvas.toDataURL("image/jpeg", 0.85)) to control output size.- CORS restrictions block
drawImagefor cross-origin images. If the image is loaded from a different domain, setcrossOrigin = "anonymous"on the<img>element before assigningsrc, or the canvas will be tainted andtoDataURL()will throw a security error.
Source Code
You can find all the code and an online demo in the following repo: