[C#]CLIP STUDIO PAINTのファイルのサムネイルを取得する

# はじめに
[先駆者の記事](https://qiita.com/gutti02/items/f021d18074323009c8ce)を参考にC#でCLIP STUDIO PAINTのファイルのサムネイルを取得します。

***

# サムネイルの取得方法
.clipファイル内にSQLiteの情報があり、その中からサムネイルの情報を取得します。

**おおまかな流れ**
1. .clipファイルをバイト配列で取得
1. "SQLite format 3"のインデックスを検索
1. それ以降のデータをデータベースファイルとして書き出し
1. 書き出したデータベースファイルをC#のSQLiteで取得
1. CanvasPreviewテーブルのImageDataカラムのデータをバイト配列で取得
1. 必要に応じてデータを変換する(今回はBitmapに変換し、PictureBoxに表示)

## ファイルを開いてSQLiteの情報を取得
ファイルをバイト配列で取得し、その中からSQLiteのデータを抜き出し、データベースファイルとして書き出します。
ファイルデータの **"SQLite format 3"** 以降がSQLiteのデータになっています。
C#では配列から配列を検索するメソッドがないため、実装する必要があります。この処理の質によってサムネイル取得の速度が大きく変わります。今回は[こちら](https://teratail.com/questions/20408)の検索メソッドを利用しました。
LINQ文によって検索結果のインデックス以降のデータをデータベースファイルとして書き出します。

```cs
string searchStr = "SQLite format 3";             //検索文字列
byte[] searchData = Encoding.UTF8.GetBytes(searchStr);  //検索データ(バイト配列)
string filePath = "~.clip";    //読み込む.clipファイル
string dbName = "temp.db";    //書き出すデータベースファイル

//ファイルを開く
using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
    //読み込んだデータを格納するバイト配列生成
    byte[] byteData = new byte[fs.Length];

    //ファイルからデータを読み込む
    fs.Read(byteData, 0, byteData.Length);

    //SQLiteのデータが始まるインデックスを取得する
    //IEnumerableExtensions - 配列検索メソッド
    int findIndex = IEnumerableExtensions.SearchBytes(byteData, searchData);

    //SQLiteのデータを取得
    byte[] byteDB = byteData.Skip(findIndex).ToArray();

    //データベースファイルに書き出す
    File.WriteAllBytes(dbName, byteDB);
}
```

## SQLiteのデータからサムネイルを取得
SQLiteを使うためにNuGetで``System.Data.SQLite``をインストールします。今回は最小限の利用になるため、``System.Data.SQLite.Core``をインストールしました。
DataSourceに書き出したファイルを指定してデータベースに接続します。
``CanvasPreview``テーブルの``ImageData``カラムのデータがサムネイルのデータになっているため取得します。
バイト配列に代入して、サムネイルの取得は完了です。
今回はBitmapに変換してPictureBoxに表示しています。

```cs
using System.Data.SQLite;   //NuGet - System.Data.SQLite.Core

//データベースからデータを抜き出す
using (SQLiteConnection connection = new SQLiteConnection())
{
    //ConnectionStringを指定
    connection.ConnectionString = "Data Source=" + dbName;

    //データベースを開く
    connection.Open();
    if (connection.State != System.Data.ConnectionState.Open)
        Console.WriteLine("Database Open Failed");  //失敗
    else
    {
        //サムネイルを取得する
        using (SQLiteCommand command = connection.CreateCommand())
        {
            /*
             SQL文
             CanvasPreviewテーブルのImageDataカラムがサムネイルのデータになっている
             */
            string sql = " select ImageData from CanvasPreview ";

            //SQL文を指定
            command.CommandText = sql;

            //SQL実行
            using (SQLiteDataReader reader = command.ExecuteReader())
            {
                //読む
                reader.Read();

                //読み込んだImageDataをバイト配列に取得
                byte[] byteThumb = (byte[])reader["ImageData"];

                //バイト配列をBitmapにしてPictureBoxに表示
                using (MemoryStream ms = new MemoryStream(byteThumb))
                {
                    //Bitmapに変換
                    Bitmap bmp = new Bitmap(ms);

                    //PictureBoxに表示
                    pictureBox.Image = bmp;
                }
            }
        }
    }
}
```


***

# おわりに
先駆者の情報を参考にC#で.clipファイルのサムネイルを取得しました。
データベース上に様々なデータがあったので他のデータについても応用できそうです。
C#の配列の探索はメソッド等が用意されていないのでまだまだ最適化できる部分なのかもしれません。

# 参考
### Pythonでのサムネイル取得
https://qiita.com/gutti02/items/f021d18074323009c8ce

### 検索アルゴリズム
https://teratail.com/questions/20408