Kinemu
Kinemu

Reputation: 31

win2D uwp won't save a highlight stroke in an inkcanvas

I'm desperately trying to save a highlight stroke as a png. I'm using win2d for UWP to make this work. It works well for strokes with 100% opacity, but when I set DrawAsHighlighter = true;, the saved png is empty, fully transparent.

Here's my code :

    private void SetHighLight()
    {
        InkDrawingAttributes attributes = new InkDrawingAttributes();
        attributes.DrawAsHighlighter = true;
        attributes.PenTip = PenTipShape.Rectangle;
        attributes.Size = new Size(4, 10);
        attributes.Color = currentColor;
        SetAttribute(attributes);
    }

    private void GetCanvasRender(out CanvasRenderTarget renderTarget)
    {
        CanvasDevice device = CanvasDevice.GetSharedDevice();
        renderTarget = new CanvasRenderTarget(device, (int)ink.ActualWidth, (int)ink.ActualHeight, 96);
        using (var ds = renderTarget.CreateDrawingSession())
        {
            ds.Clear(Colors.Transparent); //I already tried to delete this but it doesn't change anything
            ds.DrawInk(ink.InkPresenter.StrokeContainer.GetStrokes());
        }
    }

    private async void SavePicture()
    {
        CanvasRenderTarget renderTarget;
        Image img = new Image();

        GetCanvasRender(out renderTarget);
        StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
        StorageFile noteFile = await storageFolder.CreateFileAsync(i.ToString() + ".png", CreationCollisionOption.ReplaceExisting);
        using (var fileStream = await noteFile.OpenAsync(FileAccessMode.ReadWrite))
            await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
        img.Source = new BitmapImage(new Uri(storageFolder.Path + "/" + i++ + ".png"));
        img.VerticalAlignment = VerticalAlignment.Stretch;
        ContainerCanvas.Children.Add(img);
        Canvas.SetTop(img, ScrollViewerContainer.VerticalOffset);
        Canvas.SetZIndex(img, 5);
    }

I've read it might be because of the highlight not being present in the visual tree but I'm really not sure about it.

By the way when I try to change the opacity of a color(attributes.Color = Color.FromArgb(128, 255, 0, 0)), the inkcanvas doesn't apply the alpha, why ? Am I missing something ?

Upvotes: 3

Views: 966

Answers (3)

Kinemu
Kinemu

Reputation: 31

I finally figured out how to make it work. I simply added a new layer before calling DrawInk and gave it an opacity, and got rid of the attributes.DrawAsHighlighter = true;. Instead, I've made 1 inkCanvas with 0.5 opacity specially for the highlighter, looking like you're using a highlighter.

Here's the code :

private void SetHighLight()
{
    InkDrawingAttributes attributes = new InkDrawingAttributes();
    attributes.PenTip = PenTipShape.Rectangle;
    attributes.Size = new Size(4, 10);
    attributes.Color = currentColor;
    SetAttribute(attributes);
}

private void GetCanvasRender(out CanvasRenderTarget renderTarget, float opacity)
{
    CanvasDevice device = CanvasDevice.GetSharedDevice();
    renderTarget = new CanvasRenderTarget(device, (int)ink.ActualWidth, (int)ink.ActualHeight, 96);
    using (var ds = renderTarget.CreateDrawingSession())
    {
        ds.Clear(Colors.Transparent);
        using (ds.CreateLayer(opacity))
        {
            ds.DrawInk(ink.InkPresenter.StrokeContainer.GetStrokes());
        }
    }
}

private async void SavePicture(float opacity)
{
    CanvasRenderTarget renderTarget;
    Image img = new Image();

    GetCanvasRender(out renderTarget, opacity);
    StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
    StorageFile noteFile = await storageFolder.CreateFileAsync(i.ToString() + ".png", CreationCollisionOption.ReplaceExisting);
    using (var fileStream = await noteFile.OpenAsync(FileAccessMode.ReadWrite))
        await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
    img.Source = new BitmapImage(new Uri(storageFolder.Path + "/" + i++ + ".png"));
    img.VerticalAlignment = VerticalAlignment.Stretch;
    ContainerCanvas.Children.Add(img);
    Canvas.SetTop(img, ScrollViewerContainer.VerticalOffset);
    Canvas.SetZIndex(img, 5);
}

Upvotes: 0

SebastianR
SebastianR

Reputation: 2193

Try clearing the background of the canvas with:

ds.Clear(Colors.White);

The highlighter isn't visible on transparent backgrounds as it seems to multiply its value with the background color.

Upvotes: 0

Shawn Hargreaves
Shawn Hargreaves

Reputation: 264

You can't save DrawAsHighlighter ink to a bitmap format like .png - that's just fundamentally not a meaningful operation to be attempting.

Regular non-highlighter ink is drawn using standard alpha blending, so it is reasonable to write just these ink shapes into a bitmap format. You can later blend that bitmap over some other background image, and get the same result as if the ink had been drawn directly over that background.

For highlighter ink, however, the "blend over background" is a more complex operation, not just standard sourceover blending. So there is no such thing as a bitmap image that contains just this ink - you also have to provide a background in order for the appropriate blend to be carried out.

You have three options here:

  1. Don't use highligher ink mode.
  2. Instead of saving out your ink as a bitmap image, save the original ink stroke data, and use inking APIs to later blend these strokes directly to their final location.
  3. Include the background as well as the ink strokes in the same bitmap.

Upvotes: 2

Related Questions