Modifying Brightness/Contrast dynamically - by using ToByteArray() /FromByteArray()

Mar 28, 2014 at 4:49 PM
Hi there,

I am using WriteableBitmapEx as a base for a simple (wpf) image editor app, and it works wonderfully. However, recently I ran into a bit of a problem when trying to use ToByteArray() /FromByteArray() as a means to modify Brightness and Contrast of my images. Below is the code snippet with custom extension methods I wrote.

The problem that I have is that my Brightness and Contrast are just fine when I go into positive range. When the value is being changed towards lower end though ( negatives brightness ) the areas in my image that are supposed to turn black actually turn transparent! Is there a reason for this ? I also noticed that if I remove getting and setting up the alpha channel nothing changes at all. One of the issues of course is that the images I am trying to edit are greyscale, so technically I don't even need all three RGB values, but WriteableBitmapEx enforces Pbgra32 so I convert my images into it for editing. (Which is no big deal.) Btw, ToByteArray() /FromByteArray() works really really fast - I can actually drag the slider and see the change 'in real time', unlike when I use any other option. In comparison Get/SetPixel is virtually unusable here as it is extremely slow. But the pesky transparency issue I can do nothing about... Can somebody please help ?
    public unsafe static void SetBrightnessInContext(this WriteableBitmap bmp, int brightness)
    {
        if (brightness < -255) brightness = -255;
        if (brightness > 255) brightness = 255;

        byte[] pixeli = bmp.ToByteArray();
        int l = pixeli.Length;

            for (int i = 0; i < l; i++)
            {

                int pixel = pixeli[i];

                int B = (int)(pixel & 0xFF); pixel >>= 8;
                int G = (int)(pixel & 0xFF); pixel >>= 8;
                int R = (int)(pixel & 0xFF); pixel >>= 8;
                int A = (int)(pixel);

                if (A == 0)
                {
                    A = 1;
                }

                B += brightness;
                R += brightness;
                G += brightness;

                if (R > 255) R = 255; if (G > 255) G = 255; if (B > 255) B = 255;
                if (R < 0) R = 1; if (G < 0) G = 1; if (B < 0) B = 1;


                byte r = (byte)(R);
                byte g = (byte)(G);
                byte b = (byte)(B);
                byte a = (byte)(A);

                pixeli[i] = (byte)((a << 24) | (r << 16) | (g << 8) | b); //(byte)(B | (G << 8) | (R << 16) | (A << 24));
            }

            bmp = bmp.FromByteArray(pixeli);
    }

    public unsafe static void SetContrastInContext(this WriteableBitmap bmp, double contrast)
    {
        if (contrast < -100) contrast = -100;
        if (contrast > 100) contrast = 100;
        contrast = (100.0 + contrast) / 100.0;
        contrast *= contrast;

        byte[] pixeli = bmp.ToByteArray();
        int l = pixeli.Length;

        for (int i = 0; i < l; i++)
        {

            int pixel = pixeli[i];
            int B = (int)(pixel & 0xFF); pixel >>= 8;
            int G = (int)(pixel & 0xFF); pixel >>= 8;
            int R = (int)(pixel & 0xFF); pixel >>= 8;
            int A = (int)(pixel);

            R = (int)Math.Max(0, Math.Min(255, (((R - 128) * contrast) + 128)));
            G = (int)Math.Max(0, Math.Min(255, (((G - 128) * contrast) + 128)));
            B = (int)Math.Max(0, Math.Min(255, (((B - 128) * contrast) + 128)));

            if (R > 255) R = 255; if (G > 255) G = 255; if (B > 255) B = 255;
            if (R < 0) R = 1; if (G < 0) G = 1; if (B < 0) B = 1;


            byte r = (byte)R;
            byte g = (byte)G;
            byte b = (byte)B;
            byte a = (byte)A;

            pixeli[i] = (byte)((a << 24) | (r << 16) | (g << 8) | b); //(byte)(B | (G << 8) | (R << 16) | (A << 24));
        }

        bmp = bmp.FromByteArray(pixeli);
    }