Как обрезать canvas WPF
Необходимо обрезать фигуру. Нужно сделать прозрачную обводку вокруг зеленого кружочка.
Вот как есть:
А этом изображении я просто залил Stroke цветом фона. Но так не красиво и работать так как мне надо не будет:
Код XAML:
<Canvas MinHeight="50" MaxHeight="50" MinWidth="50" MaxWidth="50">
<Ellipse Width="50" Height="50">
<Ellipse.Fill>
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding ContactPhoto, FallbackValue='C://Program Files (x86)/LawChat/userdata/Images/no_photo.jpg', TargetNullValue='C://Program Files (x86)/LawChat/userdata/Images/no_photo.jpg'}"/>
</Ellipse.Fill>
</Ellipse>
<Ellipse Margin="40,35,0,0" StrokeThickness="3" Width="15" Height="15">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Style.Triggers>
<DataTrigger Binding="{Binding IsOnline}" Value="False">
<Setter Property="Fill" Value="Chartreuse"/>
<Setter Property="Stroke" Value="#FF21242A"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</Canvas>
Ответы (1 шт):
От части, тут все просто, но не совсем...
В WPF особо нет чего либо, что может взять и "вырезать" часть из другой части, такое поведение есть например в GeometryGroup, которое используется в Path, но там вы рисуете фигурами, примитивами, а не картинками и чем либо еще. В связи с этим, вам изначально нужен некий "референс", некий "макет", который будет подходить задавать вид вашей картинке при помощи OpacityMask - инструмента, который позволяет отображать лишь заданную часть, а все остальное скрывать. В качестве маски, советую использовать вектор, который можете сгенерировать без проблем из картинки при помощи онлайн инструментов, либо офлайн.
Как сделал я:
Нарисовал в первом попавшемся онлайн фотошопе изображение, взял просто круг, и вырезал из него другой круг, убрал фон, и сохранил в .PNG, получил такое:
Изображение большевато (500х500), думаю без проблем 100х100 подошло бы, но не суть..
Написал в гугле "png to svg", и нашел первой ссылкой онлайн конвертор, загрузил туда изображение, и скачал получившийся
.svg:<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="500.000000pt" height="500.000000pt" viewBox="0 0 500.000000 500.000000" preserveAspectRatio="xMidYMid meet"> <g transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none"> <path d="M2265 4989 c-419 -43 -797 -177 -1143 -405 -146 -96 -220 -155 -354 -283 -408 -389 -669 -909 -749 -1491 -17 -124 -17 -496 0 -620 102 -740 497 -1376 1102 -1774 682 -448 1509 -538 2279 -248 58 21 140 57 182 78 l77 39 -40 60 c-102 155 -142 366 -104 550 32 153 97 274 207 383 99 100 219 167 358 203 72 18 268 18 340 0 77 -20 186 -67 245 -107 l50 -34 52 108 c96 197 179 486 214 742 17 124 17 496 0 620 -102 739 -497 1376 -1101 1773 -355 233 -724 363 -1159 407 -118 12 -339 11 -456 -1z"/> </g> </svg>Все в том-же поисковике, написал "optimize svg", и все аналогично, первой ссылкой нашел оптимизатор SVG, в который закинул файл, и скачал исходный вариант, который похудел на 32%. Этот шаг я сделал не ради размера, а больше ради того, чтоб за меня убрали переходы на новую строку, которые в данном случае не нужны, в итоге файл получился таким:
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="666.667" height="666.667" viewBox="0 0 500 500"> <path d="M226.5 1.1c-41.9 4.3-79.7 17.7-114.3 40.5-14.6 9.6-22 15.5-35.4 28.3C36 108.8 9.9 160.8 1.9 219c-1.7 12.4-1.7 49.6 0 62 10.2 74 49.7 137.6 110.2 177.4 68.2 44.8 150.9 53.8 227.9 24.8 5.8-2.1 14-5.7 18.2-7.8l7.7-3.9-4-6c-10.2-15.5-14.2-36.6-10.4-55 3.2-15.3 9.7-27.4 20.7-38.3 9.9-10 21.9-16.7 35.8-20.3 7.2-1.8 26.8-1.8 34 0 7.7 2 18.6 6.7 24.5 10.7l5 3.4 5.2-10.8c9.6-19.7 17.9-48.6 21.4-74.2 1.7-12.4 1.7-49.6 0-62C487.9 145.1 448.4 81.4 388 41.7 352.5 18.4 315.6 5.4 272.1 1c-11.8-1.2-33.9-1.1-45.6.1z"/></svg>Открываем студию, и пишем XAML. Нам нужна строго квадратная панель, в которой будет картинка, растягивающаяся до максимума, и в нижнем правом углу кружочек:
<Grid Width="100" Height="100"> <Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="https://w0.peakpx.com/wallpaper/529/871/HD-wallpaper-the-wandering-earth-2-movie-poster.jpg" Stretch="UniformToFill"> </Image> <Ellipse Width="27" Height="27" Margin="0,0,1,1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Fill="#FF108E10"/> </Grid>Результатом будет такое:
Обратите внимание, я использую правильное позиционирование, у меня "статус онлайна" сразу находится в нижнем правом углу, от которого я делаю отступ всего на 1 пункт, у меня нет таких бешенных значений как у вас в
Margin. Мой совет, забудьте про позиционирование элементов отступами, это неверно, и чревато огромными проблемами!Теперь маска, при помощи которой превращаем квадрат в круг. Маску применяем картинке, задав ей
<Image.OpacityMask>, сам тип маскиVisualBrushсо свойствомStretch="Uniform", внутри делаемViewboxдля автоматического подгона размеров вектора под размеры картинки, ну а внутри делаемCanvasфиксированного размера, на котором рисуем черезPathсам вектор, где свойствоData, это самое длинное значение из .svg файла, зовется котороеd. Получаем в итоге такую разметку:<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="https://w0.peakpx.com/wallpaper/529/871/HD-wallpaper-the-wandering-earth-2-movie-poster.jpg" Stretch="UniformToFill"> <Image.OpacityMask> <VisualBrush Stretch="Uniform"> <VisualBrush.Visual> <Viewbox> <Canvas Width="100" Height="100"> <Path Data="M226.5 1.1c-41.9 4.3-79.7 17.7-114.3 40.5-14.6 9.6-22 15.5-35.4 28.3C36 108.8 9.9 160.8 1.9 219c-1.7 12.4-1.7 49.6 0 62 10.2 74 49.7 137.6 110.2 177.4 68.2 44.8 150.9 53.8 227.9 24.8 5.8-2.1 14-5.7 18.2-7.8l7.7-3.9-4-6c-10.2-15.5-14.2-36.6-10.4-55 3.2-15.3 9.7-27.4 20.7-38.3 9.9-10 21.9-16.7 35.8-20.3 7.2-1.8 26.8-1.8 34 0 7.7 2 18.6 6.7 24.5 10.7l5 3.4 5.2-10.8c9.6-19.7 17.9-48.6 21.4-74.2 1.7-12.4 1.7-49.6 0-62C487.9 145.1 448.4 81.4 388 41.7 352.5 18.4 315.6 5.4 272.1 1c-11.8-1.2-33.9-1.1-45.6.1z" Fill="Black" /> </Canvas> </Viewbox> </VisualBrush.Visual> </VisualBrush> </Image.OpacityMask> </Image>Ну а результатом будет такое:
Финальный штрих, все полученное, загоняем в
ViewBox, чтобы все подгонялось под размеры родителя, без потерь позиционирования, получив в финале такую разметку:<Viewbox> <Grid Width="100" Height="100"> <Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="https://w0.peakpx.com/wallpaper/529/871/HD-wallpaper-the-wandering-earth-2-movie-poster.jpg" Stretch="UniformToFill"> <Image.OpacityMask> <VisualBrush Stretch="Uniform"> <VisualBrush.Visual> <Viewbox> <Canvas Width="100" Height="100"> <Path Data="M226.5 1.1c-41.9 4.3-79.7 17.7-114.3 40.5-14.6 9.6-22 15.5-35.4 28.3C36 108.8 9.9 160.8 1.9 219c-1.7 12.4-1.7 49.6 0 62 10.2 74 49.7 137.6 110.2 177.4 68.2 44.8 150.9 53.8 227.9 24.8 5.8-2.1 14-5.7 18.2-7.8l7.7-3.9-4-6c-10.2-15.5-14.2-36.6-10.4-55 3.2-15.3 9.7-27.4 20.7-38.3 9.9-10 21.9-16.7 35.8-20.3 7.2-1.8 26.8-1.8 34 0 7.7 2 18.6 6.7 24.5 10.7l5 3.4 5.2-10.8c9.6-19.7 17.9-48.6 21.4-74.2 1.7-12.4 1.7-49.6 0-62C487.9 145.1 448.4 81.4 388 41.7 352.5 18.4 315.6 5.4 272.1 1c-11.8-1.2-33.9-1.1-45.6.1z" Fill="Black" /> </Canvas> </Viewbox> </VisualBrush.Visual> </VisualBrush> </Image.OpacityMask> </Image> <Ellipse Width="27" Height="27" Margin="0,0,1,1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Fill="#FF108E10" /> </Grid> </Viewbox>И как видите, все успешно подстроилось под размеры окна
Вот и все, вам остается лишь нарисовать более грамотный вектор (под свой вкус), сделать из этого отдельный контрол, и встроить его простым <control:UserImage Image=".." Status = "..." /> (названия на бум) в нужное место. Удачи!
А да, может возникнуть вопрос, почему мы сетке задаем строго статичные размеры (<Grid Width="100" Height="100">), ответ прост - Нам надо, чтобы у нас был ровный квадрат, под который Image подгонит изображение любого размера. Если у нас не будет этого, то например указав прямоугольное изображение, кружок статуса уйдет в сторону, ибо Grid автоматически расширится под самый большой объект, изображение. Вот чтоб этого не был, нам нужен строго статичный объект, который уже потом растягиваем при помощи ViewBox под нужный нам размер.





