-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.cs
105 lines (86 loc) · 5.3 KB
/
Program.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
using System;
using System.IO;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.ImageSharp.Drawing.Processing;
namespace Tiler
{
class Program
{
static void Main(string[] args)
{
var commandline = args.
Select((x, i) => new { index = i, option = x }).
Where(x => x.option.StartsWith("-")).
Select(x => new
{
option = x.option[1..],
arguments = args.
Skip(x.index + 1).
TakeWhile(m => !m.StartsWith("-")).ToArray()
}).
ToDictionary(x => x.option.ToLower(), x => x.arguments);
if (args.Length == 0 || commandline.ContainsKey("h") || commandline.ContainsKey("help"))
{
var Executable = new FileInfo(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName ?? "Tiler.exe").Name;
if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
Executable = $"./{Executable}";
Console.Write("Tiler XYZ tile maker v1.0\n" +
"Usage:\n" +
$"{Executable} image.jpg\n" +
" or\n" +
$"{Executable} -input image.jpg -size 256 -zoom 6 -filename \"image.jpg-tiles{Path.DirectorySeparatorChar}{{z}}_{{x}}_{{y}}.png\"\n");
return;
}
var sourceFile = commandline.Count == 0 && args.Length > 0 ? args[0] : commandline["input"].First();
int tile_size = commandline.ContainsKey("size") ? int.Parse(commandline["size"].First()) : 256;
using var OriginalSource = commandline.ContainsKey("stdin") ? Image.Load(Console.OpenStandardInput()) : Image.Load(sourceFile);
int maxzoom = commandline.ContainsKey("zoom") ? int.Parse(commandline["zoom"].First()) :
((int)Math.Ceiling(Math.Log(Math.Max(OriginalSource.Width, OriginalSource.Height) / (double)tile_size)) + 1); // auto detect max level
for (int zoom = 0; zoom <= maxzoom; zoom++)
{
int tiles = (int)Math.Pow(2.0, zoom);
int size = tiles * tile_size;
using var Scaled = new Image<Rgba32>(size, size);
Scaled.Mutate(i => i.Clear(Color.Transparent)); // Clear the background to transparent
int width, height;
if (OriginalSource.Width > OriginalSource.Height) // Calculate the right scale ratio
(width, height) = (Scaled.Width, Scaled.Width * OriginalSource.Height / OriginalSource.Width);
else
(height, width) = (Scaled.Height, Scaled.Height * OriginalSource.Width / OriginalSource.Height);
var Sampler = // Use Lanczos3 for reducing, Bicubic for upscaling
width < OriginalSource.Width || height < OriginalSource.Height
? (IResampler)new LanczosResampler(3.0f)
: (IResampler)new BicubicResampler();
// Scale the entire image
using (Image<Rgba32> Rescaled = new Image<Rgba32>(OriginalSource.Width, OriginalSource.Height))
{
Rescaled.Mutate(x => x.DrawImage(OriginalSource, new Point(0, 0), 1.0f).Resize(width, height, Sampler));
Scaled.Mutate(x => x.DrawImage(Rescaled, new Point((Scaled.Width - width) / 2, (Scaled.Height - height) / 2), new GraphicsOptions()));
}
// Take tiles from it
Enumerable.Range(0, tiles).SelectMany(x => Enumerable.Range(0, tiles).Select(y => new { x, y })).AsParallel().WithDegreeOfParallelism(8).ForAll((c) =>
{
using var Tile = new Image<Rgba32>(tile_size, tile_size);
lock (Scaled)
Tile.Mutate(x => x.DrawImage(Scaled.Clone(x => x.Crop(new Rectangle(c.x * tile_size, c.y * tile_size, tile_size, tile_size))), new Point(0, 0), new GraphicsOptions()));
var Variables = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase) { { "z", zoom }, { "x", c.x }, { "y", c.y } };
var Filename = Regex.Replace(
commandline.ContainsKey("filename") && commandline["filename"].Length > 0
? commandline["filename"].First()
: $"{sourceFile}-tiles{Path.DirectorySeparatorChar}{{z}}_{{x}}_{{y}}.png",
@"{(?<var>[^}]+)}", new MatchEvaluator(m => $"{Variables[m.Groups["var"].Value]}"));
var OutputDirectory = Path.GetDirectoryName(Filename);
if (OutputDirectory != null && !Directory.Exists(OutputDirectory))
Directory.CreateDirectory(OutputDirectory);
Tile.Save(Filename);
});
}
}
}
}