[niepce] Issue #2 - engine: Import more Exif properties
- From: Hubert Figuière <hub src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [niepce] Issue #2 - engine: Import more Exif properties
- Date: Fri, 21 Dec 2018 16:48:30 +0000 (UTC)
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]