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"标题="MainWindow"高度="500"宽度="700"KeyDown ="Window_KeyDown"><网格>< 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"><画布x:Name ="Pad">< Rectangle Height ="100" Width ="100" Fill ="Red" Canvas.Left ="10" Canvas.Top ="10"></Rectangle></画布></Border></Grid></Window>
c#代码:
命名空间WpfApp1{公共局部类MainWindow:Window{公共MainWindow(){InitializeComponent();}私人无效Window_KeyDown(对象发送者,KeyEventArgs e){RenderTargetBitmap rendrer =新的RenderTargetBitmap(Convert.ToInt32(Pad.ActualWidth),Convert.ToInt32(Pad.ActualHeight),96,96,PixelFormats.Pbgra32);rendrer.Render(Pad);Pad.Background =新的ImageBrush(rendrer);Pad.Children.Clear();}}}
您的主要问题源于以下事实:由于 Canvas
周围的1像素边框,其 VisualOffset
向量是(1,1)
.因此,任何视觉效果(例如背景笔刷)都将以该偏移量应用.将视觉效果渲染为位图时,它会捕获当前外观,然后将位图设置为画笔时,它会发生偏移.
具有讽刺意味的是,解决此问题的最简单方法之一是在XAML中插入另一个< Border/>
元素:
< Border BorderBrush ="Black" BorderThickness ="1" Grid.Row ="1" Grid.Column ="1"><边界><画布x:Name ="Pad"><矩形高度="100"宽度="100"填充=红色" Canvas.Left ="10" Canvas.Top ="10"/></画布></Border></Border>
然后,由外部< Border/>
元素引起的偏移量由新的< Border/>
元素的变换处理,而不是应用于< Canvas/>
元素.
仅此一项更改就能几乎完全修复您的代码.但是,您可能仍然会注意到其他一些小瑕疵:每次渲染视觉效果时,它都会变得模糊不清.这是因为 Brush
对象的 Stretch
属性的默认值为 Stretch.Fill
,并且因为您的< Canvas/>
元素并不是精确的整数或宽度,位图(必须 必须具有整数的宽度和高度)在渲染时会被拉伸.随着每次迭代,这一点变得越来越明显.
您可以通过将 Stretch
属性设置为 Stretch.None
来解决此问题.同时,您还需要将笔刷的对齐方式设置为 Left
和 Top
:
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笔刷=新的ImageBrush(renderer);brush.AlignmentX = AlignmentX.Left;brush.AlignmentY = AlignmentY.Top;brush.Stretch = Stretch.None;Pad.Background =画笔;Pad.Children.Clear();}
默认值是 Center
,它再次引起舍入误差,并且在重复该过程之后,会导致图像的移动和模糊.
通过上述更改,我发现了一个完美稳定的图像,而与迭代次数无关.
I'm having a problem with RenderTargetBitmap whenever I render canvas and clear its children and set the rendered bitmap as background of canvas it slide toward bottom right.
can't insert images until 10 reputation :(.
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>
c# code:
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();
}
}
}
Your primary problem stems from the fact that, due to the 1-pixel border around the Canvas
, its VisualOffset
vector is (1,1)
. Thus, any visual effect, like the background brush, will be applied at that offset. When you render the visual into a bitmap, it captures the present appearance, and then when you set the bitmap as the brush, it gets shifted.
Ironically, one of the easiest ways to fix this is to insert another <Border/>
element into your 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>
Then the offset caused by the outer <Border/>
element is handled by the new <Border/>
element's transform, rather than being applied to the <Canvas/>
element.
That change alone will almost fix your code completely. However, there's one other little artifact that you may still notice: every time you render the visual, it gets just a teensy bit blurrier. This is because the default value for the Brush
object's Stretch
property is Stretch.Fill
, and because your <Canvas/>
element is not precisely an integral width or height, the bitmap (which necessarily does have integral width and height) gets stretched just a teensy bit when rendered. With each iteration, this becomes more and more apparent.
You can fix that by setting the Stretch
property to Stretch.None
. At the same time, you'll also want to set the brush's alignment to Left
and Top
:
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();
}
The defaults are Center
, which again incurs the rounding error and will cause both movement and blurring of the image after repeated iterations of the process.
With the above changes, I found a perfectly stable image, regardless of the number of iterations.
The "wrap in a border" idea came from here: https://blogs.msdn.microsoft.com/jaimer/2009/07/03/rendertargetbitmap-tips/
On that page you'll find a more general-purpose solution which does not require modification of the actual XAML. In your example above, the "wrap in a border" approach seems like a reasonable work-around, but it is admittedly not as clean as forcing an unadorned context into which you can render the visual, as shown on that blog page.
这篇关于RenderTargetBitmap图像滑动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!