fix up GPS more properly

This commit is contained in:
Colin McMillen 2023-08-30 12:01:30 -04:00
parent 0ca67f2cef
commit c0ac67103f
2 changed files with 108 additions and 26 deletions

112
Photo.cs
View File

@ -9,6 +9,88 @@ using System.Xml.Linq;
namespace SemiColinGames; namespace SemiColinGames;
// https://exiftool.org/TagNames/GPS.html
public struct GpsInfo {
public byte[] VersionId;
public string Status;
public string Datestamp;
public Rational[] Timestamp;
public Rational[] Latitude;
public string LatitudeRef;
public Rational[] Longitude;
public string LongitudeRef;
public Rational Altitude;
public byte AltitudeRef;
// GpsStatus? DateStamp and TimeStamp?
public static GpsInfo? ParseExif(ExifProfile exif) {
GpsInfo gps;
IExifValue<byte[]>? versionId;
IExifValue<string>? status;
IExifValue<string>? datestamp;
IExifValue<Rational[]>? timestamp;
IExifValue<Rational[]>? latitude;
IExifValue<string>? latitudeRef;
IExifValue<Rational[]>? longitude;
IExifValue<string>? longitudeRef;
IExifValue<Rational>? altitude;
IExifValue<byte>? altitudeRef;
if (!exif.TryGetValue(ExifTag.GPSVersionID, out versionId)) {
return null;
}
gps.VersionId = versionId.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSStatus, out status)) {
return null;
}
gps.Status = status.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSDateStamp, out datestamp)) {
return null;
}
gps.Datestamp = datestamp.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSTimestamp, out timestamp)) {
return null;
}
gps.Timestamp = timestamp.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSLatitude, out latitude)) {
return null;
}
gps.Latitude = latitude.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSLatitudeRef, out latitudeRef)) {
return null;
}
gps.LatitudeRef = latitudeRef.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSLongitude, out longitude)) {
return null;
}
gps.Longitude = longitude.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSLongitudeRef, out longitudeRef)) {
return null;
}
gps.LongitudeRef = longitudeRef.Value ?? throw new NullReferenceException();
if (!exif.TryGetValue(ExifTag.GPSAltitude, out altitude)) {
return null;
}
gps.Altitude = altitude.Value;
if (!exif.TryGetValue(ExifTag.GPSAltitudeRef, out altitudeRef)) {
return null;
}
gps.AltitudeRef = altitudeRef.Value;
return gps;
}
}
public class Photo { public class Photo {
public string Filename; public string Filename;
public bool Loaded = false; public bool Loaded = false;
@ -24,8 +106,7 @@ public class Photo {
public string IsoSpeed = "<unk>"; public string IsoSpeed = "<unk>";
public int Rating = 0; public int Rating = 0;
public ushort Orientation = 1; public ushort Orientation = 1;
public Rational[]? GpsLatitude = null; public GpsInfo? Gps = null;
public Rational[]? GpsLongitude = null;
public Rectangle CropRectangle = Rectangle.Empty; public Rectangle CropRectangle = Rectangle.Empty;
private static long touchCounter = 0; private static long touchCounter = 0;
@ -93,7 +174,6 @@ public class Photo {
string filename = System.IO.Path.Combine(directory, System.IO.Path.GetFileName(Filename)); string filename = System.IO.Path.Combine(directory, System.IO.Path.GetFileName(Filename));
Console.WriteLine("saving " + filename); Console.WriteLine("saving " + filename);
// FIXME: add comments / captions as ImageDescription? // FIXME: add comments / captions as ImageDescription?
// FIXME: strip some Exif tags for privacy reasons?
// FIXME: warn if the file already exists? // FIXME: warn if the file already exists?
using (Image<Rgba32> image = await Image.LoadAsync<Rgba32>(Filename)) { using (Image<Rgba32> image = await Image.LoadAsync<Rgba32>(Filename)) {
Util.RotateImageFromExif(image, Orientation); Util.RotateImageFromExif(image, Orientation);
@ -112,8 +192,20 @@ public class Photo {
"{0:D4}:{1:D2}:{2:D2} {3:D2}:{4:D2}:{5:D2}", "{0:D4}:{1:D2}:{2:D2} {3:D2}:{4:D2}:{5:D2}",
now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
exif.SetValue<string>(ExifTag.DateTime, datetime); exif.SetValue<string>(ExifTag.DateTime, datetime);
exif.SetValue<Rational[]>(ExifTag.GPSLatitude, GpsLatitude);
exif.SetValue<Rational[]>(ExifTag.GPSLongitude, GpsLongitude); if (Gps != null) {
GpsInfo gps = (GpsInfo) Gps;
exif.SetValue<byte[]>(ExifTag.GPSVersionID, gps.VersionId);
exif.SetValue<string>(ExifTag.GPSStatus, gps.Status);
exif.SetValue<string>(ExifTag.GPSDateStamp, gps.Datestamp);
exif.SetValue<Rational[]>(ExifTag.GPSTimestamp, gps.Timestamp);
exif.SetValue<Rational[]>(ExifTag.GPSLatitude, gps.Latitude);
exif.SetValue<string>(ExifTag.GPSLatitudeRef, gps.LatitudeRef);
exif.SetValue<Rational[]>(ExifTag.GPSLongitude, gps.Longitude);
exif.SetValue<string>(ExifTag.GPSLongitudeRef, gps.LongitudeRef);
exif.SetValue<Rational>(ExifTag.GPSAltitude, gps.Altitude);
exif.SetValue<byte>(ExifTag.GPSAltitudeRef, gps.AltitudeRef);
}
image.Metadata.XmpProfile = UpdateXmp(image.Metadata.XmpProfile); image.Metadata.XmpProfile = UpdateXmp(image.Metadata.XmpProfile);
@ -272,15 +364,7 @@ public class Photo {
} }
} }
IExifValue<Rational[]>? gpsLatitude; Gps = GpsInfo.ParseExif(exifs);
if (exifs.TryGetValue(ExifTag.GPSLatitude, out gpsLatitude)) {
GpsLatitude = gpsLatitude.Value;
}
IExifValue<Rational[]>? gpsLongitude;
if (exifs.TryGetValue(ExifTag.GPSLongitude, out gpsLongitude)) {
GpsLongitude = gpsLongitude.Value;
}
} }
public string GetShortLensModel(string lensModel) { public string GetShortLensModel(string lensModel) {

View File

@ -386,8 +386,8 @@ public class Game : GameWindow {
geometry = new UiGeometry(nwSettings.Size, STAR_FILLED.Size.X); geometry = new UiGeometry(nwSettings.Size, STAR_FILLED.Size.X);
} }
private static string outputRoot = @"c:\users\colin\desktop\totte-output"; // private static string outputRoot = @"c:\users\colin\desktop\totte-output";
// private static string outputRoot = @"c:\users\colin\pictures\photos"; private static string outputRoot = @"c:\users\colin\pictures\photos";
private static Texture TEXTURE_WHITE = new(new Image<Rgba32>(1, 1, new Rgba32(255, 255, 255))); private static Texture TEXTURE_WHITE = new(new Image<Rgba32>(1, 1, new Rgba32(255, 255, 255)));
private static Texture TEXTURE_BLACK = new(new Image<Rgba32>(1, 1, new Rgba32(0, 0, 0))); private static Texture TEXTURE_BLACK = new(new Image<Rgba32>(1, 1, new Rgba32(0, 0, 0)));
@ -687,8 +687,8 @@ public class Game : GameWindow {
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\photos-test\"); // string[] files = Directory.GetFiles(@"c:\users\colin\desktop\photos-test\");
// string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\14\"); // string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\14\");
// string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\23\"); // string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\23\");
string[] files = Directory.GetFiles(@"G:\DCIM\100EOSR6\"); // string[] files = Directory.GetFiles(@"G:\DCIM\100EOSR6\");
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\totte-output\2023\07\31"); string[] files = Directory.GetFiles(@"c:\users\colin\desktop\totte-output\2023\08\29");
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\import"); // string[] files = Directory.GetFiles(@"c:\users\colin\desktop\import");
// string[] files = Directory.GetFiles(@"C:\Users\colin\Pictures\photos\2018\06\23"); // string[] files = Directory.GetFiles(@"C:\Users\colin\Pictures\photos\2018\06\23");
// string[] files = Directory.GetFiles(@"C:\Users\colin\Desktop\Germany all\104D7000"); // string[] files = Directory.GetFiles(@"C:\Users\colin\Desktop\Germany all\104D7000");
@ -705,17 +705,15 @@ public class Game : GameWindow {
allPhotos.Sort(ComparePhotosByDate); allPhotos.Sort(ComparePhotosByDate);
// Fix up photos with missing GPS. // Fix up photos with missing GPS.
Rational[]? lastLatitude = null; GpsInfo? lastGps = null;
Rational[]? lastLongitude = null;
foreach (Photo p in allPhotos) { foreach (Photo p in allPhotos) {
if (p.GpsLatitude != null && p.GpsLongitude != null) { if (p.Gps != null) {
lastLatitude = p.GpsLatitude; lastGps = p.Gps;
lastLongitude = p.GpsLongitude;
} }
if (p.GpsLatitude == null || p.GpsLongitude == null) { if (p.Gps == null) {
// FIXME: should we take from the photo immediately _before_, or after?
Console.WriteLine("fixing GPS for " + p.Filename); Console.WriteLine("fixing GPS for " + p.Filename);
p.GpsLatitude = lastLatitude; p.Gps = lastGps;
p.GpsLongitude = lastLongitude;
} }
} }
photos = allPhotos; photos = allPhotos;