131 lines
4.3 KiB
C#
131 lines
4.3 KiB
C#
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using Blake3;
|
|
using Dalamud.Game.Command;
|
|
using Dalamud.Game.Text.SeStringHandling;
|
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
|
using Newtonsoft.Json;
|
|
using WebP.Net;
|
|
|
|
namespace Screenie;
|
|
|
|
internal class Command : IDisposable {
|
|
private Plugin Plugin { get; }
|
|
private const string CommandName = "/screenie";
|
|
|
|
internal Command(Plugin plugin) {
|
|
this.Plugin = plugin;
|
|
|
|
this.Plugin.CommandManager.AddHandler(CommandName, new CommandInfo(this.OnCommand));
|
|
}
|
|
|
|
public void Dispose() {
|
|
this.Plugin.CommandManager.RemoveHandler(CommandName);
|
|
}
|
|
|
|
private static ImageCodecInfo? GetEncoder(ImageFormat format) {
|
|
var codecs = ImageCodecInfo.GetImageEncoders();
|
|
return codecs.FirstOrDefault(codec => codec.FormatID == format.Guid);
|
|
}
|
|
|
|
|
|
private void OnCommand(string command, string arguments) {
|
|
// TODO: eventually be able to do like /screenie --no-ui --format png
|
|
// etc.
|
|
if (arguments == "config") {
|
|
this.Plugin.Ui.Visible ^= true;
|
|
return;
|
|
}
|
|
|
|
var meta = ScreenshotMetadata.Capture(this.Plugin);
|
|
var bitmapOuter = Photographer.Capture();
|
|
if (bitmapOuter == null) {
|
|
return;
|
|
}
|
|
|
|
Task.Factory.StartNew(async () => {
|
|
using var bitmap = bitmapOuter;
|
|
|
|
var saveAs = this.Plugin.Config.SaveFormat;
|
|
byte[] imageData;
|
|
string ext;
|
|
if (saveAs.ToImageFormat() is { } format) {
|
|
var data = this.SaveNative(format, bitmap);
|
|
if (data == null) {
|
|
return;
|
|
}
|
|
|
|
(imageData, ext) = data.Value;
|
|
} else if (saveAs is Format.WebpLossless or Format.WebpLossy) {
|
|
using var webp = new WebPObject(bitmap);
|
|
imageData = saveAs == Format.WebpLossless
|
|
? webp.GetWebPLossless()
|
|
: webp.GetWebPLossy(this.Plugin.Config.SaveFormatData);
|
|
ext = "webp";
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
string hash;
|
|
await using (var stream = new Blake3Stream(this.OpenFile(ext, meta))) {
|
|
await stream.WriteAsync(imageData);
|
|
hash = Convert.ToHexString(stream.ComputeHash().AsSpan());
|
|
}
|
|
|
|
meta.Blake3Hash = hash;
|
|
var json = JsonConvert.SerializeObject(meta, Formatting.Indented);
|
|
// TODO: save this info to database
|
|
Plugin.Log.Info(json);
|
|
|
|
var message = new SeStringBuilder()
|
|
.AddText("Screenshot saved. [")
|
|
.AddUiForeground(12)
|
|
.Add(this.Plugin.LinkHandlers.OpenFolder)
|
|
.AddText("Open folder")
|
|
.Add(RawPayload.LinkTerminator)
|
|
.AddUiForegroundOff()
|
|
.AddText("]")
|
|
.Build();
|
|
this.Plugin.ChatGui.Print(message);
|
|
});
|
|
}
|
|
|
|
private (byte[], string)? SaveNative(ImageFormat format, Image bitmap) {
|
|
var encoder = GetEncoder(format);
|
|
if (encoder == null) {
|
|
return null;
|
|
}
|
|
|
|
// ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
|
|
var (param, ext) = this.Plugin.Config.SaveFormat switch {
|
|
Format.Jpg => (Encoder.Quality, "jpg"),
|
|
Format.Png => (Encoder.Compression, "png"),
|
|
_ => throw new ArgumentException("not a native-save format", nameof(format)),
|
|
};
|
|
|
|
var parameters = new EncoderParameters(1) {
|
|
Param = [
|
|
new EncoderParameter(param, this.Plugin.Config.SaveFormatData),
|
|
],
|
|
};
|
|
|
|
using var stream = new MemoryStream();
|
|
bitmap.Save(stream, encoder, parameters);
|
|
return (stream.ToArray(), ext);
|
|
}
|
|
|
|
private FileStream OpenFile(string ext, ScreenshotMetadata meta) {
|
|
Directory.CreateDirectory(this.Plugin.Config.SaveDirectory);
|
|
|
|
var fileName = this.Plugin.Config.SaveFileNameTemplate.Render(meta).ReplaceLineEndings(" ");
|
|
|
|
var path = Path.Join(this.Plugin.Config.SaveDirectory, fileName);
|
|
path += $".{ext}";
|
|
|
|
var parent = Path.Join(path, "..");
|
|
Directory.CreateDirectory(parent);
|
|
|
|
return new FileStream(path, FileMode.Create, FileAccess.Write);
|
|
}
|
|
}
|