Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/NesTiler.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'NesTiler/ColorFinder.cs')
-rw-r--r--NesTiler/ColorFinder.cs388
1 files changed, 194 insertions, 194 deletions
diff --git a/NesTiler/ColorFinder.cs b/NesTiler/ColorFinder.cs
index 257e9b1..0a615cb 100644
--- a/NesTiler/ColorFinder.cs
+++ b/NesTiler/ColorFinder.cs
@@ -1,194 +1,194 @@
-using SkiaSharp;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Text.Json;
-
-namespace com.clusterrr.Famicom.NesTiler
-{
- class ColorFinder
- {
- static byte[] FORBIDDEN_COLORS = { 0x0D, 0x0E, 0x0F, 0x1E, 0x1F, 0x2E, 0x2F, 0x3E, 0x3F };
-
- public readonly Dictionary<byte, SKColor> Colors;
- private readonly Dictionary<SKColor, byte> cache = new();
-
- public ColorFinder(string filename)
- {
- this.Colors = LoadColors(filename);
- }
-
- private static Dictionary<byte, SKColor> LoadColors(string filename)
- {
- Trace.WriteLine($"Loading colors from {filename}...");
- if (!File.Exists(filename)) throw new FileNotFoundException($"Could not find file '{filename}'.", filename);
- var data = File.ReadAllBytes(filename);
- Dictionary<byte, SKColor> nesColors;
- // Detect file type
- if ((Path.GetExtension(filename) == ".pal") || ((data.Length == 192 || data.Length == 1536) && data.Where(b => b >= 128).Any()))
- {
- // Binary file
- nesColors = new Dictionary<byte, SKColor>();
- for (byte c = 0; c < 64; c++)
- {
- var color = new SKColor(data[c * 3], data[(c * 3) + 1], data[(c * 3) + 2]);
- nesColors[c] = color;
- }
- }
- else
- {
- var paletteJson = File.ReadAllText(filename);
- var nesColorsStr = JsonSerializer.Deserialize<Dictionary<string, string>>(paletteJson);
- if (nesColorsStr == null) throw new InvalidDataException($"Can't parse {filename}");
- nesColors = nesColorsStr.ToDictionary(
- kv =>
- {
- try
- {
- var index = kv.Key.ToLower().StartsWith("0x") ? Convert.ToByte(kv.Key.Substring(2), 16) : byte.Parse(kv.Key);
- if (FORBIDDEN_COLORS.Contains(index))
- Trace.WriteLine($"WARNING! color #{kv.Key} is forbidden color, it will be ignored.");
- if (index > 0x3F) throw new ArgumentException($"{kv.Key} - invalid color index.", filename);
- return index;
- }
- catch (Exception ex) when (ex is FormatException || ex is OverflowException)
- {
- throw new ArgumentException($"{kv.Key} - invalid color index.", filename);
- }
- },
- kv =>
- {
- try
- {
- var color = ColorTranslator.FromHtml(kv.Value); ;
- return new SKColor(color.R, color.G, color.B);
- }
- catch (FormatException)
- {
- throw new ArgumentException($"{kv.Value} - invalid color.", filename);
- }
- }
- );
- }
- // filter out invalid colors;
- nesColors = nesColors.Where(kv => !FORBIDDEN_COLORS.Contains(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value);
- return nesColors;
- }
-
- /// <summary>
- /// Find index of most similar color from NES colors
- /// </summary>
- /// <param name="color">Input color</param>
- /// <returns>Output color index</returns>
- public byte FindSimilarColorIndex(SKColor color)
- {
- if (cache.ContainsKey(color))
- return cache[color];
- byte result = byte.MaxValue;
- double minDelta = double.MaxValue;
- SKColor c = SKColors.Transparent;
- foreach (var index in Colors.Keys)
- {
- var delta = color.GetDelta(Colors[index]);
- if (delta < minDelta)
- {
- minDelta = delta;
- result = index;
- c = Colors[index];
- }
- }
- if (result == byte.MaxValue)
- throw new KeyNotFoundException($"Invalid color: {color}.");
- if (cache != null)
- cache[color] = result;
- return result;
- }
-
- /// <summary>
- /// Find most similar color from list of colors
- /// </summary>
- /// <param name="colors">Haystack</param>
- /// <param name="color">Niddle</param>
- /// <returns>Output color</returns>
- public SKColor FindSimilarColor(IEnumerable<SKColor> colors, SKColor color)
- {
- SKColor result = SKColors.Black;
- double minDelta = double.MaxValue;
- foreach (var c in colors)
- {
- var delta = color.GetDelta(c);
- if (delta < minDelta)
- {
- minDelta = delta;
- result = c;
- }
- }
- return result;
- }
-
- /// <summary>
- /// Find most similar color from NES colors
- /// </summary>
- /// <param name="color">Input colo</param>
- /// <returns>Output color</returns>
- public SKColor FindSimilarColor(SKColor color) => Colors[FindSimilarColorIndex(color)];
-
- public void WriteColorsTable(string filename)
- {
- // Export colors to nice table image
- const int colorSize = 64;
- const int colorColumns = 16;
- const int colorRows = 4;
- const int strokeWidth = 5;
- float textSize = 20;
- float textYOffset = 39;
- using var image = new SKBitmap(colorSize * colorColumns, colorSize * colorRows);
- using var canvas = new SKCanvas(image);
- for (int y = 0; y < colorRows; y++)
- {
- for (int x = 0; x < colorColumns; x++)
- {
- SKColor color;
- SKPaint paint;
- if (Colors.TryGetValue((byte)((y * colorColumns) + x), out color))
- {
- paint = new SKPaint() { Color = color };
- canvas.DrawRegion(new SKRegion(new SKRectI(x * colorSize, y * colorSize, (x + 1) * colorSize, (y + 1) * colorSize)), paint);
-
- color = new SKColor((byte)(0xFF - color.Red), (byte)(0xFF - color.Green), (byte)(0xFF - color.Blue)); // invert color
- paint = new SKPaint()
- {
- Color = color,
- TextAlign = SKTextAlign.Center,
- TextSize = textSize,
- FilterQuality = SKFilterQuality.High,
- IsAntialias = true
- };
- canvas.DrawText($"{(y * colorColumns) + x:X02}", (x * colorSize) + (colorSize / 2), (y * colorSize) + textYOffset, paint);
- }
- else
- {
- paint = new SKPaint() { Color = SKColors.Black };
- SKPath path = new SKPath();
- canvas.DrawRegion(new SKRegion(new SKRectI(x * colorSize, y * colorSize, (x + 1) * colorSize, (y + 1) * colorSize)), paint);
- paint = new SKPaint()
- {
- Color = SKColors.Red,
- Style = SKPaintStyle.Stroke,
- StrokeCap = SKStrokeCap.Round,
- StrokeWidth = strokeWidth,
- FilterQuality = SKFilterQuality.High,
- IsAntialias = true
- };
- canvas.DrawLine((x * colorSize) + strokeWidth, (y * colorSize) + strokeWidth, ((x + 1) * colorSize) - strokeWidth, ((y + 1) * colorSize) - strokeWidth, paint);
- canvas.DrawLine(((x + 1) * colorSize) - strokeWidth, (y * colorSize) + strokeWidth, (x * colorSize) + strokeWidth, ((y + 1) * colorSize) - strokeWidth, paint);
- }
- };
- }
- File.WriteAllBytes(filename, image.Encode(SKEncodedImageFormat.Png, 0).ToArray());
- }
- }
-}
+using SkiaSharp;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+
+namespace com.clusterrr.Famicom.NesTiler
+{
+ class ColorFinder
+ {
+ static byte[] FORBIDDEN_COLORS = { 0x0D, 0x0E, 0x0F, 0x1E, 0x1F, 0x2E, 0x2F, 0x3E, 0x3F };
+
+ public readonly Dictionary<byte, SKColor> Colors;
+ private readonly Dictionary<SKColor, byte> cache = new();
+
+ public ColorFinder(string filename)
+ {
+ this.Colors = LoadColors(filename);
+ }
+
+ private static Dictionary<byte, SKColor> LoadColors(string filename)
+ {
+ Trace.WriteLine($"Loading colors from {filename}...");
+ if (!File.Exists(filename)) throw new FileNotFoundException($"Could not find file '{filename}'.", filename);
+ var data = File.ReadAllBytes(filename);
+ Dictionary<byte, SKColor> nesColors;
+ // Detect file type
+ if ((Path.GetExtension(filename) == ".pal") || ((data.Length == 192 || data.Length == 1536) && data.Where(b => b >= 128).Any()))
+ {
+ // Binary file
+ nesColors = new Dictionary<byte, SKColor>();
+ for (byte c = 0; c < 64; c++)
+ {
+ var color = new SKColor(data[c * 3], data[(c * 3) + 1], data[(c * 3) + 2]);
+ nesColors[c] = color;
+ }
+ }
+ else
+ {
+ var paletteJson = File.ReadAllText(filename);
+ var nesColorsStr = JsonSerializer.Deserialize<Dictionary<string, string>>(paletteJson);
+ if (nesColorsStr == null) throw new InvalidDataException($"Can't parse {filename}");
+ nesColors = nesColorsStr.ToDictionary(
+ kv =>
+ {
+ try
+ {
+ var index = kv.Key.ToLower().StartsWith("0x") ? Convert.ToByte(kv.Key.Substring(2), 16) : byte.Parse(kv.Key);
+ if (FORBIDDEN_COLORS.Contains(index))
+ Trace.WriteLine($"WARNING! color #{kv.Key} is forbidden color, it will be ignored.");
+ if (index > 0x3F) throw new ArgumentException($"{kv.Key} - invalid color index.", filename);
+ return index;
+ }
+ catch (Exception ex) when (ex is FormatException || ex is OverflowException)
+ {
+ throw new ArgumentException($"{kv.Key} - invalid color index.", filename);
+ }
+ },
+ kv =>
+ {
+ try
+ {
+ var color = ColorTranslator.FromHtml(kv.Value); ;
+ return new SKColor(color.R, color.G, color.B);
+ }
+ catch (FormatException)
+ {
+ throw new ArgumentException($"{kv.Value} - invalid color.", filename);
+ }
+ }
+ );
+ }
+ // filter out invalid colors;
+ nesColors = nesColors.Where(kv => !FORBIDDEN_COLORS.Contains(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value);
+ return nesColors;
+ }
+
+ /// <summary>
+ /// Find index of most similar color from NES colors
+ /// </summary>
+ /// <param name="color">Input color</param>
+ /// <returns>Output color index</returns>
+ public byte FindSimilarColorIndex(SKColor color)
+ {
+ if (cache.ContainsKey(color))
+ return cache[color];
+ byte result = byte.MaxValue;
+ double minDelta = double.MaxValue;
+ SKColor c = SKColors.Transparent;
+ foreach (var index in Colors.Keys)
+ {
+ var delta = color.GetDelta(Colors[index]);
+ if (delta < minDelta)
+ {
+ minDelta = delta;
+ result = index;
+ c = Colors[index];
+ }
+ }
+ if (result == byte.MaxValue)
+ throw new KeyNotFoundException($"Invalid color: {color}.");
+ if (cache != null)
+ cache[color] = result;
+ return result;
+ }
+
+ /// <summary>
+ /// Find most similar color from list of colors
+ /// </summary>
+ /// <param name="colors">Haystack</param>
+ /// <param name="color">Niddle</param>
+ /// <returns>Output color</returns>
+ public SKColor FindSimilarColor(IEnumerable<SKColor> colors, SKColor color)
+ {
+ SKColor result = SKColors.Black;
+ double minDelta = double.MaxValue;
+ foreach (var c in colors)
+ {
+ var delta = color.GetDelta(c);
+ if (delta < minDelta)
+ {
+ minDelta = delta;
+ result = c;
+ }
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Find most similar color from NES colors
+ /// </summary>
+ /// <param name="color">Input colo</param>
+ /// <returns>Output color</returns>
+ public SKColor FindSimilarColor(SKColor color) => Colors[FindSimilarColorIndex(color)];
+
+ public void WriteColorsTable(string filename)
+ {
+ // Export colors to nice table image
+ const int colorSize = 64;
+ const int colorColumns = 16;
+ const int colorRows = 4;
+ const int strokeWidth = 5;
+ float textSize = 20;
+ float textYOffset = 39;
+ using var image = new SKBitmap(colorSize * colorColumns, colorSize * colorRows);
+ using var canvas = new SKCanvas(image);
+ for (int y = 0; y < colorRows; y++)
+ {
+ for (int x = 0; x < colorColumns; x++)
+ {
+ SKColor color;
+ SKPaint paint;
+ if (Colors.TryGetValue((byte)((y * colorColumns) + x), out color))
+ {
+ paint = new SKPaint() { Color = color };
+ canvas.DrawRegion(new SKRegion(new SKRectI(x * colorSize, y * colorSize, (x + 1) * colorSize, (y + 1) * colorSize)), paint);
+
+ color = new SKColor((byte)(0xFF - color.Red), (byte)(0xFF - color.Green), (byte)(0xFF - color.Blue)); // invert color
+ paint = new SKPaint()
+ {
+ Color = color,
+ TextAlign = SKTextAlign.Center,
+ TextSize = textSize,
+ FilterQuality = SKFilterQuality.High,
+ IsAntialias = true
+ };
+ canvas.DrawText($"{(y * colorColumns) + x:X02}", (x * colorSize) + (colorSize / 2), (y * colorSize) + textYOffset, paint);
+ }
+ else
+ {
+ paint = new SKPaint() { Color = SKColors.Black };
+ SKPath path = new SKPath();
+ canvas.DrawRegion(new SKRegion(new SKRectI(x * colorSize, y * colorSize, (x + 1) * colorSize, (y + 1) * colorSize)), paint);
+ paint = new SKPaint()
+ {
+ Color = SKColors.Red,
+ Style = SKPaintStyle.Stroke,
+ StrokeCap = SKStrokeCap.Round,
+ StrokeWidth = strokeWidth,
+ FilterQuality = SKFilterQuality.High,
+ IsAntialias = true
+ };
+ canvas.DrawLine((x * colorSize) + strokeWidth, (y * colorSize) + strokeWidth, ((x + 1) * colorSize) - strokeWidth, ((y + 1) * colorSize) - strokeWidth, paint);
+ canvas.DrawLine(((x + 1) * colorSize) - strokeWidth, (y * colorSize) + strokeWidth, (x * colorSize) + strokeWidth, ((y + 1) * colorSize) - strokeWidth, paint);
+ }
+ };
+ }
+ File.WriteAllBytes(filename, image.Encode(SKEncodedImageFormat.Png, 0).ToArray());
+ }
+ }
+}