Поддержка браузерами
Во первых надо отметить, что для того, чтобы что-то скопировать из буфера (например скриншот) в браузере должна быть поддержка Clipboard API. Как можно видеть на caniuse только самые последние браузеры работают с этим API. IE, к сожалению, курит в сторонке не смотря на partial support.
Загрузка скриншотов на javascript
Для загрузки изображения из буфера (скриншота) сначала нужно определить обработчик paste события:
document.body.addEventListener("paste", function(e) {
...
});
Обработчик будет вызываться всегда, когда в рабочей области окна браузера происходит событие «Вставить», например по нажатию Ctrl + V. Далее нужно определить код, который собственно и примет файл изображения из буфера. Этот код идентичен для браузеров Chrome и Opera, но разный для FireFox, так как у последнего по каким-то соображениям безопасности закрыты методы объекта clipboardData.
Chrome, Opera
// e.clipboardData.items - это и есть файлы находящиеся в буфер обмене
for (var i = 0; i < e.clipboardData.items.length; i++) {
// выбираем только картинки
if (e.clipboardData.items[i].kind == "file" && e.clipboardData.items[i].type == "image/png") {
// Получаем файл как Blob (бинарные данные)
var imageFile = e.clipboardData.items[i].getAsFile();
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
// Файл прочитан в this.result его Base64 представление
loadImg(this.result);
};
// Читаем Blob как DataURL (Base64 представление бинарных данных)
fileReader.readAsDataURL(imageFile);
e.preventDefault();
break;
}
}
FireFox
В FireFox у нас нет возможности прочитать файл через clipboardData. При вставке, браузер самостоятельно создает тег с src в виде DataURL. Поэтому придется сделать «костыль»:
// При инициализации js, если браузера Mozilla, то добавляем скрытый, редактируемый (contenteditable) div и
// ставим на него фокус.
if ($.browser.mozilla) {
$(document.body).prepend('<div id="temp" contenteditable="true" style="height:1px;width:1px;color:#FFFFFF;"></div>');
$('#temp').focus();
}
// Определяем событие "Вставить"
document.body.addEventListener("paste", function(e) {
if ($.browser.mozilla) {
// Если Mozilla, то фокусируем на созданный ранее div
// (это нужно для того, чтобы FireFox вставил img в нужном месте)
$('#temp').focus();
// Удаляем предыдущий img (вдруг мы копируем 2, 3, ..., N раз)
$('#temp img').remove();
// У FireFox при создании img нет callback-а и единственный способ получить img - использовать небольшую паузу
setTimeout(function() {
// Вот тут FireFox точно вставил img в temp div, мы можем взять его DataURL и загрузить картинку
loadImg($('#temp img').attr('src'));
}, 1);
return true;
}
});
Куда загрузить картинку?
Загрузить картинку можно сразу на сервер, передавая через POST DataURL или например в canvas как сделано на Your screen:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
...
function loadImg(dataURL) {
var imageObj = new Image();
imageObj.onload = function() {
var width = this.width, height = this.height;
canvas.width = width;
canvas.height = height;
ctx.drawImage(this, 0, 0, width, height);
};
imageObj.src = dataURL;
}
Canvas удобен тем, что перед загрузкой скриншота на сервер можно его отредактировать: подчеркнуть, нарисовать, обвести, вырезать и т.д.
Что происходит на сервере?
На сервере должен быть POST контроллер, который бы принимал body в формате Base64 (DataURL) и декодировал его в бинарный файл изображения, например png. Контроллер может быть написан на любом языке, например Java с использованием SpringMVC:
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String save(@RequestBody String b64) {
File file = null;
FileOutputStream out = null;
try {
// Создаем Output поток
out = new FileOutputStream("/opt/files/somename.png");
// Декодируем Base64 в байты и сохраняем в поток
out.write(Base64.decodeBase64(StringUtils.replace(b64, "data:image/png;base64,", "")));
// Закрываем поток
IOUtils.closeQuietly(out);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return file.getName();
}
Для внимательных отмечу, что вот эта конструкция StringUtils.replace(b64, «data:image/png;base64,», "") нужна для нормализации передаваемого из Javascript DataURL. Дело в том, что при создании DataURL вначале ставится его тип и формат и после идет Base64 представление, например data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABVYAAAMAC…
Дополнительно можно ещё проверить размер файла, и если он превышает определенный максимум сжать в jpg.
Варианты использования
Сервис Your screen мы в компании Cackle используем каждый день в качестве быстрого и простого средства для снимка экранов наших клиентов. К сожалению, подобных решений в сети очень мало и те, что есть неудобны или работают только через Desktop:
- prntscr.com — копировать скриншот можно только в Chrome и без редактирования
- snag.gy — уже лучше, но скрншоты загружаются очень медленно и только один раз (первый)
- Больше не нашел...
В скором времени мы планируем перенести весь этот функционал в наш Онлайн консультант Cackle. Таким образом у клиентов будет возможность сделать скриншот и передать изображение прямо через консультанта оператору. Это в некотором смысле лучшая замена Co-Browser, так как позволяет показывать весь экран (а не только браузер), снизить издержки на разработку и минимизировать ошибки.
В заключении скажу, что проект Your screen совсем новый и будет развиваться дальше, поэтому жду вашей критики и пожеланий по функционалу.
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:
- Massacres That Matter - Part 1 - 'Responsibility To Protect' In Egypt, Libya And Syria
- Massacres That Matter - Part 2 - The Media Response On Egypt, Libya And Syria
- National demonstration: No attack on Syria - Saturday 31 August, 12 noon, Temple Place, London, UK
Комментариев нет:
Отправить комментарий