feat: integrate EXIF data extraction using nom-exif and refactor related components
This commit is contained in:
@@ -6,3 +6,4 @@ pub mod plugins;
|
||||
pub mod repositories;
|
||||
pub mod schema;
|
||||
pub mod services;
|
||||
pub mod media_utils;
|
||||
71
libertas_core/src/media_utils.rs
Normal file
71
libertas_core/src/media_utils.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use nom_exif::{AsyncMediaParser, AsyncMediaSource, Exif, ExifIter, ExifTag};
|
||||
|
||||
use crate::error::{CoreError, CoreResult};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ExtractedExif {
|
||||
pub width: Option<i32>,
|
||||
pub height: Option<i32>,
|
||||
pub location: Option<String>,
|
||||
pub date_taken: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
fn parse_exif_datetime(s: &str) -> Option<DateTime<Utc>> {
|
||||
NaiveDateTime::parse_from_str(s, "%Y:%m:%d %H:%M:%S")
|
||||
.ok()
|
||||
.map(|ndt| ndt.and_local_timezone(Utc).unwrap())
|
||||
}
|
||||
|
||||
pub async fn extract_exif_data(file_path: &Path) -> CoreResult<ExtractedExif> {
|
||||
let ms = AsyncMediaSource::file_path(file_path)
|
||||
.await
|
||||
.map_err(|e| CoreError::Unknown(format!("Failed to open file for EXIF: {}", e)))?;
|
||||
|
||||
if !ms.has_exif() {
|
||||
return Ok(ExtractedExif::default());
|
||||
}
|
||||
|
||||
let mut parser = AsyncMediaParser::new();
|
||||
let iter: ExifIter = match parser.parse(ms).await {
|
||||
Ok(iter) => iter,
|
||||
Err(e) => {
|
||||
println!("Could not parse EXIF: {}", e);
|
||||
return Ok(ExtractedExif::default());
|
||||
}
|
||||
};
|
||||
|
||||
let location = iter.parse_gps_info().ok().flatten().map(|g| g.format_iso6709());
|
||||
let exif: Exif = iter.into();
|
||||
|
||||
let width = exif
|
||||
.get(ExifTag::ExifImageWidth)
|
||||
.and_then(|f| f.as_u32())
|
||||
.map(|v| v as i32);
|
||||
|
||||
let height = exif
|
||||
.get(ExifTag::ExifImageHeight)
|
||||
.and_then(|f| f.as_u32())
|
||||
.map(|v| v as i32);
|
||||
|
||||
let dt_original = exif
|
||||
.get(ExifTag::DateTimeOriginal)
|
||||
.and_then(|f| f.as_str())
|
||||
.and_then(parse_exif_datetime);
|
||||
|
||||
let dt_modify = exif
|
||||
.get(ExifTag::ModifyDate)
|
||||
.and_then(|f| f.as_str())
|
||||
.and_then(parse_exif_datetime);
|
||||
|
||||
let date_taken = dt_original.or(dt_modify);
|
||||
|
||||
Ok(ExtractedExif {
|
||||
width,
|
||||
height,
|
||||
location,
|
||||
date_taken,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user