How to Darken an Image in WPF

I’m really getting carried away with playing with image manipulation in WPF. Here’s a short post on how to darken an image using the WriteableBitmap class.

The process is fairly simple, I manipulate each pixel by decrementing each RGB value with the provided level

unsafe static BitmapSource Darken(BitmapSource image, double level)
{
    const int PIXEL_SIZE = 4;
    int height = image.PixelHeight;
    int width = image.PixelWidth;
 
    var bitmap = new WriteableBitmap(image);
    bitmap.Lock();
 
    var backBuffer = (byte*)bitmap.BackBuffer.ToPointer();
    for (int y = 0; y < height; y++)
    {
        var row = backBuffer + (y * bitmap.BackBufferStride);
        for (int x = 0; x < width; x++)
            for (int i = 0; i < PIXEL_SIZE; i++)
                row[x * PIXEL_SIZE + i] = (byte)Math.Max(row[x * PIXEL_SIZE + i] - level, 0);
    }
 
    bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
    bitmap.Unlock();
 
    return bitmap;
}

Hope you found this useful.

How to Brighten an Image in WPF

Now I’m just getting carried away with playing with image manipulation in WPF. Here’s a short post on how to brighten an image using the WriteableBitmap class.

The process is fairly simple, I manipulate each pixel by incrementing each RGB value with the provided level

unsafe static BitmapSource Brighten(BitmapSource image, double level)
{
    const int PIXEL_SIZE = 4;
    int height = image.PixelHeight;
    int width = image.PixelWidth;
 
    var bitmap = new WriteableBitmap(image);            
    bitmap.Lock();
 
    var backBuffer = (byte*)bitmap.BackBuffer.ToPointer();
    for (int y = 0; y < height; y++)
    {
        var row = backBuffer + (y * bitmap.BackBufferStride);
        for (int x = 0; x < width; x++)
            for (int i = 0; i < PIXEL_SIZE; i++)
                row[x * PIXEL_SIZE + i] = (byte)Math.Min(row[x * PIXEL_SIZE + i] + level, 255);
    }
 
    bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
    bitmap.Unlock();
 
    return bitmap;
}

Hope you found this useful

How to Alpha Blend 2 Images in WPF

After having such fun trying to find optimal ways of manipulating images in WPF I decided to write another short post on image manipulation. This time I’d like to demonstrate how to alpha blend 2 images using the WriteableBitmap class.

I’m probably not the best one to explain how alpha blending is done but here’s the idea in a nutshell. I get the RGB values of every pixel for the each image and write them to a new bitmap where I manipulate each color information by applying the following formula:

r = ((image1 pixel (red) * alpha level) + (image2 pixel (red) * inverse alpha level)) / 256
b = ((image1 pixel (blue) * alpha level) + (image2 pixel (blue) * inverse alpha level)) / 256
g = ((image1 pixel (green) * alpha level) + (image2 pixel (green) * inverse alpha level)) / 256

unsafe static WriteableBitmap AlphaBlend(BitmapSource image1, BitmapSource image2, int alphaLevel)
{
    const int PIXEL_SIZE = 4;
    int ialphaLevel = 256 - alphaLevel;
    int height = Math.Min(image1.PixelHeight, image2.PixelHeight);
    int width = Math.Min(image1.PixelWidth, image2.PixelWidth);
 
    var bitmap = new WriteableBitmap(width, height, image1.DpiX, image1.DpiY, PixelFormats.Bgr32, null);
    var bitmap1 = new WriteableBitmap(image1);
    var bitmap2 = new WriteableBitmap(image2);
 
    bitmap.Lock();
    bitmap1.Lock();
    bitmap2.Lock();
 
    var backBuffer = (byte*)bitmap.BackBuffer.ToPointer();
    var bitmap1Buffer = (byte*)bitmap1.BackBuffer.ToPointer();
    var bitmap2Buffer = (byte*)bitmap2.BackBuffer.ToPointer();
 
    for (int y = 0; y < height; y++)
    {
        var row = backBuffer + (y * bitmap.BackBufferStride);
        var img1Row = bitmap1Buffer + (y * bitmap1.BackBufferStride);
        var img2Row = bitmap2Buffer + (y * bitmap2.BackBufferStride);
 
        for (int x = 0; x < width; x++)
            for (int i = 0; i < PIXEL_SIZE; i++)
                row[x * PIXEL_SIZE + i] = (byte)(((img1Row[x * PIXEL_SIZE + i] * alphaLevel) + (img2Row[x * PIXEL_SIZE + i] * ialphaLevel)) >> 8);
    }
 
    bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
    bitmap2.Unlock();
    bitmap1.Unlock();
    bitmap.Unlock();
 
    return bitmap;
}

The method above will probably work best if the 2 images are of the same size. I hope you found this information useful.

How to convert an image to gray scale in WPF

I’ve been playing with the Windows Presentation Foundation today and I had a task where I needed to convert an image to gray scale to do some image analysis on it. I’ve done this a bunch of times before using GDI methods or by accessing the BitmapData class in .NET. For this short post I’d like to demonstrate how to manipulate images using the WriteableBitmap class.

The easiest way to convert an image to gray scale is to set the RGB values of every pixel to the average of each pixels RBG values.
R = (R + B + G) / 3
G = (R + B + G) / 3
B = (R + B + G) / 3

Here’s a code snippet for manipulating a BitmapSource object using the WriteableBitmap class into a gray scale image:

public unsafe static BitmapSource ToGrayScale(BitmapSource source)
{
    const int PIXEL_SIZE = 4;
    int width = source.PixelWidth;
    int height = source.PixelHeight;
    var bitmap = new WriteableBitmap(source);
 
    bitmap.Lock();
    var backBuffer = (byte*)bitmap.BackBuffer.ToPointer();
    for (int y = 0; y < height; y++)
    {
        var row = backBuffer + (y * bitmap.BackBufferStride);
        for (int x = 0; x < width; x++)
        {
            var grayScale = (byte)(((row[x * PIXEL_SIZE + 1]) + (row[x * PIXEL_SIZE + 2]) + (row[x * PIXEL_SIZE + 3])) / 3);
            for (int i = 0; i < PIXEL_SIZE; i++)
                row[x * PIXEL_SIZE + i] = grayScale;
        }
    }
    bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
    bitmap.Unlock();
 
    return bitmap;
}

Another way to to convert an image to gray scale is to set the RGB values of every pixel to the sum of 30% of the red value, 59% of the green value, and 11% of the blue value. Hope you find this useful.

Scroll to top