Je me suis attaquée à ce problème il y a quelques années et téléchargé ma solution pour github comme https://github.com/rossturner/HTML5-ImageUploader
robertc la réponse utilise la solution proposée dans le Mozilla Hacks blog, cependant j'ai trouvé cela donne vraiment une mauvaise qualité d'image lors du redimensionnement à une échelle qui n'était pas de 2:1 (ou un multiple de celui-ci). J'ai commencé à expérimenter avec différents algorithmes de redimensionnement d'image, bien que la plupart fini par être assez lent, ou autre, n'étaient pas de grande qualité.
Enfin, je suis venu avec une solution qui, je crois, s'exécute rapidement et est assez bonne performance aussi - comme Mozilla solution de la copie à partir de 1 toile à l'autre fonctionne rapidement et sans perte de qualité d'image à un ratio de 2:1, donné un objectif de x pixels de large et y pixels de haut, j'utilise cette toile méthode de redimensionnement jusqu'à ce que l'image est entre x et 2 xet y et 2 y. À ce point, je puis tournez à des algorithmes de redimensionnement d'image pour la dernière "étape" de redimensionnement jusqu'à la taille de la cible. Après avoir essayé plusieurs algorithmes différents, je me suis installé sur la méthode d'interpolation bilinéaire prises à partir d'un blog qui n'est malheureusement plus disponible, ce qui donne de bons résultats, voici le code:
ImageUploader.prototype.scaleImage = function(img, completionCallback) {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
while (canvas.width >= (2 * this.config.maxWidth)) {
canvas = this.getHalfScaleCanvas(canvas);
}
if (canvas.width > this.config.maxWidth) {
canvas = this.scaleCanvasWithAlgorithm(canvas);
}
var imageData = canvas.toDataURL('image/jpeg', this.config.quality);
this.performUpload(imageData, completionCallback);
};
ImageUploader.prototype.scaleCanvasWithAlgorithm = function(canvas) {
var scaledCanvas = document.createElement('canvas');
var scale = this.config.maxWidth / canvas.width;
scaledCanvas.width = canvas.width * scale;
scaledCanvas.height = canvas.height * scale;
var srcImgData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
var destImgData = scaledCanvas.getContext('2d').createImageData(scaledCanvas.width, scaledCanvas.height);
this.applyBilinearInterpolation(srcImgData, destImgData, scale);
scaledCanvas.getContext('2d').putImageData(destImgData, 0, 0);
return scaledCanvas;
};
ImageUploader.prototype.getHalfScaleCanvas = function(canvas) {
var halfCanvas = document.createElement('canvas');
halfCanvas.width = canvas.width / 2;
halfCanvas.height = canvas.height / 2;
halfCanvas.getContext('2d').drawImage(canvas, 0, 0, halfCanvas.width, halfCanvas.height);
return halfCanvas;
};
ImageUploader.prototype.applyBilinearInterpolation = function(srcCanvasData, destCanvasData, scale) {
function inner(f00, f10, f01, f11, x, y) {
var un_x = 1.0 - x;
var un_y = 1.0 - y;
return (f00 * un_x * un_y + f10 * x * un_y + f01 * un_x * y + f11 * x * y);
}
var i, j;
var iyv, iy0, iy1, ixv, ix0, ix1;
var idxD, idxS00, idxS10, idxS01, idxS11;
var dx, dy;
var r, g, b, a;
for (i = 0; i < destCanvasData.height; ++i) {
iyv = i / scale;
iy0 = Math.floor(iyv);
// Math.ceil can go over bounds
iy1 = (Math.ceil(iyv) > (srcCanvasData.height - 1) ? (srcCanvasData.height - 1) : Math.ceil(iyv));
for (j = 0; j < destCanvasData.width; ++j) {
ixv = j / scale;
ix0 = Math.floor(ixv);
// Math.ceil can go over bounds
ix1 = (Math.ceil(ixv) > (srcCanvasData.width - 1) ? (srcCanvasData.width - 1) : Math.ceil(ixv));
idxD = (j + destCanvasData.width * i) * 4;
// matrix to vector indices
idxS00 = (ix0 + srcCanvasData.width * iy0) * 4;
idxS10 = (ix1 + srcCanvasData.width * iy0) * 4;
idxS01 = (ix0 + srcCanvasData.width * iy1) * 4;
idxS11 = (ix1 + srcCanvasData.width * iy1) * 4;
// overall coordinates to unit square
dx = ixv - ix0;
dy = iyv - iy0;
// I let the r, g, b, a on purpose for debugging
r = inner(srcCanvasData.data[idxS00], srcCanvasData.data[idxS10], srcCanvasData.data[idxS01], srcCanvasData.data[idxS11], dx, dy);
destCanvasData.data[idxD] = r;
g = inner(srcCanvasData.data[idxS00 + 1], srcCanvasData.data[idxS10 + 1], srcCanvasData.data[idxS01 + 1], srcCanvasData.data[idxS11 + 1], dx, dy);
destCanvasData.data[idxD + 1] = g;
b = inner(srcCanvasData.data[idxS00 + 2], srcCanvasData.data[idxS10 + 2], srcCanvasData.data[idxS01 + 2], srcCanvasData.data[idxS11 + 2], dx, dy);
destCanvasData.data[idxD + 2] = b;
a = inner(srcCanvasData.data[idxS00 + 3], srcCanvasData.data[idxS10 + 3], srcCanvasData.data[idxS01 + 3], srcCanvasData.data[idxS11 + 3], dx, dy);
destCanvasData.data[idxD + 3] = a;
}
}
};
Permet de redimensionner une image jusqu'à une largeur de config.maxWidth
, de maintenir le ratio d'aspect original. Au moment de l'élaboration de cette travaillé sur iPad/iPhone Safari dans les plus grands navigateurs de bureau (IE9+, Firefox, Chrome) donc j'espère qu'il sera encore compatible compte tenu de la large adoption de HTML5 aujourd'hui. Notez que la zone de travail.toDataURL() qui prend un mime type et la qualité d'image qui vous permettra de contrôler la qualité et le format de fichier de sortie (ce qui est potentiellement différent à l'entrée si vous le désirez).
Le seul point que ce n'est pas la couverture est de maintenir l'orientation de l'information, sans la connaissance de ce métadonnées de l'image est redimensionnée et enregistré en tant que-est, de perdre l'une de métadonnées à l'intérieur de l'image pour l'orientation ce qui signifie que les images prises sur une tablette "à l'envers", ont été rendus en tant que tel, bien qu'ils auraient été renversé dans l'appareil du viseur de l'appareil photo. Si c'est un souci, ce blog a un bon guide et des exemples de code sur la façon d'accomplir ceci, qui j'en suis sûr, pourrait être intégré au code ci-dessus.