【C#】Bitmap画像データの拡大縮小

Bitmap画像を拡大縮小するには、Bitmapクラスのコンストラクタで、

Bitmap bmpOrijinal = new Bitmap("sample.bmp");

int scale = 50;
Bitmap bmpResize = new Bitmap(
    bmpOrijinal,
    bmpOrijinal.Width * scale,
    bmpOrijinal.Height * scale
    );

pictureBox1.Image = bmpResize;

(処理結果)

C# Bitmap画像の拡大縮小

のようにすると簡単に画像を拡大縮小をすることができますが、このやり方では、いくつか不都合があります。

●モノクロ8bit画像に対応していない。

●補間モードを指定できない。

●画像を拡大すると、0.5画素分、位置がズレている。

●リサイズ後のBitmapは32bitになってしまう。

ということで、これらに対応したメソッドを作ってみました。

/// <summary>
/// Bitmap画像データのリサイズ
/// </summary>
/// <param name="original">元のBitmapクラスオブジェクト</param>
/// <param name="width">リサイズ後の幅</param>
/// <param name="height">リサイズ後の高さ</param>
/// <param name="interpolationMode">補間モード</param>
/// <returns>リサイズされたBitmap</returns>
private Bitmap ResizeBitmap(Bitmap original, int width, int height, System.Drawing.Drawing2D.InterpolationMode interpolationMode)
{
    Bitmap bmpResize;
    Bitmap bmpResizeColor;
    Graphics graphics = null;

    try
    {
        System.Drawing.Imaging.PixelFormat pf = original.PixelFormat;

        if (original.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
        {
            // モノクロの時は仮に24bitとする
            pf = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
        }

        bmpResizeColor = new Bitmap(width, height, pf);
        var dstRect = new RectangleF(0, 0, width, height);
        var srcRect = new RectangleF(-0.5f, -0.5f, original.Width, original.Height);
        graphics = Graphics.FromImage(bmpResizeColor);
        graphics.Clear(Color.Transparent);
        graphics.InterpolationMode = interpolationMode;
        graphics.DrawImage(original, dstRect, srcRect, GraphicsUnit.Pixel);

    }
    finally
    {
        if (graphics != null)
        {
            graphics.Dispose();
        }
    }

    if (original.PixelFormat == System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
    {
        // モノクロ画像のとき、24bit→8bitへ変換

        // モノクロBitmapを確保
        bmpResize = new Bitmap(
            bmpResizeColor.Width, 
            bmpResizeColor.Height, 
            System.Drawing.Imaging.PixelFormat.Format8bppIndexed
            );

        var pal = bmpResize.Palette;
        for (int i = 0; i < bmpResize.Palette.Entries.Length; i++)
        {
            pal.Entries[i] = original.Palette.Entries[i];
        }
        bmpResize.Palette = pal;

        // カラー画像のポインタへアクセス
        var bmpDataColor = bmpResizeColor.LockBits(
                new Rectangle(0, 0, bmpResizeColor.Width, bmpResizeColor.Height),
                System.Drawing.Imaging.ImageLockMode.ReadWrite,
                bmpResizeColor.PixelFormat
                );

        // モノクロ画像のポインタへアクセス
        var bmpDataMono = bmpResize.LockBits(
                new Rectangle(0, 0, bmpResize.Width, bmpResize.Height),
                System.Drawing.Imaging.ImageLockMode.ReadWrite,
                bmpResize.PixelFormat
                );

        int colorStride = bmpDataColor.Stride;
        int monoStride = bmpDataMono.Stride;

        unsafe
        {
            var pColor = (byte*)bmpDataColor.Scan0;
            var pMono = (byte*)bmpDataMono.Scan0;
            for (int y = 0; y < bmpDataColor.Height; y++)
            {
                for (int x = 0; x < bmpDataColor.Width; x++)
                {
                    // R,G,B同じ値のため、Bの値を代表してモノクロデータへ代入
                    pMono[x + y * monoStride] = pColor[x * 3 + y * colorStride];    
                }
            }
        }

        bmpResize.UnlockBits(bmpDataMono);
        bmpResizeColor.UnlockBits(bmpDataColor);

        // 解放
        bmpResizeColor.Dispose();
    }
    else
    {
        // カラー画像のとき
        bmpResize = bmpResizeColor;
    }

    return bmpResize;
}

このResizeBitmapメソッドを使って、このようなプログラムを書くと

Bitmap bmpOrijinal = new Bitmap("sample.bmp");

int scale = 50;
Bitmap bmpResize = ResizeBitmap(
    bmpOrijinal,
    bmpOrijinal.Width * scale,
    bmpOrijinal.Height * scale,
    System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor
    );

pictureBox1.Image = bmpResize;

(処理結果)

C# Bitmap画像の拡大縮小

となります。

モノクロの処理は少しまどろっこしい感じもしますが、画像データのリサイズや補間の部分を自前で書くよりは簡単!?

画像処理のためのC#へ戻る