Изменение размера изображения на стороне клиента с помощью JavaScript перед загрузкой на сервер


147

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

Есть ли где-нибудь в Интернете алгоритм с открытым исходным кодом?


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

1
«Нужно сделать»? Ну, в конце концов, вы МОЖЕТЕ решить ее на сервере и получить эти данные через вызовы AJAX. Но вся попытка состоит в том, чтобы сделать это на стороне клиента, и, как указывает Джереми, это МОЖЕТ быть сделано. Я думаю, что это отличный пример: github.com/rossturner/HTML5-ImageUploader
Барт

2
В последней версии Dropzone.js поддерживает изменение размера изображения на стороне клиента перед загрузкой.
user1666456

Ответы:


112

Вот суть, которая делает это: 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
привет, мне нужен фрагмент, чтобы использовать, как этот, и я думаю, что это очень хорошо, но .. function (blob, didItResize) {// didItResize будет true, если ему удалось изменить его размер, в противном случае false (и вернет оригинал файл как 'blob') document.getElementById ('preview'). src = window.URL.createObjectURL (blob); // теперь вы также можете загрузить этот BLOB-объект, используя XHR. здесь у меня проблема .. Как я могу отправить это изображение в форме, просто отправив форму. Я имею в виду, как запрос на публикацию, вызванный кнопкой отправки. Вы знаете, обычный способ. Спасибо за суть!
16:05

3
Для тех, у кого есть потеря качества (ресэмплинг), обновите контекст холста, чтобы установить imageSmoothingEnabledкак true` и imageSmoothingQualityto 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/


29
Это ответ только для ссылок, и поэтому он должен быть комментарием.
Джимбо

2
canvas.mozGetAsFile ( "foo.png"); является устаревшей функцией
Мили

12

Если вы изменяли размер перед загрузкой, я узнал об этом http://www.plupload.com/

Это делает всю магию для вас любым мыслимым способом.

К сожалению, только изменение размера HTML5 поддерживается браузером Mozilla, но вы можете перенаправить другие браузеры на Flash и Silverlight.

Я только что попробовал, и он работал с моим Android!

Я использовал http://swfupload.org/ во флэш-памяти, он отлично справляется со своей задачей, но размер изменения очень мал. (не могу вспомнить предел) и не возвращается к html4, когда флэш-память недоступна.


44
Рекомендуется выполнять изменение размера на стороне клиента, когда пользователь пытается загрузить фотографию размером 10 МБ, которая будет сохранена как фотография намного меньшего размера. Так будет загружаться намного быстрее.
Кайл

Тот же сценарий здесь, как только у вас есть файл ввода, и пользователь на смартфоне и снимает изображение с помощью камеры, на современных смартфонах это будет около 10 МБ. Если вы в любом случае на стороне сервера изменяете его размер и сохраняете только его гораздо меньшую версию, вы сэкономите много сотовых данных и время загрузки, предварительно выполнив изменение размера в клиенте.
Алекс

1
Будьте осторожны, потому что plupload - это AGPL.
Алекс

11

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

В современном браузере вы можете использовать canvas для загрузки / сохранения данных изображения. Но вы должны иметь в виду несколько вещей, если вы изменяете размер изображения на клиенте:

  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.