Здравствуйте!
Возникла задача для интернет-магазина сфотографировать большое количество товаров. Специфика товара такова, что не столько важна красивая картинка, сколько особенности конструкции товара (с какой стороны находится шлейф, есть ли петли крепления и т.п.)
Фотографировать обычным фотоаппаратом, потом заливать фото на компьютер, искать каждый товар в админке, потом искать соответствующее фото, показалось очень долго. Гораздо проще открыть товар в админке и навести телефон на товар. Тем более, что при хорошо выставленном освещении, современные смартфоны выдают вполне качественную картинку.
Теория
В андроид-маркете лежит замечательная программа IpWebCam, которая позволяет превратить свой телефон в полноценную веб-камеру. Кроме того у нее есть api для получения фотографий с автофокусом. При запуске IpWebCam, на телефоне поднимается web-сервер, который позволяет с локальной машины по wi-fi получать текущий кадр с телефона по адресу вида 192.168.0.14:8080/shot.jpg
Идея была следующая:
- Вставить в форму <img> с адресом фотографии со смартфона
- Создать canvas и в него скопировать содержимое <img>
- Сохранить данные при помощи canvas.toDataURL()
- Отправить данные на сервер при помощи ajax
К сожалению, из-за кросс-доменных политик метод toDataURL() сохраняет только черный квадрат вместо изображения. Поэтому canvas надо создавать на том же домене, из которого берется изображение. Сходив на сайт программы, я узнал, что IpWebCam позволяет создавать собственные html-страницы на своем внутреннем сервере. Для этого их достаточно залить на sd-карту и указать программе, в какой папке их искать.
Алгоритм следующий:
- На смартфоне создаем специальную страницу (например my.html)
- В форме на нашем сайте создаем <iframe>, в который грузим html-страницу со смартфона.
- На телефоне в html странице создаем canvas, в который грузим изображение с камеры.
- Сохраняем данные при помощи canvas.toDataURL() в переменную
- Передаем данные в родительскую страницу при помощи window.postMessage()
- В родительской странице получаем изображение и отправляем данные на сервер при помощи ajax
- На сервере сохраняем изображение в файл.
Решение
Во-первых, ставим на смартфон программу IpWebCam из маркета.
Создаем на смартфоне папку webcam, а в ней создаем файл my.html со следующим содержимым:
Content-Type: text/html
<html>
<head>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="jquery.jplayer.min.js"></script>
<script type="text/javascript" src="common.js"></script>
<style>
* { margin: 0; padding: 0}
</style>
<script type="text/javascript">
$(loadJsWindowed);
function shot()
{
$('#msg').text('Please wait...');
var img = new Image();
img.onload = function(){
var canvas = $('<canvas width="' + img.width + '" height="' + img.height + '">');
canvas[0].getContext('2d').drawImage(img, 0, 0);
var data = canvas[0].toDataURL('image/jpeg').replace(/data:image/jpeg;base64,/, '');
canvas.remove();
//засылаем картинку на сервер
window.parent.postMessage(data, '*');
}
img.src = 'photoaf.jpg';
}
</script>
</head>
<body>
<div id="msg" style="text-align: center; background-color: #000000; color: #FFFFFF; font-weight: bold; cursor: pointer;" onclick="shot();">Click to take a shot..</div>
<img id="img1" src="/shot.jpg?1" style="cursor: pointer; position:absolute;"/>
<img id="img2" src="/shot.jpg?2" style="cursor: pointer; position:absolute;"/>
</body>
</html>
Обратите внимание, что в начале файла идут HTTP заголовки и пустая строка перед основным содержимым страницы. За основу был взят javascript видео-проигрыватель из самой программы.
Теперь надо указать, где искать файлы для веб-сервера приложения. Для этого откройте программу на телефоне, нажмите хардварную кнопку меню и выберите единственный пункт Cheats. Теперь введите в открывшемся диалоговом окне команду set(HtmlPath,/sdcard/webcam). Обратите внимание, что после запятой не допускаются пробелы.
Теперь на нашем сервере создаем файл jquery плагина jquery.ipwebcam.js:
(function($) {
$.fn.ipWebCam = function(options) {
var settings = $.extend( {
ip: '',
width: 640,
height: 480,
action: '?',
callback: function(){}
}, options);
function ipWebCam_listener(event){
$('#ipWebCam_wnd').prev().remove();
$('#ipWebCam_wnd').remove();
$.post(settings.action, {data:event.data}, settings.callback);
}
if (window.addEventListener){
window.addEventListener('message', ipWebCam_listener,false);
} else {
window.attachEvent('onmessage', ipWebCam_listener);
}
return this.each(function() {
$(this).click(function(){
if(settings.ip=='')
settings.ip = prompt('IP Webcam address:');
$('<iframe>').css({
position: 'fixed',
width: settings.width + 'px',
marginLeft: '-' + (settings.width/2) + 'px',
left: '50%',
height: settings.height + 'px',
marginTop: '-' + (settings.height/2) + 'px',
top: '50%',
border: 0,
overflow: 'hidden',
backgroundColor: '#777777'
})
.attr('width', settings.width)
.attr('height', settings.height)
.attr('src', 'http://' + settings.ip + ':8080/my.html')
.attr('id', 'ipWebCam_wnd')
.prependTo('body');
$('<div>').css({
position:'fixed',
left: 0,
top: 0,
right:0,
bottom:0,
backgroundColor: '#000000',
opacity: 0.5
}).click(function(){
$('#ipWebCam_wnd').prev().remove();
$('#ipWebCam_wnd').remove();
}).prependTo('body');
});
});
};
})( jQuery )
Плагин цепляется к кнопке вызова диалога. Например:
$('#camera_button').ipWebCam({
ip: '', //ip адрес камеры, если не задан, то попросит ввести через prompt
action: 'save_img.php', //адрес скрипта сохранения картинки, по умолчанию та же страница
callback: function(rep){ // будет вызвана после отправки данных на сервер
window.location.reload();
},
width: 640, // размеры iframe
height: 480
});
Плагин передает данные на сервер методом POST в переменной data. Сохранить файл на php:
if(isset($_POST['data']))
{
$name = 'img/shot.jpg';
//записываем, не забывая перекодировать из base64
file_put_contents($name, base64_decode($_POST['data'] ));
echo 'ok';
}
На этом все, если кому-нибудь пригодится, буду рад.
Автор: PyroRed