197 votes

HTML5 Redimensionnez les images avant de les télécharger

Voici une nouille de scratcher.

En gardant à l'esprit que nous avons le stockage local HTML5 et xhr v2 et ce n'est pas. Je me demandais si quelqu'un pourrait trouver un exemple de travail ou même juste me donner un oui ou un non à cette question:

Est-il possible de Pré de la taille d'une image à l'aide du nouveau local de stockage (ou autre), de sorte qu'un utilisateur qui n'a pas la moindre idée de redimensionnement d'une image peuvent glisser leur image de 10 mo sur mon site, il redimensionner à l'aide de la nouvelle localstorage, PUIS le télécharger à la plus petite taille.

Je sais bien que vous pouvez le faire avec Flash, applets Java, active X... La question est de savoir si vous pouvez le faire avec Javascript + Html5.

Hâte d'être à la réponse sur ce point.

Ta pour l'instant.

196voto

robertc Points 35382

Oui, utiliser le Fichier API, vous pouvez traiter les images avec l' élément canvas.

Cette Mozilla Hacks blog vous guide dans la plupart des processus. Pour référence, voici la assemblés code source sur le post de blog:

// from an input element
var filesToUpload = input.files;
var file = filesToUpload[0];

var img = document.createElement("img");
var reader = new FileReader();  
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);

var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);

var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;

if (width > height) {
  if (width > MAX_WIDTH) {
    height *= MAX_WIDTH / width;
    width = MAX_WIDTH;
  }
} else {
  if (height > MAX_HEIGHT) {
    width *= MAX_HEIGHT / height;
    height = MAX_HEIGHT;
  }
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);

var dataurl = canvas.toDataURL("image/png");

//Post dataurl to the server with AJAX

118voto

Ross Turner Points 1162

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.

30voto

Justin Levene Points 38

Correction ci-dessus :

9voto

nanospeck Points 357

Si vous ne voulez pas de réinventer la roue, essayez plupload.com

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X