Witam ;)
Bawiąc się Chrome’em wpadłem na pomysł żeby napisać tutaj kilka linijek kodu które pokażą że hiper łatwo można napisać prosty WebCam używający podłączonej do komputera kamerki.
Zacznijmy od tego że zabierając się do tego zrobiłem sobie plik html i plik js. Uruchomiłem go (bez serwera) i niestety okazało się że nie mogę w takich warunkach używać mediów.
Więc w swoim xammpie dodałem kolejnego vhosta i wrzuciłem tam pliki. Było znacznie lepiej ale.. Nadal źle – okazało się że w najnowszej wersji Google Chrome’a nie można używać mediów bez httpsa. Nieco poirytowany tym faktem szukałem rozwiązania, pierwszym było uruchamianie przeglądarki ze specjalnym przełącznikiem – ale gdy dodałem ten przełącznik to Chrome wyświetlał zacny komunikat „nie rozpoznana opcja blabla”. Jak zawsze – wiatr w oczy i coś nie powiem w co – ale nie poddałem się. Wygenerowałem certyfikat self-signed (sądziłem że na Windows’ie będą problemy, ale nie było), podpiąłem do vhosta i.. Udało się!
No a skoro już nakreśliłem jakie problemy mnie spotkały to napiszmy kod.
Całość magii leży w funkcji
1 | getUserMedia |
– pozwala ona na dostęp do mediów zgodnie z przekazanymi jako pierwszy argument – ograniczeniami. W tym przykładzie chcę uzyskać dostęp do kamerki więc kod będzie wyglądał tak:
1 2 3 4 5 6 | navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia var media = navigator.getUserMedia({ video:true, audio:false }, successMedia, errorMedia); |
pierwsza linijka pozwala na wybór dostępnej implementacji mediów (konkretnej dla konkretnej przeglądarki) a kolejna to już właściwe wywołanie funkcji. Drugi argument to funkcja zwrotna dla sukcesu przy dostępnie do mediów i trzeci, analogicznie – dla błędu. Jeśli odmówimy dostępu to wykona się właśnie funkcja errorMedia.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | (function(){ navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia var successMedia = function(stream){ var videoDestination = document.getElementsByTagName("video")[0]; videoDestination.src = window.URL.createObjectURL(stream); } var errorMedia = function(error){ alert(error) } var media = navigator.getUserMedia({ video:true, audio:false }, successMedia, errorMedia); })(); |
Rozszerzyliśmy nasz kod. Podpięliśmy w funkcji successMedia, strumień do elementu video. Dodaliśmy go również do kodu HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <html> <head> <meta charset="utf-8"> <style type="text/css"> .video{ width: 100%; height: 600px; } .left{ float:left; width: 65%; } </style> </head> <body> <div> <div class="left"> <video class="video" autoplay> </video> </div> <div> </div> </div> </body> <script type="text/javascript" src="media.js"></script> </html> |
I to praktycznie mógłby być koniec – bo już uruchamiając taki plik – możemy zobaczyć to co widzi nasza kamerka ;)
Ale.. Rozbudujmy to nieco.
Co to za WebCam bez możliwości nadawania efektów do zdjęć?
Skorzystamy z filtrów oferowanych przez -webkit-filter.
Dodajemy więc klasę:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var EffectsManipulator = function(target){ this.target = target; this.effectsClasses = { "none":"", "blur":"blur(2px)", "grayscale":"grayscale(100%)", "sepia":"sepia(100%)", "brightness":"brightness(30%)", "contrast":"contrast(1000%)", "invert":"invert(100%)", "saturate":"saturate(700%)" }; this.currentEffect = "none"; }; EffectsManipulator.prototype.setEffect = function(effectName) { if(this.effectsClasses.hasOwnProperty(effectName)){ this.target.style['-webkit-filter']=this.effectsClasses[effectName]; this.currentEffect = effectName; } else { this.setEffect("none"); } }; |
i podpinamy ją do targetu:
1 2 3 4 | var effectsManipulator = new EffectsManipulator(document.getElementsByTagName("video")[0]); document.getElementById("effect-changer").onchange = function(el){ effectsManipulator.setEffect(el.srcElement.selectedOptions[0].value); }; |
Jak widać po kodzie – plik HTML też zmodyfikowaliśmy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <html> <head> <meta charset="utf-8"> <style type="text/css"> .video{ width: 100%; height: 600px; } .left{ float:left; width: 65%; } </style> </head> <body> <div> <div class="left"> <video class="video" autoplay> </video> </div> <div> Wybierz efekt: <select id="effect-changer"> <option value="none">Brak</option> <option value="sepia">Sepia</option> <option value="grayscale">Odcień szarości</option> <option value="contrast">Kontrast</option> <option value="saturate">Nasycenie</option> <option value="invert">Negatyw</option> <option value="blur">Rozmycie</option> <option value="brightness">Przyciemnienie</option> </select> </div> </div> </body> <script type="text/javascript" src="media.js"></script> </html> |
I już działa – możemy, wybierając z listy – nakładać efekt na to co widzi nasza kamerka.
Jaką jeszcze funkcję mają WebCam’y? Ano robienie sobie zdjęć ;)
Zaimplementujmy to w ten sposób:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | EffectsManipulator.prototype.takePhoto = function(){ var canvas = document.createElement('canvas'); canvas.width = 860; canvas.height = 640; var ctx = canvas.getContext('2d'); ctx.drawImage(this.target, 0, 0, canvas.width, canvas.height); var dataURI = canvas.toDataURL('image/jpeg'); var img = document.createElement("img"); img.src = dataURI; img.style['-webkit-filter'] = this.effectsClasses[this.currentEffect]; var newWindow = window.open("", "Image","scrollbars=0, toolbar=0, width="+img.width+", height="+img.height); newWindow.document.write(img.outerHTML); } |
Tworzymy sobie w pamięci obiekt Canvas, rysujemy na nim zawartość elementu video. Wyrysowaną zawartość pobieramy z canvas’a i przypisujemy do nowo stworzonego elementu img. Na ten element nakładamy ten sam filtr co jest nałożony na element video i otwieramy nowe okno z dołączonym elementem img.
Funkcja fajna, ale dodajmy jeszcze przycisk do HTMLa
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <html> <head> <meta charset="utf-8"> <style type="text/css"> .video{ width: 100%; height: 600px; } .left{ float:left; width: 65%; } .take-photo{ margin: auto; } </style> </head> <body> <div> <div class="left"> <video class="video" autoplay> </video> </div> <div> Wybierz efekt: <select id="effect-changer"> <option value="none">Brak</option> <option value="sepia">Sepia</option> <option value="grayscale">Odcień szarości</option> <option value="contrast">Kontrast</option> <option value="saturate">Nasycenie</option> <option value="invert">Negatyw</option> <option value="blur">Rozmycie</option> <option value="brightness">Przyciemnienie</option> </select> <p> <button class="take-photo">Zrób zdjęcie!</button> </p> </div> </div> </body> <script type="text/javascript" src="media.js"></script> </html> |
i np. taki kawałek kodu do JSa:
1 2 3 | document.getElementsByClassName("take-photo")[0].onclick = function(){ effectsManipulator.takePhoto(); }; |
DEMO można zobaczyć na stronie: https://media.mmazur.eu.org – i tak, certyfikat nadal nie prawidłowy, bo chodź podpisany to nie pasuje do mojej domeny (jest podpisany dla mojego dostawcy usług hostingowych) co powoduje że będziecie mieli komunikat – nie ma się co bać – zaakceptujcie.
PS. Nigdzie Waszych zdjęć nie zapisuję :D
PS2. Użycie -webkit-filter wymaga aby demo było uruchamiane w Chrome :P kamerka zadziała np. w FireFoxie ale już filtry nie będą się nakładały.
Matt.
Oj daaawnoo mnie tu nie było. Ale wakacje to był czas dużej liczby intensywnych wyjazdów i tak naprawdę, dopiero jakoś… Read More
Cześć! Zapraszam na krótkie podsumowanie kwietnia. Wyjazd do Niemiec A dokładniej pod granicę z Francją. Chrześnica miała pierwszą komunię. Po… Read More
Ostatnio tygodnie były tak bardzo wypełnione, że nie udało mi się napisać nawet krótkiego podsumowanie. Więc dziś zbiorczo podsumuję luty… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W styczniu przeczytałem "Homo Deus: Historia jutra". Książka łudząco podoba do wcześniejszej książki tego… Read More
Cześć! Zapraszam na podsumowanie roku 2023. Książki Zacznijmy od książek. W tym roku cel 35 książek nie został osiągnięty. Niemniej… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W grudniu skończyłem czytać Mein Kampf. Nudna książka. Ciekawsze fragmenty można by było streścić… Read More