Поддержка браузерами
Во первых надо отметить, что для того, чтобы что-то скопировать из буфера (например скриншот) в браузере должна быть поддержка 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. При вставке, браузер самостоятельно создает <img> тег с 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 совсем новый и будет развиваться дальше, поэтому жду вашей критики и пожеланий по функционалу.
ссылка на оригинал статьи http://habrahabr.ru/company/cackle/blog/201190/
Добавить комментарий