Масштабирование InkStrokes в UWP

У меня есть простое демонстрационное приложение, которое использует изображение в качестве фона InkCanvas, и я масштабирую штрихи при изменении размера отображения изображения, чтобы они оставались в одном и том же месте относительно изображения. Поскольку вы можете рисовать -> изменять размер -> рисовать -> изменять размер -> рисовать, это означает, что я должен каждый раз масштабировать каждый штрих на разную величину, назначая PointTransform для каждого штриха.

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));
}

Это отлично изменяет длину штрихов. Однако это никак не влияет на толщину штрихов. Это еще более очевидно, когда вы используете толстое или неоднородное перо (например, маркер).

Эти ссылки на два клипа экрана, которые показывают результаты. Полноэкранный – https://1drv.ms/i/s!ArHMZAt1svlBiZZDfrxFqyGU1bJ6MQ Меньшее окно – https://1drv.ms/i/s!ArHMZAt1svlBiZZCqHHYaISPfWMMpQ

Любые идеи о том, как я могу изменить толщину штрихов?


person Rob Spencer    schedule 30.03.2017    source источник


Ответы (3)


Примените ScaleTransform к элементу управления InkCanvas. Это позаботится о масштабировании мазка пера, местоположения мазка и фонового изображения. По сути, преобразование применяется ко всему, что содержится в InkCanvas. Нет необходимости использовать Matrix с 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>

Код

 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;
    }

Скриншоты

Масштабируется на 100 % png" alt="Масштаб 100%">

Масштабировано на 60% png" alt="Масштаб 60%">

person Walt Ritscher    schedule 02.04.2017
comment
Спасибо, Уолт. Сейчас я поэкспериментирую с этим и посмотрю, будет ли это работать с изображением в качестве фона холста. На самом деле я обрезаю размер холста, чтобы он соответствовал реальным размерам изображения, а не ограничивающей рамке элемента управления изображением (поскольку вокруг портретного изображения, отображаемого в полноэкранном режиме на ландшафтном мониторе, много пустого пространства). Кстати, отличное изображение :) - person Rob Spencer; 03.04.2017
comment
Кажется, что у него есть некоторые преимущества и некоторые недостатки. Мне больше не нужно изменять размер холста, так как это делает преобразование масштабирования. - person Rob Spencer; 03.04.2017
comment
... (продолжение) Есть проблема с панелью инструментов, так как масштабирование холста не отражается на размере пера. Мне придется добавить пользовательскую панель инструментов, которая не отображает образец размера пера. - person Rob Spencer; 03.04.2017

Масштабирование InkCanvas не всегда решает проблему, особенно если вы хотите сохранить масштабированные чернила в файл изображения GIF.

По-видимому, PointTransform InkStroke преобразует только расположение точек штриха, но не размер PenTip, используемого для рисования штриха. (Не задокументировано нигде, что я могу найти, но обнаружено методом проб и ошибок. Название «PointTransform» является чем-то вроде подсказки)

Таким образом, помимо применения вашего коэффициента масштабирования к PointTransform, вы также должны масштабировать PenTip следующим образом (модификация вашего исходного кода):

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

Надеюсь, это поможет кому-то...

person Robert    schedule 12.12.2017
comment
Я столкнулся с этим недавно. Точки обводки перемещаются, но ширина обводки не масштабируется должным образом. Однако, когда я реализую ваше решение. PenTipTransform не меняется. - person Seige; 02.05.2018

Чтобы изменить толщину штрихов, необходимо изменить свойство Size атрибута DrawingAttributes. PenTipTransform не работает для карандаша — выдает исключение.

Дело в том, что вы не можете установить свойство DrawingAttributes обводки напрямую: https://docs.microsoft.com/en-us/uwp/api/windows.ui.input.inking.inkdrawingattributes

Вот пример, как это получить:

    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;
    }

Полный пример: https://github.com/ycherkes/ScaledInks

person Yevhen Cherkes    schedule 24.05.2018