Table of Contents

Custom Shapes

Paint.NET's Shapes tool supports Custom Shapes as a form of declarative plugin - code is not involved! The object model is intentionally identical to WPF geometry, with only a few caveats, and is compatible with XAML files created for WPF as long as you change the namespace and wrap the geometry object in a SimpleGeometryShape element.

The object model for Custom Shapes is contained in the PaintDotNet.Shapes and PaintDotNet.UI.Media namespaces.

Links:

Differences from WPF Geometry

The Geometry object model used for Custom Shapes is identical to WPF's Geometry object model, except for a few differences:

Added:

Removed:

  • StreamGeometry does not exist
    • StreamGeometry is primarily used in code, not in XAML, and does not exist for Custom Shapes.
    • You can, however, use Path Markup syntax to initialize any property of type Geometry.
    • For example: <SimpleGeometryShape Geometry="F1 M 21,142 L 160,22 L 300,142 L 300,318 L 21,318 Z" />

Examples

There are two primary ways of expressing a custom shape. The first is with Path Markup syntax, and the other is with the Geometry object model.

Path Markup syntax example

This is an example of a coffee mug shape defined using Path Markup syntax, which is compatible with SVG path data syntax.

This example is from TechnoRobbo's shapes pack.

<ps:SimpleGeometryShape 
  xmlns="clr-namespace:PaintDotNet.UI.Media;assembly=PaintDotNet.Framework"
  xmlns:ps="clr-namespace:PaintDotNet.Shapes;assembly=PaintDotNet.Framework"                 
  DisplayName="Mug"
  Geometry="M 68,106 A 6.74,23.82,90,1,1,150.5,106 L 150.5,126 A 20.51,15.15,149.74,1,1,150.5,178.5 L 150.5,193.5 A 6.73,23.81,-90,1,1,68,193.5 L 68,106 M 73,106 A 4.03,20.96,89.29,1,1,145,105 A 6.8,24.52,-91.12,1,1,73,106 M 150.5,133.5 A 22.12,15.15,150.46,1,1,150.5,171 L 150.5,133.5 M 109,10.5 C 114.86,15.45,120,20.5,127,33,128.5,42.5,127.5,43,117.5,51,105.5,59.5,124.66,76.88,124,83.5,117,53.5,132,55.5,140.5,46,147.5,28,119.5,15,109,10.5 M 78,7 C 83.86,11.95,89,17,96,29.5,97.5,39,96.5,39.5,86.5,47.5,74.5,56,93.66,73.38,93,80,86,50,101,52,109.5,42.5,116.5,24.5,88.5,11.5,78,7" />

Coffee Mug

Geometry object model example

This is an example of a clock shape defined using the Geometry object model.

This example is from TechnoRobbo's shapes pack.

<ps:SimpleGeometryShape xmlns="clr-namespace:PaintDotNet.UI.Media;assembly=PaintDotNet.Framework"
                        xmlns:ps="clr-namespace:PaintDotNet.Shapes;assembly=PaintDotNet.Framework"
                        DisplayName="Clock">
  <GeometryGroup FillRule="EvenOdd">
    <PathGeometry>
      <PathFigure IsClosed="False" IsFilled="True" StartPoint="87,254">
        <ArcSegment Size="160,160" RotationAngle="0" IsLargeArc="True" SweepDirection="CounterClockwise" Point="408,254" />
      </PathFigure>
      <PathFigure IsClosed="False" IsFilled="True" StartPoint="87,254">
        <ArcSegment Size="160,160" RotationAngle="0" IsLargeArc="True" SweepDirection="Clockwise" Point="408,254" />
      </PathFigure>
      <PathFigure IsClosed="False" IsFilled="True" StartPoint="107,254">
        <ArcSegment Size="88,89" RotationAngle="87" IsLargeArc="True" SweepDirection="Clockwise" Point="387,254" />
        <ArcSegment Size="75,80" RotationAngle="-89" IsLargeArc="True" SweepDirection="Clockwise" Point="107,254" />
      </PathFigure>
      <PathFigure IsClosed="True" IsFilled="True" StartPoint="310,90">
        <ArcSegment Size="34,33" RotationAngle="130" IsLargeArc="True" SweepDirection="Clockwise" Point="400,170" />
        <LineSegment Point="310,90" />
      </PathFigure>
      <PathFigure IsClosed="True" IsFilled="True" StartPoint="180,90">
        <ArcSegment Size="34,34" RotationAngle="48" IsLargeArc="True" SweepDirection="CounterClockwise" Point="89,170" />
        <LineSegment Point="180,90" />
      </PathFigure>
      <PathFigure IsClosed="False" IsFilled="True" StartPoint="90,410">
        <ArcSegment Size="29,29" RotationAngle="147" IsLargeArc="True" SweepDirection="CounterClockwise" Point="100,420" />
      </PathFigure>
      <PathFigure IsClosed="False" IsFilled="True" StartPoint="410,410">
        <ArcSegment Size="29,29" RotationAngle="29" IsLargeArc="True" SweepDirection="Clockwise" Point="400,420" />
      </PathFigure>
      <PathFigure IsClosed="True" IsFilled="True" StartPoint="240,230">
        <LineSegment Point="240,140" />
        <LineSegment Point="230,140" />
        <LineSegment Point="245,120" />
        <LineSegment Point="260,140" />
        <LineSegment Point="250,140" />
        <LineSegment Point="250,230" />
        <LineSegment Point="240,230" />
      </PathFigure>
      <PathFigure IsClosed="False" IsFilled="True" StartPoint="233,244">
        <ArcSegment Size="10,12" RotationAngle="0" IsLargeArc="True" SweepDirection="CounterClockwise" Point="258,244" />
      </PathFigure>
      <PathFigure IsClosed="False" IsFilled="True" StartPoint="233,244">
        <ArcSegment Size="10,12" RotationAngle="0" IsLargeArc="True" SweepDirection="Clockwise" Point="258,244" />
      </PathFigure>
      <PathFigure IsClosed="True" IsFilled="True" StartPoint="260,250">
        <LineSegment Point="308,293" />
        <LineSegment Point="315,285" />
        <LineSegment Point="320,310" />
        <LineSegment Point="295,308" />
        <LineSegment Point="301,300" />
        <LineSegment Point="252,257" />
        <LineSegment Point="260,250" />
      </PathFigure>
      <PathFigure IsClosed="True" IsFilled="True" StartPoint="110,345">
        <LineSegment Point="135,375" />
        <LineSegment Point="100,420" />
        <LineSegment Point="90,410" />
        <LineSegment Point="110,345" />
      </PathFigure>
      <PathFigure IsClosed="True" IsFilled="True" StartPoint="356.25,377.5">
        <LineSegment Point="381.25,350" />
        <LineSegment Point="410,410" />
        <LineSegment Point="400,420" />
        <LineSegment Point="356.25,377.5" />
      </PathFigure>
    </PathGeometry>
  </GeometryGroup>
</ps:SimpleGeometryShape>

Clock