1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using ImageMagick;
using Microsoft.AspNetCore.Mvc;
namespace Spacebar.AdminApi.TestClient.Services.Services;
public class DiscordImageResizeParams {
public uint? Size { get; set; }
public DiscordImageResizeQuality Quality { get; set; } = DiscordImageResizeQuality.High;
public bool KeepAspectRatio { get; set; } = true;
public bool Passthrough { get; set; } = true;
public bool Animated { get; set; } = true;
public bool SpacebarAllowUpscale { get; set; } = false;
public bool SpacebarOptimiseGif { get; set; } = true;
public string Format { get; set; } = "webp";
public string ToSerializedName() {
return $"{(Animated ? "a_" : "")}{Size}px_{Quality.ToString()}_u.{SpacebarAllowUpscale}_o.{SpacebarOptimiseGif}.{Format}";
}
}
public static class HttpRequestExtensions {
extension(HttpRequest request) {
public DiscordImageResizeParams GetResizeParams() {
return new() {
Size = request.Query.ContainsKey("size") && uint.TryParse(request.Query["size"], out uint size) ? size : null,
Quality = request.Query.ContainsKey("quality") && Enum.TryParse<DiscordImageResizeQuality>(request.Query["quality"], true, out var quality)
? quality
: DiscordImageResizeQuality.High,
KeepAspectRatio = !request.Query.ContainsKey("keepAspectRatio") || !bool.TryParse(request.Query["keepAspectRatio"], out bool kar) || kar,
Passthrough = request.Query.ContainsKey("passthrough") && bool.TryParse(request.Query["passthrough"], out bool pt) && pt,
Animated = request.Query.ContainsKey("animated") && bool.TryParse(request.Query["animated"], out bool an) && an,
SpacebarAllowUpscale = request.Query.ContainsKey("allowUpscale") && bool.TryParse(request.Query["allowUpscale"], out bool au) && au,
SpacebarOptimiseGif = request.Query.ContainsKey("optimiseGif") && bool.TryParse(request.Query["optimiseGif"], out bool og) && og,
Format = request.Query.ContainsKey("format") ? request.Query["format"]! : "webp",
};
}
}
extension (HttpResponse response) {
public void SetSuccessCacheHeader() {
int cacheDuration = (int)TimeSpan.FromHours(6).TotalSeconds;
response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable";
}
public void SetFailureCacheHeader() {
int cacheDuration = (int)TimeSpan.FromMinutes(5).TotalSeconds;
response.Headers.CacheControl = $"public, max-age={cacheDuration}, s-maxage={cacheDuration}, immutable";
}
}
}
public enum DiscordImageResizeQuality {
[EnumMember(Value = "low")] Low,
[EnumMember(Value = "high")] High,
[EnumMember(Value = "lossless")] Lossless
}
public class DiscordImageResizeService {
//(PixelArtDetectionService pads) {
[SuppressMessage("ReSharper", "AccessToModifiedClosure")]
public async Task<MagickImageCollection> Apply(MagickImageCollection img, DiscordImageResizeParams resizeParams) {
if (resizeParams.Passthrough) return img;
if (img.First().Format == MagickFormat.Gif) {
var t = new Thread(() => {
Console.WriteLine("Coalescing gif for resize");
img.Coalesce();
});
t.Start();
while (t.IsAlive) await Task.Delay(100);
}
if (!resizeParams.Animated) {
var oldImg = img;
img = new MagickImageCollection([oldImg.First().Clone()]);
oldImg.Dispose();
}
if (resizeParams.Size.HasValue) {
if (resizeParams.Size > 4096)
resizeParams.Size = 4096;
if (img.Max(x => Math.Max(x.Height, x.Width)) > resizeParams.Size || resizeParams.SpacebarAllowUpscale) {
Parallel.ForEach(img, new ParallelOptions() { MaxDegreeOfParallelism = 16 }, frame => {
if (resizeParams.Size.HasValue) {
uint oldWidth = frame.Width, oldHeight = frame.Height;
// pads.IsPixelArt(frame)
frame.Resize(resizeParams.Size.Value, resizeParams.Size.Value,
resizeParams.Quality == DiscordImageResizeQuality.Low ? FilterType.Point : FilterType.Gaussian);
Console.WriteLine($"Resized frame from {oldWidth}x{oldHeight} to {frame.Width}x{frame.Height}: {img.IndexOf(frame)+1}/{img.Count}");
}
});
}
}
if (img.First().Format == MagickFormat.Gif && resizeParams.SpacebarOptimiseGif) {
var t = new Thread(() => {
Console.WriteLine("Optimizing gif after resize");
img.OptimizePlus();
});
t.Start();
while (t.IsAlive) await Task.Delay(100);
}
return img;
}
}
|