misc/class
lib/jquery_pnotify, lib/moment, lib/lodash, misc/notification, site/engine, misc/social
if( $.browser.msie && $.browser.version <= 8 ) include('lib/respond'); $._social.__cfg = {"init":[{"service":"basic"},{"fb_app_id":"1997094873850041","service":"fb"},{"vk_app_id":"2978320","service":"vk"},{"service":"twi"}],"like":[{"service":"fb"},{"service":"vk"},{"via":"","channel":"","hash_tag":"","service":"twi"}]}; window._SiteEngine = new classes.SiteEngine( { user_id: 0, controller: 'content_tape', action: 'tag', content_css_version: '1459538664', social_enabled: 0} );

Faiwer

Блог web-программиста

Поиск по метке: Java

Resize изображений на стороне браузера

21 марта 2016

В этой заметке я опишу, как, относительно несложным способом, можно организовать resize изображений на стороне браузера перед отправкой на сервер.

Для начала нам потребуется <input type="file"/>. Без него нам не открыть диалог для выбора файла. Чтобы вызвать его вручную необходимо в обработчике вида onclick (onkeydown и пр. отпадают из-за Firefox) вызвать file.click(). Вызвать диалог в произвольный момент времени не получится.

Отслеживаем изменение выбора файла по onchange. Сам же файл достаём из file.files[index]. Если наш <input/> работает не в multiple режиме, то index, соответственно, равен 0. Присмотревшись к свойствам этого объекта мы увидим его mime тип, размер, имя файла. Но не содержимое.

Для получения содержимого воспользуемся FileReader-ом.

const reader = new FileReader();
reader.onload = e => { e.target.result; /* base64 string */ };
reader.readAsDataURL(file);

Через него получаем DataURL вариант содержимого файла (асинхронно). Затем создаём новый Image, вешаем обработчик на onload, задаём этот dataURL ему как аттрибут src. В результате получаем валидный <img/> тег с загруженным готовым к использованию изображением.

Resize изображения будем осуществлять за счёт <canvas/>. У contextcanvas-а есть метод drawImage, который сделает за нас всю грязную работу. Ниже пример работы с ним (стояла задача вписать изображение в определённые рамки, но только если оно превышает эти сами рамки):

const canvas = document.createElement('canvas');

const w_ratio = img.width / width;
const h_ratio = img.height / height;
let ratio = Math.max(w_ratio, h_ratio);
if(ratio < 1)
	ratio = 1;

const w = Math.floor(img.width / ratio);
const h = Math.floor(img.height / ratio);

canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, w, h);
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, w, h);

return canvas.toDataURL('image/jpeg', 80);

Обратите внимание на то, что <canvas/> даже не обязательно цеплять к DOM-у браузера, и тем более делать его видимым. В результате получаем снова dataURL, но уже правильного вида и размера. Но что нам теперь с ним делать? 

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

const fd = new FormData(form);
fd.append('image', blob);

Обратите внимание на blob. Дело в том, что для маскировки под обычный input[type=file] нам нужно нашу dataURL перевести в Blob вариант. Я взял готовое решение со stackoverflow:

function dataUriToBlob(dataURI)
{
	let byteString;
	if( dataURI.split(',')[0].indexOf('base64') >= 0 )
		byteString = atob(dataURI.split(',')[1]);
	else
		byteString = window.unescape(dataURI.split(',')[1]);

	// separate out the mime component
	const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

	// write the bytes of the string to a typed array
	const ia = new Uint8Array(byteString.length);
	for(let i = 0; i < byteString.length; i ++)
		ia[i] = byteString.charCodeAt(i);

	return new Blob([ ia ], { type: mimeString });
}

Задача решена. Относительно без крови. Однако, мы воспользовались FormData, FileReader, Blob, Uint8Array,  Canvas. Тот же самый IE9 всего этого не умеет.

Кирилица и SmartGit

11 апреля 2015

Извечная беда с горячими клавишами в нестандартной (т.е. английской) раскладке. Наиболее часто попадается в Java и QT приложениях. Наиболее остро я на это натыкаюсь при использовании Mate окружения в свежем LinuxMint-е. Обе баги (что QT, что Java) уже исправлены, что, почему то не сказывается даже на свежих билдах софта, к примеру SmartGit-а. В очередной раз вооружившись поисковиком я стал искать решения в обход. И нашёл! Хороший человек написал небольшую java-утилиту для решения проблем с горячими клавишами. Вся соль в том, что необходимо запустить jar-ки с флагом -javaagent к java. В описании к репозиторию указано, как правильно это сделать для Intelli Idea и ещё ряда приложений. А для SmartGit-а вот правильное решение:

  • Создать файл ~/.smartgit/smartgit.vmoptions
  • Вписать туда -javaagent:%jarpath%/LinuxJavaFixes-%version%.jar=swt. Вместо %jarpath% указать путь к скачанным с github-а файлам, а вместо %version% текущую версию jar-ки. Обратите внимание на =swt, без этого в SmartGit ничего не заработало. SWT это фреймворк для Java, который использует SmartGit
  • Готово!

Осталось найти рецепт для QT-приложений :( Похоже, что там надо насильно ставить себе QT5.5+ и собирать из исходников каждое проблемное приложение :(