Just a few days ago, I encountered a similar issue that I resolved.
The solution lies within the <canvas>
element and its drawImage
method.
Check out the following function I created. It resizes the input image to a specified width, but it can be easily modified to accept a maximum width or height, a ratio, or any other parameter.
function resizeToWidth(image, targetWidth) {
/* Takes an HTMLImageElement as input (<img>)
and outputs an HTMLCanvasElement (<canvas>) */
var originalWidth = image.naturalWidth;
var originalHeight = image.naturalHeight;
var targetHeight = targetWidth * (originalHeight / originalWidth);
var interimCanvas = document.createElement('canvas');
interimCanvas.width = originalWidth;
interimCanvas.height = originalHeight;
var interimCtx = interimCanvas.getContext('2d');
var redrawnCanvas, redrawnCtx;
var scale = 2;
var newWidth, newHeight;
redrawnCanvas = document.createElement('canvas');
redrawnCanvas.width = targetWidth;
redrawnCanvas.height = targetHeight;
redrawnCtx = redrawnCanvas.getContext('2d');
if (originalWidth > targetWidth) {
/* We perform multiple passes, scaling the image by half each time.
This approach gives a smoother result than scaling directly
to the target size.
The loop stops when halving once more would make the image smaller than the target size.
*/
interimCtx.drawImage(image, 0, 0);
do {
redrawnCanvas = document.createElement('canvas');
newWidth = interimCanvas.width / 2;
newHeight = interimCanvas.height / 2;
redrawnCanvas.width = newWidth;
redrawnCanvas.height = newHeight;
redrawnCtx = redrawnCanvas.getContext('2d');
redrawnCtx.imageSmoothingEnabled = true;
redrawnCtx.drawImage(interimCanvas, 0, 0, newWidth, newHeight);
interimCanvas = redrawnCanvas;
scale++;
} while (interimCanvas.width / targetWidth > 2);
// Final scaling to the target width
redrawnCanvas = document.createElement('canvas');
redrawnCanvas.width = targetWidth;
redrawnCanvas.height = targetHeight;
redrawnCtx = redrawnCanvas.getContext('2d');
redrawnCtx.drawImage(interimCanvas, 0, 0, targetWidth, targetHeight);
} else {
redrawnCtx.drawImage(image, 0, 0, targetWidth, targetHeight);
}
return redrawnCanvas;
};