-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Inkify.cs
132 lines (113 loc) · 3.61 KB
/
Inkify.cs
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using cmdwtf.Dithering.ColorReduction;
using cmdwtf.Dithering.Transforms;
using Microsoft.Extensions.Logging;
namespace Inkify
{
internal class Inkify
{
private record TransformResult(FileInfo Input, IErrorDiffusion Ditherer, Bitmap Bitmap);
private ImageTransformer Transformer { get; init; }
private ILogger Logger { get; init; }
public Inkify(ImageTransformer transformer, ILogger<Inkify> logger)
{
Transformer = transformer;
Logger = logger;
}
public async Task<int> RunTransformation(InkifyOptions options)
{
int targetTransformationCount = options.Input.Length * options.Ditherers.Length;
int successfulTransforms = 0;
bool generateOutputNames = false;
if (targetTransformationCount > 1 && options.Output is not null)
{
Logger.LogCritical("More than one input file specified with an output option also specified." + Environment.NewLine +
"No output option may be specified for converting multiple input files.");
return -1;
}
if (targetTransformationCount > 1 || options.Output is null)
{
generateOutputNames = true;
}
await foreach (TransformResult result in GetTransformedImages(options))
{
FileInfo output;
if (generateOutputNames || options.Output is null)
{
string outputDirectory =
result.Input.DirectoryName ?? throw new InvalidOperationException("DirectoryName was null.");
string outputBaseName = Path.GetFileNameWithoutExtension(result.Input.Name);
string saturation = options.Saturation == 0 ? string.Empty : $"{options.Saturation}";
string runName = $"{options.Device}{saturation}.{result.Ditherer.Name}";
string outputPath = Path.Combine(outputDirectory, $"{outputBaseName}.{runName}.png");
output = new FileInfo(outputPath);
}
else
{
output = options.Output;
}
if (SavePng(result.Bitmap, output))
{
successfulTransforms++;
Logger.LogInformation("Wrote image to `{output}`", output.FullName);
}
result.Bitmap.Dispose();
}
return targetTransformationCount - successfulTransforms;
}
private async IAsyncEnumerable<TransformResult> GetTransformedImages(InkifyOptions options)
{
foreach (FileInfo input in options.Input)
{
foreach (IErrorDiffusion ditherer in options.Ditherers)
{
var job = new ImageTransformJob(input, options.Device, ditherer)
{
CustomTransform = options.Saturation != 0
? SimpleIndexedPalettePixelTransformInky.InkyImpression7Blended(options.Saturation)
: null
};
Bitmap? transformedBitmap = await Transformer.TransformAsync(job);
if (transformedBitmap is not null)
{
yield return new TransformResult(input, ditherer, transformedBitmap);
}
}
}
}
private bool SavePng(Bitmap bitmap, FileInfo file)
{
try
{
ImageCodecInfo? pngEncoder = GetEncoder(ImageFormat.Png);
var encoderParams = new EncoderParameters()
{
Param = new EncoderParameter[]
{
new(Encoder.ColorDepth, 8),
}
};
bitmap.Save(file.FullName, pngEncoder, encoderParams);
return true;
}
catch (Exception ex)
{
Logger.LogCritical("Failed to save png: {msg}", ex.Message);
return false;
}
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo? ici = ImageCodecInfo
.GetImageEncoders()
.FirstOrDefault(c => c.FormatID == format.Guid);
return ici ?? throw new NotImplementedException($"Couldn't get encoder for {format}.");
}
}
}