1

I've got a simple demo application that uses an image as the background of an InkCanvas and I scale the strokes when the display of the image is resized so that they remain in the same place relative to the image. Since you can draw -> resize -> draw -> resize -> draw this means I have to scale each stroke a different amount each time by assigning the PointTransform on each stroke.

float thisScale = (float)(scale / _prevScale);
foreach (InkStroke stroke in myCanvas.InkPresenter.StrokeContainer.GetStrokes())
{
    float thisPointScale = thisScale * stroke.PointTransform.M11;
    stroke.PointTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
}

This resizes the length of the strokes perfectly well. However, it does nothing to the thickness of the strokes. This is even more evident when you use a thick or non-uniform pen (eg the highlighter pen).

These link to two screen clips which show the results. Full-screen - https://1drv.ms/i/s!ArHMZAt1svlBiZZDfrxFqyGU1bJ6MQ Smaller window - https://1drv.ms/i/s!ArHMZAt1svlBiZZCqHHYaISPfWMMpQ

Any ideas on how I can resize the thickness of the strokes?

Rob Spencer
  • 77
  • 1
  • 7

3 Answers3

2

Apply a ScaleTransform to the InkCanvas control. That'll take care of scaling the ink stroke,the stroke locations and the background image. Essentially the transform applies to everything contained in the InkCanvas. No need to use the Matrix with the StrokeCollection.

XAML

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal">
        <Button Content="Red Highlighter "
                x:Name="InkRedAttributesButton"
                Click="InkRedAttributesButton_Click" />
        <Button Content="Blue Highlighter "
                x:Name="InkBlueAttributesButton"
                Click="InkBlueAttributesButton_Click" />
        <Button Content="Scale Down"
                x:Name="ScaleDownButton"
                Click="ScaleDownButton_Click" />
        <Button Content="Scale Up"
                x:Name="ScaleUpButton"
                Click="ScaleUpButton_Click" />
    </StackPanel>
    <InkCanvas x:Name="myCanvas"
               Grid.Row="1"  HorizontalAlignment="Left" VerticalAlignment="Top">
        <InkCanvas.Background>
            <ImageBrush ImageSource="/SO_Questions;component/Images/Star02.jpg"
                        Stretch="Fill" />
        </InkCanvas.Background>
        <InkCanvas.RenderTransform>
            <ScaleTransform x:Name="InkCanvasScaleTransform" />
        </InkCanvas.RenderTransform>
    </InkCanvas>
</Grid>

Code

 private void ScaleUpButton_Click(object sender, RoutedEventArgs e) {
      InkCanvasScaleTransform.ScaleX += .2;
      InkCanvasScaleTransform.ScaleY += .2;

    }
    private void ScaleDownButton_Click(object sender, RoutedEventArgs e) {
      InkCanvasScaleTransform.ScaleX -= .2;
      InkCanvasScaleTransform.ScaleY -= .2;

    }

    private void InkRedAttributesButton_Click(object sender, RoutedEventArgs e) {
      DrawingAttributes inkAttributes = new DrawingAttributes();

      inkAttributes.Height = 12;
      inkAttributes.Width = 12;
      inkAttributes.Color = Colors.Red;
      inkAttributes.IsHighlighter = true;
      myCanvas.DefaultDrawingAttributes = inkAttributes;
    }

    private void InkBlueAttributesButton_Click(object sender, RoutedEventArgs e) {
      DrawingAttributes inkAttributes = new DrawingAttributes();

      inkAttributes.Height = 12;
      inkAttributes.Width = 12;
      inkAttributes.Color = Colors.Blue;
      inkAttributes.IsHighlighter = true;
      myCanvas.DefaultDrawingAttributes = inkAttributes;
    }

Screenshots

Scaled 100% Scaled 100%

Scaled 60% Scaled 60%

Walt Ritscher
  • 6,977
  • 1
  • 28
  • 35
  • Thanks Walt. I'll play around with this now and see whether it is workable with the image as the canvas background too. I'm actually "cropping" the canvas size to match the real image dimensions rather than the bounding box of the image control (since there's a lot of empty space around a portrait image displayed full screen on a landscape monitor). BTW Great image :) – Rob Spencer Apr 03 '17 at 08:51
  • It seems to have some advantages and some disadvantages. I no longer need to resize the canvas as the scaling transform does that. – Rob Spencer Apr 03 '17 at 12:33
  • ... (continuing on) There's a problem though with the toolbar as the scaling of the canvas isn't reflected in the pen sizing. I'll have to add a custom toolbar that doesn't display the sample pen size. – Rob Spencer Apr 03 '17 at 12:39
2

Scaling the InkCanvas doesn't always fix the problem especially if you are wanting to save the scaled ink into a gif image file.

Apparently an InkStroke's PointTransform only transforms the location of the stroke's points, but not the size of the PenTip used to draw the stroke. (Not documented anywhere that I can find, but discovered by trial and error. The name 'PointTransform' is a bit of a clue)

So as well as applying your scaling factor to the PointTransform, you also have to scale the PenTip as follows (modification to your original code):

float thisPointScale = thisScale * stroke.PointTransform.M11;
stroke.PointTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));
stroke.DrawingAttributes.PenTipTransform = Matrix3x2.CreateScale(new Vector2(thisPointScale));

Hope this helps someone...

Robert
  • 231
  • 3
  • 10
  • I have run into this recently. The stroke points are moving, but the width of the stroke doesn't scale properly. However when I implement your solution. the PenTipTransform doesn't change. – Seige May 02 '18 at 02:51
2

To resize the thickness of the strokes you have to change the Size property of the DrawingAttributes. PenTipTransform doesn't work for pencil - it throws an exception.

The point is that you cannot set the DrawingAttributes property of the stroke directly: https://learn.microsoft.com/en-us/uwp/api/windows.ui.input.inking.inkdrawingattributes

Here is example how to get this:

    static IEnumerable<InkStroke> GetScaledStrokes(IEnumerable<InkStroke> source, float scale)
    {
        var scaleMatrix = Matrix3x2.CreateScale(scale);

        var resultStrokes = source.Select(x => x.Clone()).ToArray();

        foreach (var inkStroke in resultStrokes)
        {
            inkStroke.PointTransform = scaleMatrix;
            var da = inkStroke.DrawingAttributes;
            var daSize = da.Size;
            daSize.Width = daSize.Width * scale;
            daSize.Height = daSize.Height * scale;
            da.Size = daSize;
            inkStroke.DrawingAttributes = da;
        }

        return resultStrokes;
    }

Complete example: https://github.com/ycherkes/ScaledInks

Yevhen Cherkes
  • 626
  • 7
  • 10