microsoft / Win2D

Win2D is an easy-to-use Windows Runtime API for immediate mode 2D graphics rendering with GPU acceleration. It is available to C#, C++ and VB developers writing apps for the Windows Universal Platform (UWP). It utilizes the power of Direct2D, and integrates seamlessly with XAML and CoreWindow.
http://microsoft.github.io/Win2D
Other
1.82k stars 287 forks source link

Inking Highlighter on CanvasControl with ClearColor=Transparent #428

Closed nuiSense closed 8 years ago

nuiSense commented 8 years ago

Highlighter strokes are not visible if ClearColor property is setted to Transparent on a CanvasControl. We need to use the CanvasControl over a XAML Image and MediaElement to make inking on it. It must be transparent. How to fix it?

shawnhar commented 8 years ago

You cannot compose highlighter strokes across more than one surface in this way, because highlighter uses a "min" blending mode rather than the source-over blend that combines the CanvasControl with whatever other elements lie behind it.

Either don't use highlighter blending, or draw your background images directly into the same CanvasControl where the highlighter ink will be blended over it.

More details here: http://stackoverflow.com/a/36509014

christianrr commented 7 years ago

Found a possible solution to this problem:

1) Create a separate canvas control for the highlighter strokes and one for the normal "pen" strokes (the important thing is to set the CompositionMode of the highlighter's texture to MinBlend to blend the highlighter strokes with underlying background):

<xaml:CanvasControl x:Name="UxHighlighterInkTexture" Draw="OnRepaintHighlighterInkTexture" CompositeMode="MinBlend" /> <xaml:CanvasControl x:Name="UxInkTexture" Draw="OnRepaintInkTexture" SizeChanged="OnInkTextureSizeChanged"/>

2) In the second stage, draw the highlighter strokes on the highlighter canvas control in a two-step approach: First, draw the strokes as non-highlighter strokes into the texure to form the background to make highlighter strokes appear and then in a second stage draw the highlighter strokes on top of the non-highlighter strokes to blend all the strokes into each other.

// render highlighter strokes
var highlighterStrokes = strokesToRender.Where(stroke => stroke.DrawingAttributes.DrawAsHighlighter).ToList();

// set DrawAsHighlighter to false temporary
foreach (var stroke in highlighterStrokes)
{
    var attributes = stroke.DrawingAttributes.Clone();
    attributes.DrawAsHighlighter = false;
    stroke.DrawingAttributes = attributes;
}

// draw highlighter strokes (1st pass) - background to make texture blending work
session.DrawInk(highlighterStrokes);

// restore attributes
foreach (var stroke in highlighterStrokes)
{
    var attributes = stroke.DrawingAttributes.Clone();
    attributes.DrawAsHighlighter = true;
    stroke.DrawingAttributes = attributes;
}

// draw highlighter strokes (2nd pass) - adds blending of strokes
session.DrawInk(highlighterStrokes);

With that solution, I was able to reproduce the normal InkCanvas behavior. The first step blends your highlighter strokes with any underlying content, while the two-step approach in the second stage blends the internal highlighter strokes against each other.