2

Does anyone know of a more efficient way of adjusting the brightness of an image at runtime in UWP?

I found this question which works fine but runs terribly slow. However, I can't find any documentation online suggesting there is an alternative method.

Here is my problematic code.

// TODO Make Image Brightness Slider quicker and more intuitive. 
private 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;
}
Adam McMahon
  • 765
  • 3
  • 24
  • Possible duplicate of [Adjust brightness contrast and gamma of an image](https://stackoverflow.com/questions/15408607/adjust-brightness-contrast-and-gamma-of-an-image) – Ishaan Javali Jan 10 '19 at 14:59
  • 1
    You could also use a library like [ImageProcessor](http://imageprocessor.org/). Or look at the source code for [adjusting brightness](https://github.com/JimBobSquarePants/ImageProcessor/blob/1c65565c7f42fa5e9917fbe408d7df3827c607bb/src/ImageProcessor/Imaging/Helpers/Adjustments.cs#L104) – Lennart Stoop Jan 10 '19 at 15:04
  • @LennartStoop I'll take a look at that library and report back. Thanks :) – Adam McMahon Jan 10 '19 at 15:24
  • 1
    @LennartStoop that particular library doesn't work with UWP Apps. I'm looking at a couple of other libraries so I'll report back if I find one that works as desired. – Adam McMahon Jan 10 '19 at 15:53
  • 1
    @IshaanJavali This is not a duplicate as they are two different technologies and the answer provided in that question will not work with UWP. – Adam McMahon Jan 10 '19 at 16:29
  • 1
    Sorry I've missed the UWP part. So no `System.Drawing` for you.. Have you looked at [Win2D](https://github.com/Microsoft/Win2D)? According to the docs it can handle [adjusting brightness](http://microsoft.github.io/Win2D/html/T_Microsoft_Graphics_Canvas_Effects_BrightnessEffect.htm). I have no experience with this though – Lennart Stoop Jan 10 '19 at 17:43
  • Thanks. I'm using Win2D already for creating sprites and animations as there is no other suitable alternative. But I really wanted to steer clear of it in this instance as it vastly over complicates what should really be a simple task, plus it doesn't allow you to apply the effect directly to a BitmapImage. I'm going to leave this question unanswered and maybe place a bounty on it in hope of a better solution, and if none appears then I suppose it's back to Win2D, begrudgingly :) – Adam McMahon Jan 11 '19 at 11:21
  • Do you wish to save the image, or apply simply at runtime and that's it? If it's the latter this can be done - efficiently too - using a combination of Windows.UI.Composition API's (create a BackdropBrush, attach too a sprite, and stick as a child visual of a UIElement), and the BackdropBrush as a source for the relevant effect. See https://learn.microsoft.com/en-us/windows/uwp/composition/composition-effects – Johnny Westlake Jan 11 '19 at 23:45
  • @JohnnyWestlake, I need to save the image also. – Adam McMahon Jan 14 '19 at 09:35

1 Answers1

1

This might work. I didn't test it:

    private async Task<WriteableBitmap> ChangeBrightness(WriteableBitmap source, float increment)
    {
        var canvasBitmap = CanvasBitmap.CreateFromBytes(CanvasDevice.GetSharedDevice(), source.PixelBuffer,
            source.PixelWidth, source.PixelHeight, DirectXPixelFormat.B8G8R8A8UIntNormalized);

        var brightnessFx = new BrightnessEffect
        {
            Source = canvasBitmap,
            BlackPoint = new Vector2(0, increment)
        };

        var crt = new CanvasRenderTarget(CanvasDevice.GetSharedDevice(), source.PixelWidth, source.PixelHeight, 96);

        using (var ds = crt.CreateDrawingSession())
        {
            ds.DrawImage(brightnessFx);
        }

        crt.GetPixelBytes(source.PixelBuffer);

        return source;
    }

You have to reference win2d nuget

Jet Chopper
  • 1,478
  • 13
  • 22
  • This worked brilliantly for me +1. Quick note though, increment needs to be a double value between 0 and 1. So you need to get Slider.Value and divide by Slider.Maximum to get the required value. Also, you do not need to reference Win2d as this is all now included in Microsoft.Graphics.Canvas. Thanks! – Adam McMahon Jan 14 '19 at 10:07
  • 1
    FWIW, converting it back to a WriteableBitmap is a waste of time if you just want to save it, or even display it. You can do both things directly with the CanvasBitmap. You should also ideally dispose of the CanvasRenderTarget and the CanvasBitmap when you're done with them - they both implement IDisposable. (As a sidenote, Microsoft.Graphics.Canvas actually comes from the Win2D library) – Johnny Westlake Jan 14 '19 at 15:38