Кэш растрового изображения в DrawingVisual имеет размытые части

Недавно я перешел на DrawingVisuals повысить производительность наших трендовых графиков (особенно масштабирование и панорамирование).

Вот код, который у меня есть:

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);
        }
    }
}

Это ImprovedDrawingVisual:

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

Теперь геометрия имеет Transforms, что может быть важно.

Что происходит, так это то, что графики хорошо рисуются без кеширования растровых изображений (строки размером 1 пиксель), но когда я включаю кеширование растровых изображений, части графика иногда становятся размытыми.

размытые линии

Кто-нибудь знает, как я могу это исправить? Я пытался изменить RenderAtScale из DrawingVisual или отключив EdgeMode настройка, но это не помогает.

РЕДАКТИРОВАТЬ: опустить геометрию заливки кисти, чтобы избежать путаницы, так как это не имеет значения здесь.

1 ответ

Решение

Если вы решили попробовать GDI+ в wpfтогда рисунок будет выглядеть так:

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);
      }
}

Это в основном делает Graph на месте (не отложено wpf рендеринг, ну только блинтинг финал image). Ты звонишь InvalidateVisual() перерисовать график. уведомление GC штуки, они должны (особенно периодическая сборка мусора, если граф часто перерисовывается).

В моем коде Figures список невизуальных объектов (простые классы, также реализующие рендеринг GDI) И у вас есть визуальные дети. Это проблема, которую я оставляю вам для решения. Благо очень высокая производительность.

Другие вопросы по тегам