Ridimensionamento delle immagini lato client con JavaScript prima del caricamento sul server


147

Sto cercando un modo per ridimensionare un'immagine lato client con JavaScript (ridimensionare davvero, non solo cambiare larghezza e altezza).
So che è possibile farlo in Flash, ma vorrei evitarlo, se possibile.

Esiste un algoritmo open source da qualche parte sul web?


Per quelli di voi che vogliono ancora conoscere la risposta a questa domanda, è possibile farlo, ma sarà necessario effettuare alcune chiamate Ajax per l'elaborazione delle immagini.
poliedro,

1
'Hai bisogno di fare'? Bene, dopo tutto, PUOI risolverlo sul server e ottenere quei dati in modo trasparente attraverso le chiamate AJAX. Ma l'intero tentativo è quello di farlo lato client, e come Jeremy sottolinea che PUO 'essere fatto. Penso che questo sia un ottimo esempio: github.com/rossturner/HTML5-ImageUploader
Bart

2
Con la sua ultima versione, Dropzone.js supporta il ridimensionamento dell'immagine lato client prima del caricamento.
user1666456,

Risposte:


112

Ecco un riassunto che lo fa: https://gist.github.com/dcollien/312bce1270a5f511bf4a

(una versione es6 e una versione .js che può essere inclusa in un tag script)

Puoi usarlo come segue:

<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>

Include un sacco di rilevamento del supporto e polyfill per assicurarsi che funzioni su tutti i browser che sono riuscito a gestire.

(ignora anche le immagini gif - nel caso siano animate)


2
Sento che non hai ricevuto abbastanza elogi per questo - penso che funzioni benissimo ed è super facile. Grazie per la condivisione!
Matt,

4
Hmm..Ho avuto un buon successo con questo, ma ho scoperto che le mie immagini (oltre a essere ridimensionate) hanno anche subito un'enorme perdita di qualità (sotto forma di grave pixelazione), sebbene sia stata emessa alla risoluzione corretta.
Ruben Martinez Jr.,

1
ciao, ho bisogno di uno snippet da usare come questo, e penso che sia molto buono ma .. funzione (blob, didItResize) {// didItResize sarà vera se è riuscita a ridimensionarla, altrimenti falso (e restituirà l'originale file come 'blob') document.getElementById ('preview'). src = window.URL.createObjectURL (blob); // ora puoi anche caricare questo BLOB usando un XHR. qui ho un problema .. Come posso inviare questa immagine in un modulo semplicemente inviando il modulo. Voglio dire, come una richiesta di post attivata dal pulsante di invio. Sai, nel solito modo. Grazie per l'essenza!
iedmrc,

3
Per chiunque abbia una perdita di qualità (ricampionamento), aggiorna il contesto della tela per impostarlo su imageSmoothingEnabledtrue` e imageSmoothingQualitysu high. Nel dattiloscritto quel blocco appare come: const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height);
Sean Perkins,

1
C'è una possibilità di rendere questo un pacchetto npm? Sarebbe fantastico!
Erksch,


12

Se stavi ridimensionando prima di caricare ho appena scoperto questo http://www.plupload.com/

Fa tutta la magia per te in qualsiasi metodo immaginabile.

Purtroppo il ridimensionamento HTML5 è supportato solo con il browser Mozilla, ma è possibile reindirizzare altri browser su Flash e Silverlight.

L'ho appena provato e ha funzionato con il mio Android!

Stavo usando http://swfupload.org/ in flash, fa molto bene il lavoro, ma la dimensione del ridimensionamento è molto piccola. (non ricordo il limite) e non torna a html4 quando il flash non è disponibile.


44
È bello eseguire il ridimensionamento sul lato client per quando un utente tenta di caricare una foto da 10 MB che verrà memorizzata solo come una foto molto più piccola. Si caricherà molto più velocemente in questo modo.
Kyle,

Lo stesso scenario qui, non appena si dispone di un input di file e l'utente si trova su uno smartphone e scatta un'immagine utilizzando la fotocamera, sarà di circa 10 MB su smartphone moderni. Se sul lato server lo stai ridimensionando e memorizzandone solo una versione molto più piccola, risparmierai molti dati cellulari e tempo di caricamento nel fare il ridimensionamento in anticipo nel client.
Alex

1
Fai attenzione perché il plupload è AGPL.
Alex,

11

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

Nel browser moderno puoi usare la tela per caricare / salvare i dati delle immagini. Ma dovresti tenere a mente diverse cose se ridimensioni l'immagine sul client:

  1. Avrai solo 8 bit per canale (jpeg può avere una gamma dinamica migliore, circa 12 bit). Se non carichi foto professionali, questo non dovrebbe essere un problema.
  2. Fai attenzione all'algoritmo di ridimensionamento. La maggior parte dei resizer lato client usano una banale matematica e il risultato è peggiore di quanto potrebbe essere.
  3. Potrebbe essere necessario rendere più nitida l'immagine ridotta.
  4. Se desideri riutilizzare i metadati (exif e altri) dall'originale, non dimenticare di eliminare le informazioni del profilo colore. Perché viene applicato quando carichi l'immagine su tela.

6

Forse con il tag canvas (anche se non è portatile). C'è un blog su come ruotare un'immagine con la tela qui , suppongo che se puoi ruotarla, puoi ridimensionarla. Forse può essere un punto di partenza.

Vedi anche questa libreria .


2
Esempi molto utili. Potresti voler aggiungere uno o due frammenti alla tua risposta nel caso in cui questi collegamenti si interrompano.
Trevor,

4

È possibile utilizzare un framework di elaborazione delle immagini javascript per l'elaborazione delle immagini sul lato client prima di caricare l'immagine sul server.

Di seguito ho usato MarvinJ per creare un codice eseguibile basato sull'esempio nella pagina seguente: "Elaborazione di immagini sul lato client prima di caricarlo su un server"

Fondamentalmente uso il metodo Marvin.scale (...) per ridimensionare l'immagine. Quindi, carico l'immagine come BLOB ( usando il metodo image.toBlob () ). Il server risponde fornendo un URL dell'immagine ricevuta.

/***********************************************
 * 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>


Questo sembra fantastico!
pimbrouwers,

2

Sì, con i browser moderni questo è totalmente fattibile. Perfino fattibile fino al punto di caricare il file specificatamente come file binario dopo aver apportato un numero qualsiasi di modifiche alla tela.

http://jsfiddle.net/bo40drmv/

(questa risposta è un miglioramento della risposta accettata qui )

Tenendo presente che è possibile elaborare la presentazione dei risultati nel PHP con qualcosa di simile a:

//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);

Se uno si preoccupa del punto di Vitaly, puoi provare alcuni ritagli e ridimensionamenti sul jfiddle funzionante.


0

Nella mia esperienza, questo esempio è stata la migliore soluzione per caricare un'immagine ridimensionata: https://zocada.com/compress-resize-images-javascript-browser/

Utilizza la funzione HTML5 Canvas.

Il codice è "semplice" come questo:

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);
    };
}

C'è solo un aspetto negativo con questa opzione, ed è correlato alla rotazione dell'immagine, a causa dell'ignoranza dei dati EXIF. Su cui sto lavorando al momento. Si aggiornerà dopo che avrò finito.

Un altro aspetto negativo è la mancanza di supporto per IE / Edge, su cui sto lavorando. Sebbene ci siano informazioni nel link sopra. Per entrambi i problemi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.