Ändern der Bildgröße clientseitig mit JavaScript vor dem Hochladen auf den Server

147

Ich suche nach einer Möglichkeit, die Größe eines Bildes clientseitig mit JavaScript zu ändern (Größe wirklich ändern, nicht nur Breite und Höhe ändern).
Ich weiß, dass dies in Flash möglich ist, möchte es aber nach Möglichkeit vermeiden.

Gibt es irgendwo im Web einen Open-Source-Algorithmus?

geraud
quelle
Für diejenigen unter Ihnen, die noch die Antwort darauf wissen möchten, können Sie dies tun, aber Sie müssen einige Ajax-Aufrufe für die Bildverarbeitung tätigen.
Polyeder
1
'Muss machen'? Nun, Sie können es schließlich auf dem Server lösen und diese transparenten Daten durch AJAX-Aufrufe erhalten. Aber der ganze Versuch ist es, es clientseitig zu machen, und wie Jeremy betont, kann dies getan werden. Ich denke, das ist ein großartiges Beispiel: github.com/rossturner/HTML5-ImageUploader
Bart
2
Mit der neuesten Version unterstützt Dropzone.js die Größenänderung von clientseitigen Bildern vor dem Hochladen.
user1666456

Antworten:

110

Hier ist ein Kern, der dies tut: https://gist.github.com/dcollien/312bce1270a5f511bf4a

(eine es6-Version und eine .js-Version, die in einem Skript-Tag enthalten sein können)

Sie können es wie folgt verwenden:

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

Es enthält eine Reihe von Support-Erkennungen und Polyfills, um sicherzustellen, dass es in so vielen Browsern funktioniert, wie ich verwalten kann.

(GIF-Bilder werden ebenfalls ignoriert - falls sie animiert sind)

dcollien
quelle
2
Ich habe das Gefühl, dass Sie dafür nicht annähernd genug Lob erhalten haben - ich denke, es funktioniert großartig und ist super einfach. Danke für das Teilen!
Matt
4
Hmm..Ich hatte gute Erfolge damit, aber ich stellte fest, dass meine Bilder (zusätzlich zur Größenänderung) auch einen großen Qualitätsverlust (in Form einer starken Pixelierung) aufwiesen, obwohl sie mit der richtigen Auflösung ausgegeben wurden.
Ruben Martinez Jr.
1
Hallo, ich brauche ein Snippet, um es wie dieses zu verwenden, und ich denke, das ist sehr gut, aber .. function (blob, didItResize) {// didItResize ist wahr, wenn es gelungen ist, die Größe zu ändern, andernfalls false (und gibt das Original zurück Datei als 'blob') document.getElementById ('Vorschau'). src = window.URL.createObjectURL (blob); // Sie können diesen Blob jetzt auch mit einem XHR hochladen. Hier habe ich ein Problem. Wie kann ich dieses Bild in einem Formular senden, indem ich nur das Formular abschicke. Ich meine, wie eine Post-Anfrage, die durch die Schaltfläche "Senden" ausgelöst wird. Sie wissen, der übliche Weg. Vielen Dank für das Wesentliche!
Iedmrc
3
Aktualisieren Sie imageSmoothingEnabledfür alle Benutzer mit Qualitätsverlust (Resampling) den Canvas-Kontext auf true` und imageSmoothingQualityto high. In Typoskript sieht dieser Block wie folgt aus: const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height);
Sean Perkins
1
Gibt es eine Chance, dies zu einem npm-Paket zu machen? Wäre super toll!
erksch
62

Die Antwort darauf lautet Ja. In HTML 5 können Sie die Größe von Bildern clientseitig mithilfe des Canvas-Elements ändern. Sie können die neuen Daten auch nehmen und an einen Server senden. Siehe dieses Tutorial:

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

Jeremy Usher
quelle
27
Dies ist eine reine Linkantwort und sollte daher ein Kommentar sein.
Jimbo
2
canvas.mozGetAsFile ("foo.png"); ist eine veraltete Funktion
Mili
12

Wenn Sie vor dem Hochladen die Größe geändert haben, habe ich gerade diese http://www.plupload.com/ herausgefunden.

Es macht die ganze Magie für Sie in jeder erdenklichen Methode.

Leider wird nur die HTML5-Größenänderung mit dem Mozilla-Browser unterstützt, aber Sie können andere Browser auf Flash und Silverlight umleiten.

Ich habe es gerade versucht und es hat mit meinem Android funktioniert!

Ich habe http://swfupload.org/ in Flash verwendet, es macht den Job sehr gut, aber die Größe der Größe ist sehr klein. (kann sich nicht an das Limit erinnern) und kehrt nicht zu HTML4 zurück, wenn Flash nicht verfügbar ist.

Ignacio
quelle
44
Es ist hilfreich, eine clientseitige Größenänderung vorzunehmen, wenn ein Benutzer versucht, ein 10-MB-Foto hochzuladen, das nur als viel kleineres Foto gespeichert wird. Auf diese Weise wird es viel schneller hochgeladen.
Kyle
Das gleiche Szenario hier: Sobald Sie eine Dateieingabe haben und der Benutzer sich auf einem Smartphone befindet und mit der Kamera ein Bild aufnimmt, werden es auf modernen Smartphones etwa 10 MB sein. Wenn Sie auf der Serverseite ohnehin die Größe ändern und nur eine viel kleinere Version davon speichern, sparen Sie eine Menge Mobilfunkdaten und Ladezeit, wenn Sie die Größe zuvor im Client ändern.
Alex
1
Seien Sie vorsichtig, da plupload AGPL ist.
Alex
11

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

In modernen Browsern können Sie Canvas zum Laden / Speichern von Bilddaten verwenden. Sie sollten jedoch einige Dinge beachten, wenn Sie die Bildgröße auf dem Client ändern:

  1. Sie haben nur 8 Bit pro Kanal (JPEG kann einen besseren Dynamikbereich haben, etwa 12 Bit). Wenn Sie keine professionellen Fotos hochladen, sollte dies kein Problem sein.
  2. Seien Sie vorsichtig beim Ändern der Größe des Algorithmus. Die meisten clientseitigen Resizer verwenden triviale Mathematik, und das Ergebnis ist schlechter als es sein könnte.
  3. Möglicherweise müssen Sie das verkleinerte Bild schärfen.
  4. Wenn Sie Metadaten (exif und andere) aus dem Original wiederverwenden möchten, vergessen Sie nicht, die Farbprofilinformationen zu entfernen. Weil es angewendet wird, wenn Sie ein Bild auf die Leinwand laden.
Vitaly
quelle
6

Vielleicht mit dem Canvas-Tag (obwohl es nicht portabel ist). Es gibt einen Blog darüber , wie ein Bild mit Leinwand zu drehen , hier , ich nehme an, wenn Sie es drehen kann, kann man die Größe kann. Vielleicht kann es ein Ausgangspunkt sein.

Siehe auch diese Bibliothek .

David V.
quelle
2
Sehr nützliche Beispiele. Möglicherweise möchten Sie Ihrer Antwort ein oder zwei Schnipsel hinzufügen, falls diese Links jemals unterbrochen werden.
Trevor
4

Sie können ein Javascript-Bildverarbeitungsframework für die clientseitige Bildverarbeitung verwenden, bevor Sie das Bild auf den Server hochladen.

Unten habe ich MarvinJ verwendet , um einen ausführbaren Code basierend auf dem Beispiel auf der folgenden Seite zu erstellen: "Verarbeiten von Bildern auf der Clientseite vor dem Hochladen auf einen Server"

Grundsätzlich verwende ich die Methode Marvin.scale (...), um die Bildgröße zu ändern. Dann lade ich das Bild als Blob hoch ( mit der Methode image.toBlob () ). Der Server antwortet mit einer URL des empfangenen Bildes.

/***********************************************
 * 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
quelle
Das sieht verdammt gut aus!
Pimbrouwers
2

Ja, mit modernen Browsern ist dies völlig machbar. Es ist sogar möglich, die Datei speziell als Binärdatei hochzuladen, nachdem eine beliebige Anzahl von Canvas-Änderungen vorgenommen wurde.

http://jsfiddle.net/bo40drmv/

(diese Antwort ist eine Verbesserung der akzeptierten Antwort hier )

Denken Sie daran, die Ergebnisübermittlung in PHP mit etwas Ähnlichem zu erfassen:

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

Wenn Sie sich über Vitalys Punkt Sorgen machen, können Sie versuchen, das Zuschneiden und Ändern der Größe der funktionierenden Geige zu übernehmen.

Tatarisieren
quelle
0

Nach meiner Erfahrung war dieses Beispiel die beste Lösung zum Hochladen eines Bilds mit geänderter Größe: https://zocada.com/compress-resize-images-javascript-browser/

Es verwendet die HTML5-Canvas-Funktion.

Der Code ist so einfach:

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

Diese Option hat nur einen Nachteil und hängt mit der Bilddrehung zusammen, da EXIF-Daten ignoriert werden. Woran ich gerade arbeite. Wird aktualisiert, nachdem ich damit fertig bin.

Ein weiterer Nachteil ist der Mangel an Unterstützung für IE / Edge, an dem ich ebenfalls arbeite. Obwohl es Informationen im obigen Link gibt. Für beide Themen.

xarlymg89
quelle