Continuando a giocare con la webcam e motion…
Bene, diciamo che abbiamo il nostro device che produce una sana serie di immagini nella amata directory preposta alla scopo, quindi abbiamo una serie di foto sequenziali, e ci interessa mostrare l’ultima su di una pagina html. Che fare?

Un metodo semplice sarebbe creare una pagina html statica con un meta che fa l’auto-refresh
ma ci sono metodi migliori lato server.
La soluzione che ho approntato è un po’ macchinosa, ma almeno mi ha permesso di vedere un paio di cose interessanti.
Il tutto ruota attorno al content-type: multipart/x-mixed-replace; (Ho trovato info qui e quo).
Essenzialmente si tratta di lasciare una connessione aperta fra client e server nella quale il secondo passa contenuti al primo dopo la chiamata (server push). Citando wikipedia:
Mixed-Replace (Experimental)
The content type multipart/x-mixed-replace was developed as part of a technology to emulate server push and streaming over HTTP.
All parts of a mixed-replace message have the same semantic meaning. However, each part invalidates – “replaces” – the previous parts as soon as it is received completely. Clients should process the individual parts as soon as they arrive and should not wait for the whole message to finish.
Originally developed by Netscape, it is still supported by Mozilla, Firefox, Safari (but not in Safari on the iPhone) and Opera, but traditionally ignored by Microsoft. It is commonly used in IP cameras as the MIME type for MJPEG streams.
Quindi a parte Explorer, siamo a posto con tutti gli altri browser (strano).
Seguendo il libro della O’Reilly ho creato uno script cgi in perl utile per creare lo stream video (sostanzialmente il ciclo di immagini jpeg utili):
use strict;
use warnings;
sub display_img {
my ($file) = @_;
if ( open(FILE, ‘<’, $file) ) {
my $content_length = (stat (FILE))[7];
print "Content-type: image/jpeg\n";
print "Content-length: ", $content_length, "\n\n";
print <FILE>;
close(FILE);
} else {
print "Content-type: text/plain\n\n";
print "<p>500, File Access Error, Cannot open graphic file: $file</p>";
}
}
$| = 1;
my $boundary_string = "\n–xstring\n";
my $end_string = "\n–xstring–\n";
my $delay = 3;
my $img_path = ‘/var/www/webcam/’;
my $image = ‘webcam-snap.jpg’;
print "Content-type: multipart/x-mixed-replace; boundary=xstring","\n\n";
print $boundary_string;
while (1) {
display_img ($img_path.$image);
print $boundary_string;
sleep($delay);
}
print $end_string;
exit(0);
Il $| serve per avere lo stdout flushato automaticamente (man perlvar).
Creata questa sequenza di content-type: image/jpeg l’ho cacciata dentro un html generato dal php, in modo da controllare dinamicamente 1) se motion è in uso (ovvero se la webcam è accesa) e 2) se il browser è Explorer (nel qual caso lo stream non è visualizzabile).
function top() {
$top = <<<EOF
<html>
<head>
<title>Webcam on H</title>
<meta name="creator" content="Webcamd" />
<style type="text/css">
body {
margin: 10px 50px;
color: #999;
background-color: black;
text-align: center;
}
img, div.riquadro {
border: 1px solid #999;
padding: 3px;
width: 320px;
height: 240px;
}
.Online { color: #393; }
.Offline { color: #933; }
a:link { color: #D93; }
a:visited { color: #A43; }
a:hover { color: #AA3; }
</style>
</head>
<body>
EOF;
return $top;
}
function foot() {
$bot = <<<EOF
</body>
</html>
EOF;
return $bot;
}
function body_cam($status, $ua) {
$body = ”;
$body .= "<h1 class=\"$status\">Cam $status</h1>";
$body .= "<div style=\"margin: 1em 0 3em;\">";
if ($status == ‘Online’) {
$body .= ( preg_match(‘/MSIE/’,$ua) ) ? ‘<div class="riquadro" style="margin: 0 auto;"><p class="Online">Stream video non disponibile con Explorer.</p></div>’
: ‘<img src="http://192.168.0.1/cgi-bin/webcam"/>’;
} else {
$body .= ‘<div class="riquadro" style="margin: 0 auto;"><p class="Offline">Webcam Offline</p></div>’;
}
$body .= "</div>";
return $body;
}
function body_extra($ua) {
$body = <<<EOF
<div style="margin: 1em 0 1em;">
<p><strong>User-agent:</strong> $ua</p>
</div>
<hr/>
<p>
Made by <a href="http://www.simotrone.it">simotrone</a>,<br/>
with <a href="http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome">Motion</a>.
</p>
EOF;
return $body;
}
$user_agent = $_SERVER[‘HTTP_USER_AGENT’];
$motion_pid = ‘/tmp/motion.pid’;
if (file_exists($motion_pid)) {
$status = ‘Online’;
} else {
$status = ‘Offline’;
}
echo top();
echo body_cam($status, $user_agent);
echo body_extra($user_agent);
echo foot();
?>
Buono così.
Giochicchiando con la webcam mi sono ritrovato a volerla usare da riga di comando (cosa buona per diverse ragioni), e così ho scoperto motion.
Qui si trova di tutto: Motion.
Dopo aver fatto riconoscere la webcam al kernel (come indicato qua), si può ottenere qualche informazione con $ v4l-info (installato tramite il pacchetto v4l-conf).
Nel mio caso:
### v4l2 device info [/dev/video0] ###
general info
VIDIOC_QUERYCAP
driver : "zc3xx"
card : "USB Camera (046d:08d9)"
bus_info : "usb-0000:00:02.0-1"
version : 2.8.0
capabilities : 0×5000001 [VIDEO_CAPTURE,READWRITE,STREAMING]
standards
[…]
video capture
VIDIOC_ENUM_FMT(0,VIDEO_CAPTURE)
index : 0
type : VIDEO_CAPTURE
flags : 1
description : "JPEG"
pixelformat : 0x4745504a [JPEG]
VIDIOC_G_FMT(VIDEO_CAPTURE)
type : VIDEO_CAPTURE
fmt.pix.width : 320
fmt.pix.height : 240
fmt.pix.pixelformat : 0x4745504a [JPEG]
fmt.pix.field : NONE
fmt.pix.bytesperline : 320
fmt.pix.sizeimage : 29390
fmt.pix.colorspace : JPEG
fmt.pix.priv : 1
[…]
Avendo le dimensioni “accattabili” dalla webcam, ho dovuto solo configurare motion per convogliare una serie di screenshot in un filepath e poi “montarci” una pagina html sopra.
Una semplice configurazione di motion potrebbe essere questa:
input 8
daemon off
process_id_file /tmp/motion.pid
jpeg_filename webcam
target_dir /var/www/webcam
height 320
width 240
auto_brightness on
minimum_frame_time 2
Con questa configurazione, al lancio di motion (con daemon on va direttamente in background) verrà salvata in /var/www/webcam/webcam.jpg la foto fatta dalla webcam ogni 2 secondi.
Motion ha un miliardo di altre finezze, ma per ora è tutto.
Guardicchiando per un progetto mi sono imbattuto in HTML::CalendarMonth, un modulo perl interessante per la generazione di calendarietti in html.
Il tutto si basa sui moduli HTML::Element che creano degli oggetti per la gestione dei singoli elementi della pagina html. Segue un esempio particolarmente brutto, ma utile ai fini di capire la logica.
Il punto della questione è definire gli elementi HTML con l’apposito costruttore new(‘tag’, eventuale_attributo => ‘come hash’); gli elementi possono poi essere gestiti con una struttura parent-child attraverso il metodo push_content che ordina in un array gli elementi che lo compongono.
# HTML::Element crea oggetti con nomi/tag e attributi.
my $html = HTML::Element->new(‘html’);
my $head = HTML::Element->new(‘head’);
my $title = HTML::Element->new(‘title’);
$title->push_content(‘Titolo della pagina’);
my $body = HTML::Element->new(‘body’);
my $h1 = HTML::Element->new(‘h1′);
$h1->push_content(‘Header nel body’);
my $hlink = HTML::Element->new(‘a’, href => ‘http://www.simotrone.it’);
$hlink->push_content(‘il mio sito’);
my $p = HTML::Element->new(‘p’);
$p->push_content(‘Questo paragrafo ha un link: ‘, $hlink, ‘.’);
$head->push_content($title);
$body->push_content($h1, $p);
$html->push_content($head, $body);
print $html->as_HTML;
Per ottenere:
Ok, fin qui sembra una pompa, 150 righe per ottenerne 5. Non molto economico.
Comunque il punto della questione era far vedere HTML::CalendarMonth, che sfruttando i moduli suddetti ritorna cose interessanti con poco codice. ![]()
Con queste poche righe…
use HTML::CalendarMonth;
my $cal = HTML::CalendarMonth->new( month => 10, year => 2009 );
$cal->item($cal->year, $cal->month)->attr(style => ‘background-color: wheat; font-size: 150%;’);
$cal->col(0)->attr(style => ‘font-weight: bold’);
print $cal->as_HTML;
possiamo ottenere questo:
| October | 2009 | |||||
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
| 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 |
E con la semplice aggiunta di un ciclo for che genera i mesi e di una sub possiamo ottenere un calendario molto flessibile.
my ($mm,$yyyy) = @_;
my $cal = HTML::CalendarMonth->new( month => $mm, year => $yyyy );
$cal->item($cal->year, $cal->month)->attr(style => ‘background-color: wheat; font-size: 150%;’);
$cal->col(0)->attr(style => ‘font-weight: bold’);
print $cal->as_HTML;
print "\n";
}
for (1,2,3) {
mensile($_,1979);
}
Su Debian i pacchetti sono questi qua:
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Description
+++-=================-=================-=======================
ii libhtml-calendarm 1.19-1 generate and manipulate
calandar months in HTML
ii libhtml-element-e 1.17-3 extended HTML::Element
classes
ii libhtml-tableextr 2.10-3 module for extracting
the content contained
in tab
Tempo addietro m’ero fatto uno script in bash per scrivermi rapidamente un layout html standard (coi tag html, head, body, il doctype, ecc.).
Aveva qualche opzione, ma era una cosa semplice e comunque utile.
Ora posso farlo semplicemente così:
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<title>[% title %]</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</head>
<body>
</body>
</html>
Il [% title %] è per preparare il campo a TT, niente di che.
Come “prendere” una selezione col mouse su una pagina html grazie a javascript?
Semplice: si scrive una funzione js che accatta la selezione.
Il problema, come al solito, è capire QUALI oggetti danno la possibilità di prendere l’evento che ci interessa e COME questi oggetti operano.
(Odio i browser e javascript che sta in mezzo a ste cose.)
Nei vari browser mozzillari getSelection restituisce il testo della selezione, mentre in Exploder l’oggetto raccattato con selection è un TextRange che va manipolato ancora un pochetto.
var selected = ”;
var area = document.getElementById(‘name_area_dove_stampare’);
if (document.getSelection) {
selected = document.getSelection();
} else if (document.selection) {
// Parte per IE
selected = document.selection.createRange().text;
}
area.value = selected;
}
Per altro sui browser come FFox si puo’ fare anche un’altro numero:
var area = document.getElementById(elemento);
selected = area.value.substring(area.selectionStart, area.selectionEnd);
}
In questo caso stiamo ottenendo la substring che inizia nella posizione dove inizia la selezione, e finisce nella posizione dove finisce la selezione (in pratica estrapola la stessa porzione di testo, capendo la posizione degli estremi con selectionStart e selectionEnd).
Boh, che orticaria.
Ah, nota interessante: Opera (che è sempre un sacco avanti) supporta entrambi i metodi (document.getSelection e document.selection)
Molte info accattate su quirksmode.org.
Nota, se non si fosse capito: Il mio rapporto con javascript e coi CSS è decisamente conflittuale (più odi che amo, per intenderci).
Un indice di un resoconto di articoli sui css, da smashingmagazine.com.
Mastering CSS, Part 1: Styling Design Elements
- Layout and User Interface Techniques
- Navigation and Menu Techniques
- Image Styles and Galleries
- Typography Techniques
- Icons, Buttons and Links
Mastering CSS, Part 2: Advanced Techniques and Tools
- Calendars, Lists, Tables, and Timelines
- iPhone CSS Techniques
- Form and Search Techniques
- Visualization Techniques
- Other Handy Techniques and Tips
- CSS3 Techniques
- CSS Tools
- More Articles and Resources
Per ora ho usato i form, e letti gli articoli riguardanti le date (O_O), il testo sulle immagini, e gli angoli da sfogliare (bellissimo, provate il demo!). Molto carini anche gli articoli sulle liste visualizzabili in maniera diversa e riguardanti la validazione dei form.
Ho trovato un giochino bellissimo.
Inserite il testo. Date un’immagine a caso, e selezionate. ![]()
Hide an image in html
Genera anche il codice.
Bellissimo.