sort photos by creation time
This commit is contained in:
parent
af4827a127
commit
3b85c5d21a
74
Program.cs
74
Program.cs
@ -147,9 +147,10 @@ void main() {
|
||||
|
||||
// FIXME: this should probably be IDisposable?
|
||||
public class Photo {
|
||||
public string File;
|
||||
public string Filename;
|
||||
public bool Loaded = false;
|
||||
public Vector2i Size;
|
||||
public DateTime DateTimeOriginal;
|
||||
public string CameraModel = "";
|
||||
public string LensModel = "";
|
||||
public string FocalLength = "<unk>";
|
||||
@ -163,12 +164,14 @@ public class Photo {
|
||||
private Texture placeholder;
|
||||
private Image<Rgba32>? image = null;
|
||||
|
||||
public Photo(string file, Texture placeholder) {
|
||||
File = file;
|
||||
public Photo(string filename, Texture placeholder) {
|
||||
Filename = filename;
|
||||
this.placeholder = placeholder;
|
||||
texture = placeholder;
|
||||
|
||||
ImageInfo info = Image.Identify(file);
|
||||
DateTime creationTime = File.GetCreationTime(filename); // Local time.
|
||||
DateTimeOriginal = creationTime;
|
||||
ImageInfo info = Image.Identify(filename);
|
||||
Size = new(info.Size.Width, info.Size.Height);
|
||||
ParseExif(info.Metadata.ExifProfile);
|
||||
TryParseRating(info.Metadata.XmpProfile, out Rating);
|
||||
@ -178,7 +181,7 @@ public class Photo {
|
||||
// We don't assign to this.image until Load() is done, because we might
|
||||
// edit the image due to rotation (etc) and don't want to try generating
|
||||
// a texture for it until that's already happened.
|
||||
Image<Rgba32> tmp = await Image.LoadAsync<Rgba32>(File);
|
||||
Image<Rgba32> tmp = await Image.LoadAsync<Rgba32>(Filename);
|
||||
Util.RotateImageFromExif(tmp, Orientation);
|
||||
image = tmp;
|
||||
}
|
||||
@ -206,14 +209,34 @@ public class Photo {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exif (and other image metadata) reference, from the now-defunct Metadata Working Group:
|
||||
// https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf
|
||||
//
|
||||
// Specifically:
|
||||
//
|
||||
// In general, date/time metadata is being used to describe the following scenarios:
|
||||
// * Date/time original specifies when a photo was taken
|
||||
// * Date/time digitized specifies when an image was digitized
|
||||
// * Date/time modified specifies when a file was modified by the user
|
||||
//
|
||||
// Original Date/Time – Creation date of the intellectual content (e.g. the photograph), rather than the creation date of the content being shown
|
||||
// Exif DateTimeOriginal (36867, 0x9003) and SubSecTimeOriginal (37521, 0x9291)
|
||||
// IPTC DateCreated (IIM 2:55, 0x0237) and TimeCreated (IIM 2:60, 0x023C)
|
||||
// XMP (photoshop:DateCreated)
|
||||
//
|
||||
// Digitized Date/Time – Creation date of the digital representation
|
||||
// Exif DateTimeDigitized (36868, 0x9004) and SubSecTimeDigitized (37522, 0x9292)
|
||||
// IPTC DigitalCreationDate (IIM 2:62, 0x023E) and DigitalCreationTime (IIM 2:63, 0x023F)
|
||||
// XMP (xmp:CreateDate)
|
||||
//
|
||||
// Modification Date/Time – Modification date of the digital image file
|
||||
// Exif DateTime (306, 0x132) and SubSecTime (37520, 0x9290)
|
||||
// XMP (xmp:ModifyDate)
|
||||
private void ParseExif(ExifProfile? exifs) {
|
||||
if (exifs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: when we write out images, we'll want to correct the Exif Orientation to 1.
|
||||
// FIXME: handle date shot / edited (and sort by shot date?)
|
||||
|
||||
IExifValue<ushort>? orientation;
|
||||
if (exifs.TryGetValue(ExifTag.Orientation, out orientation)) {
|
||||
Orientation = orientation.Value;
|
||||
@ -281,6 +304,23 @@ public class Photo {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: I think the iPhone stores time in UTC but other cameras report it in local time.
|
||||
IExifValue<string>? dateTimeOriginal;
|
||||
if (exifs.TryGetValue(ExifTag.DateTimeOriginal, out dateTimeOriginal)) {
|
||||
DateTime date;
|
||||
if (DateTime.TryParseExact(
|
||||
dateTimeOriginal.Value ?? "",
|
||||
"yyyy:MM:dd HH:mm:ss",
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
System.Globalization.DateTimeStyles.AssumeLocal,
|
||||
out date)) {
|
||||
DateTimeOriginal = date;
|
||||
} else {
|
||||
Console.WriteLine($"*** WARNING: unexpected DateTimeOriginal value: {dateTimeOriginal.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
// foreach (IExifValue exif in exifs.Values) {
|
||||
// Console.WriteLine(exif.Tag.ToString() + " " + exif.GetValue().ToString());
|
||||
// }
|
||||
@ -301,7 +341,7 @@ public class Photo {
|
||||
|
||||
public string Description() {
|
||||
string shootingInfo = $"{FocalLength}, {FNumber} at {ExposureTime}, {IsoSpeed}";
|
||||
return String.Format("{0,-40} {1,-50} {2}", shootingInfo, $"{CameraModel} {LensModel}", File);
|
||||
return String.Format("{0,-40} {1,-50} {2}", shootingInfo, $"{CameraModel} {LensModel}", Filename);
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,8 +643,8 @@ public class Game : GameWindow {
|
||||
|
||||
// Load textures from JPEGs.
|
||||
// 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(@"G:\DCIM\100EOSR6\");
|
||||
string[] files = Directory.GetFiles(@"c:\users\colin\pictures\photos\2023\07\14\");
|
||||
// string[] files = Directory.GetFiles(@"G:\DCIM\100EOSR6\");
|
||||
// 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\many-birds\");
|
||||
@ -617,11 +657,23 @@ public class Game : GameWindow {
|
||||
}
|
||||
}
|
||||
|
||||
photos.Sort(ComparePhotosByDate);
|
||||
|
||||
for (int i = 0; i < 40 && i < photos.Count; i++) {
|
||||
await Task.Run( () => { photos[i].Load(); });
|
||||
}
|
||||
}
|
||||
|
||||
private static int ComparePhotosByDate(Photo x, Photo y) {
|
||||
int compare = x.DateTimeOriginal.CompareTo(y.DateTimeOriginal);
|
||||
if (compare != 0) {
|
||||
return compare;
|
||||
}
|
||||
// If the photos have the same seconds value, sort by filename
|
||||
// (since cameras usually increment the filename for successive shots.)
|
||||
return x.Filename.CompareTo(y.Filename);
|
||||
}
|
||||
|
||||
protected override void OnUnload() {
|
||||
base.OnUnload();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user