Зміна зображення на стороні клієнта за допомогою JavaScript перед завантаженням на сервер


147

Я шукаю спосіб змінити розмір зображення на стороні клієнта за допомогою JavaScript (дійсно змінити розмір, а не просто змінити ширину та висоту).
Я знаю, що це можливо зробити у Flash, але я хотів би уникнути цього, якщо можливо.

Чи є алгоритм з відкритим кодом десь в Інтернеті?


Для тих із вас, хто все ще хоче знати відповідь на це, ви можете це зробити, але вам потрібно буде зробити кілька ajax дзвінків для обробки зображень.
багатогранник

1
"Потрібно зробити"? Добре ви можете вирішити це на сервері і отримати прозорі дані через AJAX дзвінки. Але вся спроба полягає в тому, щоб зробити це клієнтом, і як Джеремі вказує, що МОЖНО зробити. Я думаю, що це чудовий приклад: github.com/rossturner/HTML5-ImageUploader
Bart

2
В останній версії Dropzone.js підтримує зміну розміру зображення на стороні клієнта перед завантаженням.
користувач1666456

Відповіді:


111

Ось істота, яка робить це: https://gist.github.com/dcollien/312bce1270a5f511bf4a

(версія es6 та версія .js, яку можна включити в тег сценарію)

Ви можете використовувати його наступним чином:

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

Він включає в себе купу виявлення підтримки та поліфілів, щоб переконатися, що він працює в багатьох браузерах, наскільки я міг керувати.

(він також ігнорує gif-зображення - на випадок, якщо вони анімовані)


2
Я відчуваю, що ти не отримав майже достатньо похвал за це - я думаю, що це чудово працює і це дуже просто. Дякую, що поділились!
Мет

4
Хм .. Я мав добрий успіх у цьому, але я виявив, що мої зображення (крім розміру) також зазнали величезної втрати якості (у вигляді сильної пікселяції), хоча це було відхилено при правильній роздільній здатності.
Рубен Мартінес-молодший

1
привіт, мені потрібен фрагмент, як цей, і я думаю, це дуже добре, але .. функція (blob, didItResize) {// didItResize буде правдою, якщо вдалося змінити її розмір, інакше false (і поверне оригінал файл як 'blob') document.getElementById ('попередній перегляд'). src = window.URL.createObjectURL (blob); // Ви також можете завантажити цю крапку за допомогою XHR. тут у мене проблема .. Як я можу надіслати це зображення у формі, просто надіславши форму. Я маю на увазі, як запит на повідомлення, викликаний кнопкою подання. Знаєте, звичайним способом. Дякую за суть!
iedmrc

3
Для тих, хто має втрату якості (перекомпонування), оновіть контекст полотна, щоб встановити значення " imageSmoothingEnabledістинно" та " imageSmoothingQualityдо" high. У машинописному тексті цей блок виглядає так: const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height);
Шон Перкінс

1
Чи є шанс зробити це пакетом npm? Було б супер чудово!
erksch

62

Відповідь на це так - в HTML 5 ви можете змінити розмір зображень на стороні клієнта за допомогою елемента "canvas". Ви також можете взяти нові дані та надіслати їх на сервер. Дивіться цей підручник:

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


28
Це відповідь лише за посиланням і як такий повинен бути коментарем.
Джимбо

2
canvas.mozGetAsFile ("foo.png"); є застарілою функцією
мілі

12

Якщо ви змінювали розмір перед завантаженням, я щойно дізнався це http://www.plupload.com/

Це робить усі чари для вас у будь-якому уявному способі.

На жаль HTML5 розмір підтримується лише в браузері Mozilla, але ви можете перенаправляти інші браузери на Flash та Silverlight.

Я просто спробував це, і він працював з моїм андроїдом!

Я використовував http://swfupload.org/ у спалах, він робить цю роботу дуже добре, але розмір розміру дуже малий. (не пам'ятаю обмеження) і не повертається до html4, коли спалах недоступний.


44
Приємно робити зміни розміру на стороні клієнта, коли користувач намагається завантажити 10-мільйонну фотографію, яка зберігається лише як набагато менша фотографія. Цей спосіб завантажується набагато швидше.
Кайл

Такий самий сценарій і тут, як тільки ви вводите файл і користувач перебуває на смартфоні і знімає зображення за допомогою камери, на сучасних смартфонах його буде близько 10 Мбіт. Якщо ви на стороні сервера все одно змінюєте його розмір і зберігаєте лише набагато меншу його версію, ви заощадите багато стільникових даних і час завантаження, попередньо виконуючи розмір клієнта.
Олексій

1
Будьте обережні, оскільки завантажувальний пристрій - це AGPL.
Олексій

11

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

У сучасному браузері можна використовувати полотно для завантаження / збереження зображень. Але слід пам’ятати про кілька речей, якщо ви змінюєте розмір зображення на клієнті:

  1. У вас буде лише 8 біт на канал (jpeg може мати кращий динамічний діапазон, приблизно 12 біт). Якщо ви не завантажуєте професійні фотографії, це не повинно бути проблемою.
  2. Будьте уважні до алгоритму зміни розміру. Більшість клієнтів-резизерів використовують тривіальну математику, а результат гірший, ніж міг би бути.
  3. Можливо, вам доведеться чіткіше зменшити масштаб зображення.
  4. Якщо ви бажаєте використовувати метадані (exif та інші) з оригіналу - не забудьте зняти інформацію про кольоровий профіль. Тому що він застосовується під час завантаження зображення на полотно.

6

Можливо, із тегом canvas (хоча це не портативно). Там в блозі про те , як повернути зображення з полотна тут , я вважаю , що якщо ви можете повернути його, ви можете змінити його розмір. Можливо, це може бути відправною точкою.

Дивіться також цю бібліотеку .


2
Дуже корисні приклади. Ви можете додати фрагмент або два до своєї відповіді, якщо ці посилання колись перервуться.
Тревор

4

Ви можете використовувати рамку обробки зображень javascript для обробки зображень на стороні клієнта перед завантаженням зображення на сервер.

Нижче я використовував MarvinJ для створення виконуваного коду на основі прикладу на наступній сторінці: "Обробка зображень на стороні клієнта перед завантаженням його на сервер"

В основному я використовую метод Marvin.scale (...) для зміни розміру зображення. Потім я завантажую зображення у вигляді краплі (використовуючи метод image.toBlob () ). Сервер відповідає на відповідь, надаючи URL-адресу отриманого зображення.

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


Це виглядає приголомшливо!
pimbrouwers

2

Так, для сучасних браузерів це цілком можливо. Навіть доцільно завантажувати файл спеціально як двійковий файл, зробивши будь-яку кількість змін полотна.

http://jsfiddle.net/bo40drmv/

(ця відповідь є вдосконаленням прийнятої відповіді тут )

Маючи на увазі, щоб обробити процес подання результату в PHP, щось подібне до:

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

Якщо хтось турбується про точку Віталія, ви можете спробувати трохи обрізати та змінити розмір робочої jfiddle.


0

На мій досвід, цей приклад став найкращим рішенням для завантаження зміненого зображення: https://zocada.com/compress-resize-images-javascript-browser/

Він використовує функцію HTML5 Canvas.

Код такий же простий, як і цей:

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

У цього варіанта є лише один недолік, і це пов'язано з обертанням зображення через ігнорування даних EXIF. Над яким я зараз працюю. Оновиться, коли я закінчу з цим.

Ще один недолік - це відсутність супротивника IE / Edge, над яким я також працюю. Хоча інформація є у вищенаведеному посиланні. Для обох питань.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.