[niepce] Issue #2 - engine: Import more Exif properties



commit 17e2981b619890584c6ab1b342c38bcc306b4adb
Author: Hubert Figuière <hub figuiere net>
Date:   Sun Nov 25 10:24:49 2018 -0500

    Issue #2 - engine: Import more Exif properties
    
    https://gitlab.gnome.org/GNOME/niepce/issues/2

 src/fwk/utils/exempi.rs | 48 +++++++++++++++++++++++++
 src/fwk/utils/exiv2.rs  | 94 +++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 131 insertions(+), 11 deletions(-)
---
diff --git a/src/fwk/utils/exempi.rs b/src/fwk/utils/exempi.rs
index e303f17..151cfe6 100644
--- a/src/fwk/utils/exempi.rs
+++ b/src/fwk/utils/exempi.rs
@@ -17,6 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+use std::convert::From;
 use std::fs::File;
 use std::io::prelude::*;
 use std::path::Path;
@@ -38,6 +39,53 @@ pub const NS_EXIF: &str = "http://ns.adobe.com/exif/1.0/";;
 pub const NS_DC: &str = "http://purl.org/dc/elements/1.1/";;
 pub const NS_AUX: &str = "http://ns.adobe.com/exif/1.0/aux/";;
 
+const XMP_TRUE: &str = "True";
+const XMP_FALSE: &str = "False";
+
+/// Convert a bool to a propstring
+fn bool_to_propstring(val: bool) -> &'static str {
+    if val {
+        XMP_TRUE
+    } else {
+        XMP_FALSE
+    }
+}
+
+/// The Flash property, decoded
+#[derive(Clone, Default, Debug)]
+pub struct Flash {
+    fired: bool,
+    rturn: u8,
+    mode: u8,
+    function: bool,
+    red_eye: bool,
+}
+
+impl From<i32> for Flash {
+    /// Interpret the exif value and make it a Flash struct
+    fn from(flash: i32) -> Flash {
+        let fired = (flash & 0x1) != 0;
+        let rturn = ((flash >> 1) & 0x3) as u8;
+        let mode = ((flash >> 3) & 0x3) as u8;
+        let function = ((flash >> 5) & 0x1) != 0;
+        let red_eye = ((flash >> 6) & 0x10) != 0;
+        Flash { fired, rturn, mode, function, red_eye }
+    }
+}
+
+impl Flash {
+    pub fn set_as_xmp_property(&self, xmp: &mut Xmp, ns: &str, property: &str) -> exempi::Result<()> {
+        // XXX use set_struct_field() as soon as it is available
+        xmp.set_property(ns, &format!("{}/exif:Fired", property), bool_to_propstring(self.fired), 
exempi::PROP_NONE)?;
+        xmp.set_property(ns, &format!("{}/exif:Return", property), &format!("{}", self.rturn), 
exempi::PROP_NONE)?;
+        xmp.set_property(ns, &format!("{}/exif:Mode", property), &format!("{}", self.mode), 
exempi::PROP_NONE)?;
+        xmp.set_property(ns, &format!("{}/exif:Function", property), bool_to_propstring(self.function), 
exempi::PROP_NONE)?;
+        xmp.set_property(ns, &format!("{}/exif:RedEyeMode", property), bool_to_propstring(self.red_eye), 
exempi::PROP_NONE)?;
+
+        Ok(())
+    }
+}
+
 pub struct NsDef {
     ns: String,
     prefix: String,
diff --git a/src/fwk/utils/exiv2.rs b/src/fwk/utils/exiv2.rs
index fc0e268..108538b 100644
--- a/src/fwk/utils/exiv2.rs
+++ b/src/fwk/utils/exiv2.rs
@@ -23,28 +23,64 @@ use std::collections::HashMap;
 use exempi;
 use rexiv2;
 
-use super::exempi::{XmpMeta, NS_TIFF, NS_EXIF, NS_XAP, xmp_date_from_exif};
+use super::exempi::{Flash, XmpMeta, NS_TIFF, NS_EXIF, NS_XAP, NS_AUX, xmp_date_from_exif};
 
-#[derive(Clone, Copy)]
+/// Property conversion rules
+#[derive(Clone, Copy, Debug)]
 enum Conversion {
+    /// Use value as is
     None,
+    /// Convert from the Exif date format to a date
     ExifDate,
+    /// Convert the Exif flash tag to the struct for XMP
+    Flash,
 }
 
-#[derive(Clone)]
+/// Converstion result
+#[derive(Clone, Debug)]
 enum Converted {
+    /// A String
     Str(String),
+    /// An int 32
+    Int(i32),
+    /// an Xmp DateTime value
     Date(Option<exempi::DateTime>),
+    /// The Flash XMP structure
+    Flash(Flash),
 }
 
 lazy_static! {
     static ref exiv2_to_xmp: HashMap<&'static str, (&'static str, &'static str, Conversion)> = {
         [
-            ("Exif.Photo.DateTimeOriginal", (NS_EXIF, "DateTimeOriginal", Conversion::ExifDate)),
-            ("Exif.Photo.DateTimeDigitized", (NS_XAP, "CreateDate", Conversion::ExifDate)),
             ("Exif.Image.DateTime", (NS_XAP, "ModifyDate", Conversion::ExifDate)),
+            ("Exif.Image.ImageHeight", (NS_TIFF, "ImageHeight", Conversion::None)),
+            ("Exif.Image.ImageWidth", (NS_TIFF, "ImageWidth", Conversion::None)),
             ("Exif.Image.Make", (NS_TIFF, "Make", Conversion::None)),
-            ("Exif.Image.Model", (NS_TIFF, "Model", Conversion::None))
+            ("Exif.Image.Model", (NS_TIFF, "Model", Conversion::None)),
+            ("Exif.Image.Orientation", (NS_TIFF, "Orientation", Conversion::None)),
+            ("Exif.Photo.ApertureValue", (NS_EXIF, "ApertureValue", Conversion::None)),
+            ("Exif.Photo.ColorSpace", (NS_EXIF, "ColorSpace", Conversion::None)),
+            ("Exif.Photo.DateTimeOriginal", (NS_EXIF, "DateTimeOriginal", Conversion::ExifDate)),
+            ("Exif.Photo.DateTimeDigitized", (NS_XAP, "CreateDate", Conversion::ExifDate)),
+            ("Exif.Photo.ExposureBiasValue", (NS_EXIF, "ExposureBiasValue", Conversion::None)),
+            ("Exif.Photo.ExposureMode", (NS_EXIF, "ExposureMode", Conversion::None)),
+            ("Exif.Photo.ExposureProgram", (NS_EXIF, "ExposureProgram", Conversion::None)),
+            ("Exif.Photo.ExposureTime", (NS_EXIF, "ExposureTime", Conversion::None)),
+            ("Exif.Photo.FNumber", (NS_EXIF, "FNumber", Conversion::None)),
+            ("Exif.Photo.Flash", (NS_EXIF, "Flash", Conversion::Flash)),
+            ("Exif.Photo.FocalLength", (NS_EXIF, "FocalLength", Conversion::None)),
+            ("Exif.Photo.ISOSpeedRatings", (NS_EXIF, "ISOSpeedRatings", Conversion::None)),
+            ("Exif.Photo.LightSource", (NS_EXIF, "LightSource", Conversion::None)),
+            ("Exif.Photo.MeteringMode", (NS_EXIF, "MeteringMode", Conversion::None)),
+            ("Exif.Photo.SceneCaptureType", (NS_EXIF, "SceneCaptureType", Conversion::None)),
+            ("Exif.Photo.ShutterSpeedValue", (NS_EXIF, "ShutterSpeedValue", Conversion::None)),
+            ("Exif.Photo.UserComment", (NS_EXIF, "UserComment", Conversion::None)),
+            ("Exif.Photo.WhiteBalance", (NS_EXIF, "WhiteBalance", Conversion::None)),
+
+            ("Exif.Canon.LensModel", (NS_AUX, "Lens", Conversion::None)),
+
+            ("Exif.OlympusEq.LensModel", (NS_AUX, "Lens", Conversion::None)),
+            ("Exif.OlympusEq.LensSerialNumber", (NS_AUX, "LensSerialNumber", Conversion::None))
         ].iter().cloned().collect()
     };
 }
@@ -53,6 +89,21 @@ fn convert(conversion: Conversion, value: &str) -> Converted {
     match conversion {
         Conversion::None => Converted::Str(value.to_string()),
         Conversion::ExifDate => Converted::Date(xmp_date_from_exif(&value)),
+        _ => {
+            err_out!("Conversion error fro str to {:?}", conversion);
+            Converted::Str(value.to_string())
+        }
+    }
+}
+
+fn convert_int(conversion: Conversion, int: i32) -> Converted {
+    match conversion {
+        Conversion::None => Converted::Int(int),
+        Conversion::Flash => Converted::Flash(Flash::from(int)),
+        _ => {
+            err_out!("Conversion error from int to {:?}", conversion);
+            Converted::Int(int)
+        }
     }
 }
 
@@ -86,6 +137,9 @@ pub fn xmp_from_exiv2<S: AsRef<OsStr>>(file: S) -> Option<XmpMeta> {
                                     } else {
                                         err_out!("Couldn't convert Exif date {}", &value);
                                     }
+                                },
+                                _ => {
+                                    err_out!("Unknown conversion result {:?}", &converted);
                                 }
                             }
                         }
@@ -95,8 +149,22 @@ pub fn xmp_from_exiv2<S: AsRef<OsStr>>(file: S) -> Option<XmpMeta> {
                     Ok(rexiv2::TagType::SignedShort) |
                     Ok(rexiv2::TagType::SignedLong) => {
                         // XXX rexiv2 returns an i32, which is a problem for UnsignedLong
-                        let value = meta.get_tag_numeric(&tag);
-                        xmp.set_property_i32(xmp_prop.0, xmp_prop.1, value, exempi::PROP_NONE);
+                        match xmp_prop.2 {
+                            Conversion::Flash => {
+                                if let Converted::Flash(flash) = convert_int(xmp_prop.2, 
meta.get_tag_numeric(&tag)) {
+                                    flash.set_as_xmp_property(&mut xmp, NS_EXIF, "Flash");
+                                }
+                            },
+                            Conversion::None => {
+                                let value = meta.get_tag_numeric(&tag);
+                                xmp.set_property_i32(xmp_prop.0, xmp_prop.1, value, exempi::PROP_NONE);
+                            },
+                            _ => {
+                                err_out!("Unknown conversion from {:?} to {:?}", tagtype, xmp_prop.2);
+                                let value = meta.get_tag_numeric(&tag);
+                                xmp.set_property_i32(xmp_prop.0, xmp_prop.1, value, exempi::PROP_NONE);
+                            }
+                        }
                     },
                     Ok(rexiv2::TagType::UnsignedRational) |
                     Ok(rexiv2::TagType::SignedRational) => {
@@ -104,14 +172,18 @@ pub fn xmp_from_exiv2<S: AsRef<OsStr>>(file: S) -> Option<XmpMeta> {
                             let value_str = format!("{}/{}", value.numer(), value.denom());
                             xmp.set_property(xmp_prop.0, xmp_prop.1, &value_str, exempi::PROP_NONE);
                         }
-                        println!("value {} = {:?}", &tag, meta.get_tag_rational(&tag));
+                    },
+                    Ok(rexiv2::TagType::Comment) => {
+                        if let Ok(value) = meta.get_tag_string(&tag) {
+                            xmp.set_property(xmp_prop.0, xmp_prop.1, &value, exempi::PROP_NONE);
+                        }
                     },
                     _ => {
-                        println!("Unhandled type {:?} for {}", tagtype, &tag);
+                        err_out!("Unhandled type {:?} for {}", tagtype, &tag);
                     }
                 }
             } else {
-                println!("Unknown property {}", &tag);
+                err_out!("Unknown property {}", &tag);
             }
         }
         meta.get_gps_info();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]