【Unity】Gradientを画像として書き出すエディタ拡張

UnityでGradientを画像にして書き出すエディタ拡張です。

ソースコードを`Editor`ディレクトリ配下に配置すると、メニューの`Window/Gradient Exporter`からウィンドウを開くことができるようになります。
以下のように設定して、`Export`ボタンを押すと、
![GradientExporter.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/ca8a156c-87e9-2e1b-3f89-b16e3056c16c.png)

このような画像が書き出されます。

![gradient.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61569/b1c176c1-e1fc-324d-c918-ae782b5b9c2b.png)


```c#:GradientExportWindow.cs
using System.IO;
using UnityEngine;
using UnityEditor;

namespace GradientExporter
{
    public enum AlphaExport
    {
        True,
        False,
        Selectable,
    }

    public enum GradientExportFormat
    {
        Png,
        Jpg,
        Tga,
        Exr
    }

    public static class GradientExportFormatExt
    {
        public static bool IsHdr(this GradientExportFormat format)
        {
            return format == GradientExportFormat.Exr;
        }

        public static AlphaExport GetAlphaExport(this GradientExportFormat format)
        {
            switch (format)
            {
                case GradientExportFormat.Png:
                case GradientExportFormat.Tga:
                    return AlphaExport.Selectable;
                case GradientExportFormat.Jpg:
                    return AlphaExport.False;
                case GradientExportFormat.Exr:
                    return AlphaExport.True;
                default:
                    throw new Exception("Unknown value of GradientExportFormat");
            }
        }

        public static TextureFormat GetTextureFormat(this GradientExportFormat format, bool alpha)
        {
            switch (format)
            {
                case GradientExportFormat.Png:
                case GradientExportFormat.Tga:
                    return alpha ? TextureFormat.ARGB32 : TextureFormat.RGB24;
                case GradientExportFormat.Jpg:
                    return TextureFormat.RGB24;
                case GradientExportFormat.Exr:
                    return TextureFormat.RGBAHalf;
                default:
                    throw new Exception("Unknown value of GradientExportFormat");
            }
        }

        public static byte[] Encode(this GradientExportFormat format, Texture2D texture)
        {
            switch (format)
            {
                case GradientExportFormat.Png:
                    return texture.EncodeToPNG();
                case GradientExportFormat.Jpg:
                    return texture.EncodeToJPG(100);
                case GradientExportFormat.Tga:
                    return texture.EncodeToTGA();
                case GradientExportFormat.Exr:
                    return texture.EncodeToEXR();
                default:
                    throw new Exception("Unknown value of GradientExportFormat");
            }
        }

        public static string GetExtension(this GradientExportFormat format)
        {
            switch (format)
            {
                case GradientExportFormat.Png:
                    return "png";
                case GradientExportFormat.Jpg:
                    return "jpg";
                case GradientExportFormat.Tga:
                    return "tga";
                case GradientExportFormat.Exr:
                    return "exr";
                default:
                    throw new Exception("Unknown value of GradientExportFormat");
            }
        }
    }

    public enum GradientExportDirection
    {
        LeftToRight,
        RightToLeft,
        BottomToTop,
        TopToBottom
    }

    public static class GradientExportDirectionExt
    {
        public static bool IsHorizontal(this GradientExportDirection direction)
        {
            return direction == GradientExportDirection.LeftToRight || direction == GradientExportDirection.RightToLeft;
        }

        public static bool IsInverted(this GradientExportDirection direction)
        {
            return direction == GradientExportDirection.RightToLeft || direction == GradientExportDirection.TopToBottom;
        }
    }

    public class GradientExportWindow : EditorWindow
    {
        Gradient gradient = new Gradient();
        Gradient hdrGradient = new Gradient();
        GradientExportFormat format = GradientExportFormat.Png;
        GradientExportDirection direction = GradientExportDirection.LeftToRight;
        bool alpha = false;
        int size = 256;

        [MenuItem("/Window/Gradient Exporter")]
        public static void CreateWindow()
        {
            GetWindow<GradientExportWindow>("Gradient Exporter");
        }

        void OnGUI()
        {
            var exportable = false;

            format = (GradientExportFormat) EditorGUILayout.EnumPopup("Format", format);
            if (format.IsHdr())
            {
                EditorGUILayout.GradientField(new GUIContent("Gradient"), hdrGradient, true);
            }
            else
            {
                EditorGUILayout.GradientField("Gradient", gradient);
            }

            size = EditorGUILayout.IntField("Image Size", size);
            if (size <= 0)
            {
                exportable = true;
                EditorGUILayout.HelpBox("Image size must be bigger than 0.", MessageType.Error);
            }

            direction = (GradientExportDirection) EditorGUILayout.EnumPopup("Image Direction", direction);

            var alphaExport = format.GetAlphaExport();
            using (new EditorGUI.DisabledGroupScope(alphaExport != AlphaExport.Selectable))
            {
                if (alphaExport == AlphaExport.True)
                {
                    alpha = true;
                }
                else if (alphaExport == AlphaExport.False)
                {
                    alpha = false;
                }
                alpha = EditorGUILayout.Toggle("Alpha", alpha);
            }

            using (new EditorGUI.DisabledGroupScope(exportable))
            {
                if (GUILayout.Button("Export"))
                {
                    var targetGradient = format.IsHdr() ? hdrGradient : gradient;
                    Export(targetGradient, format, alpha, size, direction);
                }
            }
        }

        static void Export(Gradient gradient, GradientExportFormat format, bool alpha, int size, GradientExportDirection direction)
        {
            var extension = format.GetExtension();
            var path = EditorUtility.SaveFilePanel("Export Gradient as Image", "", $"Gradient.{extension}", extension);
            if (path == "") return;

            var texture = CreateTexture(gradient, format.GetTextureFormat(alpha), size, direction);
            var binaries = format.Encode(texture);
            DestroyImmediate(texture);

            File.WriteAllBytes(path, binaries);
            AssetDatabase.Refresh();
        }

        static Texture2D CreateTexture(Gradient gradient, TextureFormat format, int size, GradientExportDirection direction)
        {

            var texture = direction.IsHorizontal() ? new Texture2D(size, 1, format, false): new Texture2D(1, size, format, false);
            var inverted = direction.IsInverted();
            var pixels = texture.GetPixels();
            for (var i = 0; i < pixels.Length; ++i)
            {
                var t = (float)i / (pixels.Length - 1);
                pixels[i] = gradient.Evaluate(inverted ? 1.0f - t : t);
            }
            texture.SetPixels(pixels);
            texture.Apply(false);
            return texture;
        }
    }
}
```