Browse Source

Added Paint.net palette format

Krzysztof Krysiński 2 years ago
parent
commit
9bf2f97e9f

+ 5 - 0
src/PixiEditor.DrawingApi.Core/ColorsImpl/Color.cs

@@ -208,5 +208,10 @@ namespace PixiEditor.DrawingApi.Core.ColorsImpl
           return false;
       }
     }
+
+    public string? ToHex()
+    {
+        return this == Empty ? null : $"{this._colorValue:X8}";
+    }
   }
 }

+ 1 - 0
src/PixiEditor/Helpers/Extensions/ServiceCollectionHelpers.cs

@@ -63,6 +63,7 @@ internal static class ServiceCollectionHelpers
         .AddSingleton<PaletteFileParser, JascFileParser>()
         .AddSingleton<PaletteFileParser, ClsFileParser>()
         .AddSingleton<PaletteFileParser, PngPaletteParser>()
+        .AddSingleton<PaletteFileParser, PaintNetTxtParser>()
         // Palette data sources
         .AddSingleton<PaletteListDataSource, LocalPalettesFetcher>();
 }

+ 11 - 1
src/PixiEditor/Models/IO/PaletteFileParser.cs

@@ -1,4 +1,6 @@
-namespace PixiEditor.Models.IO;
+using System.IO;
+
+namespace PixiEditor.Models.IO;
 
 internal abstract class PaletteFileParser
 {
@@ -6,4 +8,12 @@ internal abstract class PaletteFileParser
     public abstract Task<bool> Save(string path, PaletteFileData data);
     public abstract string FileName { get; }
     public abstract string[] SupportedFileExtensions { get; }
+
+    protected static async Task<string[]> ReadTextLines(string path)
+    {
+        using var stream = File.OpenText(path);
+        string fileContent = await stream.ReadToEndAsync();
+        string[] lines = fileContent.Split('\n');
+        return lines;
+    }
 }

+ 1 - 1
src/PixiEditor/Models/IO/PaletteParsers/ClsFileParser.cs

@@ -21,7 +21,7 @@ internal class ClsFileParser : PaletteFileParser
             }
             catch
             {
-                return new PaletteFileData("Corrupted", Array.Empty<Color>()) { IsCorrupted = true };
+                return PaletteFileData.Corrupted;
             }
 
             PaletteFileData data = new(

+ 1 - 4
src/PixiEditor/Models/IO/PaletteParsers/JascPalFile/JascFileParser.cs

@@ -14,10 +14,7 @@ internal class JascFileParser : PaletteFileParser
 
     private static async Task<PaletteFileData> ParseFile(string path)
     {
-        using var stream = File.OpenText(path);
-
-        string fileContent = await stream.ReadToEndAsync();
-        string[] lines = fileContent.Split('\n');
+        string[] lines = await ReadTextLines(path);
         string name = Path.GetFileNameWithoutExtension(path);
         string fileType = lines[0];
         string magicBytes = lines[1];

+ 76 - 0
src/PixiEditor/Models/IO/PaletteParsers/PaintNetTxtParser.cs

@@ -0,0 +1,76 @@
+using System.Globalization;
+using System.IO;
+using System.Text;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Helpers;
+
+namespace PixiEditor.Models.IO.PaletteParsers;
+
+// https://www.getpaint.net/doc/latest/WorkingWithPalettes.html
+
+internal class PaintNetTxtParser : PaletteFileParser
+{
+    public override string FileName { get; } = "Paint.NET Palette";
+    public override string[] SupportedFileExtensions { get; } = new string[] { ".txt" };
+    public override async Task<PaletteFileData> Parse(string path)
+    {
+        try
+        {
+            return await ParseFile(path);
+        }
+        catch
+        {
+            return PaletteFileData.Corrupted;
+        }
+    }
+
+    private static async Task<PaletteFileData> ParseFile(string path)
+    {
+        var lines = await ReadTextLines(path);
+        string name = Path.GetFileNameWithoutExtension(path);
+
+        lines = lines.Where(x => !x.StartsWith(";")).ToArray();
+
+        List<Color> colors = new();
+        for (int i = 0; i < lines.Length; i++)
+        {
+            // Color format aarrggbb
+            string colorLine = lines[i];
+            if(colorLine.Length < 8)
+                continue;
+
+            byte a = byte.Parse(colorLine.Substring(0, 2), NumberStyles.HexNumber);
+            byte r = byte.Parse(colorLine.Substring(2, 2), NumberStyles.HexNumber);
+            byte g = byte.Parse(colorLine.Substring(4, 2), NumberStyles.HexNumber);
+            byte b = byte.Parse(colorLine.Substring(6, 2), NumberStyles.HexNumber);
+            var color = new Color(r, g, b, a);
+            if(colors.Contains(color)) continue;
+
+            colors.Add(color);
+        }
+
+        return new PaletteFileData(name, colors.ToArray());
+    }
+
+    public override async Task<bool> Save(string path, PaletteFileData data)
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.AppendLine("; Paint.NET Palette File");
+        sb.AppendLine($"; Made using PixiEditor {VersionHelpers.GetCurrentAssemblyVersion().ToString()}");
+        sb.AppendLine($"; {data.Colors.Length} colors");
+        foreach (Color color in data.Colors)
+        {
+            sb.AppendLine(color.ToHex());
+        }
+
+        try
+        {
+            await File.WriteAllTextAsync(path, sb.ToString());
+            return true;
+        }
+        catch
+        {
+            return false;
+        }
+    }
+}

+ 5 - 0
src/PixiEditor/Views/UserControls/Palettes/PaletteViewer.xaml.cs

@@ -139,6 +139,11 @@ internal partial class PaletteViewer : UserControl
         {
             string fileName = saveFileDialog.FileName;
             var foundParser = FileParsers.First(x => x.SupportedFileExtensions.Contains(Path.GetExtension(fileName)));
+            if (Colors == null || Colors.Count == 0)
+            {
+                NoticeDialog.Show("NO_COLORS_TO_SAVE", "ERROR");
+                return;
+            }
             bool saved = await foundParser.Save(fileName, new PaletteFileData(Colors.ToArray()));
             if (!saved)
             {