00001 #!/usr/local/sbin/php -q
00002 <?php
00077
00078
00079
00080
00081
00082 $ExifDeviceTemplateFilename="/dev/exif_template";
00083 $ExifDeviceMetadirFilename= "/dev/exif_metadir";
00084 $ExifDeviceExifFilename= "/dev/exif_exif";
00085 $ExifDeviceMetaFilename= "/dev/exif_meta";
00086
00087
00090
00091 $ExifXMLName="/etc/Exif_template.xml";
00092 $init=false;
00093 if ($_SERVER['REQUEST_METHOD']=="GET") {
00094 if ($_GET["init"]!==NULL) {
00095 if ($_GET["init"]) $ExifXMLName=$_GET["init"];
00096 $init=true;
00097 $noGPS= ($_GET["noGPS"]!==NULL);
00098 $nocompass= ($_GET["nocompass"]!==NULL);
00099 }
00100 } else {
00101 foreach ($_SERVER['argv'] as $param) if (substr($param,0,4)=="init") {
00102 $param=substr($param,5);
00103 if (strlen($param)>0) $ExifXMLName=$param;
00104 $init=true;
00105 break;
00106 }
00107 if ($init) {
00108 $noGPS= in_array ('noGPS' , $_SERVER['argv']);
00109 $nocompass= in_array ('nocompass', $_SERVER['argv']);
00110 } else {
00111 echo <<<USAGE
00112
00113 Usage: {$_SERVER['argv'][0]} [init[=filename.xml] [noGPS] [nocompass]]
00114
00115
00116 USAGE;
00117 exit (0);
00118 }
00119 }
00120
00121 define("EXIF_BYTE", 1);
00122 define("EXIF_ASCII", 2);
00123 define("EXIF_SHORT", 3);
00124 define("EXIF_LONG", 4);
00125 define("EXIF_RATIONAL", 5);
00126 define("EXIF_SBYTE", 6);
00127 define("EXIF_UNDEFINED", 7);
00128 define("EXIF_SSHORT", 8);
00129 define("EXIF_SLONG", 9);
00130 define("EXIF_SRATIONAL",10);
00131
00132 define("EXIF_LSEEK_ENABLE", 2);
00133
00135 if ($init) {
00136 $exif_head= array (
00137 0xff, 0xe1,
00138
00139 0x00, 0x00,
00140 0x45,0x78,0x69,0x66,0x00,0x00);
00141 $Exif_length_offset= 2;
00142
00143 $exif_data= array (
00144 0x4d,0x4d,
00145 0x00,0x2a,
00146 0x00,0x00,0x00,0x08);
00147 $xml_exif = simplexml_load_file($ExifXMLName);
00148 if ($xml_exif->GPSInfo) {
00150 if ($nocompass) {
00151 $tounset=array();
00152 foreach ($xml_exif->GPSInfo->children() as $entry) if (strpos ($entry->getName() , "Compass" )!==false) $tounset[]=$entry->getName();
00153 foreach ($tounset as $entry) unset ($xml_exif->GPSInfo->{$entry});
00154 }
00155 if ($noGPS) {
00156 unset($xml_exif->GPSInfo);
00157 unset($xml_exif->Image->GPSTag);
00158 }
00159 }
00160
00161 $IFD_offset= count($exif_data);
00162 $SUB_IFD_offset= 12*count($xml_exif->Image->children())+2+4+$IFD_offset;
00163 $GPSInfo_offset= 12*count($xml_exif->Photo->children())+2+4+$SUB_IFD_offset;
00164 $data_offset= $GPSInfo_offset+(($xml_exif->GPSInfo)?(12*count($xml_exif->GPSInfo->children())+2+4):0);
00165 if ($_SERVER['REQUEST_METHOD']) {
00166 echo "<pre>";
00167 printf ("IFD_offset=0x%x\n",$IFD_offset);
00168 printf ("SUB_IFD_offset=0x%x\n",$SUB_IFD_offset);
00169 printf ("GPSInfo_offset=0x%x\n",$GPSInfo_offset);
00170 printf ("data_offset=0x%x\n",$data_offset);
00171 }
00172
00174 foreach ($xml_exif->Image->children() as $entry) substitute_value($entry);
00175 foreach ($xml_exif->Photo->children() as $entry) substitute_value($entry);
00176 if ($xml_exif->GPSInfo) {
00177 foreach ($xml_exif->GPSInfo->children() as $entry) substitute_value($entry);
00178 }
00179 $ifd_pointer=$IFD_offset;
00180 $data_pointer=$data_offset;
00181 start_ifd(count($xml_exif->Image->children()));
00182 foreach ($xml_exif->Image->children() as $entry) process_ifd_entry($entry,0);
00183 finish_ifd();
00184
00185 $ifd_pointer=$SUB_IFD_offset;
00186 start_ifd(count($xml_exif->Photo->children()));
00187 foreach ($xml_exif->Photo->children() as $entry) process_ifd_entry($entry,1);
00188 finish_ifd();
00189
00190 if ($xml_exif->GPSInfo) {
00191 $ifd_pointer=$GPSInfo_offset;
00192 start_ifd(count($xml_exif->GPSInfo->children()));
00193 foreach ($xml_exif->GPSInfo->children() as $entry) process_ifd_entry($entry,2);
00194 finish_ifd();
00195 }
00196 $exif_len=count($exif_head)+count($exif_data)-$Exif_length_offset;
00197 $exif_head[$Exif_length_offset]= ($exif_len >> 8) & 0xff;
00198 $exif_head[$Exif_length_offset+1]= $exif_len & 0xff;
00199
00200 $Exif_str="";
00201 for ($i=0; $i<count($exif_head);$i++) $Exif_str.= chr ($exif_head[$i]);
00202 for ($i=0; $i<count($exif_data);$i++) $Exif_str.= chr ($exif_data[$i]);
00203
00204 $Exif_file = fopen($ExifDeviceTemplateFilename, 'w');
00205 fwrite ($Exif_file,$Exif_str);
00206 fclose($Exif_file);
00207
00209 $dir_sequence=array();
00210 $dir_entries=array();
00211
00212 foreach ($xml_exif->Image->children() as $entry) addDirEntry($entry);
00213 foreach ($xml_exif->Photo->children() as $entry) addDirEntry($entry);
00214 if ($xml_exif->GPSInfo) {
00215 foreach ($xml_exif->GPSInfo->children() as $entry) addDirEntry($entry);
00216 }
00217 array_multisort($dir_sequence,$dir_entries);
00218
00219 $frame_meta_size=0;
00220 for ($i=0;$i<count($dir_entries);$i++) {
00221 $dir_entries[$i]["src"]=$frame_meta_size;
00222 $frame_meta_size+=$dir_entries[$i]["len"];
00223 }
00224
00225 $Exif_str="";
00226 foreach ($dir_entries as $entry) $Exif_str.=pack("V*",$entry["ltag"],$entry["len"],$entry["src"],$entry["dst"]);
00227 $Exif_meta_file = fopen($ExifDeviceMetadirFilename, 'w');
00228 fwrite ($Exif_meta_file,$Exif_str);
00229 fclose($Exif_meta_file);
00230
00232
00233 $Exif_file = fopen($ExifDeviceTemplateFilename, 'w');
00234 fseek ($Exif_file, EXIF_LSEEK_ENABLE, SEEK_END) ;
00235 fclose($Exif_file);
00236
00237 if ($_SERVER['REQUEST_METHOD']) {
00238 echo "</pre>";
00239 }
00240 if ($_SERVER['REQUEST_METHOD']) {
00241 echo "<hr/>\n";
00242 test_print_header();
00243 echo "<hr/>\n";
00244 test_print_directory();
00245 }
00246 }
00249 if ($_GET["description"]!==NULL) {
00250
00252
00253 $Exif_file = fopen($ExifDeviceMetadirFilename, 'r');
00254 fseek ($Exif_file, 0, SEEK_END) ;
00255 fseek ($Exif_file, 0, SEEK_SET) ;
00256 $metadir=fread ($Exif_file, 4096);
00257 fclose($Exif_file);
00258 $dir_entries=array();
00259 for ($i=0; $i<strlen($metadir);$i+=16) {
00260 $dir_entries[]=unpack("V*",substr($metadir,$i,16));
00261 }
00262 foreach ($dir_entries as $entry)
00263 if ($entry[1]==0x010e) {
00264 $descr=$_GET["description"];
00265 $Exif_file = fopen($ExifDeviceMetaFilename, 'w+');
00266 fseek ($Exif_file, $entry[3], SEEK_SET) ;
00267 $descr_was=fread ($Exif_file, $entry[2]);
00268 $zero=strpos($descr_was,chr(0));
00269 if ($zero!==false) $descr_was=substr($descr_was,0, $zero);
00270 if ($descr) {
00271 $descr= str_pad($descr, $entry[2], chr(0));
00272 fseek ($Exif_file, $entry[3], SEEK_SET) ;
00273 fwrite($Exif_file, $descr,$entry[2]);
00274 }
00275 fclose($Exif_file);
00276 var_dump($descr_was); echo "<br/>\n";
00277 break;
00278 }
00279 }
00281 if ($_GET["template"]!==NULL) {
00282 $Exif_file = fopen($ExifDeviceTemplateFilename, 'r');
00283 fseek ($Exif_file, 0, SEEK_END) ;
00284 echo "<hr/>\n";
00285 echo "ftell()=".ftell($Exif_file).", ";
00286 fseek ($Exif_file, 0, SEEK_SET) ;
00287 $template=fread ($Exif_file, 4096);
00288 fclose($Exif_file);
00289 echo "read ".strlen($template)." bytes<br/>\n";
00290 hexdump($template);
00291 }
00293 if ($_GET["metadir"]!==NULL) {
00294 $Exif_file = fopen($ExifDeviceMetadirFilename, 'r');
00295 fseek ($Exif_file, 0, SEEK_END) ;
00296 echo "<hr/>\n";
00297 echo "ftell()=".ftell($Exif_file).", ";
00298 fseek ($Exif_file, 0, SEEK_SET) ;
00299 $metadir=fread ($Exif_file, 4096);
00300 fclose($Exif_file);
00301 echo "read ".strlen($metadir)." bytes<br/>\n";
00302 $dir_entries=array();
00303 for ($i=0; $i<strlen($metadir);$i+=16) {
00304 $dir_entries[]=unpack("V*",substr($metadir,$i,16));
00305 }
00306 print_directory($dir_entries);
00307 }
00309 if ($_GET["exif"]!==NULL) {
00310 $frame=$_GET["exif"]+0;
00311 echo "<hr/>\n";
00312 printf ("Reading frame %d, ",$frame);
00313 $Exif_file = fopen($ExifDeviceExifFilename, 'r');
00314 fseek ($Exif_file, 1, SEEK_END) ;
00315 $exif_size=ftell($Exif_file);
00316 if ($frame) fseek ($Exif_file, $frame, SEEK_END) ;
00317 else fseek ($Exif_file, 0, SEEK_SET) ;
00318 echo "ftell()=".ftell($Exif_file).", ";
00319 $exif_data=fread ($Exif_file, $exif_size);
00320 fclose($Exif_file);
00321 echo "read ".strlen($exif_data)." bytes<br/>\n";
00322 hexdump($exif_data);
00323 }
00324 exit(0);
00326 function hexdump($data) {
00327 global $exif_head, $exif_data;
00328 $l=strlen($data);
00329 printf ("<h2>Exif size=%d bytes</h2>\n",$l);
00330 printf ("<table border=\"0\">\n");
00331 for ($i=0; $i<$l;$i=$i+16) {
00332 printf("<tr><td>%03x</td><td>|</td>\n",$i);
00333 for ($j=$i; $j<$i+16;$j++) {
00334 printf("<td>");
00335 if ($j<$l) {
00336 $d=ord($data[$j]);
00337 printf(" %02x",$d);
00338 } else printf (" ");
00339 printf("</td>");
00340 }
00341 printf("<td>|</td>");
00342 for ($j=$i; $j< ($i+16);$j++) {
00343 printf("<td>");
00344 if ($j<$l) {
00345 $d=ord($data[$j]);
00346 if ($d<32 or $d>126) printf(".");
00347 else printf ("%c",$d);
00348 } else printf (" ");
00349 printf("</td>");
00350
00351 }
00352 printf("</tr>\n");
00353 }
00354 printf ("</table>");
00355 }
00356
00357 function print_directory($dir_entries) {
00358 $meta_size=0;
00359 foreach ($dir_entries as $entry) if (($entry[3]+$entry[2])>$meta_size) $meta_size=$entry[3]+$entry[2];
00360 printf ("<h2>Frame meta data size=%d bytes</h2>\n",$meta_size);
00361 printf ("<table border=\"1\">\n");
00362 printf ("<tr><td>ltag</td><td>meta offset</td><td>Exif offset</td><td>length</td></tr>\n");
00363 foreach ($dir_entries as $entry) {
00364 printf ("<tr><td>0x%x</td><td>0x%x</td><td>0x%x</td><td>0x%x</td></tr>\n",$entry[1],$entry[3],$entry[4],$entry[2]);
00365 }
00366 printf ("</table>");
00367 }
00368
00369 function test_print_header() {
00370 global $exif_head, $exif_data;
00371 $lh=count($exif_head);
00372 $ld=count($exif_data);
00373 printf ("<h2>Exif size=%d bytes (head=%d, data=%d)</h2>\n",$lh+$ld,$lh,$ld);
00374 printf ("<table border=\"0\">\n");
00375 for ($i=0; $i<$lh+$ld;$i=$i+16) {
00376 printf("<tr><td>%03x</td><td>|</td>\n",$i);
00377 for ($j=$i; $j<$i+16;$j++) {
00378 printf("<td>");
00379 if ($j<($lh+$ld)) {
00380 $d=($j<$lh)?$exif_head[$j]:$exif_data[$j-$lh];
00381 printf(" %02x",$d);
00382 } else printf (" ");
00383 printf("</td>");
00384 }
00385 printf("<td>|</td>");
00386 for ($j=$i; $j< ($i+16);$j++) {
00387 printf("<td>");
00388 if ($j<($lh+$ld)) {
00389 $d=($j<$lh)?$exif_head[$j]:$exif_data[$j-$lh];
00390 if ($d<32 or $d>126) printf(".");
00391 else printf ("%c",$d);
00392 } else printf (" ");
00393 printf("</td>");
00394
00395 }
00396 printf("</tr>\n");
00397 }
00398 printf ("</table>");
00399 }
00400
00401 function test_print_directory() {
00402 global $dir_entries,$frame_meta_size;
00403 printf ("<h2>Frame meta data size=%d bytes</h2>\n",$frame_meta_size);
00404 printf ("<table border=\"1\">\n");
00405 printf ("<tr><td>ltag</td><td>meta offset</td><td>Exif offset</td><td>length</td></tr>\n");
00406 foreach ($dir_entries as $entry)
00407 printf ("<tr><td>0x%x</td><td>0x%x</td><td>0x%x</td><td>0x%x</td></tr>\n",$entry["ltag"],$entry["src"],$entry["dst"],$entry["len"]);
00408 printf ("</table>");
00409 }
00410
00411
00412
00413
00414 function start_ifd($count) {
00415 global $exif_data, $ifd_pointer;
00416
00417 $exif_data[$ifd_pointer++]= ($count >> 8) & 0xff;
00418 $exif_data[$ifd_pointer++]= $count & 0xff;
00419 }
00420 function finish_ifd() {
00421 global $exif_data, $ifd_pointer;
00422
00423 $exif_data[$ifd_pointer++]=0;
00424 $exif_data[$ifd_pointer++]=0;
00425 $exif_data[$ifd_pointer++]=0;
00426 $exif_data[$ifd_pointer++]=0;
00427 }
00428
00429
00430
00431 function addDirEntry($ifd_entry) {
00432 global $dir_sequence,$dir_entries,$exif_head;
00433 $lh=count($exif_head);
00434
00435 $attrs = $ifd_entry->attributes();
00436
00437
00438 if ($attrs["seq"]) {
00439
00440 $dir_sequence[]=((string) $attrs["seq"])+0;
00441 $len= (integer) $ifd_entry->value_length;
00442 $offs=$lh+(integer) $ifd_entry->value_offest;
00443
00444 if ($attrs["dlen"]) $len=min($len,((string) $attrs["dlen"])+0);
00445 $dir_entries[]=array("ltag"=>((integer)$ifd_entry->ltag),"dst"=>$offs,"len"=>$len);
00446 }
00447 }
00448
00449 function substitute_value($ifd_entry) {
00450 global $SUB_IFD_offset,$GPSInfo_offset;
00451 $attrs = $ifd_entry->attributes();
00452 switch ($attrs["function"]) {
00453 case "BRAND":
00454 $ifd_entry->addChild ('value',exec("bootblocktool -x BRAND"));
00455 break;
00456 case "MODEL":
00457 $ifd_entry->addChild ('value',exec("bootblocktool -x MODEL").exec("bootblocktool -x REVISION"));
00458 break;
00459 case "SOFTWARE":
00460 $ifd_entry->addChild ('value',exec("ls /usr/html/docs/"));
00461 break;
00462 case "SERIAL":
00463 $s=exec("bootblocktool -x SERNO");
00464 $ifd_entry->addChild ('value',substr($s,0,2).":".substr($s,2,2).":".substr($s,4,2).":".substr($s,6,2).":".substr($s,8,2).":".substr($s,10,2));
00465 break;
00466 case "EXIFTAG":
00467 $ifd_entry->addChild ('value',$SUB_IFD_offset);
00468 break;
00469 case "GPSTAG":
00470 $ifd_entry->addChild ('value',$GPSInfo_offset);
00471 break;
00472 }
00473 }
00474
00475
00476 function process_ifd_entry($ifd_entry, $group) {
00477 global $exif_data, $ifd_pointer, $data_pointer,$SUB_IFD_offset,$GPSInfo_offset;
00478 $attrs = $ifd_entry->attributes();
00479 $ifd_tag= ((string) $attrs["tag"])+0;
00480 $ifd_format=constant("EXIF_".$attrs["format"]);
00481 $ifd_count= $attrs["count"];
00482
00483
00484
00485 if (!$ifd_count) {
00486 if($ifd_format==EXIF_ASCII) $ifd_count=strlen($ifd_entry->value)+1;
00487 else $ifd_count=1 ;
00488 }
00489
00490 $exif_data[$ifd_pointer++]= ($ifd_tag >> 8) & 0xff;
00491 $exif_data[$ifd_pointer++]= $ifd_tag & 0xff;
00492 $exif_data[$ifd_pointer++]= ($ifd_format >> 8 ) & 0xff;
00493 $exif_data[$ifd_pointer++]= $ifd_format & 0xff;
00494 $exif_data[$ifd_pointer++]= ($ifd_count >> 24) & 0xff;
00495 $exif_data[$ifd_pointer++]= ($ifd_count >> 16) & 0xff;
00496 $exif_data[$ifd_pointer++]= ($ifd_count >> 8) & 0xff;
00497 $exif_data[$ifd_pointer++]= $ifd_count & 0xff;
00498
00499 $ifd_bytes=0;
00500 switch ($ifd_format) {
00501 case EXIF_SHORT:
00502 case EXIF_SSHORT: $ifd_bytes=2; break;
00503 case EXIF_LONG:
00504 case EXIF_SLONG: $ifd_bytes=4; break;
00505 case EXIF_RATIONAL:
00506 case EXIF_SRATIONAL: $ifd_bytes=8; break;
00507 default: $ifd_bytes=1;
00508 }
00509 $ifd_bytes=$ifd_bytes*$ifd_count;
00510
00511 switch ($ifd_format) {
00512 case EXIF_BYTE:
00513 case EXIF_SBYTE:
00514 $ifd_data= array ();
00515 foreach ($ifd_entry->value as $a) $ifd_data[]= $a & 0xff;
00516 break;
00517 case EXIF_ASCII:
00518 $ifd_data= str_split($ifd_entry->value);
00519 foreach($ifd_data as &$d) $d=ord($d);
00520 break;
00521 case EXIF_SHORT:
00522 case EXIF_SSHORT:
00523 $ifd_data= array ();
00524 foreach ($ifd_entry->value as $a) $ifd_data=array_merge($ifd_data,array(($a >> 8) & 0xff, $a & 0xff));
00525 break;
00526 case EXIF_LONG:
00527 case EXIF_SLONG:
00528 $ifd_data= array ();
00529 foreach ($ifd_entry->value as $a) $ifd_data=array_merge($ifd_data,array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff));
00530 break;
00531 case EXIF_RATIONAL:
00532 case EXIF_SRATIONAL:
00533 $nom= array ();
00534 foreach ($ifd_entry->nominator as $a) $nom[]= array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff);
00535 $denom= array ();
00536 foreach ($ifd_entry->denominator as $a) $denom[]=array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff);
00537 $ifd_data= array ();
00538
00539
00540
00541
00542
00543
00544
00545 for ($i=0;$i<count($nom);$i++) {
00546
00547
00548
00549 $ifd_data=array_merge($ifd_data,$nom[$i],$denom[$i]);
00550 }
00551 break;
00552
00553 case EXIF_UNDEFINED:
00554 $ifd_data= array_fill(0,$ifd_bytes,0);
00555 break;
00556 }
00557
00558
00559
00560
00561 $ifd_data=array_pad($ifd_data,$ifd_bytes,0);
00562
00563 $ifd_entry->addChild ('value_length',count($ifd_data));
00564
00565 if ($attr["ltag"]) $ltag= ((string) $attrs["ltag"])+0;
00566 else $ltag= $ifd_tag+($group<<16) ;
00567 $ifd_entry->addChild ("ltag",$ltag );
00568 if (count($ifd_data) <=4) {
00569 $ifd_entry->addChild ('value_offest',$ifd_pointer);
00570 $ifd_data= array_pad($ifd_data,-4,0);
00571 for ($i=0;$i<4;$i++) $exif_data[$ifd_pointer++]=$ifd_data[$i];
00572 } else {
00573 $ifd_entry->addChild ('value_offest',$data_pointer);
00574 $exif_data[$ifd_pointer++]= ($data_pointer >> 24) & 0xff;
00575 $exif_data[$ifd_pointer++]= ($data_pointer >> 16) & 0xff;
00576 $exif_data[$ifd_pointer++]= ($data_pointer >> 8) & 0xff;
00577 $exif_data[$ifd_pointer++]= $data_pointer & 0xff;
00578 for ($i=0;$i<count($ifd_data);$i++) {
00579 $exif_data[$data_pointer++]=$ifd_data[$i];
00580 }
00581 }
00582 }
00583
00584 ?>