2016年8月30日火曜日

Bitmapの高速アクセス

C#のBitmapでGetPixelとかSetPixelをやるとかなり遅いので、直接メモリアクセスするライブラリ。

本家ソースコードはこちら
NonSoft - Bitmap処理を高速化するサンプル(C#.NET)

ただしこのコードは24bppRgbアクセスのため、透過情報が破棄されてしまう。ということで32bppArgbに書き直している。ほとんどコピペだけど。

あと色情報をbyte配列で受け取るメソッドを追加してある(与えるメソッドは無い)。

このクラスを使用する場合はSystemとSystem.Drawingの名前空間が必要です。



http://homepage2.nifty.com/nonnon/SoftSample/CS.NET/SampleBitmapPlus.html

/// <summary>
/// Bitmap処理を高速化するためのクラス
/// </summary>
class BitmapPlus
{
    /// <summary>
    /// オリジナルのBitmapオブジェクト
    /// </summary>
    private Bitmap _bmp = null;

    /// <summary>
    /// Bitmapに直接アクセスするためのオブジェクト
    /// </summary>
    private System.Drawing.Imaging.BitmapData _img = null;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="original"></param>
    public BitmapPlus(Bitmap original)
    {
        // オリジナルのBitmapオブジェクトを保存
        _bmp = original;
    }

    /// <summary>
    /// Bitmap処理の高速化開始
    /// </summary>
    public void BeginAccess()
    {
        // Bitmapに直接アクセスするためのオブジェクト取得(LockBits)
        _img = _bmp.LockBits(new Rectangle(0, 0, _bmp.Width, _bmp.Height),
            System.Drawing.Imaging.ImageLockMode.ReadWrite,
            System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    }

    /// <summary>
    /// Bitmap処理の高速化終了
    /// </summary>
    public void EndAccess()
    {
        if (_img != null)
        {
            // Bitmapに直接アクセスするためのオブジェクト開放(UnlockBits)
            _bmp.UnlockBits(_img);
            _img = null;
        }
    }

    /// <summary>
    /// BitmapGetPixel同等
    /// </summary>
    /// <param name="x">X座標</param>
    /// <param name="y">Y座標</param>
    /// <returns>Colorオブジェクト</returns>
    public Color GetPixel(int x, int y)
    {
        if (_img == null)
        {
            // Bitmap処理の高速化を開始していない場合はBitmap標準のGetPixel
            return _bmp.GetPixel(x, y);
        }

        // Bitmap処理の高速化を開始している場合はBitmapメモリへの直接アクセス
        IntPtr adr = _img.Scan0;
        int pos = x * 4 + _img.Stride * y;
        byte b = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 0);
        byte g = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 1);
        byte r = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 2);
        byte a = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 3);
        return Color.FromArgb(a, r, g, b);
    }

    /// <summary>
    /// BitmapSetPixel同等
    /// </summary>
    /// <param name="x">X座標</param>
    /// <param name="y">Y座標</param>
    /// <param name="col">Colorオブジェクト</param>
    public void SetPixel(int x, int y, Color col)
    {
        if (_img == null)
        {
            // Bitmap処理の高速化を開始していない場合はBitmap標準のSetPixel
            _bmp.SetPixel(x, y, col);
            return;
        }

        // Bitmap処理の高速化を開始している場合はBitmapメモリへの直接アクセス
        IntPtr adr = _img.Scan0;
        int pos = x * 4 + _img.Stride * y;
        System.Runtime.InteropServices.Marshal.WriteByte(adr, pos + 0, col.B);
        System.Runtime.InteropServices.Marshal.WriteByte(adr, pos + 1, col.G);
        System.Runtime.InteropServices.Marshal.WriteByte(adr, pos + 2, col.R);
        System.Runtime.InteropServices.Marshal.WriteByte(adr, pos + 3, col.A);
    }

    public byte[] GetBytes(int x, int y)
    {
        if (_img == null)
        {
            return (null);
        }

        // Bitmap処理の高速化を開始している場合はBitmapメモリへの直接アクセス
        IntPtr adr = _img.Scan0;
        int pos = x * 4 + _img.Stride * y;
        byte b = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 0);
        byte g = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 1);
        byte r = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 2);
        byte a = System.Runtime.InteropServices.Marshal.ReadByte(adr, pos + 3);
        return new byte[] { a, r, g, b };
    }

}

0 件のコメント:

コメントを投稿