我在"Visual to RenderTargetBitmap"问题上找到了新的转折!
我正在为设计师渲染WPF的预览.这意味着我需要获取WPF视觉效果并将其渲染为位图,而不会显示该视觉效果.有一个很好的小方法来做它喜欢在这里看到它
private static BitmapSource CreateBitmapSource(FrameworkElement visual)
{
Border b = new Border { Width = visual.Width, Height = visual.Height };
b.BorderBrush = Brushes.Black;
b.BorderThickness = new Thickness(1);
b.Background = Brushes.White;
b.Child = visual;
b.Measure(new Size(b.Width, b.Height));
b.Arrange(new Rect(b.DesiredSize));
RenderTargetBitmap rtb = new RenderTargetBitmap(
(int)b.ActualWidth,
(int)b.ActualHeight,
96,
96,
PixelFormats.Pbgra32);
// intermediate step here to ensure any VisualBrushes are rendered properly
DrawingVisual dv = new DrawingVisual();
using (var dc = dv.RenderOpen())
{
var vb = new VisualBrush(b);
dc.DrawRectangle(vb, null, …Run Code Online (Sandbox Code Playgroud) 我试图创建一些图表图像,而无需在屏幕上显示这些图表.我已经在这方面工作了很长一段时间并尝试了很多不同的东西,但似乎没有任何工作.如果我首先在窗口中显示图表,代码可以正常工作,但如果我不在窗口中显示它,则位图只是白色,带有黑色边框(不知道为什么).
我尝试在渲染之前将图表添加到边框,并为边框指定绿色borderBrush.在位图中,我看到绿色borderBrush然后是黑色边框和白色背景但没有图表.图表不包含在黑色寄宿生中,所以我不知道它来自哪里.
我已经尝试将图表添加到窗口而不调用window.Show()并再次我得到黑色边框和白色背景.但是,如果我调用window.Show(),则位图包含图表.
我已经使用drawingVisual作为解释试图在这里,同样的结果.
这是代码(不包括将元素添加到边框或窗口):
private static BitmapSource CreateElementScreenshot(FrameworkElement element, int dpi)
{
if (!element.IsMeasureValid)
{
Size size = new Size(element.Width, element.Height);
element.Measure(size);
element.Arrange(new Rect(size));
}
element.UpdateLayout();
var scale = dpi/96.0;
var renderTargetBitmap = new RenderTargetBitmap
(
(int)(scale * element.RenderSize.Width),(int)(scale * element.RenderSize.Height),dpi,dpi,PixelFormats.Default
);
// this is waiting for dispatcher to perform measure, arrange and render passes
element.Dispatcher.Invoke(((Action)(() => renderTargetBitmap.Render(element))), DispatcherPriority.Render);
return renderTargetBitmap;
}
Run Code Online (Sandbox Code Playgroud)
注意:图表是ContentControl.
无论如何我可以让图表呈现而不先在窗口中显示它吗?
我正在渲染RenderTargetBitmap的几十个视觉效果.每个都在它自己的Rect中呈现.我想要做的是将RenderTargetBitmap实例渲染的这些Rect区域之一复制到WriteableBitmap的同一区域...快速复制rect像素或smth.像那样.
那么,有没有办法以快速的方式将Rect从RenderTargetBitmap复制到WriteableBitmap?
我正试图像现在的"懒惰"VisualBrush一样实现某些东西.有没有人知道如何做到这一点?含义:某些行为类似于VisualBrush,但不会更新Visual中的每个更改,但最多每秒一次(或其他).
我最好还应该给出一些背景知识,为什么我这样做以及我猜测我猜想:)
问题:我现在的工作是提高相当大的WPF应用程序的性能.我跟踪了应用程序中使用的一些可视画笔的主要性能问题(无论如何在UI级别).该应用程序包含一个带有一些相当复杂的UserControls的"桌面"区域和一个包含桌面缩小版本的导航区域.导航区域使用可视化笔刷完成工作.只要桌面项目或多或少是静态的,一切都很好.但是如果元素经常变化(因为它们包含动画),那么VisualBrushes就会变得疯狂.它们将随动画的帧速率一起更新.降低帧速率当然有帮助,但我正在寻找一个更普遍的解决方案来解决这个问题.虽然"源"控件仅渲染受动画影响的小区域,但可视刷子容器将完全呈现,从而导致应用程序性能下降到地狱.我已经尝试过使用BitmapCacheBrush.不幸的是没有帮助.动画在控件内.所以无论如何必须刷新刷子.
可能的解决方案:我创建的Control表现或多或少像VisualBrush.它需要一些视觉效果(如VisualBrush),但使用DiapatcherTimer和RenderTargetBitmap来完成这项工作.现在我正在订阅控件的LayoutUpdated事件,每当它更改时,它将被安排为"渲染"(使用RenderTargetBitmap).然后由DispatcherTimer触发实际渲染.这样,控件将在DispatcherTimer的频率中最大程度地重新绘制自身.
这是代码:
public sealed class VisualCopy : Border
{
#region private fields
private const int mc_mMaxRenderRate = 500;
private static DispatcherTimer ms_mTimer;
private static readonly Queue<VisualCopy> ms_renderingQueue = new Queue<VisualCopy>();
private static readonly object ms_mQueueLock = new object();
private VisualBrush m_brush;
private DrawingVisual m_visual;
private Rect m_rect;
private bool m_isDirty;
private readonly Image m_content = new Image();
#endregion
#region constructor
public VisualCopy()
{
m_content.Stretch = Stretch.Fill;
Child = m_content;
}
#endregion
#region dependency properties
public FrameworkElement Visual …Run Code Online (Sandbox Code Playgroud) 这看起来像一个重复的问题,但是没有人回答实际的问题.
以下是:基本上,我将ViewPort3D渲染为代码中的2D快照,但需要将该类型的RenderTargetBitmap转换为System.Drawing.BitMap类型(以便在2D端进行进一步处理).
Dim bmpRen As New RenderTargetBitmap(1024, 550, 96, 96, PixelFormats.Pbgra32)
bmpRen.Render(Me.vp3dTiles) 'render the viewport as 2D snapshot
Run Code Online (Sandbox Code Playgroud)
虽然我知道如何将其保存到文件中,但我宁愿跳过该步骤并将bmpRen转换为System.Drawing.Bitmap类型,但是没有方法可以这样做.
所以我试图在WPF C#中拍摄我的画布快照,以便我可以将其保存为png.目前图像保存不正确,因为它包括左边距和上边距.
这就是我所拥有的:
为画布大小创建一个矩形.如果canvas.Margin.Left和Top设置为0,则保存的图像大小正确但仍然会发生偏移,从而切割底部和右侧边缘.设置Margin.Left和Top仍会导致偏移发生,但整个图像被保存但尺寸错误(margin.Left + ActualWidth)而不仅仅是ActualWidth
Rect rect = new Rect(canvas.Margin.Left, canvas.Margin.Top, canvas.ActualWidth, canvas.ActualHeight);
double dpi = 96d;
RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right, (int)rect.Bottom, dpi, dpi, System.Windows.Media.PixelFormats.Default);
rtb.Render(canvas);
BitmapEncoder pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));
try
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
pngEncoder.Save(ms);
ms.Close();
System.IO.File.WriteAllBytes(filename, ms.ToArray());
}
catch (Exception err)
{
MessageBox.Show(err.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
Run Code Online (Sandbox Code Playgroud) 我必须将TextBox中的文本呈现为WriteableBitmap.此代码运行良好,但其中的文本模糊或消除锯齿.关于如何保持别名和清晰的任何想法?
text = new FormattedText(tb.Text,
new CultureInfo("de-de"),
FlowDirection.LeftToRight,
new Typeface(tb.FontFamily, FontStyles.Normal, tb.FontWeight, new FontStretch()),
tb.FontSize,
tb.Foreground);
drawingContext = dv.RenderOpen();
drawingContext.DrawText(text, Pos);
drawingContext.Close();
rtb.Render(dv);
rtb.CopyPixels(new Int32Rect(0, 0, rtb.PixelWidth, rtb.PixelHeight), wb.BackBuffer, wb.BackBufferStride * wb.PixelHeight, wb.BackBufferStride);
Run Code Online (Sandbox Code Playgroud)
我发现的不起作用:
TextOptions.SetTextFormattingMode(dv, TextFormattingMode.Display);
TextOptions.SetTextRenderingMode(dv, TextRenderingMode.Aliased);
Run Code Online (Sandbox Code Playgroud)
要么
RenderOptions.SetBitmapScalingMode(dv, BitmapScalingMode.NearestNeighbor);
RenderOptions.SetEdgeMode(dv, EdgeMode.Aliased);
Run Code Online (Sandbox Code Playgroud) writeablebitmap formatted-text rendertargetbitmap drawingvisual
我期待呈现DrawingVisual(在示例性视觉)到使用位图RenderTargetBitmap的观点来设置此位图作为背景的Canvas,如下:
var bmp = new RenderTargetBitmap(2000, 50, 120, 96, PixelFormats.Indexed2);
bmp.Render(visual);
var brush = new ImageBrush(bmp) { Stretch = Stretch.Fill };
Canvas.Background = brush;
Run Code Online (Sandbox Code Playgroud)
当使用PixelFormats.Default最后一个参数时RenderTargetBitmap,图像按预期呈现.然而,当我选择PixelFormats.Indexed2(或任何的PixelFormats.IndexedX),我的代码似乎退出方法没有例外,该bmp.Render线不会被调用,因此在图像上没有显示Canvas.
如何使用IndexedX像素格式RenderTargetBitmap?或者还有其他方法可以减少图像的内存占用量吗?它只使用三种颜色,所以使用调色板而不是32位RGB似乎是要走的路.
我正在尝试创建一个位图图像,并具有以下代码:
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(uielement);
IBuffer pixels = await renderTargetBitmap.GetPixelsAsync();
. . .
var pixelArray = pixels.ToArray();
Run Code Online (Sandbox Code Playgroud)
为了得到ToArray()扩展,我遇到了这个问题。所以我补充说:
using System.Runtime.InteropServices.WindowsRuntime; // For ToArray
Run Code Online (Sandbox Code Playgroud)
对我的代码。但是,当我运行时,出现以下错误:
抛出异常:System.Runtime.WindowsRuntime.dll中的“ System.ArgumentException”
附加信息:指定的缓冲区索引不在缓冲区容量之内。
当我深入研究细节时,它在堆栈跟踪中显示:
在> System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.ToArray(IBuffer源)
这种提取像素阵列的方法是否仍然适用于UWP?如果是,是否有任何方法可以从此错误消息中获取更多详细信息?
在我的场景中,我想在我想在后台任务中渲染它之前冻结一个不变的BitmapCacheBrush.不幸的是我收到错误"这个Freezable不能被冻结".是否有任何解决方法或hacky方式冻结也不是freezable对象?也许可以通过反射设置正确的属性来达到这个目标?提前谢谢你们.
编辑:(我的示例代码请求)
public static class ext
{
public static async Task<BitmapSource> RenderAsync(this Visual visual)
{
var bounds = VisualTreeHelper.GetDescendantBounds(visual);
var bitmapCacheBrush = new BitmapCacheBrush(visual);
bitmapCacheBrush.BitmapCache = new BitmapCache();
// We need to disconnect the visual here to make the freezable freezable :). Of course this will make our rendering blank
//bitmapCacheBrush.Target = null;
bitmapCacheBrush.Freeze();
var bitmapSource = await Task.Run(() =>
{
var renderBitmap = new RenderTargetBitmap((int)bounds.Width,
(int)bounds.Height, 96, 96, PixelFormats.Pbgra32);
var dVisual = new DrawingVisual();
using (DrawingContext context = dVisual.RenderOpen()) …Run Code Online (Sandbox Code Playgroud)