186 lines
7.6 KiB
C#
186 lines
7.6 KiB
C#
using System.Numerics;
|
|
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
|
|
namespace SDFMapCreator;
|
|
|
|
public static class ImageUtil {
|
|
public static T[,] LoadImage<T>(string path) where T : struct, IEquatable<T> {
|
|
var image = SixLabors.ImageSharp.Image.Load(path);
|
|
using var image16 = image as Image<Rgba64> ?? throw new NotSupportedException($"Image format not supported");
|
|
int width = image.Width;
|
|
int height = image.Height;
|
|
//result = new T[image.Width, image.Height];
|
|
return image switch {
|
|
Image<Rgba64> img => img.ProcessPixelsRgba64<T>(),
|
|
Image<Rgb24> img => img.ProcessPixelsRgb24<T>(),
|
|
Image<Rgba32> img => img.ProcessPixelsRgba32<T>(),
|
|
Image<Rgb48> img => img.ProcessPixelsRgb48<T>(),
|
|
_ => throw new NotSupportedException($"Image format not supported")
|
|
};
|
|
}
|
|
|
|
static T[,] ProcessPixelsRgba64<T>(this Image<Rgba64> image) where T : struct, IEquatable<T> {
|
|
int width = image.Width;
|
|
int height = image.Height;
|
|
var result = new T[image.Width, image.Height];
|
|
image.ProcessPixelRows(accessor => {
|
|
//we use Y as the row index and X as the column index
|
|
for (int y = 0; y < height; y++) {
|
|
var span = accessor.GetRowSpan(y);
|
|
for (int x = 0; x < width; x++) {
|
|
switch (result) {
|
|
case float[,] f:
|
|
f[x, y] = span[x].R;
|
|
break;
|
|
case Vector2[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G);
|
|
break;
|
|
case Vector3[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
|
break;
|
|
case Vector4[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
static T[,] ProcessPixelsRgb24<T>(this Image<Rgb24> image) where T : struct, IEquatable<T> {
|
|
int width = image.Width;
|
|
int height = image.Height;
|
|
var result = new T[image.Width, image.Height];
|
|
image.ProcessPixelRows(accessor => {
|
|
//we use Y as the row index and X as the column index
|
|
for (int y = 0; y < height; y++) {
|
|
var span = accessor.GetRowSpan(y);
|
|
for (int x = 0; x < width; x++) {
|
|
switch (result) {
|
|
case float[,] f:
|
|
f[x, y] = span[x].R;
|
|
break;
|
|
case Vector2[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G);
|
|
break;
|
|
case Vector3[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
|
break;
|
|
case Vector4[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
static T[,] ProcessPixelsRgba32<T>(this Image<Rgba32> image) where T : struct, IEquatable<T> {
|
|
int width = image.Width;
|
|
int height = image.Height;
|
|
var result = new T[image.Width, image.Height];
|
|
image.ProcessPixelRows(accessor => {
|
|
//we use Y as the row index and X as the column index
|
|
for (int y = 0; y < height; y++) {
|
|
var span = accessor.GetRowSpan(y);
|
|
for (int x = 0; x < width; x++) {
|
|
switch (result) {
|
|
case float[,] f:
|
|
f[x, y] = span[x].R;
|
|
break;
|
|
case Vector2[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G);
|
|
break;
|
|
case Vector3[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
|
break;
|
|
case Vector4[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
static T[,] ProcessPixelsRgb48<T>(this Image<Rgb48> image) where T : struct, IEquatable<T> {
|
|
using var image16 = image as Image<Rgb48> ?? throw new NotSupportedException($"Image format not supported");
|
|
int width = image.Width;
|
|
int height = image.Height;
|
|
var result = new T[image.Width, image.Height];
|
|
image16.ProcessPixelRows(accessor => {
|
|
//we use Y as the row index and X as the column index
|
|
for (int y = 0; y < height; y++) {
|
|
var span = accessor.GetRowSpan(y);
|
|
for (int x = 0; x < width; x++) {
|
|
switch (result) {
|
|
case float[,] f:
|
|
f[x, y] = span[x].R;
|
|
break;
|
|
case Vector2[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G);
|
|
break;
|
|
case Vector3[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B);
|
|
break;
|
|
case Vector4[,] f:
|
|
f[x, y] = new(span[x].R, span[x].G, span[x].B, 1f);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
public static void SaveImage<T>(this T[,] array, string path) where T : struct, IEquatable<T> {
|
|
var width = array.GetLength(0);
|
|
var height = array.GetLength(1);
|
|
uint channels = array switch {
|
|
float[,] => 1,
|
|
Vector2[,] => 2,
|
|
Vector3[,] => 3,
|
|
Vector4[,] => 4,
|
|
_ => throw new NotSupportedException($"Type {typeof(T)} is not supported.")
|
|
};
|
|
Console.Write($"Writing image {path}...");
|
|
using Image<Rgb48> image = new(width, height);
|
|
image.ProcessPixelRows(accessor => {
|
|
for (int y = 0; y < height; y++) {
|
|
var span = accessor.GetRowSpan(y);
|
|
for (int x = 0; x < width; x++) {
|
|
switch (array) {
|
|
case float[,] f:
|
|
span[x] = new Rgb48((ushort)f[x, y], (ushort)f[x, y], (ushort)f[x,y]);
|
|
break;
|
|
case Vector2[,] f:
|
|
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, 0);
|
|
break;
|
|
case Vector3[,] f:
|
|
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
|
|
break;
|
|
case Vector4[,] f:
|
|
span[x] = new Rgb48((ushort)f[x,y].X, (ushort)f[x,y].Y, (ushort)f[x,y].Z);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
Console.WriteLine($"Done!");
|
|
image.Save(path);
|
|
}
|
|
|
|
private static void ImageData(SixLabors.ImageSharp.Image image1, string path) {
|
|
Console.WriteLine(
|
|
$"""
|
|
Image file: {path}
|
|
Resolution: {image1.Width}x{image1.Height}
|
|
Total Pixels: {image1.Width*image1.Height} |{"NaN"} channels, {image1.PixelType.BitsPerPixel/4} bits per channel
|
|
|
|
""");
|
|
}
|
|
} |