Рисование изображения с использованием эффектов размытия в UWP имеет неправильный размер для изображения

Я хочу размыть изображение с помощью ползунка. Для этого я использовал эффекты Win2D Blur и нарисовал изображение в CanvasControl и добавил холст поверх фактического изображения.

Загрузите образец здесь

Шаги. 1. Добавлен CanvasControl при нажатии кнопки. Он добавит дочерний элемент в сетку поверх фактического элемента 2. Измените ползунок, чтобы применить размытие 3. Проблема: изображение растянуто, его размер слишком велик и выглядит как обрезанное. Не в указанном размере (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();
        }

введите описание изображения здесь

введите описание изображения здесь Я хочу динамически применить эффекты размытия к изображению с помощью ползунка. Но я не хочу менять фактическое изображение на размытие. Итак, я использовал холст поверх фактического изображения и рисовал с эффектом размытия.

С уважением,

Бхаратхи.


person Bharathi    schedule 20.08.2019    source источник
comment
Update2 работает?   -  person Nico Zhu - MSFT    schedule 23.08.2019


Ответы (1)


Рисование изображения с использованием эффектов размытия в UWP имеет неправильный размер для изображения

Проблема в том, что размер CanvasControl не подходит для источника изображения (Image: 960 * 640 CanvasControl: 500 * 400). Если вы хотите, чтобы CanvasControl мог отображать полное изображение, установите доступное dpi при вызове метода CanvasBitmap.LoadAsync. Для моего тестирования 185 подходит для вашего сценария.

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

}

Обновить

//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;

Обновление 1

Если бы также можно было установить CanvasControl size с размером изображения, чтобы избежать вычисления Dpi.

Обновление 2

И вы также можете изменить размер изображения в соответствии с CanvasControl, см. Следующий код.

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;
}

Использование

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));    
}
person Nico Zhu - MSFT    schedule 20.08.2019
comment
Спасибо за решение. Если я установил 185, он работает нормально. Но я загружу другой размер изображения. Итак, я не могу определить размер изображения. Пожалуйста, позвольте мне, как рассчитать значение dpi в целом. Я использовал строку ниже. Но это не работает. в моей системе возвращает значение dpi как 13,99. Пожалуйста, посоветуйте мне это. var dpi = DisplayInformation.GetForCurrentView (). DiagonalSizeInInches; cbi = ожидание CanvasBitmap.LoadAsync (отправитель, Flower1.jpg, (float) dpi); - person Bharathi; 20.08.2019
comment
И это будет использоваться в другой системе. Поэтому мне нужно рассчитать значение dpi на основе конкретной системы. - person Bharathi; 20.08.2019
comment
@Bharathi, и вы также можете изменить размер изображения в соответствии с CanvasControl - person Nico Zhu - MSFT; 20.08.2019
comment
Я пробовал значения dpi и lastdpi, но на моем компьютере они не работают. если я использовал 184,5, он отлично работает для высоты (500 400). Пожалуйста, дайте мне знать, в чем я ошибся. cbi = ожидание CanvasBitmap.LoadAsync (отправитель, Flower1.jpg, (float) lastdpi); - person Bharathi; 21.08.2019
comment
Теперь я удалил статический размер (500, 400) и установил размер из события Image SizeChanged. Это сценарий в реальном времени. Загрузите образец по ссылке ниже. github.com/bharathirajauk/MySamples/blob/master/ - person Bharathi; 21.08.2019
comment
Да, имеет смысл установить размер CanvasControl с размером исходного изображения - person Nico Zhu - MSFT; 21.08.2019
comment
Но, все еще есть проблема при рисовании на холсте. Не могли бы вы проверить приведенный выше образец? - person Bharathi; 21.08.2019
comment
Давайте продолжим это обсуждение в чате. - person Nico Zhu - MSFT; 21.08.2019
comment
Пожалуйста, проверьте обновление 2, которое изменяет размер вашего изображения в соответствии с CanvasControl, и вы можете сделать статический размер CanvasControl. - person Nico Zhu - MSFT; 21.08.2019
comment
Я упрощаю часть кода, пожалуйста, обратитесь к последней редакции. - person Nico Zhu - MSFT; 21.08.2019
comment
@ NicoZhu-MSFT Я пробовал ваш код, но в моем случае он не работает. Я попробовал ваш расчет, чтобы узнать значение dpi. Но в моем разрешении экрана это не работает. Поэтому я попробовал другой способ установить DPI. Пожалуйста, проверьте образец. Это тоже не работает. Не могли бы вы подсказать мне, как изменить dpi растрового изображения в зависимости от разрешения экрана? Пример: github.com/SanthiyaArulsamy/Win2DSample/tree/master/ - person Santhiya; 23.08.2019
comment
В приведенном выше случае проверьте обновление 2, которое изменяет размер изображения в соответствии с CanvasControl, и оно работает. - person Nico Zhu - MSFT; 23.08.2019