save rating in XMP data. also change default window size
This commit is contained in:
parent
9e03d8f2c5
commit
58a19d061d
53
Program.cs
53
Program.cs
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user