Bitmap cache on DrawingVisual has blurry parts

喜夏-厌秋 提交于 2020-01-15 11:48:29

问题


Recently I switched to DrawingVisuals to increase the performance of our trending graphs (especially zooming and panning).

Here's the code I have:

blocksToBeRendered = (baseItem as AvgCurve).GetStreamGeometryBlocks(ActualWidth, ActualHeight, _minPoint.X, _maxPoint.X, FixTimeStep ? _timeStep : 0, IsMainChart);

Pen stroke = new Pen((baseItem as AvgCurve).LineBrush, 1);

foreach (GeometryGroup group in blocksToBeRendered)
{
    if (group.Children.Count != 0)
    {
        if (!cachedBlocks[baseItem].Any(x => x.Children[0] == group.Children[0]))
        {
            cachedBlocks[baseItem].Add(group);

            ImprovedDrawingVisual vis = new ImprovedDrawingVisual();

            BitmapCache cache = new BitmapCache() { SnapsToDevicePixels = true };
            vis.CacheMode = cache;

            using (DrawingContext context = vis.RenderOpen())
            {
                RenderOptions.SetEdgeMode(group, EdgeMode.Aliased);
                if (group.Children.Count > 0)
                {
                    context.DrawGeometry(null, stroke, group.Children[0]);
                }
            }

            _host.VisualCollection.Add(vis);
        }
    }
}

This is the ImprovedDrawingVisual:

public class ImprovedDrawingVisual: DrawingVisual
{
    public ImprovedDrawingVisual()
    {
        VisualEdgeMode = EdgeMode.Aliased;
        VisualBitmapScalingMode = BitmapScalingMode.NearestNeighbor;
    }
}

Now, the geometries do have Transforms, which might be important.

What happens is that the graphs are drawn nicely without bitmap caching (1 px lines), but when I turn on bitmap caching, parts of the graph go all blurry sometimes.

Does anyone know how I can fix this? I tried changing the RenderAtScale of the DrawingVisual or turning off the EdgeMode setting, but that doesn't help.

EDIT: Left out the brush fill geometry to avoid confusion since it's not relevant here.


回答1:


If you decide to try GDI+ in wpf, then drawing will looks like this:

using GDI = System.Drawing;

private int _counter; // count redraws

protected override void OnRender(DrawingContext context)
{
    if (Figures != null && RenderSize.Height > 0 && RenderSize.Width > 0)
        using (var bitmap = new GDI.Bitmap((int)RenderSize.Width, (int)RenderSize.Height))
        {
            using (var graphics = GDI.Graphics.FromImage(bitmap))
                foreach (var figure in Figures)
                    figure.Render(this, graphics);
            // draw image
            var hbitmap = bitmap.GetHbitmap();
            var size = bitmap.Width * bitmap.Height * 4;
            GC.AddMemoryPressure(size);
            var image = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            image.Freeze();
            context.DrawImage(image, new Rect(RenderSize));
            DeleteObject(hbitmap);
            GC.RemoveMemoryPressure(size);
            // trigger garbage collecting
            if (_counter++ > 10)
                GC.Collect(3);
      }
}

This basically renders Graph in place (no deffered wpf rendering, well, only blitting of final image). You call InvalidateVisual() to redraw graph. Notice GC thingies, they are must (especially periodic garbage collection if graph gets redrawn frequently).

In my code Figures is a list of non-visuals (simple classes, implementing GDI rendering as well). And you have visual children. It's the problem, which I leave for you to solve. The benefit is very high performance.



来源:https://stackoverflow.com/questions/26138099/bitmap-cache-on-drawingvisual-has-blurry-parts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!