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