c# 解析atlas文件

沒找到c#版本的,於是打算自己寫一下

參考鏈接來源:https://blog.csdn.net/w88219003/article/details/41909421

 

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;

namespace ConsoleApp11
{
    /// <summary>
    /// 
    /// </summary>
    public struct Vector2Int
    {
        public int X { get; set; }

        public int Y { get; set; }

        public override bool Equals(object obj)
        {
            if(!(obj is Vector2Int other))
            {
                return false;
            }
            return other.X == X && other.Y == Y;
        }

        public override int GetHashCode()
        {
            return X.GetHashCode() + Y.GetHashCode();
        }

        public static bool operator ==(Vector2Int left, Vector2Int right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(Vector2Int left, Vector2Int right)
        {
            return !(left == right);
        }

        public override string ToString()
        {
            return $"({X},{Y})";
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class PNGData
    {
        private string[] name = Array.Empty<string>();

        /// <summary>
        /// 名字
        /// </summary>
        public string[] GetName()
        {
            return name;
        }

        /// <summary>
        /// 名字
        /// </summary>
        public void SetName(string[] value)
        {
            name = value;
        }

        /// <summary>
        /// 旋轉
        /// </summary>
        public bool Rotate { get; set; }

        /// <summary>
        /// 座標
        /// </summary>
        public Vector2Int Position { get; set; }

        /// <summary>
        /// 大小
        /// </summary>
        public Vector2Int Size { get; set; }

        /// <summary>
        /// ...
        /// </summary>
        public Vector2Int Orig { get; set; }

        /// <summary>
        /// 偏移
        /// </summary>
        public Vector2Int Offset { get; set; }

        /// <summary>
        /// 索引
        /// </summary>
        public int Index { get; set; }

        public override string ToString()
        {
            return $"{GetName()},Position{Position},Size{Size}";
        }

        public string GetAndCreateFullPath(string folder)
        {
            for(int i = 0; i < name.Length; ++i)
            {
                string n = name[i];
                if (i == name.Length - 1)
                {
                    if (!Directory.Exists(folder))
                    {
                        Directory.CreateDirectory(folder);
                    }
                }
                folder += n;
                if (i == name.Length - 1)
                {
                    folder += ".png";
                }
                else
                {
                    folder += "\\";
                }
            }
            return folder;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class AtlasFileData
    {
        /// <summary>
        /// 文件名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 文件夾
        /// </summary>
        public string Folder { get; set; }

        /// <summary>
        /// 文件大小
        /// </summary>
        public Vector2Int Size { get; set; }

        /// <summary>
        /// 文件格式
        /// </summary>
        public string Format { get; set; }

        /// <summary>
        /// 文件格式
        /// </summary>
        public string Filter { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string Repeat { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public List<PNGData> PNG { get; } = new List<PNGData>();
    }

    /// <summary>
    /// 解析圖集
    /// </summary>
    public static class AtlasParser
    {
        /// <summary>
        /// 指定atlas文件的全路徑然後加載,加載出來的圖片默認在當前文件夾下的子文件夾中
        /// </summary>
        /// <param name="inputPath">atlas文件的全路徑</param>
        public static bool Load(string inputPath)
        {
            if (string.IsNullOrEmpty(inputPath))
            {
                return false;
            }

            if (!inputPath.EndsWith(".atlas"))
            {
                return false;
            }

            inputPath = inputPath.Replace('/', '\\');

            string folder = inputPath.Substring(0, inputPath.LastIndexOf('\\') + 1);

            //debug
            Console.WriteLine($"圖集路徑:{inputPath}");

            List<AtlasFileData> atlases = new List<AtlasFileData>();

            using (var fs = new FileStream(inputPath, FileMode.Open, FileAccess.Read))
            {
                using (var reader = new StreamReader(fs, Encoding.UTF8))
                {
                    //跳過下一行
                    bool skipNext = false;

                    while (!reader.EndOfStream)
                    {
                        var curAtlas = Parse(new AtlasFileData(), reader, ref skipNext);
                        if (curAtlas != null)
                        {
                            curAtlas.Folder = folder;
                            atlases.Add(curAtlas);
                        }
                    }
                }
            }

            //debug
            Console.WriteLine($"解析完畢,數量:{atlases.Count}");

            foreach (var atlas in atlases)
            {
                Split(atlas);
            }

            return true;
        }

        private static void Split(AtlasFileData fileData)
        {
            string fullSourcePath = $"{fileData.Folder}{fileData.Name}";

            if (!File.Exists(fullSourcePath))
            {
                Console.WriteLine($"路徑不存在:{fullSourcePath}");
                return;
            }

            string folderName = fileData.Name.Substring(0, fileData.Name.LastIndexOf('.'));

            string folderPath = $"{fileData.Folder}{folderName}\\";

            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }

            //debug
            Console.WriteLine();
            Console.WriteLine($"開始分割圖片至文件夾:{folderPath}");

            Bitmap source = new Bitmap(fullSourcePath);

            foreach(var png in fileData.PNG)
            {
                var nameDepth = png.GetName();
                if(nameDepth.Length == 0)
                {
                    //debug
                    Console.WriteLine($"png圖片的名字不能爲空");
                    continue;
                }
                int x, y, z, w = 0;
            
                if (png.Rotate)
                {
                    x = png.Position.X;
                    y = png.Position.Y;
                    z = x + png.Size.Y;
                    w = y + png.Size.X;
                }
                else
                {
                    x = png.Position.X;
                    y = png.Position.Y;
                    z = x + png.Size.X;
                    w = y + png.Size.Y;
                }

                int width = z - x;
                int height = w - y;
                Bitmap b = new Bitmap(width, height);
                try
                {
                    using (Graphics g = Graphics.FromImage(b))
                    {
                        //清空畫布並以透明背景色填充
                        g.Clear(Color.Transparent);
                        //在指定位置並且按指定大小繪製原圖片的指定部分
                        g.DrawImage(source, new Rectangle(0, 0, width, height), x, y, width, height, GraphicsUnit.Pixel);
                        //
                        if (png.Rotate)
                        {
                            b.RotateFlip(RotateFlipType.Rotate270FlipNone);
                        }
                        else
                        {
                            b.RotateFlip(RotateFlipType.RotateNoneFlipNone);
                        }

                        string fullPNGPath = png.GetAndCreateFullPath(folderPath);

                        b.Save(fullPNGPath, System.Drawing.Imaging.ImageFormat.Png);

                        //debug
                        Console.WriteLine($"圖片已保存至:{fullPNGPath}");
                    }
                }
                catch (Exception e)
                {
                    throw e;
                }
                finally
                {
                    b.Dispose();
                }
            }

            source.Dispose();
        }

        private static bool ReadFileName(AtlasFileData fileData, StreamReader reader)
        {
            if (reader.EndOfStream)
            {
                return false;
            }

            string line = reader.ReadLine();

            fileData.Name = line;

            return true;
        }

        private static bool ReadFileSize(AtlasFileData fileData, StreamReader reader)
        {
            if (reader.EndOfStream)
            {
                return false;
            }

            string line = reader.ReadLine();

            if (!line.StartsWith("size:"))
            {
                return false;
            }

            line = line.Substring(5);

            var coll = line.Split(',');

            if(coll.Length != 2)
            {
                return false;
            }

            fileData.Size = new Vector2Int()
            {
                X = Convert.ToInt32(coll[0]),
                Y = Convert.ToInt32(coll[1])
            };

            return true;
        }

        private static bool ReadFileFormat(AtlasFileData fileData, StreamReader reader)
        {
            if (reader.EndOfStream)
            {
                return false;
            }

            string line = reader.ReadLine();

            if (!line.StartsWith("format:"))
            {
                return false;
            }

            line = line.Substring(7);

            fileData.Format = line;

            return true;
        }

        private static bool ReadFileFilter(AtlasFileData fileData, StreamReader reader)
        {
            if (reader.EndOfStream)
            {
                return false;
            }

            string line = reader.ReadLine();

            if (!line.StartsWith("filter:"))
            {
                return false;
            }

            line = line.Substring(7);

            fileData.Filter = line;

            return true;
        }

        private static bool ReadFileRepeatMode(AtlasFileData fileData, StreamReader reader)
        {
            if (reader.EndOfStream)
            {
                return false;
            }

            string line = reader.ReadLine();

            if (!line.StartsWith("repeat:"))
            {
                return false;
            }

            line = line.Substring(7);

            fileData.Repeat = line;

            return true;
        }

        private static AtlasFileData Parse(AtlasFileData fileData, StreamReader reader,ref bool skipNext)
        {
            if (!skipNext)
            {
                reader.ReadLine();
            }
            //讀取文件名
            if (!ReadFileName(fileData, reader))
            {
                return null;
            }
            //讀取大小
            if (!ReadFileSize(fileData, reader))
            {
                return null;
            }
            //讀取格式
            if (!ReadFileFormat(fileData, reader))
            {
                return null;
            }
            //讀取格式
            if (!ReadFileFilter(fileData, reader))
            {
                return null;
            }
            //讀取
            if (!ReadFileRepeatMode(fileData, reader))
            {
                return null;
            }

            //開始讀取圖集數據
            while (!reader.EndOfStream)
            {
                //讀取png名字
                var pngData = ReadPNGData(reader, ref skipNext);
                if(pngData == null)
                {
                    return fileData;
                }

                fileData.PNG.Add(pngData);
            }

            return fileData;
        }

        private static bool ParsePNGName(PNGData pngData,string line)
        {
            var name = line.Split('/');

            pngData.SetName(name);

            return true;
        }

        private static bool ParsePNGRotate(PNGData pngData,string line)
        {
            line = line.Trim(' ');
            var coll = line.Split(':');
            if (coll.Length != 2)
            {
                return false;
            }
            if(coll[0]!= "rotate")
            {
                return false;
            }
            pngData.Rotate = Convert.ToBoolean(coll[1]);
            return true;
        }

        private static bool ParsePNGXY(PNGData pngData, string line)
        {
            line = line.Trim(' ');
            var coll = line.Split(':');
            if (coll.Length != 2)
            {
                return false;
            }
            if (coll[0] != "xy")
            {
                return false;
            }
            coll = coll[1].Split(',');
            pngData.Position = new Vector2Int()
            {
                X = Convert.ToInt32(coll[0]),
                Y = Convert.ToInt32(coll[1])
            };
            return true;
        }

        private static bool ParsePNGSize(PNGData pngData, string line)
        {
            line = line.Trim(' ');
            var coll = line.Split(':');
            if (coll.Length != 2)
            {
                return false;
            }
            if (coll[0] != "size")
            {
                return false;
            }
            coll = coll[1].Split(',');
            pngData.Size = new Vector2Int()
            {
                X = Convert.ToInt32(coll[0]),
                Y = Convert.ToInt32(coll[1])
            };
            return true;
        }

        private static bool ParsePNGOrig(PNGData pngData, string line)
        {
            line = line.Trim(' ');
            var coll = line.Split(':');
            if (coll.Length != 2)
            {
                return false;
            }
            if (coll[0] != "orig")
            {
                return false;
            }
            coll = coll[1].Split(',');
            pngData.Orig = new Vector2Int()
            {
                X = Convert.ToInt32(coll[0]),
                Y = Convert.ToInt32(coll[1])
            };
            return true;
        }

        private static bool ParsePNGOffset(PNGData pngData, string line)
        {
            line = line.Trim(' ');
            var coll = line.Split(':');
            if (coll.Length != 2)
            {
                return false;
            }
            if (coll[0] != "offset")
            {
                return false;
            }
            coll = coll[1].Split(',');
            pngData.Offset = new Vector2Int()
            {
                X = Convert.ToInt32(coll[0]),
                Y = Convert.ToInt32(coll[1])
            };
            return true;
        }

        private static bool ParsePNGIndex(PNGData pngData, string line)
        {
            line = line.Trim(' ');
            var coll = line.Split(':');
            if (coll.Length != 2)
            {
                return false;
            }
            if (coll[0] != "index")
            {
                return false;
            }
            pngData.Index = Convert.ToInt32(coll[1]);
            return true;
        }

        private static PNGData ReadPNGData(StreamReader reader, ref bool skipNext)
        {
            string line = reader.ReadLine();
            //讀取到空行
            if (string.IsNullOrEmpty(line))
            {
                skipNext = true;
                return null;
            }

            PNGData pngData = new PNGData();
            //讀取名字

            if (!ParsePNGName(pngData, line))
            {
                return null;
            }
            //讀取rotate
            line = reader.ReadLine();
            if (!ParsePNGRotate(pngData, line))
            {
                return null;
            }
            //讀取xy
            line = reader.ReadLine();
            if (!ParsePNGXY(pngData, line))
            {
                return null;
            }
            //讀取size
            line = reader.ReadLine();
            if (!ParsePNGSize(pngData, line))
            {
                return null;
            }
            //讀取orig
            line = reader.ReadLine();
            if (!ParsePNGOrig(pngData, line))
            {
                return null;
            }
            //讀取offset
            line = reader.ReadLine();
            if (!ParsePNGOffset(pngData, line))
            {
                return null;
            }
            //讀取index
            line = reader.ReadLine();
            if (!ParsePNGIndex(pngData, line))
            {
                return null;
            }
            return pngData;
        }
    }
}

測試 

using System;
using System.IO;
using System.Threading.Tasks;

namespace ConsoleApp11
{
    class Program
    {
        static bool isloading = false;

        static void Main(string[] args)
        {
            while (true)
            {
                if (isloading)
                {
                    continue;
                }
                Console.WriteLine("1.Q鍵退出 2.空格鍵執行解析");
                ConsoleKeyInfo key = Console.ReadKey();
                if(key.Key == ConsoleKey.Q)
                {
                    //退出
                    Console.WriteLine("退出程序");
                    break;
                }
                else if(key.Key == ConsoleKey.Spacebar)
                {
                    Console.WriteLine("請輸入atlas文件全路徑");
                    string line = Console.ReadLine();
                    if(string.IsNullOrEmpty(line) || !File.Exists(line))
                    {
                        Console.WriteLine("路徑不存在");
                    }
                    else
                    {
                        Load(line);
                    }
                }
            }
            Console.ReadKey();
        }

        static async void Load(string path)
        {
            isloading = true;
            var result = await Task.Run(() => {
                return AtlasParser.Load(path);
            });
            isloading = false;
            Console.WriteLine();
            if(result)
            {
                Console.WriteLine($"執行完畢!結果:成功...");
            }
            else
            {
                Console.WriteLine($"執行完畢!結果:失敗...");
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章