将绑定的 wpf 控件从屏幕渲染到位图
我有一个自定义 wpf 控件来执行任意反向图像扭曲,它使用 Viewport3D 和自定义矩阵,以及带有 ImageBrush 的网格...
我试图将其渲染为完全在屏幕外的位图。我能够很好地渲染位图(我发现在渲染之前调用 .Measure() .Arrange(new Rectangle(...)) 和 .UpdateLayout()),但绑定尚未完成,因此网格不可见(图像画笔源尚未加载)...
我缺少什么?是否有阻塞方式来等待绑定完成?
[我处理“Loaded”事件的尝试没有成功...]
更新,示例代码:
示例代码如下。预期输出是一个 300x300 的蓝色矩形,其中堆栈溢出徽标被挤压/旋转为菱形。 (尝试打开 DiamondControl.xaml 设计器,并更改代码以对图像 url 进行硬编码...有趣的是,这种变化仍然不在渲染的位图中,这表明我的问题与绑定的图像 url 无关,但是图像尚未加载)
Program.cs(一个控制台应用程序,添加了对 System.Windows.Presentation 的引用)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace ConsoleApplication3 {
class Program {
[STAThread]
static void Main(string[] args) {
// try exporting a bitmap...
var content = new DiamondControl();
content.DataContext = new Uri("http://sstatic.net/so/img/logo.png");
//content.ApplyTemplate(); // this doesn't seem to work
int width = 300, height = 300;
var rect = new Rect(0, 0, width, height);
content.Measure(new Size(width, height));
content.Arrange(rect);
//content.UpdateLayout(); // not required in this case, seems to be required if I render the control more than once
PngBitmapEncoder encoder = new PngBitmapEncoder();
RenderTargetBitmap render = new RenderTargetBitmap(
width,
height,
96,
96,
PixelFormats.Pbgra32);
render.Render(content);
encoder.Frames.Add(BitmapFrame.Create(render));
using (Stream s = File.Open("outputfile.png", FileMode.Create)) {
encoder.Save(s);
}
}
}
}
DiamondControl.xaml:
<UserControl x:Class="ConsoleApplication3.DiamondControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<Rectangle Fill="CornflowerBlue" />
<Viewport3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<!-- simple diamond -->
<MeshGeometry3D x:Name="mesh"
Positions="-.5 0 0, 0 .5 0, 0 -.5 0, .5 0 0"
TextureCoordinates="0 1, 0 0, 1 1, 1 0"
TriangleIndices="0 2 1, 2 3 1" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<!--<SolidColorBrush Color="Red" />-->
<ImageBrush ImageSource="{Binding}" />
<!--<ImageBrush ImageSource="http://sstatic.net/so/img/logo.png" />-->
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
<!-- Light source. -->
<AmbientLight Color="White" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
<!-- Camera. -->
<Viewport3D.Camera>
<OrthographicCamera Position="0 0 1"
LookDirection="0 0 -1"
UpDirection="0 1 0"
Width="1" />
</Viewport3D.Camera>
</Viewport3D>
</Grid>
</UserControl>
I have a custom wpf control to do an arbitrary reverse image warp, that use a Viewport3D and custom matrix, and a mesh with an ImageBrush...
I'm trying to render this to a bitmap entirely off screen. I am able to render a bitmap fine (I found to call .Measure() .Arrange(new Rectangle(...)) and .UpdateLayout()) before rendering, but the binding hasn't completed yet so the mesh is invisible (the image brush source hasn't loaded yet)...
What am I missing? is there a blocking way to wait for binding to complete?
[My attempts to handle the "Loaded" event haven't been successful...]
Update, sample code:
Sample code is below. The expected output is a 300x300 blue rectangle with the stack overflow logo squashed/rotated in a diamond. (try opening the DiamondControl.xaml designer, and changing the code to have the image url hard coded... interestingly, this variation continues to not be in the rendered bitmap suggesting my problem isn't related to the image url being bound, but the image not yet being loaded)
Program.cs (a console app with added references to System.Windows.Presentation)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace ConsoleApplication3 {
class Program {
[STAThread]
static void Main(string[] args) {
// try exporting a bitmap...
var content = new DiamondControl();
content.DataContext = new Uri("http://sstatic.net/so/img/logo.png");
//content.ApplyTemplate(); // this doesn't seem to work
int width = 300, height = 300;
var rect = new Rect(0, 0, width, height);
content.Measure(new Size(width, height));
content.Arrange(rect);
//content.UpdateLayout(); // not required in this case, seems to be required if I render the control more than once
PngBitmapEncoder encoder = new PngBitmapEncoder();
RenderTargetBitmap render = new RenderTargetBitmap(
width,
height,
96,
96,
PixelFormats.Pbgra32);
render.Render(content);
encoder.Frames.Add(BitmapFrame.Create(render));
using (Stream s = File.Open("outputfile.png", FileMode.Create)) {
encoder.Save(s);
}
}
}
}
DiamondControl.xaml:
<UserControl x:Class="ConsoleApplication3.DiamondControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<Rectangle Fill="CornflowerBlue" />
<Viewport3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<!-- simple diamond -->
<MeshGeometry3D x:Name="mesh"
Positions="-.5 0 0, 0 .5 0, 0 -.5 0, .5 0 0"
TextureCoordinates="0 1, 0 0, 1 1, 1 0"
TriangleIndices="0 2 1, 2 3 1" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<!--<SolidColorBrush Color="Red" />-->
<ImageBrush ImageSource="{Binding}" />
<!--<ImageBrush ImageSource="http://sstatic.net/so/img/logo.png" />-->
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
<!-- Light source. -->
<AmbientLight Color="White" />
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
<!-- Camera. -->
<Viewport3D.Camera>
<OrthographicCamera Position="0 0 1"
LookDirection="0 0 -1"
UpDirection="0 1 0"
Width="1" />
</Viewport3D.Camera>
</Viewport3D>
</Grid>
</UserControl>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您的位图对应于网址,则可以使用 如何渲染<图像>在后台 WPF 进程中?
另外,请包含一个 您控件中的元素(即使大小为 0x0)。我不知道为什么这会起作用,而且看起来完全是一个混杂。
If your bitmap corresponds to a web address, you use the solution in How to render an <image> in a background WPF process?
Also, include an <image> element (even if sized 0x0) in your control. I'm not sure why this works and it seems like a total kludge.