Lexa

WPF, C#, Objective C and a little Math

Transform Bitmap in WPF

Sometimes Effects are not enough when you need to modify an imageĀ  – in example to highlight it.

Originally the task was to higlight an image (wich might have alpha channel) with different colors – red, green, blue, etc., depending on the state of the application. Googling didnt help a lot, thats why I finished with writing my own (rather plain) function which transforms image content.

This is the function in form of extension:

public static class BitmapSourceExtension
{
    public static BitmapSource HighlightedBitmap(this BitmapSource bitmapSource, Color color)
    {
        if (bitmapSource.Format.BitsPerPixel != 32)
        {
            if (bitmapSource.Format != System.Windows.Media.PixelFormats.Bgra32)
            {
                bitmapSource = new FormatConvertedBitmap(bitmapSource, 
                              System.Windows.Media.PixelFormats.Bgra32, null, 0);
            }
        }

        WriteableBitmap writeableBitmap = new WriteableBitmap(bitmapSource);

        int width = writeableBitmap.PixelWidth;
        int height = writeableBitmap.PixelHeight;

        float cr = ((float)color.R) / 255;
        float cg = ((float)color.G) / 255;
        float cb = ((float)color.B) / 255;
        float ca = ((float)color.A) / 255;

        writeableBitmap.Lock();

        unsafe
        {
            // Get a pointer to the back buffer.
            int pBackBuffer = (int)writeableBitmap.BackBuffer;

            for (int i = 0; i < width * height; ++i, pBackBuffer += 4)
            {
                // Find the address of the pixel to draw.
                uint ucolor = *((uint*)pBackBuffer);

                // Compute the pixel's color.
                uint a = (ucolor >> 24);
                uint r = (ucolor >> 16) & 0xff;
                uint g = (ucolor >> 8 ) & 0xff;
                uint b = (ucolor) & 0xff;

                ucolor =
                    ((uint)(a * ca) << 24) |
                    ((uint)(r * cr) << 16) |
                    ((uint)(g * cg) << 8 ) |
                    ((uint)(b * cb));

                // Assign the color data back to the pixel.
                *((uint*)pBackBuffer) = ucolor;
            }
        }

        // Specify the area of the bitmap that changed.
        writeableBitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, width, height));

        // Release the back buffer and make it available for display.
        writeableBitmap.Unlock();

        return writeableBitmap;
    }
}

And this is an example of the Converter which uses the extension:

public class HighlightImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, 
                          object parameter, System.Globalization.CultureInfo culture)
    {
        if (parameter == null || (value as BitmapSource) == null)
        {
            return value;
        }
        else
        {
            Color color = Colors.White;
            if (value.GetType() == typeof(Color))
            {
                color = (Color)parameter;
            }
            else
            {
                color = (Color)ColorConverter.ConvertFromString(parameter.ToString());
            }
            return ((BitmapSource)value).HighlightedBitmap(color);
        }
    }

    public object ConvertBack(object value, Type targetType, 
                              object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

And this is the part of a xaml which generates the result shown above:

<Image Source="robot.jpg" Name="originalImage"/>
<Image Grid.Column="1"
    Source="{Binding Source, 
    ElementName=originalImage,
    Converter={StaticResource HighlightImageConverter},
    ConverterParameter=Orange}" 
    />

Categorised as: WPF


2 Comments

  1. Jeff Tayler says:

    Hi there – It’s good to see a site like this with worked examples with well commented code. I’m struggling looking for example of floodfilling regions of a bitmap in WPF – are there any examples here on this site of this?

    thanks

    p.s. when I posted this message – the page blanked to ‘could not open socket’ after I pressed ‘post comment’ – so I am posting twice

    Jeff

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>