Knickerless-Noggins Knickerless-Noggins - 15 days ago 9
C# Question

Manipulating a Bitmap via an integer array in C# (Fast PictureBox editing)

I'm trying to make an integer array and Bitmap work in harmony as part of a C# winforms project for fast PictureBox editing (avoiding the slow SetPixel command).

I added a Button and a PictureBox, a click event on the aformentioned Button and a closing event on the Form.

The code for the Form is now like so:

public partial class Form1 : Form
{
uint[] _Pixels { get; set; }

Bitmap _Bitmap { get; set; }

GCHandle _Handle { get; set; }

IntPtr _Addr { get; set; }


public Form1()
{
InitializeComponent();

int imageWidth = 100; //1920;

int imageHeight = 100; // 1080;

PixelFormat fmt = PixelFormat.Format32bppRgb;

int pixelFormatSize = Image.GetPixelFormatSize(fmt);

int stride = imageWidth * pixelFormatSize;

int padding = 32 - (stride % 32);

if (padding < 32)
{
stride += padding;
}

_Pixels = new uint[(stride / 32) * imageHeight + 1];

_Handle = GCHandle.Alloc(_Pixels, GCHandleType.Pinned);

_Addr = Marshal.UnsafeAddrOfPinnedArrayElement(_Pixels, 0);

_Bitmap = new Bitmap(imageWidth, imageHeight, stride / 8, fmt, _Addr);

pictureBox1.Image = _Bitmap;

}

private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < _Pixels.Length; i++)
{
_Pixels[i] = ((uint)(255 | (255 << 8) | (255 << 16) | 0xff000000));

}

}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_Addr = IntPtr.Zero;

if (_Handle.IsAllocated)
{
_Handle.Free();

}

_Bitmap.Dispose();

_Bitmap = null;

_Pixels = null;

}

}


When run, a black image as expected is present in the beginning.

The image should turn white when the button is clicked, but I'm missing something.

What am I forgetting to do?

Answer

Add pictureBox1.Refresh() after updating the array and it works.

The code for the form is now like so:

public partial class Form1 : Form
{
    uint[] _Pixels { get; set; }

    Bitmap _Bitmap { get; set; }

    GCHandle _Handle { get; set; }

    IntPtr _Addr { get; set; }


    public Form1()
    {
        InitializeComponent();

        int imageWidth = 100; //1920;

        int imageHeight = 100; // 1080;

        PixelFormat fmt = PixelFormat.Format32bppRgb;

        int pixelFormatSize = Image.GetPixelFormatSize(fmt);

        int stride = imageWidth * pixelFormatSize;

        int padding = 32 - (stride % 32);

        if (padding < 32)
        {
            stride += padding;
        }

        _Pixels = new uint[(stride / 32) * imageHeight + 1];

         _Handle = GCHandle.Alloc(_Pixels, GCHandleType.Pinned);

        _Addr = Marshal.UnsafeAddrOfPinnedArrayElement(_Pixels, 0);

        _Bitmap = new Bitmap(imageWidth, imageHeight, stride / 8, fmt, _Addr);

        pictureBox1.Image = _Bitmap;

    }

    private void button1_Click(object sender, EventArgs e)
    {
        for (int i = 0; i < _Pixels.Length; i++)
        {
            _Pixels[i] = ((uint)(255 | (255 << 8) | (255 << 16) | 0xff000000));

        }

        pictureBox1.Refresh();

    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        _Addr = IntPtr.Zero;

        if (_Handle.IsAllocated)
        {
            _Handle.Free();

        }

        _Bitmap.Dispose();

        _Bitmap = null;

        _Pixels = null;

    }

}