【Unity】AdobeのASEファイルのRGB値を抽出してみる

# はじめに
AdobeのASEファイルをUnity上で読み込ませたいなぁと思ったので、ASEファイルから色を取り出すものを作ってみました。

# 環境
Unity 5.6.1f1
Windows 10

# ASEファイルとは
![image.png](https://qiita-image-store.s3.amazonaws.com/0/44288/6ebebf7f-4fcd-60f1-ec2c-929d1eb6fc7e.png)

Adobe製品(PhotoshopやIllustratorなど)では、色のセットを共有できる仕組みが用意されています。
そこで使うのが**ASE**ファイルです。

ASEファイルには複数の**RGB**カラーが格納されています。


<br>
今回はUnity上でASEファイルからRGBデータを取り出していきたいと思います。

# ASEファイルのバイナリを覗いてみる
今回はASEファイルの **バイナリ** を読んで、RGB値がどこに保存されているかを解読して行きたいと思います。

# 今回使用するASEファイル
今回はバイナリ上で色がどこに並んでいるかを見つけやすくするため、RGB=(255, 255, 255)が３つ登録されている.aseファイルを使用します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/44288/d89c010b-8bb9-3b00-2f31-dcf320412ca2.png)

# ASEファイルのバイナリを覗いてみる
バイナリツール( http://qiita.com/r-ngtm/items/8abca767afbb5a6df3cc )を使ってUnity上でASEファイルのバイナリを表示させてみます。


ASEファイルを開くと以下のような感じになります。　数字がたくさん並んでいます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/44288/59604b6a-474c-3f57-ba26-fd47507b9318.png)

このバイナリをよく観察すると、バイト列 **3F8000** が複数回表れていることが読み取れます。

![1_aseバイナリ_RGB.png](https://qiita-image-store.s3.amazonaws.com/0/44288/61d739eb-035e-50f7-b6f7-8a8ed1a3911d.png)

この **3F8000** がRGB値ではないかと私は予想しました。


# ASEファイルの構造
さらに調べていったところ、バイナリの構造は以下のようになっているということが分かりました。

![1_aseバイナリ.png](https://qiita-image-store.s3.amazonaws.com/0/44288/4ce734b7-7439-f088-fe35-5b8104cc0c86.png)

# 3F8000 の正体
この **3F8000** ですが、floatの1.0を16進数で表したものになっています。
どうやら、ASEファイルにはRGBの各チャンネルの数値が0.0 ~ 1.0の範囲で保存されているようです。

# RGBを抽出するコードを書いてみる
RGB個数とRGB値の格納場所が把握できたので、ASEファイルからRGBを抽出するコードを書いていきます。

```csharp:.aseファイルから情報を取り出すクラス
using System.IO;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// .aseファイルから情報を抽出するクラス
/// </summary>
public static class AseExtractor
{
    /// <summary>
    /// .aseファイルの色を取り出す
    /// </summary>
    public static IEnumerable<Color> GetColors(Object ase)
    {
        // .aseのバイナリを取得
        byte[] bin = ToBinary(ase);

        // RGBの個数の取得
        int colorCount = bin[11];

        // RGB値を取り出していく
        int pos = 40;
        for (int i = 0; i < colorCount; i++)
        {
            float r = ReadFloatBE(bin, pos, 4);
            float g = ReadFloatBE(bin, pos + 4, 4);
            float b = ReadFloatBE(bin, pos + 8, 4);
            yield return new Color(r, g, b, 1f);
            pos += 42; 
        }
    }
   
    static float ReadFloatBE(byte[] bytes, int pos, int length)
    {
        byte[] b = new byte[length];
        int src = pos + length - 1;
        for (int i = 0; i < length; i++)
        {
            b[i] = bytes[src--];
        }
        return System.BitConverter.ToSingle(b, 0);
    }

    /// <summary>
    /// Assetをバイト列にする 
    /// </summary>
    static byte[] ToBinary(Object asset)
    {
        var split = AssetDatabase.GetAssetPath(asset).Split('/');
        var path = Application.dataPath + "/";
        for (int i = 1; i < split.Length - 1; i++)
        {
            path += split[i] + "/";
        }
        path += split[split.Length - 1];
        FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
        BinaryReader bin = new BinaryReader(fileStream);
        return bin.ReadBytes((int)bin.BaseStream.Length);
    }
}
```

上記クラスの **GetColors** メソッドへASEファイルを指定するとRGB一覧が取得できます。(完)

# ASEファイルフォーマット
今回はASEファイルのバイナリを読んで強引にインポートツールを作ってしまいましたが、
ASEのファイルフォーマットやC#での読み込み方法についてまとめたWebページが既にあったようです。 (この記事を書き終えた後に見つけてしまいました。)

>Reading Adobe Swatch Exchange (ase) files using C#
https://www.cyotek.com/blog/reading-adobe-swatch-exchange-ase-files-using-csharp


こちらを参考にインポートツールを作ったほうが良いかもしれません。

# 参考URL
アプリケーション間でのスウォッチの共有（交換用スウォッチ） 
http://www.dtp-transit.jp/adobe/illustrator/post_1963.html

Photoshopスウォッチの管理方法 
http://www.syumpei.com/blog/2014/04/swatch.html