QuickImage – Rev 2
?pathlinks?
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using ImageMagick;
using ImageMagick.Formats;
using QuickImage.Utilities;
using Serilog;
namespace QuickImage
{
public class TagManager
{
private readonly MagickReadSettings _magickReaderSettings;
private readonly FileMutex _fileMutex;
private TagManager()
{
_magickReaderSettings = new MagickReadSettings { FrameIndex = 0, FrameCount = 1 };
}
public TagManager(FileMutex fileMutex) : this()
{
_fileMutex = fileMutex;
}
public async Task<bool> StripIptcProfile(string fileName, CancellationToken cancellationToken)
{
await _fileMutex[fileName].WaitAsync(cancellationToken);
try
{
using var imageCollection = new MagickImageCollection(fileName);
using var image = imageCollection[0];
var profile = image.GetIptcProfile();
if (profile == null)
{
return true;
}
image.RemoveProfile(profile);
await imageCollection.WriteAsync(fileName, cancellationToken);
return true;
}
catch (Exception exception)
{
Log.Error(exception, "Could not add keywords.");
}
finally
{
_fileMutex[fileName].Release();
}
return false;
}
public async Task<bool> AddIptcKeywords(string fileName, IEnumerable<string> keywords,
CancellationToken cancellationToken)
{
await _fileMutex[fileName].WaitAsync(cancellationToken);
try
{
using var imageCollection = new MagickImageCollection(fileName);
using var image = imageCollection[0];
var profile = image.GetIptcProfile();
if (profile == null)
{
profile = new IptcProfile();
foreach (var keyword in keywords)
{
profile.SetValue(IptcTag.Keyword, keyword);
}
image.SetProfile(profile);
await imageCollection.WriteAsync(fileName, cancellationToken);
return true;
}
var union = keywords.Union(profile.GetAllValues(IptcTag.Keyword).Select(iptcValue => iptcValue.Value),
StringComparer.Ordinal).ToList();
profile.RemoveValue(IptcTag.Keyword);
foreach (var keyword in union)
{
profile.SetValue(IptcTag.Keyword, keyword);
}
image.SetProfile(profile);
using var writeStream = new FileStream(fileName, FileMode.OpenOrCreate);
await imageCollection.WriteAsync(writeStream, cancellationToken);
return true;
}
catch (Exception exception)
{
Log.Error(exception, "Could not add keywords.");
}
finally
{
_fileMutex[fileName].Release();
}
return false;
}
public async Task<bool> RemoveIptcKeywords(string fileName, IEnumerable<string> keywords, CancellationToken cancellationToken)
{
await _fileMutex[fileName].WaitAsync(cancellationToken);
try
{
using var imageCollection = new MagickImageCollection(fileName);
using var image = imageCollection[0];
var profile = image.GetIptcProfile();
if (profile == null)
{
return true;
}
foreach (var keyword in keywords)
{
profile.RemoveValue(IptcTag.Keyword, keyword);
}
image.SetProfile(profile);
imageCollection.Optimize();
await imageCollection.WriteAsync(fileName, cancellationToken);
return true;
}
catch (Exception exception)
{
Log.Error(exception, "Could not remove keywords.");
}
finally
{
_fileMutex[fileName].Release();
}
return false;
}
public async IAsyncEnumerable<string> GetIptcKeywords(string fileName, [EnumeratorCancellation] CancellationToken cancellationToken)
{
await _fileMutex[fileName].WaitAsync(cancellationToken);
try
{
using var imageCollection = new MagickImageCollection(fileName, _magickReaderSettings);
using var image = imageCollection[0];
var profile = image.GetIptcProfile();
if (profile == null)
{
yield break;
}
foreach (var keyword in profile.GetAllValues(IptcTag.Keyword))
{
yield return keyword.Value;
}
}
finally
{
_fileMutex[fileName].Release();
}
}
public IEnumerable<string> GetIptcKeywords(IMagickImage<ushort> imageFrame)
{
var profile = imageFrame.GetIptcProfile();
if (profile == null)
{
yield break;
}
foreach (var keyword in profile.GetAllValues(IptcTag.Keyword))
{
yield return keyword.Value;
}
}
}
}