diff --git a/src-tauri/src/exif_processing.rs b/src-tauri/src/exif_processing.rs index cea2ba4d2c..90f9aba586 100644 --- a/src-tauri/src/exif_processing.rs +++ b/src-tauri/src/exif_processing.rs @@ -15,6 +15,7 @@ use little_exif::ifd::ExifTagGroup; use little_exif::metadata::Metadata; use little_exif::rational::{iR64, uR64}; use rawler::decoders::RawMetadata; +use rawler::exif::ExifGPS; use rawler::lens::LensDescription; use serde::{Deserialize, Serialize}; @@ -285,15 +286,35 @@ fn to_ir64(val: &exif::SRational) -> iR64 { } } +fn rawler_to_ur64(val: rawler::formats::tiff::Rational) -> uR64 { + uR64 { + nominator: val.n, + denominator: val.d, + } +} + +fn rawler_to_ir64(val: rawler::formats::tiff::SRational) -> iR64 { + iR64 { + nominator: val.n, + denominator: val.d, + } +} + fn clean_creation_datetime_str(s: &str) -> &str { s.trim().trim_matches('"').trim_matches('\'').trim() } -fn fmt_date_str(s: String) -> String { - if let Some(dt) = parse_creation_datetime(&s) { - return dt.format("%Y-%m-%d %H:%M:%S").to_string(); +const EXIF_DATETIME_FORMAT: &str = "%Y:%m:%d %H:%M:%S"; + +fn format_creation_datetime(s: &str, format: &str) -> String { + if let Some(dt) = parse_creation_datetime(s) { + return dt.format(format).to_string(); } - clean_creation_datetime_str(&s).to_string() + clean_creation_datetime_str(s).to_string() +} + +fn fmt_date_str(s: String) -> String { + format_creation_datetime(&s, "%Y-%m-%d %H:%M:%S") } fn normalize_creation_datetime(s: &str) -> Option { @@ -418,10 +439,17 @@ pub fn read_exif(file_bytes: &[u8]) -> Option { } pub fn read_raw_metadata(file_bytes: &[u8]) -> Option { + raw_metadata_from_source(&rawler::rawsource::RawSource::new_from_slice(file_bytes)) +} + +fn read_raw_metadata_from_path(path_str: &str) -> Option { + raw_metadata_from_source(&rawler::rawsource::RawSource::new(Path::new(path_str)).ok()?) +} + +fn raw_metadata_from_source(raw_source: &rawler::rawsource::RawSource) -> Option { let loader = rawler::RawLoader::new(); - let raw_source = rawler::rawsource::RawSource::new_from_slice(file_bytes); - let decoder = loader.get_decoder(&raw_source).ok()?; - decoder.raw_metadata(&raw_source, &Default::default()).ok() + let decoder = loader.get_decoder(raw_source).ok()?; + decoder.raw_metadata(raw_source, &Default::default()).ok() } fn insert_missing_lens_fields(map: &mut HashMap, lens: &LensDescription) { @@ -1090,6 +1118,72 @@ fn apply_sidecar_field_overrides(metadata: &mut Metadata, map: &HashMap String { match &field.value { exif::Value::Ascii(vec) => vec @@ -1458,84 +1523,11 @@ pub fn write_image_with_metadata( } } - if !source_read_success && is_raw_file(original_path_str) { - let loader = rawler::RawLoader::new(); - if let Ok(raw_source) = rawler::rawsource::RawSource::new(Path::new(original_path_str)) - && let Ok(decoder) = loader.get_decoder(&raw_source) - && let Ok(meta) = decoder.raw_metadata(&raw_source, &Default::default()) - { - if !meta.make.is_empty() { - metadata.set_tag(ExifTag::Make(meta.make.clone())); - } - if !meta.model.is_empty() { - metadata.set_tag(ExifTag::Model(meta.model.clone())); - } - let exif = meta.exif; - if let Some(artist) = exif.artist { - metadata.set_tag(ExifTag::Artist(artist)); - } - if let Some(copyright) = exif.copyright { - metadata.set_tag(ExifTag::Copyright(copyright)); - } - if let Some(dt) = exif.date_time_original { - metadata.set_tag(ExifTag::DateTimeOriginal(dt)); - } - if let Some(dt) = exif.create_date { - metadata.set_tag(ExifTag::CreateDate(dt)); - } - if let Some(lens_make) = exif.lens_make { - metadata.set_tag(ExifTag::LensMake(lens_make)); - } - if let Some(lens_model) = exif.lens_model { - metadata.set_tag(ExifTag::LensModel(lens_model)); - } - if let Some(f) = exif.fnumber { - metadata.set_tag(ExifTag::FNumber(vec![uR64 { - nominator: f.n, - denominator: f.d, - }])); - } - if let Some(t) = exif.exposure_time { - metadata.set_tag(ExifTag::ExposureTime(vec![uR64 { - nominator: t.n, - denominator: t.d, - }])); - } - if let Some(fl) = exif.focal_length { - metadata.set_tag(ExifTag::FocalLength(vec![uR64 { - nominator: fl.n, - denominator: fl.d, - }])); - } - if let Some(iso) = exif.iso_speed { - metadata.set_tag(ExifTag::ISO(vec![iso as u16])); - } else if let Some(iso) = exif.iso_speed_ratings { - metadata.set_tag(ExifTag::ISO(vec![iso])); - } - if let Some(ev) = exif.exposure_bias { - metadata.set_tag(ExifTag::ExposureCompensation(vec![iR64 { - nominator: ev.n, - denominator: ev.d, - }])); - } - if let Some(flash) = exif.flash { - metadata.set_tag(ExifTag::Flash(vec![flash])); - } - if let Some(metering) = exif.metering_mode { - metadata.set_tag(ExifTag::MeteringMode(vec![metering])); - } - if let Some(wb) = exif.white_balance { - metadata.set_tag(ExifTag::WhiteBalance(vec![wb])); - } - if let Some(prog) = exif.exposure_program { - metadata.set_tag(ExifTag::ExposureProgram(vec![prog])); - } - } - } - if !strip_gps { if is_raw_file(original_path_str) { - apply_gps_from_rawler(&mut metadata, original_path_str); + if let Some(gps) = raw_metadata.and_then(|meta| meta.exif.gps) { + apply_gps_from_rawler(&mut metadata, gps); + } } else { apply_gps_from_kamadak(&mut metadata, original_path); } @@ -1548,6 +1540,11 @@ pub fn write_image_with_metadata( metadata.set_tag(ExifTag::Software("RapidRAW".to_string())); metadata.set_tag(ExifTag::Orientation(vec![1u16])); metadata.set_tag(ExifTag::ColorSpace(vec![1u16])); + metadata.set_tag(ExifTag::ExifVersion(b"0232".to_vec())); + metadata.set_tag(ExifTag::FlashpixVersion(b"0100".to_vec())); + if matches!(file_type, FileExtension::JPEG) { + metadata.set_tag(ExifTag::ComponentsConfiguration(vec![1, 2, 3, 0])); + } if let Ok(reader) = image::ImageReader::new(Cursor::new(image_bytes.as_slice())).with_guessed_format()