ETC用にマスク画像を作るツール


前回の記事で紹介したマスク素材を作るためのツールの説明です。

##開発環境
VisualStudio2008
C#
.NetFramwork 3.5

##概要
画像ファイルを入れるとマスク画像を出力する
CreateMask.exe [マスク元のファイル]

##オプション
[-w] 横にマスクを持つ画像を生成
[-h] 縦にマスクを持つ画像を生成
[-o] [出力ファイル] 指定されたファイル名で出力(この指定がない場合は、入力ファイル名に_mをつけて出力)

##プロジェクトの設定

* Bitmapを使用するため、参照の設定で「System.Drawing」を追加

![ref_setting.png](https://qiita-image-store.s3.amazonaws.com/0/64194/57325785-6515-e7ef-6300-baf28ea9fdcb.png)

***

* ポインタを使用するため、プロパティのアンセーフコードの許可にチェックを入れる
![unsafe.png](https://qiita-image-store.s3.amazonaws.com/0/64194/dd1c4028-cf1e-9830-a56a-5df00b4314ef.png)

##ソース

```csharp:CreateMask.cs
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace CreateMack
{
    class Program
    {
        /// <summary>
        /// 通常のマスク画像生成
        /// </summary>
        /// <param name="src">入力ビットマップデータ</param>
        /// <param name="dst">出力ビットマップデータ</param>
        static void CreateMaskNormal(BitmapData src, BitmapData dst)
        {
            unsafe
            {
                for (int y = 0; y < src.Height; ++y)
                {
                    byte* sp = (byte*)src.Scan0 + y * src.Stride;
                    byte* dp = (byte*)dst.Scan0 + y * dst.Stride;
                    for (int x = 0; x < src.Width; ++x)
                    {
                        dp[0] = dp[1] = dp[2] = sp[3];
                        sp += 4;
                        dp += 3;
                    }
                }
            }
        }

        /// <summary>
        /// 横にマスクがある画像生成
        /// </summary>
        /// <param name="src">入力ビットマップデータ</param>
        /// <param name="dst">出力ビットマップデータ</param>
        static void CreateMaskWidth(BitmapData src, BitmapData dst)
        {
            unsafe
            {
                for (int y = 0; y < src.Height; ++y)
                {
                    byte* sp = (byte*)src.Scan0 + y * src.Stride;
                    byte* dp = (byte*)dst.Scan0 + y * dst.Stride;
                    byte* dpm = (byte*)dst.Scan0 + y * dst.Stride + src.Width * 3;
                    for (int x = 0; x < src.Width; ++x)
                    {
                        // 通常データの書き込み
                        dp[0] = sp[0];
                        dp[1] = sp[1];
                        dp[2] = sp[2];
                        // マスクデータの書き込み
                        dpm[0] = dpm[1] = dpm[2] = sp[3];
                        // ポインタ移動
                        sp += 4;
                        dp += 3;
                        dpm += 3;
                    }
                }
            }
        }

        /// <summary>
        /// 縦にマスクがある画像生成
        /// </summary>
        /// <param name="src">入力ビットマップデータ</param>
        /// <param name="dst">出力ビットマップデータ</param>
        static void CreateMaskHeight(BitmapData src, BitmapData dst)
        {
            unsafe
            {
                for (int y = 0; y < src.Height; ++y)
                {
                    byte* sp = (byte*)src.Scan0 + y * src.Stride;
                    byte* dp = (byte*)dst.Scan0 + y * dst.Stride;
                    byte* dpm = (byte*)dst.Scan0 + (y + src.Height) * dst.Stride;
                    for (int x = 0; x < src.Width; ++x)
                    {
                        // 通常データの書き込み
                        dp[0] = sp[0];
                        dp[1] = sp[1];
                        dp[2] = sp[2];
                        // マスクデータの書き込み
                        dpm[0] = dpm[1] = dpm[2] = sp[3];
                        // ポインタ移動
                        sp += 4;
                        dp += 3;
                        dpm += 3;
                    }
                }
            }
        }

        /// <summary>
        /// マスク画像の生成
        /// </summary>
        /// <param name="in_file">入力ファイル名</param>
        /// <param name="out_file">出力ファイル名</param>
        /// <param name="w_scale">幅のスケール</param>
        /// <param name="h_scale">高さのスケール</param>
        static void CreateMask(string in_file, string out_file, int w_scale, int h_scale)
        {
            // ビットマップを生成
            Bitmap src_bmp = new Bitmap(in_file);
            Bitmap dst_bmp = new Bitmap(src_bmp.Width * w_scale,
                                        src_bmp.Height * h_scale,
                                        System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            // ビットマップデータを生成
            var src = src_bmp.LockBits(new Rectangle(0, 0, src_bmp.Width, src_bmp.Height),
                                       System.Drawing.Imaging.ImageLockMode.ReadOnly,
                                       System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            var dst = dst_bmp.LockBits(new Rectangle(0, 0, dst_bmp.Width, dst_bmp.Height),
                                       System.Drawing.Imaging.ImageLockMode.ReadOnly,
                                       System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            // マスクを書き込む
            if (w_scale != 1)      CreateMaskWidth(src, dst);   // 横にマスク画像を作る形式
            else if (h_scale != 1) CreateMaskHeight(src, dst);  // 縦にマスク画像を作る形式
            else                   CreateMaskNormal(src, dst);  // マスク画像のみを作る形式

            src_bmp.UnlockBits(src);
            dst_bmp.UnlockBits(dst);

            // 保存して終了
            dst_bmp.Save(out_file, System.Drawing.Imaging.ImageFormat.Png);
            dst_bmp.Clone();
            src_bmp.Clone();
        }

        /// <summary>
        /// メイン関数
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            bool w = false; // 横にマスクを作成の有無
            bool h = false; // 縦にマスクを作成の有無
            string in_file = "";    // 入力ファイル名
            string out_file = "";   // 出力ファイル名
            // 引数を確認
            for (int i = 0; i < args.Length; ++i)
            {
                if (args[i] == "-w")      w = true;
                else if (args[i] == "-h") h = true;
                else if (args[i] == "-o") out_file = args[++i];
                else                      in_file = args[i];
            }

            // 入力ファイルが存在しない場合はHELP表示
            if (in_file == "")
            {
                Console.WriteLine("CreateMask.exe [読み込む画像ファイル名]");
                Console.WriteLine("-w                横にマスクを生成");
                Console.WriteLine("-h                縦にマスクを生成");
                Console.WriteLine("-o 出力ファイル名  出力ファイル名を設定");
                Console.WriteLine("                  設定がない場合は、入力ファイルに_mが追加されて出力");
                return;
            }
            if (out_file == "")
            {
                // 出力ファイル名がない場合は入力ファイルに_mを追加したものを設定
                out_file = Path.GetFileNameWithoutExtension(in_file) + "_m.png";
            }
            else if (Path.GetExtension(out_file) != ".png")
            {
                // 拡張子に.pngを設定
                out_file = Path.GetFileNameWithoutExtension(out_file) + ".png";
            }

            // マスクを作成
            CreateMask(in_file,
                       out_file,
                       w ? 2 : 1,
                       (!w && h) ? 2 : 1); // 横にマスクを作る形式を優先する
        }
    }
}
```

##最後に
AndroidSDKに付属しているetc1tool.exeを組み合わせれば、簡単にマスク付きETCファイルを生成できます。
cocos2d-xを使えば、windows,macの両対応したツールも作れたと思いますが
面倒だったのでVisualStudioのC#で作成しました。
それではまた次回！！！