0
votes

I want to blur the image using slider. For this, I have used Win2D Blur effects and draw the image in CanvasControl and added the canvas over the actual image.

Download sample here

Steps. 1. Added CanvasControl in button click. It will add a child to grid over the actual element 2. Change Slider to apply the blur 3. Issue: Image stretched and it's size too large and look like cropped. Not in the given size (500, 400)

[XAML]

<Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="7*"/>
                <ColumnDefinition Width="3*"/>
            </Grid.ColumnDefinitions>
        <Grid x:Name="imageGrid">
            <Image x:Name="image" Source="Flower1.jpg" Width="500" Height="400"
                       HorizontalAlignment="Left" VerticalAlignment="Top"/>
        </Grid>
        <StackPanel Grid.Column="1" Orientation="Vertical">

            <Button Content="AddCanvas" Width="100" x:Name="addCanvas"
                        Click="AddCanvas_Click"/>

            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Blur" Width="100"/>
                <Slider x:Name="slider" Minimum="0" Maximum="5" Width="200"
                        ValueChanged="Slider_ValueChanged"/>
            </StackPanel>

        </StackPanel>
    </Grid>

[C#]

        bool isBlurred;
        GaussianBlurEffect blur = new GaussianBlurEffect();
        CanvasControl canv = new CanvasControl();
        CanvasBitmap cbi;

        public MainPage()
        {
            this.InitializeComponent();
        }
        private void AddCanvas_Click(object sender, RoutedEventArgs e)
        {
            canv.HorizontalAlignment = HorizontalAlignment.Left;
            canv.VerticalAlignment = VerticalAlignment.Top;
            canv.Draw += Canv_Draw;
            canv.CreateResources += Canv_CreateResources;
            canv.Height = 400;
            canv.Width = 500;

            imageGrid.Children.Add(canv);
        }

        private void Canv_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {
            args.DrawingSession.Units = CanvasUnits.Pixels;
            if (isBlurred)
            {
                args.DrawingSession.DrawImage(blur, new Rect(0, 0, 500, 400), new Rect(0, 0, 500, 400));
            }
        }

        private void Canv_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args)
        {
            args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
        }
        async Task CreateResourcesAsync(CanvasControl sender)
        {
            cbi = await CanvasBitmap.LoadAsync(sender, "Flower1.jpg");
        }

        private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            isBlurred = true;
            blur.Source = cbi;
            blur.BlurAmount = (float)e.NewValue;
            canv.Invalidate();
        }

enter image description here

enter image description here I would like to apply the Blur effects to the Image using slider dynamically. But i don't want to change the Actual image to Blur. So, I used Canvas over the Actual image and draw with Blur effect.

Regards,

Bharathi.

1
Does the Update2 work ?Nico Zhu - MSFT

1 Answers

1
votes

Drawing image using Blur effects in UWP is not properly set size for the image

The problem is that the size of CanvasControl is not suit for image source (Image: 960*640 CanvasControl:500*400). If you want to make CanvasControl could display the full image, please set available dpi when call CanvasBitmap.LoadAsync method. For my testing 185 is suit for your scenario.

async Task CreateResourcesAsync(CanvasControl sender)
{
    cbi = await CanvasBitmap.LoadAsync(sender, "Flower1.jpg",185);

}

Update

//var dpi = DisplayInformation.GetForCurrentView().LogicalDpi;
var display = DisplayInformation.GetForCurrentView();
// calculate your monitor's dpi
var dpi = Math.Sqrt(Math.Pow(display.ScreenWidthInRawPixels, 2) + Math.Pow(display.ScreenHeightInRawPixels, 2)) / display.DiagonalSizeInInches;
// get the CanvasControl inch 
var inch = Math.Sqrt(Math.Pow(500, 2) + Math.Pow(400, 2)) / dpi;
// calculate last dpi with the image size
var lastdpi = Math.Sqrt(Math.Pow(960, 2) + Math.Pow(640, 2)) / inch;

Update 1

If could also set CanvasControl size with image size that could avoid to calculate Dpi.

Update 2

And you could also resize your image to suit for CanvasControl, Please refer the following code.

public async Task<IRandomAccessStream> ResizeImage(StorageFile file, int reqWidth, int reqHeight)
{
    var memStream = new MemoryStream();
    using (Stream stream = await file.OpenStreamForReadAsync())
    {
        stream.CopyTo(memStream);
    }
    IRandomAccessStream imageStream = memStream.AsRandomAccessStream();
    var decoder = await BitmapDecoder.CreateAsync(imageStream);
    if (decoder.PixelHeight > reqHeight || decoder.PixelWidth > reqWidth)
    {
        using (imageStream)
        {
            var resizedStream = new InMemoryRandomAccessStream();

            BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(resizedStream, decoder);
            double widthRatio = (double)reqWidth / decoder.PixelWidth;
            double heightRatio = (double)reqHeight / decoder.PixelHeight;

            double scaleRatio = Math.Min(widthRatio, heightRatio);

            if (reqWidth == 0)
                scaleRatio = heightRatio;

            if (reqHeight == 0)
                scaleRatio = widthRatio;

            uint aspectHeight = (uint)Math.Floor(decoder.PixelHeight * scaleRatio);
            uint aspectWidth = (uint)Math.Floor(decoder.PixelWidth * scaleRatio);

            encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;

            encoder.BitmapTransform.ScaledHeight = aspectHeight;
            encoder.BitmapTransform.ScaledWidth = aspectWidth;

            await encoder.FlushAsync();

            return resizedStream;
        }
    }
    return imageStream;
}

Usage

async Task CreateResourcesAsync(CanvasControl sender)
{
    var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Flower1.jpg")); 
    cbi = await CanvasBitmap.LoadAsync(sender, await ResizeImage(file, 500, 400));    
}