Xamarin Android – Grayscaling and Brightness Adjustment For Bitmaps With The Canvas

In this post I’ll be covering how to grayscale and brightness adjust bitmaps and render them using the canvas for hardware accelerated rendering

Advertisements

One of the more powerful features in Android is the canvas, a hardware accelerated drawing surface that allows you to do hardware rendering instead of typical, slow software rendering of pixel data. In this post, I’d like to share some useful image adjustment features I’ve learned, which utilize the canvas allowing for super fast, real time image editing in Android.

Grayscale via saturation adjustment

To grayscale an image, the fastest method I’ve found is to simply adjust the saturation level with the canvas and a color matrix. So, let’s take a look at some code I’ve written for doing just that:

public static Bitmap GrayscaleBitmap(Bitmap bmpOriginal)
{
    int width, height;
    height = bmpOriginal.Height;
    width = bmpOriginal.Width;

    // Create a temporary bitmap to preserve the original image for the final draw
    Bitmap bitmapGrayscale = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888);
    Canvas canvas = new Canvas(bitmapGrayscale);

    // Create a paint object to specify the saturation for the final draw
    Paint paint = new Paint();
    ColorMatrix colorMatrix = new ColorMatrix();
    colorMatrix.SetSaturation(0);

    // Apply the saturation filter and draw the final bitmap using the origin bitmap
    ColorMatrixColorFilter saturationFilter = new ColorMatrixColorFilter(colorMatrix);
    paint.SetColorFilter(saturationFilter);
    canvas.DrawBitmap(bmpOriginal, 0, 0, paint);
    return bitmapGrayscale;
}

This code is a little weird if you’ve never used paint or color matrix objects, but basically all that happens here is we pass a bitmap, get it’s width and height and use that to create a new bitmap which will represent the grayscaled bitmap, then create a color matrix with a saturation of zero. The color matrix will represent a matrix which will be multiplied against the bitmap pixel data, the big reason we use this is because it’s all hardware accelerated, so it will execute on the GPU, which is exponentially faster for this type of work than the CPU. We then assign the color matrix to a paint object, which we then pass to the canvas DrawBitmap method, which will draw the bitmap using our paint object. This will result in a grayscaled image.

Brightness adjustment

Next, let’s look at brightness adjustment:

public static Bitmap ApplyBitmapBrightness(int brightnessLevel, Bitmap bitmap)
{
    // Create a temporary bitmap to preserve the original image for the final draw
    Bitmap brightnessAdjustedBitmap = Bitmap.CreateBitmap(bitmap.Width, bitmap.Height, Bitmap.Config.Argb8888);
    Canvas c = new Canvas(brightnessAdjustedBitmap);
    Paint paint = new Paint();
    ColorMatrix colorMatrix = new ColorMatrix();

    // Apply the brightness filter and draw the final bitmap using 
    // the paint object and the origin bitmap
    ColorMatrixColorFilter brightnessFilter = AdjustBrightness(brightnessLevel);
    paint.SetColorFilter(brightnessFilter);
    c.DrawBitmap(bitmap, 0, 0, paint);
    return brightnessAdjustedBitmap;
}

Here, we create a bitmap based on the original bitmaps height and width as we did before, and we create a new canvas object, passing our bitmap to it. The way this is set up is a little weird because I needed it to work in realtime based on a slider, but the idea is we again create a color matrix by calling another method, AdjustBrightness, which is this bit of code here:

        public static ColorMatrixColorFilter AdjustBrightness(int BrightnessLevel)
        {

            /*
             Calculted as follows:
             Matrix:
              [ a, b, c, d, e,
                f, g, h, i, j,
                k, l, m, n, o,
                p, q, r, s, t ]
             Matrix Calculations:
                R’ = a*R + b*G + c*B + d*A + e;
                G’ = f*R + g*G + h*B + i*A + j;
                B’ = k*R + l*G + m*B + n*A + o;
                A’ = p*R + q*G + r*B + s*A + t;
             */
            ColorMatrix matrix = new ColorMatrix();

            // This is essentially an identity matrix that adjusts colors based on the fourth 
            // element of each row of the matrix
            matrix.Set(new float[] {
                    1, 0, 0, 0, BrightnessLevel,
                    0, 1, 0, 0, BrightnessLevel,
                    0, 0, 1, 0, BrightnessLevel,
                    0, 0, 0, 1, 0 });

            ColorMatrixColorFilter brightnessFilter = new ColorMatrixColorFilter(matrix);
            return brightnessFilter;
        }

So all that happens here is we create an identity matrix where the 4th element adjusts the brightness level of each pixel it’s multiplied against. This gets returned to the bitmap brightness adjustment method and is used to then create a paint object and draw the bitmap as we did in the grayscaling method.

Conclusion

That’s all I’ve got for now, it’s all pretty straightforward, but adds really cool functionality to an app that does any sort of work with images, just having the option to edit an image at all in my opinion takes your app to another level, even though what’s going on under the hood isn’t really all that complicated. Hopefully you found this helpful, and if you enjoyed this post, leave a comment or a like and consider following the blog. Thanks, and until next time.

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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s

Advertisements
Advertisements
%d bloggers like this: