Получение фото с android-смартфона прямо в html форму

    Здравствуйте!

    image

    Возникла задача для интернет-магазина сфотографировать большое количество товаров. Специфика товара такова, что не столько важна красивая картинка, сколько особенности конструкции товара (с какой стороны находится шлейф, есть ли петли крепления и т.п.)

    Фотографировать обычным фотоаппаратом, потом заливать фото на компьютер, искать каждый товар в админке, потом искать соответствующее фото, показалось очень долго. Гораздо проще открыть товар в админке и навести телефон на товар. Тем более, что при хорошо выставленном освещении, современные смартфоны выдают вполне качественную картинку.

    Теория


    В андроид-маркете лежит замечательная программа IpWebCam, которая позволяет превратить свой телефон в полноценную веб-камеру. Кроме того у нее есть api для получения фотографий с автофокусом. При запуске IpWebCam, на телефоне поднимается web-сервер, который позволяет с локальной машины по wi-fi получать текущий кадр с телефона по адресу вида 192.168.0.14:8080/shot.jpg

    Идея была следующая:
    1. Вставить в форму <img> с адресом фотографии со смартфона
    2. Создать canvas и в него скопировать содержимое <img>
    3. Сохранить данные при помощи canvas.toDataURL()
    4. Отправить данные на сервер при помощи ajax


    К сожалению, из-за кросс-доменных политик метод toDataURL() сохраняет только черный квадрат вместо изображения. Поэтому canvas надо создавать на том же домене, из которого берется изображение. Сходив на сайт программы, я узнал, что IpWebCam позволяет создавать собственные html-страницы на своем внутреннем сервере. Для этого их достаточно залить на sd-карту и указать программе, в какой папке их искать.

    Алгоритм следующий:
    1. На смартфоне создаем специальную страницу (например my.html)
    2. В форме на нашем сайте создаем <iframe>, в который грузим html-страницу со смартфона.
    3. На телефоне в html странице создаем canvas, в который грузим изображение с камеры.
    4. Сохраняем данные при помощи canvas.toDataURL() в переменную
    5. Передаем данные в родительскую страницу при помощи window.postMessage()
    6. В родительской странице получаем изображение и отправляем данные на сервер при помощи ajax
    7. На сервере сохраняем изображение в файл.

    Решение


    Во-первых, ставим на смартфон программу 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';
    }
    

    На этом все, если кому-нибудь пригодится, буду рад.

    upd Идея была в том, что администратор работает в админке за большим компом, так удобнее (он ведь не только фотки делает). А смартфон кладется на штатив и не трогается. Непосредственно фотографирование (предпросмотр и нажатие спуска) происходит на большом компе, чтобы лишний раз к телефону не бегать. Поэтому саму фотографию придется передавать непосредственно в html форму на большом компе. Это можно сделать только подняв веб-сервер на смарте. Можно было бы написать программу самому, но зачем если уже есть готовое решение — IpWebCam.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 16
    • –4
      А если много народу придет, смартфон не помрёт от нагрузки? Может быть, правильнее дергать файл на сервер, а там уже его показывать всем желающим?
      • +2
        Согласен, стормозил — в вашем случае и не предвидится много коннектов. :)
        • +1
          вы о чем?
          автор фоткает на телефоне товар, потом по http заливает на север конкретном товару, сохраняет, profit. Далее все кому нужно смотрят товар с фото на сервере.
          чего телефон должен помирать?
          • +2
            Да я уже понял, что стормозил. В голове уже крутился вариант, куда можно присобачить парочку ненужных андроидных телефонов в качестве камер, потому вопрос, фактически был задан себе, а не автору статьи. Но «ушел» автору.
        • НЛО прилетело и опубликовало эту надпись здесь
          • +2
            Ждем программу и статью :)
          • +3
            Вроде бы PhoneGap имеет доступ к камере как раз для фотографий, ну это если знаний по Java вообще нету.
            Хотя способ конечно креативный в статье описан.
            • 0
              Честно говоря, мне показалось, что на PhoneGap то же самое можно сделать существенно проще и без всяких хаков…
              • 0
                Ну так и есть :) При этом хватит знаний JavaScript+Html и можно сделать приложение не только под android.
            • +2
              Opera Mobile 12 + getUserMedia()?
              • 0
                Идея была в том, чтобы нажимать кнопку на большом компьютере, а телефон положить на штатив и не трогать.

                Хотя про этот метод не знал, обязательно посмотрю подробнее, спасибо.
              • 0
                Красиво. Я в гораздо худшем исполнении делал приложение под iOS для украшения скриншотами статей на Хабре. Единственно, чего нет у Вас — масштабирования под меньший размер.
                • 0
                  Удобно, конечно, но вешать фотографии с телефона в интернет магазин — по моему не очень профессионально.
                  • +1
                    Всё от света зависит (как и указано в статье, тут он правда должен быть постоянным) и от фона. Для фотографий предметов размером 300х300 пикселей вы не отличите хороший смартфон от какой-нибудь говнозеркалки. Можете провести слепой тест. Пресловутые «размытие, боке, рисунок» в этом случае — технический брак, а не художественные достоинства.
                    Так что всё ок.
                  • +1
                    Я бы сделал проще
                    1) поместил бы на страничке товара QR-код
                    2) написал бы endpoint
                    3)Написал бы клиента для Дроида
                    а) Оператор фоткает QR-код продукта прямо с экрана
                    б) оператор фоткает товар
                    в) клиент ломится на end-point и шлет ему фотки и id товара (полученного из QR кода)

                    При необходимости можно выкинуть этап с QR кодом и заменить его на ввод любого ID прямо в клиент
                    • 0
                      Если снимать хочется всё-таки фотоаппаратом (например, если нужно поджигать вспышки), можно сделать почти то же самое, только использовать Eye-fi карточку.

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