ビットマップファイルからC#のソースコードを生成する

C# コンピュータ
C#
ビットマップファイルを読み込んでアイコンを作成するC#のソースコードを生成することが目的です。

実行環境構築

プロジェクトの作成

mkdir BmpToCsicon
cd BmpToCsicon
dotnet new console
dotnet add package System.Drawing.Common

ソースプログラム

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;


public class BmpToCs 
{
    static public void Main(string[] args)
    {
        if (!OperatingSystem.IsWindows() || args.Length == 0)
        {
            return;
        }

        var path = args[0];
        using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
        using var bmp = new Bitmap(fs);

        var bmpData = bmp.LockBits(
            new Rectangle(0, 0, bmp.Width, bmp.Height),
            ImageLockMode.ReadOnly,
            bmp.PixelFormat);

        var col = Math.Abs(bmpData.Stride);
        byte[] bytes = new byte[col * bmp.Height];

        System.Runtime.InteropServices.Marshal.Copy(
            bmpData.Scan0,
            bytes, 0, bytes.Length);

        string srcCode = "";
        srcCode += "using System.Drawing;\n";
        srcCode += "using System.Drawing.Imaging;\n";
        srcCode += "\n";
        srcCode += "public class IconBin\n";
        srcCode += "{\n";
        srcCode += String.Format("\tstatic public int Height = {0};\n", bmp.Height);
        srcCode += String.Format("\tstatic public int Width = {0};\n", bmp.Width);
        srcCode += String.Format("\tstatic public int PFormat = {0};\n", (int)bmp.PixelFormat);
        srcCode += "\tstatic public byte[] Bytes = new byte[]\n";
        srcCode += "\t{\n";
        for (var i = 0; i < bytes.Length; i++)
        {
            if ((i % 64) == 0) srcCode += "\n\t\t";
            srcCode += String.Format("0x{0:X},", bytes[i]);
        }
        srcCode += "\n\t};//bins\n";

srcCode += @"
    static public Icon GetIcon()
    {
        var dst = new Bitmap(Width, Height, (System.Drawing.Imaging.PixelFormat)PFormat);

        var bmpData = dst.LockBits(
            new Rectangle(0, 0, dst.Width, dst.Height),
            ImageLockMode.ReadWrite,
            dst.PixelFormat);

        System.Runtime.InteropServices.Marshal.Copy(
            Bytes,
            0, bmpData.Scan0,
            Bytes.Length);
        dst.UnlockBits(bmpData);

        return Icon.FromHandle(dst.GetHicon());
    }
";

        srcCode += "}//class\n";

        bmp.UnlockBits(bmpData);

        using (var sw = new StreamWriter("icon.cs", false))
        {
            sw.Write(srcCode);
        }

    }
}

実行

PS<BmpToCsicon.exe <ビットマップファイルのパス>

成功すると”icon.cs”が出来上がります。

icon.csを使ってみる

適当なWinFormsのプロジェクトフォルダにicon.csをコピーします。
Form1.csでicon.cs内のクラスメソッドIconBin.GetIcon()を呼び出しフォームのIconプロパティに割り当てます。

namespace TestForm;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        this.Icon = IconBin.GetIcon();
    }
}

実行してみるとフォームにアイコンが割り当てられたことが確認出来ます。

感想

dotnet sdk環境でアイコンなどのリソースを.exeに埋め込む方法が見つけられなかったので、ビットマップをbyte配列にしてC#のソースコードに埋め込むという苦肉の策を思いつき試してみました。

無圧縮のビットマップのバイナリをテキストとしてソースコードに書き込みますので、ソースファイルのサイズは大きくなります。ちなみに32×32のビットマップファイルから生成したicon.csのファイルサイズは約16KBほどでした。

コメント