save rating in XMP data. also change default window size

This commit is contained in:
Colin McMillen 2023-07-31 20:50:53 -04:00
parent 9e03d8f2c5
commit 58a19d061d

View File

@ -15,6 +15,7 @@ using SixLabors.ImageSharp.Formats.Jpeg;
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml.Linq;
namespace SemiColinGames;
@ -199,8 +200,8 @@ public class Photo {
DateTimeOriginal = creationTime;
ImageInfo info = Image.Identify(filename);
Size = new(info.Size.Width, info.Size.Height);
Rating = ParseRating(info.Metadata.XmpProfile);
ParseExif(info.Metadata.ExifProfile);
TryParseRating(info.Metadata.XmpProfile, out Rating);
}
public async void LoadAsync() {
@ -221,7 +222,7 @@ public class Photo {
}
}
public async void SaveAsJpeg(string outputRoot, JpegEncoder encoder) {
public async void SaveAsJpegAsync(string outputRoot, JpegEncoder encoder) {
// FIXME: if nothing was changed about this image, just copy the file bytes directly, possibly with metadata changed?
string directory = System.IO.Path.Combine(
outputRoot,
@ -231,7 +232,7 @@ public class Photo {
Directory.CreateDirectory(directory);
string filename = System.IO.Path.Combine(directory, System.IO.Path.GetFileName(Filename));
Console.WriteLine("saving " + filename);
// FIXME: update Rating data.
// FIXME: what if we also saved Exif rating?
// FIXME: add comments / captions as ImageDescription?
// FIXME: strip some Exif tags for privacy reasons?
// FIXME: warn if the file already exists?
@ -249,31 +250,50 @@ public class Photo {
now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
exif.SetValue<string>(ExifTag.DateTime, datetime);
image.Metadata.XmpProfile = UpdateXmp(image.Metadata.XmpProfile);
await image.SaveAsync(filename, encoder);
}
}
private bool TryParseRating(XmpProfile? xmp, out int rating) {
rating = 0;
private XElement? GetXmpRoot(XmpProfile? xmp) {
if (xmp == null) {
return false;
return null;
}
XDocument? doc = xmp.GetDocument();
if (doc == null) {
return false;
return null;
}
XElement? root = doc.Root;
return doc.Root;
}
private int ParseRating(XmpProfile? xmp) {
XElement? root = GetXmpRoot(xmp);
if (root == null) {
return false;
return 0;
}
foreach (XElement elt in root.Descendants()) {
if (elt.Name == "{http://ns.adobe.com/xap/1.0/}Rating") {
int rating = 0;
if (int.TryParse(elt.Value, out rating)) {
return true;
return rating;
}
}
}
return false;
return 0;
}
private XmpProfile? UpdateXmp(XmpProfile? xmp) {
if (xmp == null) {
return null;
}
string xmlIn = Encoding.UTF8.GetString(xmp.ToByteArray());
int index = xmlIn.IndexOf("</xmp:Rating>");
if (index == -1) {
return xmp;
}
string xmlOut = xmlIn.Substring(0, index - 1) + Rating.ToString() + xmlIn.Substring(index);
return new XmpProfile(Encoding.UTF8.GetBytes(xmlOut));
}
// Exif (and other image metadata) reference, from the now-defunct Metadata Working Group:
@ -627,6 +647,7 @@ public class Game : GameWindow {
bool ctrlIsDown = input.IsKeyDown(Keys.LeftControl) || input.IsKeyDown(Keys.RightControl);
// FIXME: add a confirm dialog before closing. (Also for the window-close button.)
// FIXME: don't quit if there's pending file-write operations.
// Close when Escape is pressed.
if (input.IsKeyPressed(Keys.Escape)) {
Close();
@ -826,7 +847,7 @@ public class Game : GameWindow {
// 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\desktop\totte-output\2023\07\28");
// string[] files = Directory.GetFiles(@"c:\users\colin\desktop\totte-output\2023\07\31");
// 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\");
@ -913,9 +934,10 @@ public class Game : GameWindow {
// FIXME: show a progress bar or something.
private async void ExportPhotos() {
JpegEncoder encoder = new JpegEncoder() { Quality = 100 };
string outputRoot = @"c:\users\colin\pictures\photos\";
string outputRoot = @"c:\users\colin\desktop\totte-output";
// string outputRoot = @"c:\users\colin\pictures\photos";
foreach (Photo p in photos) {
await Task.Run( () => { p.SaveAsJpeg(outputRoot, encoder); });
await Task.Run( () => { p.SaveAsJpegAsync(outputRoot, encoder); });
}
}
@ -1088,7 +1110,8 @@ static class Program {
nwSettings.WindowState = WindowState.Normal;
nwSettings.CurrentMonitor = bestMonitor.Handle;
nwSettings.Location = new Vector2i(bestMonitor.WorkArea.Min.X + 1, bestMonitor.WorkArea.Min.Y + 31);
nwSettings.Size = new Vector2i(bestMonitor.WorkArea.Size.X - 2, bestMonitor.WorkArea.Size.Y - 32);
// nwSettings.Size = new Vector2i(bestMonitor.WorkArea.Size.X - 2, bestMonitor.WorkArea.Size.Y - 32);
nwSettings.Size = new Vector2i(1600, 900);
nwSettings.MinimumSize = UiGeometry.MIN_WINDOW_SIZE;
nwSettings.Title = "Totte";
nwSettings.IsEventDriven = false;