Image manipulation in C# WPF/Silverlight

In my previous post, I demonstrated how to manipulate an image in WPF – the editable bitmap class is called WriteableImage. There is a class with the same name in Silverlight, but unfortunately, they’re not really similar. I’ve extended my extensions to also work under Silverlight – so that the same code can be used in C#/WPF and Silverlight.

The following helper class works the same in C#/WPF and in Silverlight;

using System;
using System.Windows;
using System.Windows.Media.Imaging;

namespace ImageEvolvatron.Core
{
    public static class WriteableBitmapHelper
    {
#if SILVERLIGHT
        public static WriteableBitmap CreateBitmap(int width, int height)
        {
            return new WriteableBitmap(width, height);
        }

        public static void SetEachPixelColour(
            this WriteableBitmap bitmap,
            Func<Point, PixelColor> colourFunc)
        {
            Point point = new Point(0, 0);
            int[] pixels = bitmap.Pixels;
            int pixelPos = 0;
            for (int y = 0; y < bitmap.PixelHeight; y++)
            {
                point.Y = y;
                for (int x = 0; x < bitmap.PixelWidth; x++)
                {
                    point.X = x;
                    PixelColor color = colourFunc(point);
                    pixels[pixelPos++] = color.AsInt;
                }
            }
        }
#else
        public static WriteableBitmap CreateBitmap(int width, int height)
        {
            return new WriteableBitmap(
                width,
                height,
                96,
                96,
                System.Windows.Media.PixelFormats.Bgr32,
                null);
        }

        public static void SetEachPixelColour(
            this WriteableBitmap bitmap,
            Func<Point, PixelColor> colourFunc)
        {
            // See http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap.aspx
            unsafe
            {
                // Get a pointer to the back buffer.
                bitmap.Lock();
                Point point = new Point(0, 0);
                int backBuffer = (int)bitmap.BackBuffer;

                for (int y = 0; y < bitmap.PixelHeight; y++)                    
                {
                    point.Y = y; 
                    for (int x = 0; x < bitmap.PixelWidth; x++)
                    {
                        point.X = x;

                        // Find the address of the pixel to draw.
                        PixelColor color = colourFunc(point);

                        // Assign the color data to the pixel.
                        *((int*)backBuffer) = color.AsInt;
                        
                        // Step to the next pixel - 4 bytes per pixel
                        backBuffer += 4;
                    }
                }

                // The entire bitmap has been regenerated
                bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
                bitmap.Unlock();
            }
        }
#endif
    }
}

 

The PixelColor source;

using System.Runtime.InteropServices;

namespace ImageEvolvatron.Core
{
    [StructLayout(LayoutKind.Sequential)]
    public struct PixelColor
    {
        public byte Blue;
        public byte Green;
        public byte Red;
        public byte Alpha;

        public static PixelColor FromArgb(byte red, byte green, byte blue)
        {
            return
                new PixelColor
                    {
                        Blue = blue,
                        Red = red,
                        Green = green,
                        Alpha = 255
                    };
        }

        public int AsInt
        {
            get
            {
                return
                    Alpha << 24 // Alpha
                  | Red << 16  // R
                  | Green << 8   // G
                  | Blue << 0;   // B
            }
        }
    }
}

This code, either in Silverlight or C#/WPF, works to produce the image shown;

silverlightDistanceFromCenter

Actual Silverlight/C# code:

        public static BitmapSource ShowDistanceFromCenter(int width, int height)
        {
            Point imageCenter = new Point(width / 2.0, height / 2.0);
            WriteableBitmap bitmap = WriteableBitmapHelper.CreateBitmap(width, height);
            double maxDistance = Distance(imageCenter.X, imageCenter.Y);
            bitmap.SetEachPixelColour(
                point =>
                {
                    double dist = Distance(
                        point.X - imageCenter.X,
                        point.Y - imageCenter.Y);

                    byte core = Convert.ToByte(255 * dist / maxDistance);
                    PixelColor color = PixelColor.FromArgb(core, core, core);

                    if (Math.Round(point.X) == Math.Round(imageCenter.X))
                    {
                        color.Red = (byte)(255 - color.Red);
                    }

                    if (Math.Round(point.Y) == Math.Round(imageCenter.Y))
                    {
                        color.Blue = (byte)(255 - color.Blue);
                    }

                    return color;
                });
            return bitmap;
        }

        private static double Distance(double dx, double dy)
        {
            return Math.Sqrt((dx * dx) + (dy * dy));
        }

About mfagerlund
Writes code in my sleep - and sometimes it even compiles!

One Response to Image manipulation in C# WPF/Silverlight

  1. Pingback: 2010 in review « Mattias Fagerlund's Coding Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: