Redimensionnement de l'image côté client avec JavaScript avant téléchargement sur le serveur

147

Je cherche un moyen de redimensionner une image côté client avec JavaScript (vraiment redimensionner, pas seulement changer la largeur et la hauteur).
Je sais qu'il est possible de le faire en Flash mais j'aimerais l'éviter si possible.

Existe-t-il un algorithme open source quelque part sur le Web?

géraud
la source
Pour ceux d'entre vous qui veulent toujours connaître la réponse à cette question, vous pouvez le faire, mais vous devrez faire des appels ajax pour le traitement d'image.
polyèdre
1
'Besoin de faire'? Eh bien, vous POUVEZ le résoudre sur le serveur après tout et obtenir ces données de manière transparente via des appels AJAX. Mais toute la tentative est de le faire côté client, et comme Jeremy le souligne, cela PEUT être fait. Je pense que c'est un excellent exemple: github.com/rossturner/HTML5-ImageUploader
Bart
2
Avec sa dernière version, Dropzone.js prend en charge le redimensionnement de l'image côté client avant le téléchargement.
user1666456

Réponses:

112

Voici l'essentiel qui fait ceci: https://gist.github.com/dcollien/312bce1270a5f511bf4a

(une version es6 et une version .js qui peuvent être incluses dans une balise de script)

Vous pouvez l'utiliser comme suit:

<input type="file" id="select">
<img id="preview">
<script>
document.getElementById('select').onchange = function(evt) {
    ImageTools.resize(this.files[0], {
        width: 320, // maximum width
        height: 240 // maximum height
    }, function(blob, didItResize) {
        // didItResize will be true if it managed to resize it, otherwise false (and will return the original file as 'blob')
        document.getElementById('preview').src = window.URL.createObjectURL(blob);
        // you can also now upload this blob using an XHR.
    });
};
</script>

Il comprend un tas de détection de support et de polyfills pour s'assurer qu'il fonctionne sur autant de navigateurs que je peux gérer.

(il ignore également les images gif - au cas où elles seraient animées)

décollien
la source
2
J'ai l'impression que vous n'avez pas reçu assez d'éloges pour cela - je pense que cela fonctionne très bien et est super facile. Merci d'avoir partagé!
Matt
4
Hmm..J'ai eu un bon succès avec cela, mais j'ai trouvé que mes images (en plus d'être redimensionnées) souffraient également d'une énorme perte de qualité (sous la forme d'une pixellisation sévère), bien qu'elles aient été produites à la résolution correcte.
Ruben Martinez Jr.
1
salut, j'ai besoin d'un extrait de code à utiliser comme celui-ci, et je pense que c'est très bien mais .. function (blob, didItResize) {// didItResize sera vrai s'il réussit à le redimensionner, sinon faux (et retournera l'original fichier comme 'blob') document.getElementById ('aperçu'). src = window.URL.createObjectURL (blob); // vous pouvez également télécharger cet objet blob à l'aide d'un XHR. ici j'ai un problème .. Comment puis-je envoyer cette image dans un formulaire en soumettant simplement le formulaire. Je veux dire, comme une demande de publication déclenchée par le bouton d'envoi. Vous savez, la manière habituelle. Merci pour l'essentiel!
iedmrc
3
Pour toute personne ayant une perte de qualité (rééchantillonnage), mettez à jour le contexte du canevas sur imageSmoothingEnabledtrue` et imageSmoothingQualityto high. En texte dactylographié, ce bloc ressemble à: const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height);
Sean Perkins
1
Y a-t-il une chance d'en faire un package npm? Ce serait super génial!
erksch
62

La réponse à cette question est oui - en HTML 5, vous pouvez redimensionner les images côté client à l'aide de l'élément canvas. Vous pouvez également prendre les nouvelles données et les envoyer à un serveur. Voir ce tutoriel:

http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/

Jeremy Usher
la source
29
Ceci est une réponse de lien seulement et en tant que telle devrait être un commentaire.
Jimbo le
2
canvas.mozGetAsFile ("foo.png"); est une fonction obsolète
mili
12

Si vous redimensionniez avant le téléchargement, je viens de découvrir ceci http://www.plupload.com/

Il fait toute la magie pour vous dans n'importe quelle méthode imaginable.

Malheureusement, le redimensionnement HTML5 n'est pris en charge qu'avec le navigateur Mozilla, mais vous pouvez rediriger d'autres navigateurs vers Flash et Silverlight.

Je viens de l'essayer et cela a fonctionné avec mon Android!

J'utilisais http://swfupload.org/ en flash, il fait très bien le travail, mais la taille de redimensionnement est très petite. (je ne me souviens plus de la limite) et ne revient pas à html4 lorsque le flash n'est pas disponible.

ignacio
la source
44
C'est bien de faire un redimensionnement côté client lorsqu'un utilisateur essaie de télécharger une photo de 10 Mo qui ne sera stockée que sous forme de photo beaucoup plus petite. Il sera téléchargé beaucoup plus rapidement de cette façon.
Kyle
Même scénario ici, dès que vous avez une entrée de fichier et que l'utilisateur est sur un smartphone et prend une image à l'aide de l'appareil photo, cela va faire environ 10 Mo sur les smartphones modernes. Si vous le redimensionnez du côté du serveur et ne stockez qu'une version beaucoup plus petite de celui-ci, vous économiserez beaucoup de données cellulaires et de temps de chargement en effectuant le redimensionnement au préalable dans le client.
Alex
1
Soyez prudent car plupload est AGPL.
Alex
11

http://nodeca.github.io/pica/demo/

Dans un navigateur moderne, vous pouvez utiliser le canevas pour charger / enregistrer des données d'image. Mais vous devez garder à l'esprit plusieurs choses si vous redimensionnez l'image sur le client:

  1. Vous n'aurez que 8 bits par canal (jpeg peut avoir une meilleure plage dynamique, environ 12 bits). Si vous ne téléchargez pas de photos professionnelles, cela ne devrait pas poser de problème.
  2. Faites attention à l'algorithme de redimensionnement. La plupart des redimensionneurs côté client utilisent des mathématiques triviales, et le résultat est pire qu'il ne pourrait l'être.
  3. Vous devrez peut-être améliorer la netteté de l'image réduite.
  4. Si vous souhaitez réutiliser les métadonnées (exif et autres) de l'original - n'oubliez pas de supprimer les informations de profil de couleur. Parce qu'il est appliqué lorsque vous chargez l'image sur le canevas.
Vitaly
la source
6

Peut-être avec la balise canvas (bien que ce ne soit pas portable). Il y a un blog sur la façon de faire pivoter une image avec une toile ici , je suppose que si vous pouvez la faire pivoter, vous pouvez la redimensionner. Peut-être que cela peut être un point de départ.

Voir aussi cette bibliothèque .

David V.
la source
2
Exemples très utiles. Vous voudrez peut-être ajouter un extrait ou deux à votre réponse au cas où ces liens se rompraient.
Trevor
4

Vous pouvez utiliser une infrastructure de traitement d'image javascript pour le traitement d'image côté client avant de télécharger l'image sur le serveur.

Ci-dessous, j'ai utilisé MarvinJ pour créer un code exécutable basé sur l'exemple de la page suivante: "Traitement des images côté client avant de les télécharger sur un serveur"

En gros, j'utilise la méthode Marvin.scale (...) pour redimensionner l'image. Ensuite, je télécharge l'image sous forme de blob (en utilisant la méthode image.toBlob () ). Le serveur répond en fournissant une URL de l'image reçue.

/***********************************************
 * GLOBAL VARS
 **********************************************/
var image = new MarvinImage();

/***********************************************
 * FILE CHOOSER AND UPLOAD
 **********************************************/
 $('#fileUpload').change(function (event) {
	form = new FormData();
	form.append('name', event.target.files[0].name);
	
	reader = new FileReader();
	reader.readAsDataURL(event.target.files[0]);
	
	reader.onload = function(){
		image.load(reader.result, imageLoaded);
	};
	
});

function resizeAndSendToServer(){
  $("#divServerResponse").html("uploading...");
	$.ajax({
		method: 'POST',
		url: 'https://www.marvinj.org/backoffice/imageUpload.php',
		data: form,
		enctype: 'multipart/form-data',
		contentType: false,
		processData: false,
		
	   
		success: function (resp) {
       $("#divServerResponse").html("SERVER RESPONSE (NEW IMAGE):<br/><img src='"+resp+"' style='max-width:400px'></img>");
		},
		error: function (data) {
			console.log("error:"+error);
			console.log(data);
		},
		
	});
};

/***********************************************
 * IMAGE MANIPULATION
 **********************************************/
function imageLoaded(){
  Marvin.scale(image.clone(), image, 120);
  form.append("blob", image.toBlob());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<form id="form" action='/backoffice/imageUpload.php' style='margin:auto;' method='post' enctype='multipart/form-data'>
				<input type='file' id='fileUpload' class='upload' name='userfile'/>
</form><br/>
<button type="button" onclick="resizeAndSendToServer()">Resize and Send to Server</button><br/><br/>
<div id="divServerResponse">
</div>

Gabriel Ambrósio Archanjo
la source
Cela a l'air génial!
pimbrouwers
2

Oui, avec les navigateurs modernes, c'est totalement faisable. Même faisable au point de télécharger le fichier spécifiquement en tant que fichier binaire après avoir effectué un certain nombre de modifications de la toile.

http://jsfiddle.net/bo40drmv/

(cette réponse est une amélioration de la réponse acceptée ici )

En gardant à l'esprit pour attraper le processus de soumission des résultats dans le PHP avec quelque chose qui ressemble à:

//File destination
$destination = "/folder/cropped_image.png";
//Get uploaded image file it's temporary name
$image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0];
//Move temporary file to final destination
move_uploaded_file($image_tmp_name, $destination);

Si vous vous inquiétez du point de vue de Vitaly, vous pouvez essayer une partie du recadrage et du redimensionnement sur le jfiddle qui fonctionne.

Tatarize
la source
0

D'après mon expérience, cet exemple a été la meilleure solution pour télécharger une image redimensionnée: https://zocada.com/compress-resize-images-javascript-browser/

Il utilise la fonctionnalité HTML5 Canvas.

Le code est aussi `` simple '' que celui-ci:

compress(e) {
    const fileName = e.target.files[0].name;
    const reader = new FileReader();
    reader.readAsDataURL(e.target.files[0]);
    reader.onload = event => {
        const img = new Image();
        img.src = event.target.result;
        img.onload = () => {
                const elem = document.createElement('canvas');
                const width = Math.min(800, img.width);
                const scaleFactor = width / img.width;
                elem.width = width;
                elem.height = img.height * scaleFactor;

                const ctx = elem.getContext('2d');
                // img.width and img.height will contain the original dimensions
                ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
                ctx.canvas.toBlob((blob) => {
                    const file = new File([blob], fileName, {
                        type: 'image/jpeg',
                        lastModified: Date.now()
                    });
                }, 'image/jpeg', 1);
            },
            reader.onerror = error => console.log(error);
    };
}

Il n'y a qu'un seul inconvénient avec cette option, et il est lié à la rotation de l'image, en raison de l'ignorance des données EXIF. Sur quoi je travaille en ce moment. Mettra à jour après que j'en ai terminé.

Un autre inconvénient est le manque de support pour IE / Edge, sur lequel je travaille également. Bien qu'il y ait des informations dans le lien ci-dessus. Pour les deux problèmes.

xarlymg89
la source