繁体   English   中英

RenderTargetBitmap 图像滑动

[英]RenderTargetBitmap Image Sliding

每当我渲染画布并清除其子项并将渲染的位图设置为画布的背景时,我都会遇到 RenderTargetBitmap 问题,它向右下方滑动。

直到 10 声望才能插入图像:(。

WPF:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="500" Width="700"
        KeyDown="Window_KeyDown">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="50"/>
        </Grid.ColumnDefinitions>
        <Border BorderBrush="Black" BorderThickness="1" Grid.Row="1" Grid.Column="1">
            <Canvas x:Name="Pad">
                <Rectangle Height="100" Width="100" Fill="Red" Canvas.Left="10" Canvas.Top="10"></Rectangle>
        </Canvas>
        </Border>
    </Grid>
</Window>

代码:

namespace WpfApp1
{
    public partial class MainWindow : Window
    {

         public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            RenderTargetBitmap rendrer = new RenderTargetBitmap(Convert.ToInt32(Pad.ActualWidth),                                                    Convert.ToInt32(Pad.ActualHeight), 96, 96, PixelFormats.Pbgra32);
            rendrer.Render(Pad);
            Pad.Background = new ImageBrush(rendrer);
            Pad.Children.Clear();
        }

    }

}

为了避免将 Visual 绘制到 RenderTargetBitmap 时出现任何偏移问题,您可以使用中间 DrawingVisual:

var rect = new Rect(Pad.RenderSize);
var visual = new DrawingVisual();

using (var dc = visual.RenderOpen())
{
    dc.DrawRectangle(new VisualBrush(Pad), null, rect);
}

var bitmap = new RenderTargetBitmap(
    (int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Default);
bitmap.Render(visual);

Pad.Background = new ImageBrush(bitmap);
Pad.Children.Clear();

请注意,无需设置 ImageBrush 的任何其他属性(例如其视口),它将填充矩形的整个区域。 有关详细信息,请参阅TileBrush 概述

您的主要问题源于这样一个事实,由于Canvas周围的 1 像素边框,其VisualOffset向量为(1,1) 因此,任何视觉效果,如背景画笔,都将在该偏移处应用。 当您将视觉呈现为位图时,它会捕获当前外观,然后当您将位图设置为画笔时,它会发生偏移。

具有讽刺意味的是,解决此问题的最简单方法之一是将另一个<Border/>元素插入到您的 XAML 中:

<Border BorderBrush="Black" BorderThickness="1" Grid.Row="1" Grid.Column="1">
  <Border>
    <Canvas x:Name="Pad">
      <Rectangle Height="100" Width="100" Fill="Red" Canvas.Left="10" Canvas.Top="10"/>
    </Canvas>
  </Border>
</Border>

然后由外部<Border/>元素引起的偏移由新的<Border/>元素的变换处理,而不是应用于<Canvas/>元素。

仅此更改就几乎可以完全修复您的代码。 但是,您可能仍会注意到另外一个小瑕疵:每次渲染视觉效果时,它都会变得更加模糊。 这是因为在默认值Brush对象的Stretch属性是Stretch.Fill ,因为你的<Canvas/>元素不正是不可或缺的宽度和高度,位图(这必然确实有整体宽度和高度)获取只是一个拉伸渲染时有点小。 随着每次迭代,这变得越来越明显。

您可以通过将Stretch属性设置为Stretch.None来解决这个Stretch.None 同时,您还需要将画笔的对齐方式设置为LeftTop

private void Window_KeyDown(object sender, KeyEventArgs e)
{
    RenderTargetBitmap renderer = new RenderTargetBitmap(
        Convert.ToInt32(Pad.ActualWidth), Convert.ToInt32(Pad.ActualHeight), 96, 96, PixelFormats.Pbgra32);
    renderer.Render(Pad);
    ImageBrush brush = new ImageBrush(renderer);
    brush.AlignmentX = AlignmentX.Left;
    brush.AlignmentY = AlignmentY.Top;
    brush.Stretch = Stretch.None;
    Pad.Background = brush;
    Pad.Children.Clear();
}

默认值为Center ,这会再次导致舍入误差,并且在重复该过程的迭代后会导致图像移动和模糊。

通过上述更改,无论迭代次数如何,我都找到了一个完美稳定的图像。

“环绕边框”的想法来自这里: https : //blogs.msdn.microsoft.com/jaimer/2009/07/03/rendertargetbitmap-tips/

在该页面上,您将找到一个更通用的解决方案,它不需要修改实际的 XAML。 在上面的示例中,“环绕边框”方法似乎是一种合理的解决方法,但不可否认,它不如强制您可以呈现视觉效果的原始上下文那么干净,如该博客页面所示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM