Кешът на растерните изображения на 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 px линии), но когато включа кеширането на растерни изображения, части от графиката понякога се размазват.

размазани линии

Някой знае ли как мога да поправя това? Опитах да променя RenderAtScale на DrawingVisual или да изключа настройката EdgeMode, но това не помага.

РЕДАКТИРАНЕ: Изоставете геометрията на запълване на четката, за да избегнете объркване, тъй като тя не е подходяща тук.


person Toon Casteele    schedule 01.10.2014    source източник
comment
Вие използвате BitmapCache (вижте моя въпрос), който изглежда като растерно изображение, използващо jpg-компресия. Може би можете да внедрите собствен BitmapCache (който няма да бъде jpg)? Между другото, за да имам графика с наистина висока производителност, трябваше да използвам GDI+ в wpf.   -  person Sinatr    schedule 01.10.2014
comment
Имате ли пример за използване на GDI+, как да го направя, като започна от моя пример за код?   -  person Toon Casteele    schedule 01.10.2014


Отговори (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 изобразяване). И имате визуални деца. Това е проблемът, който оставям на вас да решите. Ползата е много висока производителност.

person Sinatr    schedule 01.10.2014
comment
Преди имах геометрии върху платно, които се преначертаваха всеки път, когато панорамирах или мащабирах. Това по-така ли е? - person Toon Casteele; 01.10.2014
comment
Не, защото визуализациите и wpf са бавни. Задавате ли визуални елементи в xaml? Или, казано по друг начин, графичните фигури (линии, ортове, фон и т.н.) трябва ли да са визуални? Ако отговорът е не, тогава ги заменете с невизуални, които знаят само как да изобразят себе си в родител Graph. - person Sinatr; 01.10.2014
comment
Преди имах пътеки, а не визуализации. Тези пътеки имаха геометрия и бяха добавени върху платното. - person Toon Casteele; 01.10.2014
comment
Мащабиране/панорамиране се извършва по време на рендиране. Има локални координати, например точка (100,100) на графиката. И има координати на мишка. Когато изобразявате графика, преобразувате локални координати в мишка и след това използвате GDI функции, за да рисувате линии или каквото и да е друго. WPF трансформацията изглежда добре в началото, но все още имате проблем с изчисляването назад (известен още като координати на мишката в коя точка е това). Визуалните елементи решават тестовете за попадение, но са бавни. - person Sinatr; 01.10.2014
comment
Благодаря. Ще го пробвам с няколко теста. Донякъде е гадно, че ще трябва да изхвърля/силно да адаптирам цялата си логика за създаване на геометрия все пак :p - person Toon Casteele; 01.10.2014
comment
Добре. В момента внедрявам GDI. Доста страхотно е, когато сравните производителността с wpf чертежа. Наистина невероятно. Благодаря. - person Toon Casteele; 06.10.2014