Commit a3eb9430 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Edit two Exif fields

HostComputer exif field containing serial number was replaced with more
suitable CameraSerialNumber. IPTCNAA field containing frame number was
replaced with ImageNumber.
parent 6393936e
......@@ -9,6 +9,9 @@
dlen: length of a variable data field, stored in frame buffer
ltag: Exif_tag+(group<<16). If specified, is used by the software, while the Exif output will still have tag
SubSecTimeOriginal should go immediately after DateTimeOriginal (in the sequence numbers, not in the Exif templete)
Update, June 2016: PageNumber field is used as sensor port number, HostComputer field is replaced with CameraSerialNumber and
FrameNumber field (which actually was IPTCNAA field) is replaced with standart ImageNumber field.
-->
<Exif>
<Image>
......@@ -22,8 +25,8 @@
<DateTime tag="0x0132" format="ASCII" count="20" seq="1" dlen="20">
<value>2001:06:21 12:00:00</value>
</DateTime>
<HostComputer tag="0x013c" format="ASCII" function="SERIAL"/>
<FrameNumber tag="0x83bb" format="LONG" count="1" seq="25" dlen="4"/>
<CameraSerialNumber tag="0xc62f" format="ASCII" function="SERIAL"/>
<ImageNumber tag="0x9211" format="LONG" count="1" seq="25" dlen="4"/>
<Orientation tag="0x112" format="SHORT" count="1" seq="27" dlen="2"/>
<PageNumber tag="0x129" format="SHORT" count="1" seq="28" dlen="2"/>
<ExifTag tag="0x8769" format="LONG" function="EXIFTAG"/>
......
#!/usr/local/sbin/php -q
#!/usr/bin/env php
<?php
/*!
*! FILE NAME : exif.php
*! DESCRIPTION: This program collects information about the camera (version, software, sensor)
*! and combines it with the Exif template (default is /etc/Exif_template.xml) to prepare generation
*! of Exif headers.
*! It works in a command line with a single optional parameter - location of the template file and
*! trough the CGI interface. In that case it accepts the following parameter
*! init - program Exif with default /etc/Exif_template.xml
*! init=path - program Exif with alternative file
*! noGPS - don't include GPS-related fields
*! nocompass - don't include compass-related fields
*! template - print currently loaded template data (hex dump)
*! metadir - print currently loaded meta directory that matches variable Exif fields with the template
*! exif=0 - print current Exif page (updated in real time)
*! exif=NNN - print one of the Exif pages in the buffer (debug feature, current buffer pointer is not known here)
*!
*! Copyright (C) 2007-2008 Elphel, Inc
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*! $Log: exif.php,v $
*! Revision 1.2 2010/08/10 21:14:31 elphel
*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! $Log: exif.php,v $
*! Revision 1.2 2010/08/10 21:14:31 elphel
*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! Revision 1.1.1.1 2007/10/03 19:05:53 elphel
*! This is a fresh tree based on elphel353-2.10
*!
*! Revision 1.6 2007/10/03 19:05:53 elphel
*! cosmetic
*!
*! Revision 1.5 2007/10/03 18:37:53 elphel
*! Made nice html output to see the result data
*!
*! Revision 1.4 2007/10/03 06:33:31 elphel
*! fixed wrong copyright year
*!
*! Revision 1.3 2007/10/02 19:44:03 elphel
*! minor bug fixes, added "manufacturer note" field for raw frame metadata (36 bytes - /include/asm-cris/c313.h frame_params_t)
*!
*! Revision 1.2 2007/09/25 23:34:02 elphel
*! Fixed time strings to the right length
*!
*! Revision 1.1 2007/09/24 07:27:57 elphel
*! Started php script that prepares Exif header information for serving images by imgsrv
*!
*/
*! FILE NAME : exif.php
*! DESCRIPTION: This program collects information about the camera (version, software, sensor)
*! and combines it with the Exif template (default is /etc/Exif_template.xml) to prepare generation
*! of Exif headers.
*! It works in a command line with a single optional parameter - location of the template file and
*! trough the CGI interface. In that case it accepts the following parameter
*! init - program Exif with default /etc/Exif_template.xml
*! init=path - program Exif with alternative file
*! noGPS - don't include GPS-related fields
*! nocompass - don't include compass-related fields
*! template - print currently loaded template data (hex dump)
*! metadir - print currently loaded meta directory that matches variable Exif fields with the template
*! exif=0 - print current Exif page (updated in real time)
*! exif=NNN - print one of the Exif pages in the buffer (debug feature, current buffer pointer is not known here)
*!
*! Copyright (C) 2007-2016 Elphel, Inc
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*! $Log: exif.php,v $
*! Revision 1.2 2010/08/10 21:14:31 elphel
*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! $Log: exif.php,v $
*! Revision 1.2 2010/08/10 21:14:31 elphel
*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! Revision 1.1.1.1 2007/10/03 19:05:53 elphel
*! This is a fresh tree based on elphel353-2.10
*!
*! Revision 1.6 2007/10/03 19:05:53 elphel
*! cosmetic
*!
*! Revision 1.5 2007/10/03 18:37:53 elphel
*! Made nice html output to see the result data
*!
*! Revision 1.4 2007/10/03 06:33:31 elphel
*! fixed wrong copyright year
*!
*! Revision 1.3 2007/10/02 19:44:03 elphel
*! minor bug fixes, added "manufacturer note" field for raw frame metadata (36 bytes - /include/asm-cris/c313.h frame_params_t)
*!
*! Revision 1.2 2007/09/25 23:34:02 elphel
*! Fixed time strings to the right length
*!
*! Revision 1.1 2007/09/24 07:27:57 elphel
*! Started php script that prepares Exif header information for serving images by imgsrv
*!
*/
//TODO: Decide with the start sequence, more data is availble after the sensor is initialized.
// Or leave it to imgsrv (it still needs sensor to start first), just put placeholders
// use http://www.exiv2.org/tags.html for reference of the Exif fields if you need to add modify
......@@ -90,6 +90,10 @@ $ExifDeviceMetadirFilename= "/dev/exif_metadir";
$ExifDeviceExifFilename= "/dev/exif_exif";
$ExifDeviceMetaFilename= "/dev/exif_meta";
$DeviceSNFilename = "/sys/devices/soc0/elphel393-init/serial";
$DeviceRevisionFilename = "/sys/devices/soc0/elphel393-init/revision";
$DeviceBrand = "Elphel";
$DeviceModel = "Elphel393";
//! if called from the command line - accepts just one parameter - configuration file,
//! through CGI - accepts more parameters
......@@ -138,10 +142,10 @@ define("EXIF_SRATIONAL",10);
define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
/// ===== init/init= CGI parameters or command line mode =======
if ($init) { // configure Exif data
if ($init) { // configure Exif data
$exif_head= array (
0xff, 0xe1, // APP1 marker
// offset=2 - start of Exif header
// offset=2 - start of Exif header
0x00, 0x00, // - length of the Exif header (including this length bytes) - we'll fill it later, we do not know it yet
0x45,0x78,0x69,0x66,0x00,0x00); // Exif header
$Exif_length_offset= 2; // put total length here (big endian, 2 bytes)
......@@ -152,7 +156,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
0x00,0x00,0x00,0x08); //offset to first IDF (from the beginning of the TIFF header, so 8 is minimum)
$xml_exif = simplexml_load_file($ExifXMLName);
if ($xml_exif->GPSInfo) {
/// remove all tags named "Compass..."
/// remove all tags named "Compass..."
if ($nocompass) {
$tounset=array();
foreach ($xml_exif->GPSInfo->children() as $entry) if (strpos ($entry->getName() , "Compass" )!==false) $tounset[]=$entry->getName();
......@@ -176,7 +180,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
printf ("data_offset=0x%x\n",$data_offset);
}
/// Now modify variable fields substituting values
/// Now modify variable fields substituting values
foreach ($xml_exif->Image->children() as $entry) substitute_value($entry);
foreach ($xml_exif->Photo->children() as $entry) substitute_value($entry);
if ($xml_exif->GPSInfo) {
......@@ -211,7 +215,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fwrite ($Exif_file,$Exif_str); /// will disable and invalidate Exif data
fclose($Exif_file);
///Exif template is done, now we need a directory to map frame meta data to fields in the template.
///Exif template is done, now we need a directory to map frame meta data to fields in the template.
$dir_sequence=array();
$dir_entries=array();
......@@ -234,7 +238,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fwrite ($Exif_meta_file,$Exif_str); /// will disable and invalidate Exif data
fclose($Exif_meta_file);
///Rebuild buffer and enable Exif generation/output:
///Rebuild buffer and enable Exif generation/output:
$Exif_file = fopen($ExifDeviceTemplateFilename, 'w');
fseek ($Exif_file, EXIF_LSEEK_ENABLE, SEEK_END) ;
......@@ -249,12 +253,12 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
echo "<hr/>\n";
test_print_directory();
}
} //if ($init) // configure Exif data
} //if ($init) // configure Exif data
/// ===== processing optional parameters =======
/// ===== read template =======
if ($_GET["description"]!==NULL) {
if ($_GET["description"]!==NULL) {
/// Read metadir to find the length of the description field
/// Read metadir to find the length of the description field
$Exif_file = fopen($ExifDeviceMetadirFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ;
......@@ -282,9 +286,9 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
var_dump($descr_was); echo "<br/>\n";
break;
}
}
}
/// ===== read template =======
if ($_GET["template"]!==NULL) {
if ($_GET["template"]!==NULL) {
$Exif_file = fopen($ExifDeviceTemplateFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ;
echo "<hr/>\n";
......@@ -294,9 +298,9 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fclose($Exif_file);
echo "read ".strlen($template)." bytes<br/>\n";
hexdump($template);
}
}
/// ===== read meta directory =======
if ($_GET["metadir"]!==NULL) {
if ($_GET["metadir"]!==NULL) {
$Exif_file = fopen($ExifDeviceMetadirFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ;
echo "<hr/>\n";
......@@ -310,9 +314,9 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
$dir_entries[]=unpack("V*",substr($metadir,$i,16));
}
print_directory($dir_entries);
}
}
/// ===== read one of the Exif pages (0 - current, 1..512 - buffer) =======
if ($_GET["exif"]!==NULL) {
if ($_GET["exif"]!==NULL) {
$frame=$_GET["exif"]+0;
echo "<hr/>\n";
printf ("Reading frame %d, ",$frame);
......@@ -326,8 +330,8 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fclose($Exif_file);
echo "read ".strlen($exif_data)." bytes<br/>\n";
hexdump($exif_data);
}
exit(0);
}
exit(0);
/// ======================================= Functions ======================================
function hexdump($data) {
global $exif_head, $exif_data;
......@@ -419,13 +423,13 @@ function test_print_directory() {
function start_ifd($count) {
global $exif_data, $ifd_pointer;
// printf("start_ifd: ifd_pointer=0x%04x \n", $ifd_pointer);
// printf("start_ifd: ifd_pointer=0x%04x \n", $ifd_pointer);
$exif_data[$ifd_pointer++]= ($count >> 8) & 0xff;
$exif_data[$ifd_pointer++]= $count & 0xff; // may apply & 0xff in the end to all elements
}
function finish_ifd() { // we do not have additional IFDs
global $exif_data, $ifd_pointer;
// printf("finish_ifd: ifd_pointer=0x%04x \n", $ifd_pointer);
// printf("finish_ifd: ifd_pointer=0x%04x \n", $ifd_pointer);
$exif_data[$ifd_pointer++]=0;
$exif_data[$ifd_pointer++]=0;
$exif_data[$ifd_pointer++]=0;
......@@ -439,14 +443,14 @@ function addDirEntry($ifd_entry) {
$lh=count($exif_head);
$attrs = $ifd_entry->attributes();
// var_dump($attrs);
// if (array_key_exists ( "seq" , $attrs )) {
// var_dump($attrs);
// if (array_key_exists ( "seq" , $attrs )) {
if ($attrs["seq"]) {
// echo $attrs["seq"].;
// echo $attrs["seq"].;
$dir_sequence[]=((string) $attrs["seq"])+0;
$len= (integer) $ifd_entry->value_length;
$offs=$lh+(integer) $ifd_entry->value_offest;
// if (array_key_exists ( "dlen" , $attrs ))
// if (array_key_exists ( "dlen" , $attrs ))
if ($attrs["dlen"]) $len=min($len,((string) $attrs["dlen"])+0);
$dir_entries[]=array("ltag"=>((integer)$ifd_entry->ltag),"dst"=>$offs,"len"=>$len);
}
......@@ -454,11 +458,12 @@ function addDirEntry($ifd_entry) {
function substitute_value($ifd_entry) {
global $SUB_IFD_offset,$GPSInfo_offset;
global $DeviceSNFilename, $DeviceRevisionFilename, $DeviceBrand, $DeviceModel;
$attrs = $ifd_entry->attributes();
switch ($attrs["function"]) {
case "BRAND":
$ifd_entry->addChild ('value',exec("bootblocktool -x BRAND"));
$ifd_entry->addChild('value', $DeviceBrand);
break;
case "MODEL":
if (file_exists ('/var/state/APPLICATION')) {
......@@ -467,17 +472,20 @@ function substitute_value($ifd_entry) {
$model.=' CHN'.file_get_contents('/var/state/APPLICATION_MODE');
}
} else {
$model= exec("bootblocktool -x MODEL").exec("bootblocktool -x REVISION");
$model = $DeviceModel;
}
/// $ifd_entry->addChild ('value',exec("bootblocktool -x MODEL").exec("bootblocktool -x REVISION"));
$ifd_entry->addChild ('value',$model);
break;
case "SOFTWARE":
if (file_exists("/usr/html/docs/")) {
$ifd_entry->addChild ('value',exec("ls /usr/html/docs/")); // filter
}
break;
case "SERIAL":
$s=exec("bootblocktool -x SERNO");
$s = "";
if (file_exists($DeviceSNFilename)) {
$s = exec('cat '.$DeviceSNFilename);
}
$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));
break;
case "EXIFTAG":
......@@ -496,14 +504,14 @@ function process_ifd_entry($ifd_entry, $group) {
$ifd_tag= ((string) $attrs["tag"])+0;
$ifd_format=constant("EXIF_".$attrs["format"]);
$ifd_count= $attrs["count"];
// echo "\nifd_tag=$ifd_tag, entry=";print_r($ifd_entry);
// echo "\nifd_count=$ifd_count";
// echo "\nifd_bytes:";var_dump($ifd_bytes);
// echo "\nifd_tag=$ifd_tag, entry=";print_r($ifd_entry);
// echo "\nifd_count=$ifd_count";
// echo "\nifd_bytes:";var_dump($ifd_bytes);
if (!$ifd_count) {
if($ifd_format==EXIF_ASCII) $ifd_count=strlen($ifd_entry->value)+1;
else $ifd_count=1 ; /// may change?
}
//echo "\nifd_count=$ifd_count";
//echo "\nifd_count=$ifd_count";
$exif_data[$ifd_pointer++]= ($ifd_tag >> 8) & 0xff;
$exif_data[$ifd_pointer++]= $ifd_tag & 0xff;
$exif_data[$ifd_pointer++]= ($ifd_format >> 8 ) & 0xff;
......@@ -524,7 +532,7 @@ function process_ifd_entry($ifd_entry, $group) {
default: $ifd_bytes=1; //1,2,6,7
}
$ifd_bytes=$ifd_bytes*$ifd_count;
// now prepare ifd_data - array of bytes
// now prepare ifd_data - array of bytes
switch ($ifd_format) {
case EXIF_BYTE:
case EXIF_SBYTE:
......@@ -558,9 +566,9 @@ echo "\n";
var_dump($denom);
echo "\n";
//exit(0);
*/
*/
for ($i=0;$i<count($nom);$i++) {
// echo "i=$i\n";
// echo "i=$i\n";
// echo "\nnom=";var_dump($nom[$i]);
// echo "\ndenom=";var_dump($denom[$i]);
$ifd_data=array_merge($ifd_data,$nom[$i],$denom[$i]);
......@@ -571,14 +579,14 @@ echo "\n";
$ifd_data= array_fill(0,$ifd_bytes,0); // will just fill with "0"-s
break;
}
// echo "\nifd_tag=$ifd_tag, entry=";print_r($i=$ifd_entry->value);
// echo "\nifd_data:";var_dump($ifd_data);
// echo "\nifd_bytes:";var_dump($ifd_bytes);
// echo "\nifd_tag=$ifd_tag, entry=";print_r($i=$ifd_entry->value);
// echo "\nifd_data:";var_dump($ifd_data);
// echo "\nifd_bytes:";var_dump($ifd_bytes);
$ifd_data=array_pad($ifd_data,$ifd_bytes,0);
$ifd_entry->addChild ('value_length',count($ifd_data));
// if (array_key_exists ( "ltag" , $attrs )) $ltag= ((string) $attrs["ltag"])+0;
// if (array_key_exists ( "ltag" , $attrs )) $ltag= ((string) $attrs["ltag"])+0;
if ($attr["ltag"]) $ltag= ((string) $attrs["ltag"])+0;
else $ltag= $ifd_tag+($group<<16) ;
$ifd_entry->addChild ("ltag",$ltag );
......
......@@ -289,7 +289,7 @@ int printExifXML(int exif_page, struct file_set *fset)
while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry)) > 0) {
switch (dir_table_entry.ltag) {
case Exif_Image_ImageDescription: indx = Exif_Image_ImageDescription_Index; break;
case Exif_Image_FrameNumber: indx = Exif_Image_FrameNumber_Index; break;
case Exif_Image_ImageNumber: indx = Exif_Image_ImageNumber_Index; break;
case Exif_Photo_DateTimeOriginal: indx = Exif_Photo_DateTimeOriginal_Index; break;
case Exif_Photo_SubSecTimeOriginal: indx = Exif_Photo_SubSecTimeOriginal_Index; break;
case Exif_Photo_ExposureTime: indx = Exif_Photo_ExposureTime_Index; break;
......@@ -349,14 +349,14 @@ int printExifXML(int exif_page, struct file_set *fset)
saferead255(fd_exif, val, exif_dir[Exif_Image_ImageDescription_Index].len);
printf("<ImageDescription>\"%s\"</ImageDescription>\n", val);
}
///Exif_Image_FrameNumber_Index 0x13
if (exif_dir[Exif_Image_FrameNumber_Index].ltag == Exif_Image_FrameNumber) { // Exif_Image_FrameNumber_Index is present in template
///Exif_Image_ImageNumber_Index 0x13
if (exif_dir[Exif_Image_ImageNumber_Index].ltag == Exif_Image_ImageNumber) { // Exif_Image_ImageNumber_Index is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_FrameNumber_Index].dst,
exif_page_start + exif_dir[Exif_Image_ImageNumber_Index].dst,
SEEK_SET);
read(fd_exif, rational3, 4);
sprintf(val, "%ld", (long)__cpu_to_be32( rational3[0]));
printf("<FrameNumber>\"%s\"</FrameNumber>\n", val);
printf("<ImageNumber>\"%s\"</ImageNumber>\n", val);
}
///Exif_Image_Orientation_Index 0x14
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment