Using Lambda to manipulate Silverlight/Wpf bitmaps

[Damn, I recently re-installed my entire computer because I added an SSD disc, and ever since, Visual Studio keeps crashing unexpectantly- and my computer bluescreens! I haven’t had bluescreens since ages ago. It’s driving me bonkers, I just lost an entire blogpost,  – I’m retyping it below]

A while pack, I wrote a post about Using Lambda to manipulate images, the code provided can be used with WPF (throught converting the bitmap to a jpeg/png and reloading it in WPF), but it could not be used with Silverlight. I wanted to do some image manipulation in Silverlight, so I researched how to do the same things – turns out to messier. Basically, you’ll need to use the WriteableBitmap. Btw, WritaeblaBitmap is s incorrectly spelled WritableBitmap in about 10k webpages, while there are about 70k pages that spell it correctly. That’s more than 10%….

Here’s the code for my extensions and helpers that allow me to manipulate images;

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

namespace MyNamespace
{
    public static class WriteableBitmapHelper
    {
        public static WriteableBitmap CreateBitmap(int width, int height)
        {
            return new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, null);
        }

        public static void PutPixel(
            this WriteableBitmap bitmap, 
            PixelColor color, 
            int x, 
            int y)
        {
            bitmap.Lock();
            PixelColor[,] pixels = new PixelColor[0, 0];
            pixels[0, 0] = color;
            bitmap.WritePixels(new Int32Rect(0, 0, 1, 1), pixels, bitmap.PixelWidth * 4, x, y);
            bitmap.Unlock();
        }

        public static PixelColor[,] GetPixels(WriteableBitmap source)
        {
            /* I wish this code would work, but it doesn't...
            if (source.PixelFormat != PixelFormats.Bgra32)
            {
                source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);
            }*/

            int width = source.PixelWidth;
            int height = source.PixelHeight;
            PixelColor[,] result = new PixelColor[width, height];

            source.CopyPixels(result, width * 4, 0);
            return result;
        }

        public static void PutPixels(
            this WriteableBitmap 
            bitmap,
            PixelColor[,] pixels, 
            int x, 
            int y)
        {
            bitmap.Lock();
            int width = pixels.GetLength(0);
            int height = pixels.GetLength(1);
            bitmap.WritePixels(
                new Int32Rect(0, 0, width, height), 
                pixels, 
                width * 4,
                x, 
                y);
            bitmap.Unlock();
        }

        public static void SetEachPixelColour(
            this WriteableBitmap bitmap, 
            Func<Point, PixelColor> colourFunc)
        {
            PixelColor[,] pixels = 
                new PixelColor[
                    bitmap.PixelWidth, 
                    bitmap.PixelHeight];
            Point point = new Point(0, 0);
            for (int x = 0; x < bitmap.PixelWidth; x++)
            {
                point.X = x;
                for (int y = 0; y < bitmap.PixelHeight; y++)
                {
                    point.Y = y;
                    pixels[x, y] = colourFunc(point);
                }
            }
            
            bitmap.PutPixels(pixels, 0, 0);
        }
    }
}

 

Here’s an example using the code above – it generetas an image where the brightness denotes the distance from the center of the image;

distanceFromCenter

Here’s the code;

using System;
using System.Windows;
using System.Windows.Media.Imaging;
using ImageEvolvatron.Core;

namespace ImageEvolvatron.Wpf
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            ShowDistanceFromCenter();
        }

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

        private void ShowDistanceFromCenter()
        {

            WriteableBitmap bitmap = 
                WriteableBitmapHelper.CreateBitmap(
                (int)myImage.Width, 
                (int)myImage.Height);
            Point imageCenter = new Point(
                bitmap.Width / 2, 
                bitmap.Height / 2);
            double maxDistance = Distance(imageCenter.X, imageCenter.Y);
            bitmap.SetEachPixelColour(
                point =>
                {
                    double dist = Distance(
                        point.X - imageCenter.X, 
                        point.Y - imageCenter.Y);
                    byte b = Convert.ToByte(
                        255 * dist / maxDistance);
                    return PixelColor.FromArgb(b, b, b);
                });
            myImage.Source = bitmap;
        }
    }
}

To run this, just create a WPF application and add this xaml;

<Window x:Class="ImageEvolvatron.Wpf.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="420" Width="498">
    <Grid Background="AliceBlue">
        <Image x:Name="myImage" Width="256" Height="256"></Image>
    </Grid>
</Window>

Let me know if you have any suggestions!

Technorati-taggar: ,,,

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

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: