Search code examples
c#wpfcanvasbytepixel

WPF: Looking for a fast method to display a rgb pixel array (byte) to canvas to create an image


i have an array = byte[512,512] in each field i have an value from 0 to 255 which then represents gray color (from white to black) for each pixel. Until now i cameup with a code which creates a new rectangle (width 1 height 1) for each array field and then puts it on canvas. This method is very slow (at least on my laptop). It usualy takes up to 30 or maybe 40 seconds.

I would be very happy if someone could show me how to do this in some other way. thank you in advance.

private void draw_a_pixel(Rectangle pixel, double top, int widthCounter)
    {
        Canvas.SetTop(pixel, Convert.ToInt32(top));
        Canvas.SetLeft(pixel, widthCounter);
        canvas1.Children.Add(pixel);

    }

this is the section of the code that takes the most amount of time i think.


Solution

  • As Chris said, you should use the WriteableBitmap.

    Here is some material to start:

    /// <summary>
    /// method that will create a source for your image object,
    /// and fill it with a specified array of pixels
    /// </summary>
    /// <param name="pixels">your array of pixels</param>
    /// <returns>your image object</returns>
    public BitmapSource DrawImage(Int32[,] pixels)
    {
        int resX = pixels.GetUpperBound(0) + 1;
        int resY = pixels.GetUpperBound(1) + 1;
    
        WriteableBitmap writableImg = new WriteableBitmap(resX, resY, 96, 96, PixelFormats.Bgr32, null);
    
        //lock the buffer
        writableImg.Lock();
    
        for (int i = 0; i < resX; i++)
        {
            for (int j = 0; j < resY; j++)
            {
                IntPtr backbuffer = writableImg.BackBuffer;
                //the buffer is a monodimensionnal array...
                backbuffer += j * writableImg.BackBufferStride;
                backbuffer += i * 4;
                System.Runtime.InteropServices.Marshal.WriteInt32(backbuffer, pixels[i,j]);
            }
        }
    
        //specify the area to update
        writableImg.AddDirtyRect(new Int32Rect(0, 0, resX, resY));
        //release the buffer and show the image
        writableImg.Unlock();
    
        return writableImg;
    }
    

    Each pixel of your array has to be an Int32. Here is a function to convert RGB color code to Int32

    /// <summary>
    /// Return the specified color code as a Int32
    /// </summary>
    public Int32 GetColor(byte r, byte g, byte b)
    {
        return Int32.Parse(Color.FromRgb(r, g, b).ToString().Trim('#'), System.Globalization.NumberStyles.HexNumber);
    }
    

    Fill your array of pixels the way you want.

    Add a Image to your XAML and update the source.

    <Image x:Name="Chart"/>
    
    Chart.Source = DrawImage(pixels);