|
|
@ -9,6 +9,88 @@ using System.Xml.Linq; |
|
|
|
|
|
|
|
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 string Filename; |
|
|
|
public bool Loaded = false; |
|
|
@ -24,8 +106,7 @@ public class Photo { |
|
|
|
public string IsoSpeed = "<unk>"; |
|
|
|
public int Rating = 0; |
|
|
|
public ushort Orientation = 1; |
|
|
|
public Rational[]? GpsLatitude = null; |
|
|
|
public Rational[]? GpsLongitude = null; |
|
|
|
public GpsInfo? Gps = null; |
|
|
|
public Rectangle CropRectangle = Rectangle.Empty; |
|
|
|
|
|
|
|
private static long touchCounter = 0; |
|
|
@ -93,7 +174,6 @@ public class Photo { |
|
|
|
string filename = System.IO.Path.Combine(directory, System.IO.Path.GetFileName(Filename)); |
|
|
|
Console.WriteLine("saving " + filename); |
|
|
|
// FIXME: add comments / captions as ImageDescription?
|
|
|
|
// FIXME: strip some Exif tags for privacy reasons?
|
|
|
|
// FIXME: warn if the file already exists?
|
|
|
|
using (Image<Rgba32> image = await Image.LoadAsync<Rgba32>(Filename)) { |
|
|
|
Util.RotateImageFromExif(image, Orientation); |
|
|
@ -112,8 +192,20 @@ public class Photo { |
|
|
|
"{0:D4}:{1:D2}:{2:D2} {3:D2}:{4:D2}:{5:D2}", |
|
|
|
now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); |
|
|
|
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); |
|
|
|
|
|
|
@ -272,15 +364,7 @@ public class Photo { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
IExifValue<Rational[]>? gpsLatitude; |
|
|
|
if (exifs.TryGetValue(ExifTag.GPSLatitude, out gpsLatitude)) { |
|
|
|
GpsLatitude = gpsLatitude.Value; |
|
|
|
} |
|
|
|
|
|
|
|
IExifValue<Rational[]>? gpsLongitude; |
|
|
|
if (exifs.TryGetValue(ExifTag.GPSLongitude, out gpsLongitude)) { |
|
|
|
GpsLongitude = gpsLongitude.Value; |
|
|
|
} |
|
|
|
Gps = GpsInfo.ParseExif(exifs); |
|
|
|
} |
|
|
|
|
|
|
|
public string GetShortLensModel(string lensModel) { |
|
|
|