4

I have an image and i want to adjust its brightness and contrast through a slider in xaml. I don't know where to start.Any help would be appreciated. I am trying to implement this

public  WriteableBitmap ChangeBrightness(WriteableBitmap inputBitmap, double brightnessValue )
{
    double Value = brightnessValue;
    var inputPixels = inputBitmap.Pixels;
    for (int i = 0; i < inputPixels.Length; i++)
    {
        // Extract color components
        var c = inputBitmap.Pixels[i];
        var a = (byte)(c >> 24);
        var r = (byte)(c >> 16);
        var g = (byte)(c >> 8);
        var b = (byte)(c);

        int ri = r + (int)Value;
        int gi = g + (int)Value;
        int bi = b + (int)Value;

        // Clamp to byte boundaries
        r = (byte)(ri > 255 ? 255 : (ri < 0 ? 0 : ri));
        g = (byte)(gi > 255 ? 255 : (gi < 0 ? 0 : gi));
        b = (byte)(bi > 255 ? 255 : (bi < 0 ? 0 : bi));
        inputBitmap.Pixels[i] = (a << 24) | (r << 16) | (g << 8) | b;
    }
    return inputBitmap;          
}

but it is of no use i guess and i am not finding any useful article for it.

Chubosaurus Software
  • 8,133
  • 2
  • 20
  • 26
Pranav Mahajan
  • 2,048
  • 2
  • 23
  • 36

2 Answers2

3

See Formula For Adjusting Brightness

Using the adding formula you're missing 2 Parts in your program.

Part 1: Create a new Writeable Bitmap instead of modifing the input bitmap (return this new bitmap)
Part 2: You have to save an original copy of the Bitmap (Brightness is not reversible like the above link said)


A extremely slow implementation to get you started. Most of this stuff can be found on MSDN if you just take some time to read (it's a habit you need to get into if you want to make programs more advance than Hello World).

<StackPanel>
    <Image x:Name="myImage" Stretch="None" Source="Assets/bling.png"/>
    <Slider x:Name="mySilder" ValueChanged="mySilder_ValueChanged"></Slider>
</StackPanel>

// namespaces
using Windows.UI.Xaml.Media.Imaging;
using Windows.Storage;

// our copy of the image
WriteableBitmap copy;

public MainPage()
{
    this.InitializeComponent();
}

private async void Page_Loaded(object sender, RoutedEventArgs e)
{

    // storage file for the image (load it)
    StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/bling.png"));

    // create a bitmap image
    BitmapImage bi = new BitmapImage();

    using (
        // Open a stream for the selected file.
    Windows.Storage.Streams.IRandomAccessStream fileStream =
        await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
    {
        // load the image into the BitmapImage
        await bi.SetSourceAsync(fileStream);

        // create a copy of the image            
        copy = new WriteableBitmap(bi.PixelWidth, bi.PixelHeight);

        // load the image into writeablebitmap copy
        fileStream.Seek(0);
        await copy.SetSourceAsync(fileStream);
    }
}

private WriteableBitmap ChangeBrightness(WriteableBitmap source, byte change_value)
{
    WriteableBitmap dest = new WriteableBitmap(source.PixelWidth, source.PixelHeight);        

    byte[] color = new byte[4];

    using (Stream s = source.PixelBuffer.AsStream())
    {
        using (Stream d = dest.PixelBuffer.AsStream())
        {
            // read the pixel color
            while (s.Read(color, 0, 4) > 0)
            {
                // color[0] = b
                // color[1] = g 
                // color[2] = r
                // color[3] = a

                // do the adding algo per byte (skip the alpha)
                for (int i = 0; i < 4; i++)
                {
                    if ((int)color[i] + change_value > 255) color[i] = 255; else color[i] = (byte)(color[i] + change_value);
                }

                // write the new pixel color
                d.Write(color, 0, 4);                        
            }
        }
    }

    // return the new bitmap
    return dest;
}

private void mySilder_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    if (this.mySilder != null)
    {
        // deterime the brightness to add
        byte value_to_add = (byte)((this.mySilder.Value / this.mySilder.Maximum) * 255);

        // get the new bitmap with the new brightness
        WriteableBitmap ret = ChangeBrightness(copy, value_to_add);

        // set it as the source so we can see the change
        this.myImage.Source = ret;
    }
}

Code In Action

enter image description here


If you are looking for "bling.png" can be found here : bling.png

Community
  • 1
  • 1
Chubosaurus Software
  • 8,133
  • 2
  • 20
  • 26
  • Can you please tell me how to implement this because i am very much new to this. – Pranav Mahajan Oct 31 '14 at 12:12
  • @PranavMahajan I think the problem is you're trying to implement Windows Phone code into Window Store App. Even though they are similar stuff, it doesn't convert 1 for 1. For example, there is no such thing as .Pixel (byte[]), there is a .PixelBuffer which is an IBuffer. – Chubosaurus Software Oct 31 '14 at 13:29
  • I am getting exception in this line WriteableBitmap dest = new WriteableBitmap(source.PixelWidth, source.PixelHeight); when i try to increase the slider – Pranav Mahajan Nov 01 '14 at 05:48
  • @PranavMahajan make sure the bling.png (image) is actually inside the Assets folder. If that doesn't work, what is the actual error on the Exception, just saying you got one doesn't mean help at all. – Chubosaurus Software Nov 01 '14 at 06:17
  • @PranavMahajan you also need to make sure `private async void Page_Loaded` is actually hooked up to the page event. – Chubosaurus Software Nov 01 '14 at 06:21
  • It is giving this "An exception of type 'System.NullReferenceException' occurred in Brightness.exe but was not handled in user code". – Pranav Mahajan Nov 01 '14 at 06:23
  • @PranavMahajan Page_Loaded is not hooked, hook it. – Chubosaurus Software Nov 01 '14 at 06:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/64079/discussion-between-pranav-mahajan-and-chubosaurus-software). – Pranav Mahajan Nov 01 '14 at 06:34
  • Can anyone tell me the formula for the contrast also? The above one is only for the Brightness. – Pranav Mahajan Nov 01 '14 at 07:39
  • @PranavMahajan instead of adding, you multiple each color component by a percentage. `new_red = old_red * 0.5f` for example – Chubosaurus Software Nov 01 '14 at 08:02
  • Exactly where do i have to change in the code for Contrast? – Pranav Mahajan Nov 04 '14 at 09:04
  • @PranavMahajan umm, the only place where I modify the colors. Inside the for loop. – Chubosaurus Software Nov 04 '14 at 09:27
  • for (int i = 0; i < 4; i++) { if ((int)color[i] + change_value > 255) color[i] = 255; else color[i] = (byte)(color[i] * change_value); } this is my for loop for Contrast. – Pranav Mahajan Nov 04 '14 at 09:34
  • @PranavMahajan 50% correct, you still have that color[i] + change_value. Think about it. – Chubosaurus Software Nov 04 '14 at 09:39
  • Do you mean both add signs should be replaced with multiply sign.I've tried that but it not working as expected.Also when I increase the contrast and then sliding it to 0 then Image is disappearing.Please help me. – Pranav Mahajan Nov 04 '14 at 09:48
  • @PranavMahajan the image prose to be black when the value_change is 0, because everything will be 0 (anything times 0 is 0). Remember that you are multiplying by a PERCENTAGE. So the value_change needs to be change from an byte to a DOUBLE/FLOAT. And you need to recalculate the percentage that you're passing from the slider. If you having trouble understanding the `if statement` separate it to multiple lines, maybe having it all on a single line is messing up your reasoning. It is a simple if statement to cap the value. – Chubosaurus Software Nov 04 '14 at 09:58
  • Now my for loop is like this - for (int i = 0; i < 4; i++) { if ((int)color[i] * change_value > 255) color[i] = 255; else color[i] = Convert.ToByte((double)(color[i] * change_value)); } and I am changing the slider value like this - double value_to_add = (double)((this.slider2.Value / this.slider2.Maximum) * 255); Please correct me if i am wrong. – Pranav Mahajan Nov 04 '14 at 10:41
  • @PranavMahajan Yes, but you already have 99% of the sample code here. Would be better to learn to manipulate memory/values the way you want to rather than calling a library function in the long run. Like I said before, contrast is a function of `scale`. A good slider will pass for example these ranges of contrast values [0% -> 100% -> 300%] which in `double` terms are [0.0 -> 1.0 -> 3.0] – Chubosaurus Software Nov 14 '14 at 09:18
  • @PranavMahajan no, not even close. Your slider values will go from (value/max) * 255... if I'm reading that correct it would be 0% to 25500% (that is some crazy scale)... I think you need to learn how to use break points. Like I said, a good scale value will be 0.0...1.0...3.0 – Chubosaurus Software Nov 15 '14 at 01:30
  • I am getting an exception of "Value does not fall within the expected range" if i am giving some dynamic URL.Any solution for this?? – Pranav Mahajan Dec 05 '14 at 13:32
  • I think it is because of the size of the image.Can we give the File size Chubosaurus Software?? – Pranav Mahajan Dec 08 '14 at 05:35
  • this method is not working with dynamic image sources.Do you have any idea? i am getting this exception "Value does not fall within the expected range." – Pranav Mahajan Dec 09 '14 at 10:18
  • Is it possible to get image uri from Source property set in xaml, instead of hardcoding it again in the code with ms-appx:// prefix? – duo Apr 20 '16 at 12:14
0

Btw, correct function for increasing brightness of premultiplied images is

    public static WriteableBitmap ChangeBrightness(WriteableBitmap source, int increment)
    {
        var dest = new WriteableBitmap(source.PixelWidth, source.PixelHeight);

        byte[] color = new byte[4];

        using (var srcBuffer = source.PixelBuffer.AsStream())
        using (var dstBuffer = dest.PixelBuffer.AsStream())
        {
            while (srcBuffer.Read(color, 0, 4) > 0)
            {
                for (int i = 0; i < 3; i++)
                {
                    var value = (float)color[i];
                    var alpha = color[3] / (float)255;
                    value /= alpha;
                    value += increment;
                    value *= alpha;

                    if (value > 255)
                    {
                        value = 255;
                    }

                    color[i] = (byte)value;
                }

                dstBuffer.Write(color, 0, 4);
            }
        }

        return dest;
    }
duo
  • 330
  • 4
  • 8