Voici mon code, que j'espère pourra être utile à quelqu'un dans la communauté SO :
Vous pouvez inclure les dimensions de l'image cible comme un paramètre dans l'appel de votre script. Cela donnera la valeur résultante de la largeur ou de la hauteur de votre image, quelle que soit la plus grande. La dimension la plus petite est redimensionnée en conservant le ratio de votre image inchangé. Vous pouvez également définir votre taille cible par défaut dans le script.
Vous pouvez facilement modifier le script pour répondre à vos besoins spécifiques, comme le type d'image que vous souhaitez (par défaut, "image/png") pour une sortie et décider en combien d'étapes en pourcentage vous voulez redimensionner votre image pour un résultat plus précis (voir const percentStep dans le code).
const ResizeImage = ( _ => {
const MAX_LENGTH = 260; // taille cible par défaut de la plus grande dimension, soit la largeur ou la hauteur
const percentStep = .3; // pas de redimensionnement jusqu'à atteindre la taille cible en pourcentage (30% par défaut)
const canvas = document.createElement("canvas");
const canvasContext = canvas.getContext("2d");
const image = new Image();
const doResize = (callback, maxLength) => {
// annuler avec une erreur si l'image a une dimension égale à zéro
if(image.width == 0 || image.height == 0) {
return {blob: null, error: "soit la largeur soit la hauteur de l'image était égale à zéro "};
}
// utiliser la dimension de l'appeleur ou la longueur par défaut si aucune n'est fournie
const length = maxLength == null ? MAX_LENGTH : maxLength;
canvas.width = image.width;
canvas.height = image.height;
canvasContext.drawImage(image, 0, 0, image.width, image.height);
// si la taille de l'image est déjà dans la taille cible, copier simplement et retourner le blob
if(image.width <= length && image.height <= length) {
canvas.toBlob( blob => {
callback({ blob: blob, error: null });
}, "image/png", 1);
return;
}
var startDim = Math.max(image.width, image.height);
var startSmallerDim = Math.min(image.width, image.height);
// écart à diminuer de taille jusqu'à atteindre la taille cible,
// que ce soit en réduisant la largeur ou la hauteur de l'image,
// quelle que soit la plus grande
const gap = startDim - length;
// pas de chaque itération de redimensionnement
const step = parseInt(percentStep*gap);
// nombre d'itérations
var nSteps = 0;
if(step == 0) {
step = 1;
} else {
nSteps = parseInt(gap/step);
}
// longueur de la dernière étape de redimensionnement supplémentaire, si nécessaire
const lastStep = gap % step;
// rapport hauteur/largeur = valeur par laquelle nous allons multiplier la dimension la plus petite
// afin de conserver le ratio de l'image inchangé à chaque itération
const ratio = startSmallerDim/startDim;
var newDim; // nouvelle longueur calculée pour la plus grande dimension de l'image, qu'il s'agisse de la largeur ou de la hauteur de l'image
var smallerDim; // longueur le long de la dimension la plus petite de l'image, la largeur ou la hauteur
for(var i = 0; i < nSteps; i++) {
// diminuer la dimension la plus longue d'un pas en pixels
newDim = startDim - step;
// diminuer la dimension la plus courte de manière proportionnelle, afin de conserver le ratio
smallerDim = parseInt(ratio*newDim);
// assigner les variables calculées à leur dimension respective du canevas, largeur ou hauteur
if(image.width > image.height) {
[canvas.width, canvas.height] = [newDim, smallerDim];
} else {
[canvas.width, canvas.height] = [smallerDim, newDim];
}
// dessiner l'image une étape plus petite
canvasContext.drawImage(canvas, 0, 0, canvas.width, canvas.height);
// varier la dimension de départ pour la nouvelle boucle
startDim = newDim;
}
// faire la dernière étape de redimensionnement manquante pour atteindre enfin la taille de l'image cible
if(lastStep > 0) {
if(image.width > image.height) {
[canvas.width, canvas.height] = [startDim - lastStep, parseInt(ratio*(startDim - lastStep))];
} else {
[canvas.width, canvas.height] = [parseInt(ratio*(startDim -lastStep)), startDim - lastStep];
}
canvasContext.drawImage(image, 0, 0, canvas.width, canvas.height);
}
// envoyer le blob à l'appeleur
canvas.toBlob( blob => {
callback({blob: blob, error: null});
}, "image/png", 1);
};
const resize = async (imgSrc, callback, maxLength) => {
image.src = imgSrc;
image.onload = _ => {
doResize(callback, maxLength);
};
};
return { resize: resize }
})();
Utilisation :
ResizeImage.resize("./chemin/vers/image/ou/blob/octets/à/redimensionner", imageObject => {
if(imageObject.error != null) {
// gérer les erreurs ici
console.log(imageObject.error);
return;
}
// faites ce que vous voulez avec le blob, comme l'assigner à
// un élément img, ou le télécharger dans une base de données
// ...
document.querySelector("#my-image").src = imageObject.blob;
// ...
}, 300);