You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何旋转PathGeometry实现心形图片裁剪并支持缩放?

问题描述

最终目标

使用心形形状裁剪图片。

尝试过程

已将SVG路径数据转换为等效的Geometry对象,但需要旋转最终的Geometry对象。和WPF不同,PathGeometry和PathFigure类型继承自BindableObject而非VisualElement,没有Rotation属性或RotateTo()、Transform()方法。

当前问题

  • 如何解决旋转问题?
  • 是否有方法让图片裁剪对象可缩放/调整大小?

当前代码

<DataTemplate>
...
 <Image Aspect="AspectFill"
        Source="{Binding .}"
        VerticalOptions="Center"
        WidthRequest="300">
     <Image.Clip>
         <PathGeometry>
             <PathGeometry.Figures>
                 <PathFigureCollection>
                     <PathFigure IsClosed="False" StartPoint="0,200">
                         <PathFigure.Segments>
                             <PathSegmentCollection>
                                 <LineSegment Point="0,0" />
                                 <LineSegment Point="200,0" />
                                 <ArcSegment IsLargeArc="True"
                                             Point="200,200"
                                             RotationAngle="90"
                                             Size="100,100"
                                             SweepDirection="Clockwise" />

                                 <ArcSegment IsLargeArc="True"
                                             Point="0,200"
                                             RotationAngle="90"
                                             Size="100,100"
                                             SweepDirection="Clockwise" />
                             </PathSegmentCollection>
                         </PathFigure.Segments>
                     </PathFigure>
                 </PathFigureCollection>
             </PathGeometry.Figures>
         </PathGeometry>
     </Image.Clip>
 </Image>
...
<DataTemplate>

截图说明

截图展示

  • 红色:目标心形形状。
  • 蓝色:当前裁剪形状,需旋转后得到红色心形。
  • 注:蓝色与红色形状为同一路径,仅存在旋转差异。

目标SVG(带旋转)

<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" height="315" width="342" viewBox="20 -10 315 342">
 <defs>
  <style type="text/css"><![CDATA[
    .outline { stroke:none; stroke-width:0 }
  ]]></style>
   <g id="heart">
   <path
    stroke="red"
    pathLength="1"
    stroke-width="5"
    d="M0 200 v-200 h200 
    a100,100 90 0,1 0,200
    a100,100 90 0,1 -200,0
    z" />
  </g>
 </defs>
 <desc>
   a nearly perfect heart
     made of two arcs and a right angle
 </desc>
  <use xlink:href="#heart" class="outline " fill="none" transform="rotate(225,150,121)" />
</svg>

未旋转的SVG效果

<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" height="315" width="342" viewBox="20 -10 315 342">
 <defs>
  <style type="text/css"><![CDATA[
    .outline { stroke:none; stroke-width:0 }
  ]]></style>
   <g id="heart">
   <path
    stroke="red"
    pathLength="1"
    stroke-width="5"
    d="M0 200 v-200 h200 
    a100,100 90 0,1 0,200
    a100,100 90 0,1 -200,0
    z" />
  </g>
 </defs>
 <desc>
   a nearly perfect heart
     made of two arcs and a right angle
 </desc>
  <use xlink:href="#heart" class="outline " fill="none"" />
</svg>

参考WPF相关问题:如何垂直翻转PathGeometry?


解决方案

一、解决旋转问题

由于PathGeometry不支持直接旋转,有两种可行方案:

1. 手动计算旋转后坐标(性能优先)

根据目标SVG的旋转参数(225度,旋转中心(150,121)),用旋转公式计算所有路径点的新坐标,直接替换原有路径。

旋转坐标公式(以(cx, cy)为中心旋转θ度):

x' = (x - cx) * cosθ - (y - cy) * sinθ + cx
y' = (x - cx) * sinθ + (y - cy) * cosθ + cy

225度对应的cos值≈-0.7071,sin值≈-0.7071,计算后可得到如下旋转完成的心形路径:

<PathGeometry>
    <PathFigure IsClosed="True" StartPoint="150,21.9">
        <PathSegmentCollection>
            <LineSegment Point="260.7,121" />
            <ArcSegment IsLargeArc="True" Point="150,220.1" RotationAngle="90" Size="100,100" SweepDirection="Clockwise" />
            <ArcSegment IsLargeArc="True" Point="39.3,121" RotationAngle="90" Size="100,100" SweepDirection="Clockwise" />
            <LineSegment Point="150,21.9" />
        </PathSegmentCollection>
    </PathFigure>
</PathGeometry>

2. 使用Transform属性(便捷优先)

MAUI中PathGeometry提供了Transform属性,可添加RotateTransform设置旋转角度和中心:

<Image.Clip>
    <PathGeometry>
        <PathGeometry.Transform>
            <RotateTransform Angle="225" CenterX="150" CenterY="121" />
        </PathGeometry.Transform>
        <!-- 保留原有路径代码 -->
    </PathGeometry>
</Image.Clip>

注意需确保旋转中心与路径中心对齐,避免出现偏移。

二、实现裁剪对象的缩放/调整大小

1. 结合ScaleTransform动态缩放

通过TransformGroup同时添加旋转和缩放变换,绑定缩放比例实现动态调整:

<PathGeometry.Transform>
    <TransformGroup>
        <RotateTransform Angle="225" CenterX="150" CenterY="121" />
        <ScaleTransform ScaleX="{Binding ScaleFactor}" ScaleY="{Binding ScaleFactor}" CenterX="150" CenterY="121" />
    </TransformGroup>
</PathGeometry.Transform>

在ViewModel中定义ScaleFactor属性,修改该值即可调整裁剪形状大小。

2. 使用Viewbox包裹

将Image放入Viewbox中,通过调整Viewbox的宽高间接缩放裁剪形状,同时保持比例:

<Viewbox WidthRequest="{Binding ClipWidth}" HeightRequest="{Binding ClipHeight}">
    <Image Aspect="AspectFill" Source="{Binding .}">
        <Image.Clip>
            <!-- 已旋转的心形PathGeometry -->
        </Image.Clip>
    </Image>
</Viewbox>

三、替代方案

若上述方法复杂,可直接使用SkiaSharp绘制心形裁剪路径,或转换SVG为Path的Data属性作为裁剪,灵活性更高。


内容的提问来源于stack exchange,提问作者Cfun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 23:37:02