Avalonia icon indicating copy to clipboard operation
Avalonia copied to clipboard

Allow custom DrawingContext implementations

Open appel1 opened this issue 10 months ago • 10 comments

Is your feature request related to a problem? Please describe.

We'd like to implement our own DrawingContext to provide our own export functionality. This would allow us to make certain Avalonia controls aware of our implementation so that it can inject additional context into the output when for example creating an svg or emf.

Describe the solution you'd like

public DrawingContext ctor protected instead of internal.

Describe alternatives you've considered

We've tried using the built in skia impementation to export to svg but it is not complete and does not allow us the same flexibility.

Additional context

No response

appel1 avatar Apr 23 '24 08:04 appel1

How would this API look like? I can't imagine. Are you referring to somehow extending rendering engine so it can support extra types?

maxkatz6 avatar Apr 23 '24 08:04 maxkatz6

Perhaps I'm missing something obvious, but I did a simple test and made the DrawingContext ctor protected instead of internal, built my own class inheriting from it and then rendered an Avalonia object using ImmediateRenderer.Render. I didn't do a complete implementation for my test, but for the operations I implemented it worked fine.

appel1 avatar Apr 23 '24 08:04 appel1

From what it sounds, this idea might conflict with our plans on drawing context related code.

ImmediateRenderer is going to be removed. Primarily because we are migrating to async CompositionRenderer, which can utilize GPU resources, unlikely ImmediateRenderer.

DrawingContext is protected since it's backend by a platform specific implementation (skia, d2d) or intermediate presentation of a context (anything that records draw calls, like a visual brush).

I can see overriding a DrawingContext can be useful to record draw calls yourself for any kind of statistics. IIRC, WPF allows that as well.

maxkatz6 avatar Apr 25 '24 03:04 maxkatz6

I don't think that ImmediateRenderer is the issue here, but rather the possibility to derive your own implementation from DrawingContext. It is currently not possible since the CTOR is "internal". It could still be backed by internal platform specific implementations.

mb-to avatar Apr 25 '24 07:04 mb-to

DrawingContext is abstract by design so people can use it as a drawing operation sink

https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Base/Media/DrawingContext.cs

The internal ctor is wrong

Gillibald avatar Apr 25 '24 08:04 Gillibald

cc @kekekeks

maxkatz6 avatar Apr 25 '24 08:04 maxkatz6

WPF has DrawingContext's .ctor to be internal too.

In general we are currently quite reluctant to make internal-ish classes to be user-implementable mostly because of backwards compatibility guarantees. I. e. adding new members to that class would break user implementations and we don't want to be blocked from adding those during 11.x.y lifecycle.

kekekeks avatar Apr 25 '24 09:04 kekekeks

In WPF you can get a DrawingGroup from any Visual using VisualTreeHelper.GetDrawing. So to convert WPF element to some other format you can traverse the visual tree, get a drawing group for each visual and process the drawing groups since they mostly contains the most basic "building blocks" like GeometryDrawing, DrawingGroup, GlyphRunDrawing or ImageDrawing.

If you are reluctant to open up DrawingContext then perhaps something similar would be more feasible?

appel1 avatar Apr 25 '24 11:04 appel1

Will have to try, but maybe it is possible to use the existing API to accomplish something similar.

Traverse the visual tree, for each visual create a new DrawingGroup, and render the visual to the DrawingGroup using the context from DrawingGroup.Open.

appel1 avatar May 16 '24 10:05 appel1

Ok, that isn't possible right now either because Geometry.PlatformImpl is internal so there's no way to get the real geometries.

appel1 avatar May 16 '24 17:05 appel1

Ok, seems like it works by rendering each Geometry separately using a SKSvgCanvas and then replacing the fill and stroke attributes appropriately.

appel1 avatar May 22 '24 07:05 appel1