From d443a3c2509889533ca812c163056bace396b586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Wed, 14 Jun 2023 20:35:58 +0200 Subject: New upstream version 0.32.1 --- src/Photo.vala | 161 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 110 insertions(+), 51 deletions(-) (limited to 'src/Photo.vala') diff --git a/src/Photo.vala b/src/Photo.vala index b67457e..f31a17d 100644 --- a/src/Photo.vala +++ b/src/Photo.vala @@ -155,7 +155,7 @@ public enum Rating { // particular photo without modifying the backing image file. The interface allows for // transformations to be stored persistently elsewhere or in memory until they're committed en // masse to an image file. -public abstract class Photo : PhotoSource, Dateable { +public abstract class Photo : PhotoSource, Dateable, Positionable { // Need to use "thumb" rather than "photo" for historical reasons -- this name is used // directly to load thumbnails from disk by already-existing filenames public const string TYPENAME = "thumb"; @@ -183,7 +183,7 @@ public abstract class Photo : PhotoSource, Dateable { "pns", "jps", "mpo", // RAW extensions - "3fr", "arw", "srf", "sr2", "bay", "crw", "cr2", "cap", "iiq", "eip", "dcs", "dcr", "drf", + "3fr", "arw", "srf", "sr2", "bay", "crw", "cr2", "cr3", "cap", "iiq", "eip", "dcs", "dcr", "drf", "k25", "kdc", "dng", "erf", "fff", "mef", "mos", "mrw", "nef", "nrw", "orf", "ptx", "pef", "pxn", "r3d", "raf", "raw", "rw2", "rwl", "rwz", "x3f", "srw" }; @@ -210,7 +210,7 @@ public abstract class Photo : PhotoSource, Dateable { // Here, we cache the exposure time to avoid paying to access the row every time we // need to know it. This is initially set in the constructor, and updated whenever // the exposure time is set (please see set_exposure_time() for details). - private time_t cached_exposure_time; + private DateTime? cached_exposure_time; public enum Exception { NONE = 0, @@ -640,7 +640,7 @@ public abstract class Photo : PhotoSource, Dateable { File file = File.new_for_path(bpr.filepath); FileInfo info = file.query_info(DirectoryMonitor.SUPPLIED_ATTRIBUTES, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null); - TimeVal timestamp = info.get_modification_time(); + var timestamp = info.get_modification_date_time(); PhotoFileInterrogator interrogator = new PhotoFileInterrogator( file, PhotoFileSniffer.Options.GET_ALL); @@ -655,7 +655,7 @@ public abstract class Photo : PhotoSource, Dateable { bpr.dim = detected.image_dim; bpr.filesize = info.get_size(); - bpr.timestamp = timestamp.tv_sec; + bpr.timestamp = timestamp; bpr.original_orientation = detected.metadata != null ? detected.metadata.get_orientation() : Orientation.TOP_LEFT; @@ -832,7 +832,7 @@ public abstract class Photo : PhotoSource, Dateable { if (!developments.has_key(d)) return; // we tried! - // Disgard changes. + // Discard changes. revert_to_master(false); // Switch master to the new photo. @@ -1185,7 +1185,7 @@ public abstract class Photo : PhotoSource, Dateable { return ImportResult.UNSUPPORTED_FORMAT; } - TimeVal timestamp = info.get_modification_time(); + var timestamp = info.get_modification_date_time(); // if all MD5s supplied, don't sniff for them if (params.exif_md5 != null && params.thumbnail_md5 != null && params.full_md5 != null) @@ -1217,8 +1217,9 @@ public abstract class Photo : PhotoSource, Dateable { } Orientation orientation = Orientation.TOP_LEFT; - time_t exposure_time = 0; + DateTime? exposure_time = null; string title = ""; + GpsCoords gps_coords = GpsCoords(); string comment = ""; Rating rating = Rating.UNRATED; @@ -1234,6 +1235,7 @@ public abstract class Photo : PhotoSource, Dateable { orientation = detected.metadata.get_orientation(); title = detected.metadata.get_title(); + gps_coords = detected.metadata.get_gps_coords(); comment = detected.metadata.get_comment(); params.keywords = detected.metadata.get_keywords(); rating = detected.metadata.get_rating(); @@ -1255,7 +1257,7 @@ public abstract class Photo : PhotoSource, Dateable { params.row.master.filepath = file.get_path(); params.row.master.dim = detected.image_dim; params.row.master.filesize = info.get_size(); - params.row.master.timestamp = timestamp.tv_sec; + params.row.master.timestamp = timestamp; params.row.exposure_time = exposure_time; params.row.orientation = orientation; params.row.master.original_orientation = orientation; @@ -1269,6 +1271,7 @@ public abstract class Photo : PhotoSource, Dateable { params.row.flags = 0; params.row.master.file_format = detected.file_format; params.row.title = title; + params.row.gps_coords = gps_coords; params.row.comment = comment; params.row.rating = rating; @@ -1296,8 +1299,8 @@ public abstract class Photo : PhotoSource, Dateable { params.row.master.filepath = file.get_path(); params.row.master.dim = Dimensions(0,0); params.row.master.filesize = 0; - params.row.master.timestamp = 0; - params.row.exposure_time = 0; + params.row.master.timestamp = null; + params.row.exposure_time = null; params.row.orientation = Orientation.TOP_LEFT; params.row.master.original_orientation = Orientation.TOP_LEFT; params.row.import_id = params.import_id; @@ -1310,6 +1313,7 @@ public abstract class Photo : PhotoSource, Dateable { params.row.flags = 0; params.row.master.file_format = PhotoFileFormat.JFIF; params.row.title = null; + params.row.gps_coords = GpsCoords(); params.row.comment = null; params.row.rating = Rating.UNRATED; @@ -1350,10 +1354,10 @@ public abstract class Photo : PhotoSource, Dateable { return null; } - TimeVal modification_time = info.get_modification_time(); + var modification_time = info.get_modification_date_time(); backing.filepath = file.get_path(); - backing.timestamp = modification_time.tv_sec; + backing.timestamp = modification_time; backing.filesize = info.get_size(); backing.file_format = detected.file_format; backing.dim = detected.image_dim; @@ -1462,14 +1466,22 @@ public abstract class Photo : PhotoSource, Dateable { list += "image:orientation"; updated_row.master.original_orientation = backing.original_orientation; } - + + GpsCoords gps_coords = GpsCoords(); + if (detected.metadata != null) { MetadataDateTime? date_time = detected.metadata.get_exposure_date_time(); - if (date_time != null && updated_row.exposure_time != date_time.get_timestamp()) + if (date_time != null && updated_row.exposure_time != null && + !updated_row.exposure_time.equal(date_time.get_timestamp())) list += "metadata:exposure-time"; if (updated_row.title != detected.metadata.get_title()) list += "metadata:name"; + + gps_coords = detected.metadata.get_gps_coords(); + if (updated_row.gps_coords != gps_coords) + list += "metadata:gps"; + if (updated_row.comment != detected.metadata.get_comment()) list += "metadata:comment"; @@ -1490,7 +1502,8 @@ public abstract class Photo : PhotoSource, Dateable { MetadataDateTime? date_time = detected.metadata.get_exposure_date_time(); if (date_time != null) updated_row.exposure_time = date_time.get_timestamp(); - + + updated_row.gps_coords = gps_coords; updated_row.title = detected.metadata.get_title(); updated_row.comment = detected.metadata.get_comment(); updated_row.rating = detected.metadata.get_rating(); @@ -1601,6 +1614,7 @@ public abstract class Photo : PhotoSource, Dateable { if (reimport_state.metadata != null) { set_title(reimport_state.metadata.get_title()); + set_gps_coords(reimport_state.metadata.get_gps_coords()); set_comment(reimport_state.metadata.get_comment()); set_rating(reimport_state.metadata.get_rating()); apply_user_metadata_for_reimport(reimport_state.metadata); @@ -1695,17 +1709,17 @@ public abstract class Photo : PhotoSource, Dateable { // Use this only if the master file's modification time has been changed (i.e. touched) public void set_master_timestamp(FileInfo info) { - TimeVal modification = info.get_modification_time(); + var modification = info.get_modification_date_time(); try { lock (row) { - if (row.master.timestamp == modification.tv_sec) + if (row.master.timestamp.equal(modification)) return; - PhotoTable.get_instance().update_timestamp(row.photo_id, modification.tv_sec); - row.master.timestamp = modification.tv_sec; + PhotoTable.get_instance().update_timestamp(row.photo_id, modification); + row.master.timestamp = modification; } - } catch (DatabaseError err) { + } catch (Error err) { AppWindow.database_error(err); return; @@ -1718,15 +1732,15 @@ public abstract class Photo : PhotoSource, Dateable { } // Use this only if the editable file's modification time has been changed (i.e. touched) - public void update_editable_modification_time(FileInfo info) throws DatabaseError { - TimeVal modification = info.get_modification_time(); + public void update_editable_modification_time(FileInfo info) throws Error { + var modification = info.get_modification_date_time(); bool altered = false; lock (row) { - if (row.editable_id.is_valid() && editable.timestamp != modification.tv_sec) { + if (row.editable_id.is_valid() && !editable.timestamp.equal(modification)) { BackingPhotoTable.get_instance().update_timestamp(row.editable_id, - modification.tv_sec); - editable.timestamp = modification.tv_sec; + modification); + editable.timestamp = modification; altered = true; } } @@ -1739,8 +1753,13 @@ public abstract class Photo : PhotoSource, Dateable { public static void update_many_editable_timestamps(Gee.Map map) throws DatabaseError { DatabaseTable.begin_transaction(); - foreach (Photo photo in map.keys) - photo.update_editable_modification_time(map.get(photo)); + foreach (Photo photo in map.keys) { + try { + photo.update_editable_modification_time(map.get(photo)); + } catch (Error err) { + debug("Failed to update modification time: %s", err.message); + } + } DatabaseTable.commit_transaction(); } @@ -1853,7 +1872,7 @@ public abstract class Photo : PhotoSource, Dateable { } } } - } catch (DatabaseError err) { + } catch (Error err) { AppWindow.database_error(err); } @@ -1906,7 +1925,7 @@ public abstract class Photo : PhotoSource, Dateable { } } } - } catch (DatabaseError err) { + } catch (Error err) { AppWindow.database_error(err); } @@ -1993,7 +2012,7 @@ public abstract class Photo : PhotoSource, Dateable { } } - public override time_t get_timestamp() { + public override DateTime? get_timestamp() { lock (row) { return backing_photo_row.timestamp; } @@ -2169,7 +2188,7 @@ public abstract class Photo : PhotoSource, Dateable { } } - public void set_master_metadata_dirty(bool dirty) throws DatabaseError { + public void set_master_metadata_dirty(bool dirty) throws Error { bool committed = false; lock (row) { if (row.metadata_dirty != dirty) { @@ -2277,7 +2296,7 @@ public abstract class Photo : PhotoSource, Dateable { error("Unable to read file information for %s: %s", to_string(), err.message); } - TimeVal timestamp = info.get_modification_time(); + var timestamp = info.get_modification_date_time(); // interrogate file for photo information PhotoFileInterrogator interrogator = new PhotoFileInterrogator(file); @@ -2297,7 +2316,7 @@ public abstract class Photo : PhotoSource, Dateable { bool success; lock (row) { success = PhotoTable.get_instance().master_exif_updated(get_photo_id(), info.get_size(), - timestamp.tv_sec, detected.md5, detected.exif_md5, detected.thumbnail_md5, row); + timestamp, detected.md5, detected.exif_md5, detected.thumbnail_md5, row); } if (success) @@ -2324,7 +2343,7 @@ public abstract class Photo : PhotoSource, Dateable { } } - public override time_t get_exposure_time() { + public override DateTime? get_exposure_time() { return cached_exposure_time; } @@ -2362,6 +2381,29 @@ public abstract class Photo : PhotoSource, Dateable { if (committed) notify_altered(new Alteration("metadata", "name")); } + + public GpsCoords get_gps_coords() { + lock (row) { + return row.gps_coords; + } + } + + public void set_gps_coords(GpsCoords gps_coords) { + DatabaseError dberr = null; + lock (row) { + try { + PhotoTable.get_instance().set_gps_coords(row.photo_id, gps_coords); + row.gps_coords = gps_coords; + } catch (DatabaseError err) { + dberr = err; + } + } + if (dberr == null) + notify_altered(new Alteration("metadata", "gps")); + else + warning("Unable to write gps coordinates for %s: %s", to_string(), dberr.message); + } + public override bool set_comment(string? comment) { string? new_comment = prep_comment(comment); @@ -2455,7 +2497,7 @@ public abstract class Photo : PhotoSource, Dateable { file_exif_updated(); } - public void set_exposure_time(time_t time) { + public void set_exposure_time(DateTime time) { bool committed; lock (row) { committed = PhotoTable.get_instance().set_exposure_time(row.photo_id, time); @@ -2469,7 +2511,7 @@ public abstract class Photo : PhotoSource, Dateable { notify_altered(new Alteration("metadata", "exposure-time")); } - public void set_exposure_time_persistent(time_t time) throws Error { + public void set_exposure_time_persistent(DateTime time) throws Error { PhotoFileReader source = get_source_reader(); // Try to write to backing file @@ -2742,7 +2784,8 @@ public abstract class Photo : PhotoSource, Dateable { lock (row) { return row.transformations == null && (row.orientation != backing_photo_row.original_orientation - || (date_time != null && row.exposure_time != date_time.get_timestamp())); + || (date_time != null && row.exposure_time != null && + !row.exposure_time.equal(date_time.get_timestamp()))); } } @@ -2763,7 +2806,7 @@ public abstract class Photo : PhotoSource, Dateable { // No, use file timestamp as date/time. lock (row) { // Did we manually set an exposure date? - if(backing_photo_row.timestamp != row.exposure_time) { + if(nullsafe_date_time_comperator(backing_photo_row.timestamp, row.exposure_time) != 0) { // Yes, we need to save this. return true; } @@ -2773,7 +2816,7 @@ public abstract class Photo : PhotoSource, Dateable { lock (row) { return row.transformations != null || row.orientation != backing_photo_row.original_orientation - || (date_time != null && row.exposure_time != date_time.get_timestamp()) + || (date_time != null && !row.exposure_time.equal(date_time.get_timestamp())) || (get_comment() != comment) || (get_title() != title); } @@ -3212,6 +3255,7 @@ public abstract class Photo : PhotoSource, Dateable { double orientation_time = 0.0; total_timer.start(); + #endif // get required fields all at once, to avoid holding the row lock @@ -3618,7 +3662,7 @@ public abstract class Photo : PhotoSource, Dateable { debug("Updating metadata of %s", writer.get_filepath()); - if (get_exposure_time() != 0) + if (get_exposure_time() != null) metadata.set_exposure_date_time(new MetadataDateTime(get_exposure_time())); else metadata.set_exposure_date_time(null); @@ -3714,7 +3758,7 @@ public abstract class Photo : PhotoSource, Dateable { metadata.set_comment(get_comment()); metadata.set_software(Resources.APP_TITLE, Resources.APP_VERSION); - if (get_exposure_time() != 0) + if (get_exposure_time() != null) metadata.set_exposure_date_time(new MetadataDateTime(get_exposure_time())); else metadata.set_exposure_date_time(null); @@ -3970,15 +4014,15 @@ public abstract class Photo : PhotoSource, Dateable { return; } - TimeVal timestamp = info.get_modification_time(); + var timestamp = info.get_modification_date_time(); - BackingPhotoTable.get_instance().update_attributes(editable_id, timestamp.tv_sec, + BackingPhotoTable.get_instance().update_attributes(editable_id, timestamp, info.get_size()); lock (row) { - timestamp_changed = editable.timestamp != timestamp.tv_sec; + timestamp_changed = !editable.timestamp.equal(timestamp); filesize_changed = editable.filesize != info.get_size(); - editable.timestamp = timestamp.tv_sec; + editable.timestamp = timestamp; editable.filesize = info.get_size(); } } else { @@ -4057,7 +4101,7 @@ public abstract class Photo : PhotoSource, Dateable { PhotoTable.get_instance().detach_editable(row); backing_photo_row = row.master; } - } catch (DatabaseError err) { + } catch (Error err) { warning("Unable to remove editable from PhotoTable: %s", err.message); } @@ -4976,7 +5020,12 @@ public class LibraryPhoto : Photo, Flaggable, Monitorable { this.import_keywords = null; thumbnail_scheduler = new OneShotScheduler("LibraryPhoto", generate_thumbnails); - + // import gps coords of photos imported with prior versions of shotwell + if (row.gps_coords.has_gps == -1) { + var gps_import_scheduler = new OneShotScheduler("LibraryPhoto", import_gps_metadata); + gps_import_scheduler.at_priority_idle(Priority.LOW); + } + // if marked in a state where they're held in an orphanage, rehydrate their backlinks if ((row.flags & (FLAG_TRASH | FLAG_OFFLINE)) != 0) rehydrate_backlinks(global, row.backlinks); @@ -5097,7 +5146,12 @@ public class LibraryPhoto : Photo, Flaggable, Monitorable { // fire signal that thumbnails have changed notify_thumbnail_altered(); } - + + private void import_gps_metadata() { + GpsCoords gps_coords = get_metadata().get_gps_coords(); + set_gps_coords(gps_coords); + } + // These keywords are only used during import and should not be relied upon elsewhere. public Gee.Collection? get_import_keywords() { return import_keywords; @@ -5218,7 +5272,7 @@ public class LibraryPhoto : Photo, Flaggable, Monitorable { if (location != null) { face.attach(dupe); FaceLocation.create(face.get_face_id(), dupe.get_photo_id(), - location.get_serialized_geometry()); + location.get_face_data()); } } } @@ -5332,10 +5386,14 @@ public class LibraryPhoto : Photo, Flaggable, Monitorable { PhotoMetadata? metadata = get_metadata(); if (metadata == null) - return tags != null || tags.size > 0 || get_rating() != Rating.UNRATED; + return tags != null || tags.size > 0 || get_rating() != Rating.UNRATED || get_gps_coords().has_gps != 0; if (get_rating() != metadata.get_rating()) return true; + + var old_coords = metadata.get_gps_coords(); + if (!get_gps_coords().equals(ref old_coords)) + return true; Gee.Set? keywords = metadata.get_keywords(); int tags_count = (tags != null) ? tags.size : 0; @@ -5366,6 +5424,7 @@ public class LibraryPhoto : Photo, Flaggable, Monitorable { metadata.set_keywords(null); metadata.set_rating(get_rating()); + metadata.set_gps_coords(get_gps_coords()); } protected override void apply_user_metadata_for_reimport(PhotoMetadata metadata) { -- cgit v1.2.3