Mengubah ukuran sisi klien dengan JavaScript sebelum mengunggah ke server


147

Saya mencari cara untuk mengubah ukuran sisi klien gambar dengan JavaScript (benar-benar mengubah ukuran, tidak hanya mengubah lebar dan tinggi).
Saya tahu dimungkinkan untuk melakukannya dalam Flash tetapi saya ingin menghindarinya jika memungkinkan.

Apakah ada algoritma open source di suatu tempat di web?


Bagi Anda yang masih ingin tahu jawabannya, Anda Dapat Melakukan Ini, tetapi Anda harus melakukan beberapa panggilan ajax untuk pemrosesan gambar.
polyhedron

1
'Perlu dibuat'? Yah Anda BISA menyelesaikannya di server setelah semua dan mendapatkan data secara transparan melalui panggilan AJAX. Tetapi seluruh upaya adalah untuk melakukannya di sisi klien, dan seperti yang ditunjukkan Jeremy bahwa BISA dilakukan. Saya pikir ini adalah contoh yang bagus: github.com/rossturner/HTML5-ImageUploader
Bart

2
Dengan versi terbarunya, Dropzone.js mendukung pengubahan ukuran gambar sisi klien sebelum diunggah.
user1666456

Jawaban:


111

Inilah intinya yang melakukan ini: https://gist.github.com/dcollien/312bce1270a5f511bf4a

(versi es6, dan versi .js yang dapat dimasukkan dalam tag skrip)

Anda dapat menggunakannya sebagai berikut:

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

Ini mencakup banyak deteksi dukungan dan polyfill untuk memastikan itu berfungsi pada sebanyak mungkin browser yang bisa saya kelola.

(itu juga mengabaikan gambar gif - kalau-kalau itu animasi)


2
Saya merasa seperti Anda belum menerima pujian yang cukup untuk ini - saya pikir itu bekerja dengan baik dan sangat mudah. Terima kasih telah berbagi!
Matt

4
Hmm..saya berhasil dengan ini, tetapi saya menemukan bahwa gambar saya (selain diubah ukurannya) juga mengalami kehilangan kualitas yang sangat besar (dalam bentuk pixelation yang parah), meskipun dihasilkan pada resolusi yang benar.
Ruben Martinez Jr.

1
hai, saya perlu cuplikan untuk digunakan seperti ini, dan saya pikir ini sangat bagus tapi .. berfungsi (gumpalan, didItResize) {// didItResize akan benar jika berhasil mengubah ukurannya, jika tidak palsu (dan akan mengembalikan yang asli file sebagai 'blob') document.getElementById ('preview'). src = window.URL.createObjectURL (blob); // Anda sekarang juga dapat mengunggah gumpalan ini menggunakan XHR. di sini saya punya masalah .. Bagaimana saya bisa mengirim gambar ini dalam bentuk hanya dengan mengirimkan formulir. Maksud saya, seperti permintaan pos yang dipicu oleh tombol kirim. Anda tahu, cara biasa. Terima kasih untuk intinya!
iedmrc

3
Bagi siapa pun yang kehilangan kualitas (resampling), perbarui konteks kanvas untuk ditetapkan imageSmoothingEnabledsebagai true` dan imageSmoothingQualityke high. Dalam naskah yang memblokir terlihat seperti: const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height);
Sean Perkins

1
Apakah ada peluang menjadikan ini paket npm? Akan menjadi super hebat!
erksch


12

Jika Anda mengubah ukuran sebelum mengunggah, saya baru tahu ini http://www.plupload.com/

Itu melakukan semua keajaiban untuk Anda dalam metode apa pun yang bisa Anda bayangkan.

Sayangnya ukuran HTML5 hanya didukung dengan browser Mozilla, tetapi Anda dapat mengarahkan browser lain ke Flash dan Silverlight.

Saya baru saja mencobanya dan itu bekerja dengan android saya!

Saya menggunakan http://swfupload.org/ dalam sekejap, ia melakukan pekerjaan dengan sangat baik, tetapi ukurannya sangat kecil. (tidak ingat batasnya) dan tidak kembali ke html4 ketika flash tidak tersedia.


44
Sangat menyenangkan untuk melakukan pengubahan ukuran sisi klien ketika seorang pengguna mencoba mengunggah foto 10MB yang hanya akan disimpan sebagai foto yang jauh lebih kecil. Ini akan mengunggah lebih cepat dengan cara ini.
Kyle

Skenario yang sama di sini, segera setelah Anda memiliki input file dan pengguna pada smartphone dan mengambil gambar menggunakan kamera, itu akan menjadi sekitar 10 mb pada smartphone modern. Jika Anda di sisi server mengubah ukurannya dan hanya menyimpan versi yang jauh lebih kecil, Anda akan menghemat banyak data seluler dan memuat waktu untuk melakukan pengubahan ukuran sebelumnya di klien.
Alex

1
Hati-hati karena plupload adalah AGPL.
Alex

11

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

Di browser modern, Anda dapat menggunakan kanvas untuk memuat / menyimpan data gambar. Tetapi Anda harus mengingat beberapa hal jika Anda mengubah ukuran gambar pada klien:

  1. Anda hanya akan memiliki 8 bit per saluran (jpeg dapat memiliki jangkauan dinamis yang lebih baik, sekitar 12 bit). Jika Anda tidak mengunggah foto profesional, itu seharusnya tidak menjadi masalah.
  2. Hati-hati dengan algoritma pengubahan ukuran. Sebagian besar dari resizer sisi klien menggunakan matematika sepele, dan hasilnya lebih buruk daripada yang seharusnya.
  3. Anda mungkin perlu mempertajam gambar yang diturunkan.
  4. Jika Anda ingin menggunakan kembali metadata (exif dan lainnya) dari aslinya - jangan lupa untuk menghapus info profil warna. Karena itu diterapkan ketika Anda memuat gambar ke kanvas.

6

Mungkin dengan tag kanvas (meskipun ini tidak portabel). Ada sebuah blog tentang cara memutar gambar dengan kanvas di sini , saya kira jika Anda dapat memutarnya, Anda dapat mengubah ukurannya. Mungkin itu bisa menjadi titik awal.

Lihat perpustakaan ini juga.


2
Contoh yang sangat berguna. Anda mungkin ingin menambahkan satu atau dua snippet ke jawaban Anda seandainya tautan ini rusak.
Trevor

4

Anda dapat menggunakan kerangka kerja pemrosesan gambar javascript untuk pemrosesan gambar sisi klien sebelum mengunggah gambar ke server.

Di bawah ini saya menggunakan MarvinJ untuk membuat kode runnable berdasarkan contoh di halaman berikut: "Memproses gambar di sisi klien sebelum mengunggahnya ke server"

Pada dasarnya saya menggunakan metode Marvin.scale (...) untuk mengubah ukuran gambar. Lalu, saya mengunggah gambar sebagai gumpalan (menggunakan metode image.toBlob () ). Server menjawab kembali dengan memberikan URL gambar yang diterima.

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


Ini terlihat sangat keren!
pimbrouwers

2

Ya, dengan browser modern ini benar-benar bisa dilakukan. Bahkan bisa dilakukan hingga mengunggah file secara khusus sebagai file biner setelah melakukan sejumlah perubahan kanvas.

http://jsfiddle.net/bo40drmv/

(jawaban ini merupakan peningkatan dari jawaban yang diterima di sini )

Perlu diketahui proses pengiriman hasil dalam PHP dengan sesuatu yang mirip dengan:

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

Jika ada yang khawatir tentang poin Vitaly, Anda dapat mencoba beberapa cropping dan mengubah ukuran pada jfiddle yang berfungsi.


0

Dalam pengalaman saya, contoh ini telah menjadi solusi terbaik untuk mengunggah gambar yang diubah ukurannya: https://zocada.com/compress-resize-images-javascript-browser/

Ini menggunakan fitur Kanvas HTML5.

Kode ini sesederhana ini:

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

Hanya ada satu kelemahan dengan opsi ini, dan ini terkait dengan rotasi gambar, karena mengabaikan data EXIF. Yang sedang saya kerjakan saat ini. Akan diperbarui setelah saya selesai dengan itu.

Kelemahan lain, adalah kurangnya dukungan musuh IE / Edge, yang saya kerjakan juga. Meskipun ada informasi di tautan di atas. Untuk kedua masalah tersebut.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.