Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ImportedProjects
SVG
Commits
780b5150
Commit
780b5150
authored
Sep 23, 2014
by
Tebjan Halm
Browse files
Merge pull request #93 from erdomke/master
Initial Filter, Svg Font, and Text on a Path Support
parents
1bc4c0f3
4200d302
Changes
107
Expand all
Show whitespace changes
Inline
Side-by-side
Source/Filter Effects/feColourMatrix/SvgColourMatrixType.cs
View file @
780b5150
...
...
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using
System.Linq
;
using
System.Text
;
namespace
Svg.Filter
_
Effects
.feColourMatrix
namespace
Svg.FilterEffects
{
public
enum
SvgColourMatrixType
{
...
...
Source/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs
View file @
780b5150
...
...
@@ -67,7 +67,10 @@ namespace Svg.FilterEffects
public
Bitmap
Apply
(
Image
inputImage
)
{
using
(
RawBitmap
src
=
new
RawBitmap
(
new
Bitmap
(
inputImage
)))
var
bitmapSrc
=
inputImage
as
Bitmap
;
if
(
bitmapSrc
==
null
)
bitmapSrc
=
new
Bitmap
(
inputImage
);
using
(
RawBitmap
src
=
new
RawBitmap
(
bitmapSrc
))
{
using
(
RawBitmap
dest
=
new
RawBitmap
(
new
Bitmap
(
inputImage
.
Width
,
inputImage
.
Height
)))
{
...
...
@@ -250,11 +253,11 @@ namespace Svg.FilterEffects
public
override
Bitmap
Process
()
public
override
void
Process
(
ImageBuffer
buffer
)
{
//Todo
return
n
ul
l
;
var
inputImage
=
buffer
[
this
.
Input
];
var
result
=
Apply
(
inputImage
);
buffer
[
this
.
Result
]
=
res
ul
t
;
}
...
...
Source/Filter Effects/feMerge/SvgMerge.cs
View file @
780b5150
...
...
@@ -5,44 +5,34 @@ using System.Text;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
System.Drawing.Imaging
;
using
System.Linq
;
namespace
Svg.FilterEffects
{
[
SvgElement
(
"feMerge"
)]
public
class
SvgMerge
:
SvgFilterPrimitive
{
public
StringCollection
MergeResults
{
get
;
private
set
;
}
public
SvgMerge
()
public
override
void
Process
(
ImageBuffer
buffer
)
{
MergeResults
=
new
StringCollection
();
}
public
override
Bitmap
Process
(
)
var
children
=
this
.
Children
.
OfType
<
SvgMergeNode
>().
ToList
();
var
inputImage
=
buffer
[
children
.
First
().
Input
];
var
result
=
new
Bitmap
(
inputImage
.
Width
,
inputImage
.
Height
);
using
(
var
g
=
Graphics
.
FromImage
(
result
)
)
{
//Todo
//Bitmap merged = new Bitmap((int)this.Owner.Width.Value, (int)this.Owner.Height.Value);
//Graphics mergedGraphics = Graphics.FromImage(merged);
//foreach (string resultId in this.MergeResults)
//{
// mergedGraphics.DrawImageUnscaled(this.Owner.Results[resultId](), new Point(0, 0));
//}
//mergedGraphics.Save();
//mergedGraphics.Dispose();
//results.Add(this.Result, () => merged);
return
null
;
foreach
(
var
child
in
children
)
{
g
.
DrawImage
(
buffer
[
child
.
Input
],
new
Rectangle
(
0
,
0
,
inputImage
.
Width
,
inputImage
.
Height
),
0
,
0
,
inputImage
.
Width
,
inputImage
.
Height
,
GraphicsUnit
.
Pixel
);
}
g
.
Flush
();
}
result
.
Save
(
@"C:\test.png"
);
buffer
[
this
.
Result
]
=
result
;
}
public
override
SvgElement
DeepCopy
()
{
throw
new
NotImplementedException
();
return
DeepCopy
<
SvgMerge
>
();
}
}
...
...
Source/Filter Effects/feMerge/SvgMergeNode.cs
View file @
780b5150
...
...
@@ -10,13 +10,13 @@ namespace Svg.FilterEffects
{
[
SvgElement
(
"feMergeNode"
)]
public
class
SvgMergeNode
:
Svg
FilterPrimitive
public
class
SvgMergeNode
:
Svg
Element
{
public
override
Bitmap
Process
()
[
SvgAttribute
(
"in"
)]
public
string
Input
{
//Todo
return
null
;
get
{
return
this
.
Attributes
.
GetAttribute
<
string
>(
"in"
);
}
set
{
this
.
Attributes
[
"in"
]
=
value
;
}
}
public
override
SvgElement
DeepCopy
()
...
...
Source/Filter Effects/feOffset/SvgOffset.cs
View file @
780b5150
using
System
;
using
System.Drawing
;
using
System.Collections.Generic
;
using
Svg.Filter_Effects.feColourMatrix
;
namespace
Svg.FilterEffects
{
...
...
@@ -28,13 +27,27 @@ namespace Svg.FilterEffects
/// Note: this is not used in calculations to bitmap - used only to allow for svg xml output
/// </summary>
[
SvgAttribute
(
"dy"
)]
public
string
Dy
{
get
;
set
;
}
public
SvgUnit
Dy
{
get
;
set
;
}
public
override
Bitmap
Process
()
public
override
void
Process
(
ImageBuffer
buffer
)
{
return
null
;
var
inputImage
=
buffer
[
this
.
Input
];
var
result
=
new
Bitmap
(
inputImage
.
Width
,
inputImage
.
Height
);
var
pts
=
new
PointF
[]
{
new
PointF
(
this
.
Dx
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Horizontal
,
null
),
this
.
Dy
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Vertical
,
null
))
};
buffer
.
Transform
.
TransformVectors
(
pts
);
using
(
var
g
=
Graphics
.
FromImage
(
result
))
{
g
.
DrawImage
(
inputImage
,
new
Rectangle
((
int
)
pts
[
0
].
X
,
(
int
)
pts
[
0
].
Y
,
inputImage
.
Width
,
inputImage
.
Height
),
0
,
0
,
inputImage
.
Width
,
inputImage
.
Height
,
GraphicsUnit
.
Pixel
);
g
.
Flush
();
}
buffer
[
this
.
Result
]
=
result
;
}
...
...
Source/Painting/EnumConverters.cs
View file @
780b5150
...
...
@@ -137,6 +137,23 @@ namespace Svg
}
}
public
sealed
class
SvgCoordinateUnitsConverter
:
EnumBaseConverter
<
SvgCoordinateUnits
>
{
public
override
object
ConvertFrom
(
ITypeDescriptorContext
context
,
CultureInfo
culture
,
object
value
)
{
if
(
value
==
null
||
value
.
ToString
()
==
""
)
return
SvgCoordinateUnits
.
Inherit
;
return
base
.
ConvertFrom
(
context
,
culture
,
value
);
}
public
override
object
ConvertTo
(
ITypeDescriptorContext
context
,
CultureInfo
culture
,
object
value
,
Type
destinationType
)
{
if
(
destinationType
==
typeof
(
string
)
&&
value
is
SvgCoordinateUnits
&&
(
SvgCoordinateUnits
)
value
==
SvgCoordinateUnits
.
Inherit
)
{
return
null
;
}
return
base
.
ConvertTo
(
context
,
culture
,
value
,
destinationType
);
}
}
public
sealed
class
SvgTextDecorationConverter
:
EnumBaseConverter
<
SvgTextDecoration
>
{
public
override
object
ConvertFrom
(
ITypeDescriptorContext
context
,
CultureInfo
culture
,
object
value
)
...
...
Source/Painting/ISvgStylable.cs
View file @
780b5150
...
...
@@ -19,6 +19,6 @@ namespace Svg
float
StrokeMiterLimit
{
get
;
set
;
}
SvgUnitCollection
StrokeDashArray
{
get
;
set
;
}
SvgUnit
StrokeDashOffset
{
get
;
set
;
}
GraphicsPath
Path
(
SvgRenderer
renderer
);
GraphicsPath
Path
(
I
SvgRenderer
renderer
);
}
}
\ No newline at end of file
Source/Painting/SvgColourServer.cs
View file @
780b5150
...
...
@@ -35,7 +35,7 @@ namespace Svg
set
{
this
.
_colour
=
value
;
}
}
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
SvgRenderer
renderer
,
float
opacity
)
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
I
SvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
//is none?
if
(
this
==
SvgPaintServer
.
None
)
return
new
SolidBrush
(
System
.
Drawing
.
Color
.
Transparent
);
...
...
Source/Painting/SvgDeferredPaintServer.cs
View file @
780b5150
...
...
@@ -2,6 +2,7 @@
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Drawing
;
namespace
Svg
{
...
...
@@ -44,10 +45,10 @@ namespace Svg
}
}
public
override
System
.
Drawing
.
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
SvgRenderer
renderer
,
float
opacity
)
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
I
SvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
EnsureServer
(
styleOwner
);
return
_concreteServer
.
GetBrush
(
styleOwner
,
renderer
,
opacity
);
return
_concreteServer
.
GetBrush
(
styleOwner
,
renderer
,
opacity
,
forStroke
);
}
public
override
SvgElement
DeepCopy
()
...
...
Source/Painting/SvgFallbackPaintServer .cs
0 → 100644
View file @
780b5150
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Drawing
;
namespace
Svg
{
/// <summary>
/// A wrapper for a paint server has a fallback if the primary server doesn't work.
/// </summary>
public
class
SvgFallbackPaintServer
:
SvgPaintServer
{
private
IEnumerable
<
SvgPaintServer
>
_fallbacks
;
private
SvgPaintServer
_primary
;
public
SvgFallbackPaintServer
()
:
base
()
{
}
public
SvgFallbackPaintServer
(
SvgPaintServer
primary
,
IEnumerable
<
SvgPaintServer
>
fallbacks
)
:
this
()
{
_fallbacks
=
fallbacks
;
_primary
=
primary
;
}
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
ISvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
try
{
_primary
.
GetCallback
=
()
=>
_fallbacks
.
FirstOrDefault
();
return
_primary
.
GetBrush
(
styleOwner
,
renderer
,
opacity
,
forStroke
);
}
finally
{
_primary
.
GetCallback
=
null
;
}
}
public
override
SvgElement
DeepCopy
()
{
return
base
.
DeepCopy
<
SvgFallbackPaintServer
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgFallbackPaintServer
;
newObj
.
_fallbacks
=
this
.
_fallbacks
;
newObj
.
_primary
=
this
.
_primary
;
return
newObj
;
}
}
}
Source/Painting/SvgGradientServer.cs
View file @
780b5150
...
...
@@ -88,7 +88,7 @@ namespace Svg
/// <summary>
/// Gets or sets another gradient fill from which to inherit the stops from.
/// </summary>
[
SvgAttribute
(
"href"
)]
[
SvgAttribute
(
"href"
,
SvgAttributeAttribute
.
XLinkNamespace
)]
public
SvgPaintServer
InheritGradient
{
get
{
return
this
.
_inheritGradient
;
}
...
...
@@ -101,17 +101,11 @@ namespace Svg
[
SvgAttribute
(
"gradientTransform"
)]
public
SvgTransformCollection
GradientTransform
{
get
{
return
(
this
.
Attributes
.
GetAttribute
<
SvgTransformCollection
>(
"gradientTransform"
));
}
set
{
this
.
Attributes
[
"gradientTransform"
]
=
value
;
}
get
{
return
(
this
.
Attributes
.
GetAttribute
<
SvgTransformCollection
>(
"gradientTransform"
));
}
set
{
this
.
Attributes
[
"gradientTransform"
]
=
value
;
}
}
pr
ivate
Matrix
EffectiveGradientTransform
pr
otected
Matrix
EffectiveGradientTransform
{
get
{
...
...
@@ -130,7 +124,7 @@ namespace Svg
/// </summary>
/// <param name="owner">The parent <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the colour blend.</param>
protected
ColorBlend
GetColorBlend
(
SvgRenderer
renderer
,
float
opacity
,
bool
radial
)
protected
ColorBlend
GetColorBlend
(
I
SvgRenderer
renderer
,
float
opacity
,
bool
radial
)
{
int
colourBlends
=
this
.
Stops
.
Count
;
bool
insertStart
=
false
;
...
...
@@ -184,9 +178,9 @@ namespace Svg
for
(
int
i
=
0
;
i
<
colourBlends
;
i
++)
{
var
currentStop
=
this
.
Stops
[
radial
?
this
.
Stops
.
Count
-
1
-
actualStops
:
actualStops
];
var
boundWidth
=
renderer
.
Boundable
().
Bounds
.
Width
;
var
boundWidth
=
renderer
.
Get
Boundable
().
Bounds
.
Width
;
mergedOpacity
=
opacity
*
currentStop
.
Opacity
;
mergedOpacity
=
opacity
*
currentStop
.
Get
Opacity
()
;
position
=
radial
?
1
-
(
currentStop
.
Offset
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
)
/
boundWidth
)
...
...
@@ -229,24 +223,6 @@ namespace Svg
}
}
protected
PointF
TransformPoint
(
PointF
originalPoint
)
{
var
newPoint
=
new
[]
{
originalPoint
};
EffectiveGradientTransform
.
TransformPoints
(
newPoint
);
return
newPoint
[
0
];
}
protected
PointF
TransformVector
(
PointF
originalVector
)
{
var
newVector
=
new
[]
{
originalVector
};
EffectiveGradientTransform
.
TransformVectors
(
newVector
);
return
newVector
[
0
];
}
protected
static
double
CalculateDistance
(
PointF
first
,
PointF
second
)
{
return
Math
.
Sqrt
(
Math
.
Pow
(
first
.
X
-
second
.
X
,
2
)
+
Math
.
Pow
(
first
.
Y
-
second
.
Y
,
2
));
...
...
Source/Painting/SvgGradientStop.cs
View file @
780b5150
...
...
@@ -13,8 +13,6 @@ namespace Svg
public
class
SvgGradientStop
:
SvgElement
{
private
SvgUnit
_offset
;
private
SvgPaintServer
_colour
;
private
float
_opacity
;
/// <summary>
/// Gets or sets the offset, i.e. where the stop begins from the beginning, of the gradient stop.
...
...
@@ -59,20 +57,31 @@ namespace Svg
/// </summary>
[
SvgAttribute
(
"stop-color"
)]
[
TypeConverter
(
typeof
(
SvgPaintServerFactory
))]
public
SvgPaintServer
Colo
u
r
public
SvgPaintServer
Stop
Color
{
get
{
return
this
.
_colour
;
}
set
{
this
.
_colour
=
value
;
}
get
{
var
direct
=
this
.
Attributes
.
GetAttribute
<
SvgPaintServer
>(
"stop-color"
,
SvgColourServer
.
NotSet
);
if
(
direct
==
SvgColourServer
.
Inherit
)
return
this
.
Attributes
[
"stop-color"
]
as
SvgPaintServer
??
SvgColourServer
.
NotSet
;
return
direct
;
}
set
{
this
.
Attributes
[
"stop-color"
]
=
value
;
}
}
/// <summary>
/// Gets or sets the opacity of the gradient stop (0-1).
/// </summary>
[
SvgAttribute
(
"stop-opacity"
)]
public
float
Opacity
public
string
Opacity
{
get
{
return
this
.
Attributes
[
"stop-opacity"
]
as
string
;
}
set
{
this
.
Attributes
[
"stop-opacity"
]
=
value
;
}
}
public
float
GetOpacity
()
{
get
{
return
this
.
_o
pacity
;
}
s
et
{
this
.
_opacity
=
value
;
}
var
opacity
=
this
.
O
pacity
;
r
et
urn
string
.
IsNullOrEmpty
(
opacity
)
?
1.0f
:
float
.
Parse
(
opacity
);
}
/// <summary>
...
...
@@ -81,8 +90,6 @@ namespace Svg
public
SvgGradientStop
()
{
this
.
_offset
=
new
SvgUnit
(
0.0f
);
this
.
_colour
=
SvgColourServer
.
NotSet
;
this
.
_opacity
=
1.0f
;
}
/// <summary>
...
...
@@ -93,13 +100,11 @@ namespace Svg
public
SvgGradientStop
(
SvgUnit
offset
,
Color
colour
)
{
this
.
_offset
=
offset
;
this
.
_colour
=
new
SvgColourServer
(
colour
);
this
.
_opacity
=
1.0f
;
}
public
Color
GetColor
(
SvgElement
parent
)
{
var
core
=
SvgDeferredPaintServer
.
TryGet
<
SvgColourServer
>(
_c
olo
u
r
,
parent
);
var
core
=
SvgDeferredPaintServer
.
TryGet
<
SvgColourServer
>(
this
.
StopC
olor
,
parent
);
if
(
core
==
null
)
throw
new
InvalidOperationException
(
"Invalid paint server for gradient stop detected."
);
return
core
.
Colour
;
}
...
...
@@ -113,9 +118,6 @@ namespace Svg
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgGradientStop
;
newObj
.
Offset
=
this
.
Offset
;
newObj
.
Colour
=
this
.
Colour
;
newObj
.
Opacity
=
this
.
Opacity
;
return
newObj
;
}
}
...
...
Source/Painting/SvgLinearGradientServer.cs
View file @
780b5150
This diff is collapsed.
Click to expand it.
Source/Painting/SvgMarker.cs
View file @
780b5150
...
...
@@ -87,11 +87,11 @@ namespace Svg
Overflow
=
SvgOverflow
.
hidden
;
}
public
override
System
.
Drawing
.
Drawing2D
.
GraphicsPath
Path
(
SvgRenderer
renderer
)
public
override
System
.
Drawing
.
Drawing2D
.
GraphicsPath
Path
(
I
SvgRenderer
renderer
)
{
var
path
=
this
.
Children
.
FirstOrDefault
(
x
=>
x
is
Svg
Path
);
var
path
=
this
.
Children
.
FirstOrDefault
(
x
=>
x
is
Svg
VisualElement
);
if
(
path
!=
null
)
return
(
path
as
Svg
Path
).
Path
(
renderer
);
return
(
path
as
Svg
VisualElement
).
Path
(
renderer
);
return
null
;
}
...
...
@@ -131,7 +131,7 @@ namespace Svg
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
Svg
Path
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
)
public
void
RenderMarker
(
I
SvgRenderer
pRenderer
,
Svg
VisualElement
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
...
...
@@ -148,7 +148,7 @@ namespace Svg
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
/// <param name="pMarkerPoint3"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
Svg
Path
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
,
PointF
pMarkerPoint3
)
public
void
RenderMarker
(
I
SvgRenderer
pRenderer
,
Svg
VisualElement
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
,
PointF
pMarkerPoint3
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
...
...
@@ -168,13 +168,14 @@ namespace Svg
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint"></param>
private
void
RenderPart2
(
float
fAngle
,
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pMarkerPoint
)
private
void
RenderPart2
(
float
fAngle
,
ISvgRenderer
pRenderer
,
SvgVisualElement
pOwner
,
PointF
pMarkerPoint
)
{
using
(
var
pRenderPen
=
CreatePen
(
pOwner
,
pRenderer
))
{
using
(
var
markerPath
=
GetClone
(
pOwner
))
{
using
(
var
transMatrix
=
new
Matrix
())
{
Pen
pRenderPen
=
CreatePen
(
pOwner
,
pRenderer
);
GraphicsPath
markerPath
=
GetClone
(
pOwner
);
Matrix
transMatrix
=
new
Matrix
();
transMatrix
.
Translate
(
pMarkerPoint
.
X
,
pMarkerPoint
.
Y
);
if
(
Orient
.
IsAuto
)
transMatrix
.
Rotate
(
fAngle
);
...
...
@@ -194,21 +195,22 @@ namespace Svg
break
;
}
markerPath
.
Transform
(
transMatrix
);
pRenderer
.
DrawPath
(
pRenderPen
,
markerPath
);
if
(
pRenderPen
!=
null
)
pRenderer
.
DrawPath
(
pRenderPen
,
markerPath
);
SvgPaintServer
pFill
=
Fill
;
SvgPaintServer
pFill
=
this
.
Children
.
First
().
Fill
;
SvgFillRule
pFillRule
=
FillRule
;
// TODO: What do we use the fill rule for?
float
fOpacity
=
FillOpacity
;
if
(
pFill
!=
null
)
{
Brush
pBrush
=
pFill
.
GetBrush
(
this
,
pRenderer
,
fOpacity
);
using
(
var
pBrush
=
pFill
.
GetBrush
(
this
,
pRenderer
,
fOpacity
))
{
pRenderer
.
FillPath
(
pBrush
,
markerPath
);
pBrush
.
Dispose
();
}
pRenderPen
.
Dispose
();
markerPath
.
Dispose
();
transMatrix
.
Dispose
();
}
}
}
}
}
/// <summary>
...
...
@@ -216,8 +218,9 @@ namespace Svg
/// </summary>
/// <param name="pStroke"></param>
/// <returns></returns>
private
Pen
CreatePen
(
Svg
Path
pPath
,
SvgRenderer
renderer
)
private
Pen
CreatePen
(
Svg
VisualElement
pPath
,
I
SvgRenderer
renderer
)
{
if
(
pPath
.
Stroke
==
null
)
return
null
;
Brush
pBrush
=
pPath
.
Stroke
.
GetBrush
(
this
,
renderer
,
Opacity
);
switch
(
MarkerUnits
)
{
...
...
@@ -231,18 +234,20 @@ namespace Svg
}
/// <summary>
/// Get a clone of the current path, scaled for the stroke with
/// Get a clone of the current path, scaled for the stroke wi
d
th
/// </summary>
/// <returns></returns>
private
GraphicsPath
GetClone
(
Svg
Path
pPath
)
private
GraphicsPath
GetClone
(
Svg
VisualElement
pPath
)
{
GraphicsPath
pRet
=
Path
(
null
).
Clone
()
as
GraphicsPath
;
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
Matrix
transMatrix
=
new
Matrix
();
using
(
var
transMatrix
=
new
Matrix
())
{
transMatrix
.
Scale
(
AdjustForViewBoxWidth
(
pPath
.
StrokeWidth
),
AdjustForViewBoxHeight
(
pPath
.
StrokeWidth
));
pRet
.
Transform
(
transMatrix
);
}
break
;
case
SvgMarkerUnits
.
userSpaceOnUse
:
break
;
...
...
@@ -258,7 +263,7 @@ namespace Svg
private
float
AdjustForViewBoxWidth
(
float
fWidth
)
{
// TODO: We know this isn't correct
return
(
fWidth
/
ViewBox
.
Width
);
return
(
ViewBox
.
Width
<=
0
?
1
:
fWidth
/
ViewBox
.
Width
);
}
/// <summary>
...
...
@@ -269,7 +274,7 @@ namespace Svg
private
float
AdjustForViewBoxHeight
(
float
fHeight
)
{
// TODO: We know this isn't correct
return
(
fHeight
/
ViewBox
.
Height
);
return
(
ViewBox
.
Height
<=
0
?
1
:
fHeight
/
ViewBox
.
Height
);
}
}
}
\ No newline at end of file
Source/Painting/SvgPaintServer.cs
View file @
780b5150
...
...
@@ -13,6 +13,8 @@ namespace Svg
[
TypeConverter
(
typeof
(
SvgPaintServerFactory
))]
public
abstract
class
SvgPaintServer
:
SvgElement
{
public
Func
<
SvgPaintServer
>
GetCallback
{
get
;
set
;
}
/// <summary>
/// An unspecified <see cref="SvgPaintServer"/>.
/// </summary>
...
...
@@ -26,10 +28,10 @@ namespace Svg
}
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="
I
SvgRenderer"/> object.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected
override
void
Render
(
SvgRenderer
renderer
)
/// <param name="renderer">The <see cref="
I
SvgRenderer"/> object to render to.</param>
protected
override
void
Render
(
I
SvgRenderer
renderer
)
{
// Never render paint servers or their children
}
...
...
@@ -39,7 +41,7 @@ namespace Svg
/// </summary>
/// <param name="styleOwner">The owner <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the brush.</param>
public
abstract
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
SvgRenderer
renderer
,
float
opacity
);
public
abstract
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
I
SvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
);
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
...
...
Source/Painting/SvgPaintServerFactory.cs
View file @
780b5150
using
System
;
using
System.ComponentModel
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Text.RegularExpressions
;
using
System.Xml
;
using
System.ComponentModel
;
using
System.Drawing
;
using
System.Globalization
;
using
System.Linq
;
namespace
Svg
{
internal
class
SvgPaintServerFactory
:
TypeConverter
{
private
static
readonly
SvgColourConverter
_colourConverter
;
private
static
readonly
Regex
_urlRefPattern
;
static
SvgPaintServerFactory
()
{
_colourConverter
=
new
SvgColourConverter
();
_urlRefPattern
=
new
Regex
(
@"url\((#[^)]+)\)"
);
}
public
static
SvgPaintServer
Create
(
string
value
,
SvgDocument
document
)
...
...
@@ -35,11 +31,18 @@ namespace Svg
{
return
new
SvgDeferredPaintServer
(
document
,
value
);
}
else
if
(
value
.
IndexOf
(
"url(#"
)
>
-
1
)
else
{
var
servers
=
new
List
<
SvgPaintServer
>();
while
(!
string
.
IsNullOrEmpty
(
value
))
{
Match
match
=
_urlRefPattern
.
Match
(
value
);
Uri
id
=
new
Uri
(
match
.
Groups
[
1
].
Value
,
UriKind
.
Relative
);
return
(
SvgPaintServer
)
document
.
IdManager
.
GetElementById
(
id
);
if
(
value
.
StartsWith
(
"url(#"
))
{
var
leftParen
=
value
.
IndexOf
(
')'
,
5
);
Uri
id
=
new
Uri
(
value
.
Substring
(
5
,
leftParen
-
5
),
UriKind
.
Relative
);
value
=
value
.
Substring
(
leftParen
+
1
).
Trim
();
servers
.
Add
((
SvgPaintServer
)
document
.
IdManager
.
GetElementById
(
id
));
}
// If referenced to to a different (linear or radial) gradient
else
if
(
document
.
IdManager
.
GetElementById
(
value
)
!=
null
&&
document
.
IdManager
.
GetElementById
(
value
).
GetType
().
BaseType
==
typeof
(
SvgGradientServer
))
...
...
@@ -48,19 +51,49 @@ namespace Svg
}
else
if
(
value
.
StartsWith
(
"#"
))
// Otherwise try and parse as colour
{
try
switch
(
CountHexDigits
(
value
,
1
))
{
case
3
:
servers
.
Add
(
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Substring
(
0
,
4
))));
value
=
value
.
Substring
(
4
).
Trim
();
break
;
case
6
:
servers
.
Add
(
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Substring
(
0
,
7
))));
value
=
value
.
Substring
(
7
).
Trim
();
break
;
default
:
return
new
SvgDeferredPaintServer
(
document
,
value
);
}
}
else
{
return
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Trim
()));
}
catch
}
if
(
servers
.
Count
>
1
)
{
return
new
Svg
Deferred
PaintServer
(
document
,
value
);
return
new
Svg
Fallback
PaintServer
(
servers
[
0
],
servers
.
Skip
(
1
)
);
}
return
servers
[
0
];
}
else
}
private
static
int
CountHexDigits
(
string
value
,
int
start
)
{
return
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Trim
()));
int
i
=
Math
.
Max
(
start
,
0
);
int
count
=
0
;
while
(
i
<
value
.
Length
&&
((
value
[
i
]
>=
'0'
&&
value
[
i
]
<=
'9'
)
||
(
value
[
i
]
>=
'a'
&&
value
[
i
]
<=
'f'
)
||
(
value
[
i
]
>=
'A'
&&
value
[
i
]
<=
'F'
)))
{
count
++;
i
++;
}
return
count
;
}
public
override
object
ConvertFrom
(
ITypeDescriptorContext
context
,
System
.
Globalization
.
CultureInfo
culture
,
object
value
)
...
...
Source/Painting/SvgPatternServer.cs
View file @
780b5150
...
...
@@ -6,6 +6,7 @@ using System.Drawing;
using
System.ComponentModel
;
using
Svg.Transforms
;
using
System.Linq
;
namespace
Svg
{
...
...
@@ -19,9 +20,10 @@ namespace Svg
private
SvgUnit
_height
;
private
SvgUnit
_x
;
private
SvgUnit
_y
;
private
SvgPaintServer
_inheritGradient
;
private
SvgViewBox
_viewBox
;
private
SvgCoordinateUnits
_patternUnits
;
private
SvgCoordinateUnits
_patternContentUnits
;
private
SvgCoordinateUnits
_patternUnits
=
SvgCoordinateUnits
.
Inherit
;
private
SvgCoordinateUnits
_patternContentUnits
=
SvgCoordinateUnits
.
Inherit
;
[
SvgAttribute
(
"overflow"
)]
public
SvgOverflow
Overflow
...
...
@@ -76,7 +78,7 @@ namespace Svg
/// <summary>
/// Gets or sets the width of the pattern.
/// </summary>
[
SvgAttribute
(
"patternUnits"
)]
[
SvgAttribute
(
"pattern
Content
Units"
)]
public
SvgCoordinateUnits
PatternContentUnits
{
get
{
return
this
.
_patternContentUnits
;
}
...
...
@@ -113,15 +115,56 @@ namespace Svg
set
{
this
.
_y
=
value
;
}
}
/// <summary>
/// Gets or sets another gradient fill from which to inherit the stops from.
/// </summary>
[
SvgAttribute
(
"href"
,
SvgAttributeAttribute
.
XLinkNamespace
)]
public
SvgPaintServer
InheritGradient
{
get
{
return
this
.
_inheritGradient
;
}
set
{
this
.
_inheritGradient
=
value
;
}
}
[
SvgAttribute
(
"patternTransform"
)]
public
SvgTransformCollection
PatternTransform
{
get
{
return
(
this
.
Attributes
.
GetAttribute
<
SvgTransformCollection
>(
"gradientTransform"
));
}
set
{
this
.
Attributes
[
"gradientTransform"
]
=
value
;
}
}
protected
Matrix
EffectivePatternTransform
{
get
{
var
transform
=
new
Matrix
();
if
(
PatternTransform
!=
null
)
{
transform
.
Multiply
(
PatternTransform
.
GetMatrix
());
}
return
transform
;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgPatternServer"/> class.
/// </summary>
public
SvgPatternServer
()
{
this
.
_x
=
new
SvgUnit
(
0.0f
);
this
.
_y
=
new
SvgUnit
(
0.0f
);
this
.
_width
=
new
SvgUnit
(
0.0f
);
this
.
_height
=
new
SvgUnit
(
0.0f
);
this
.
_x
=
SvgUnit
.
None
;
this
.
_y
=
SvgUnit
.
None
;
this
.
_width
=
SvgUnit
.
None
;
this
.
_height
=
SvgUnit
.
None
;
}
private
SvgUnit
NormalizeUnit
(
SvgUnit
orig
)
{
return
(
orig
.
Type
==
SvgUnitType
.
Percentage
&&
this
.
PatternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
new
SvgUnit
(
SvgUnitType
.
User
,
orig
.
Value
/
100
)
:
orig
);
}
/// <summary>
...
...
@@ -129,76 +172,85 @@ namespace Svg
/// </summary>
/// <param name="renderingElement">The owner <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the brush.</param>
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
SvgRenderer
renderer
,
float
opacity
)
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
ISvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
var
chain
=
new
List
<
SvgPatternServer
>();
var
curr
=
this
;
while
(
curr
!=
null
)
{
// If there aren't any children, return null
if
(
this
.
Children
.
Count
==
0
)
return
null
;
chain
.
Add
(
curr
);
curr
=
SvgDeferredPaintServer
.
TryGet
<
SvgPatternServer
>(
curr
.
_inheritGradient
,
renderingElement
);
}
// Can't render if there are no dimensions
if
(
this
.
_width
.
Value
==
0.0f
||
this
.
_height
.
Value
==
0.0f
)
return
null
;
var
childElem
=
chain
.
Where
((
p
)
=>
p
.
Children
!=
null
&&
p
.
Children
.
Count
>
0
).
FirstOrDefault
();
if
(
childElem
==
null
)
return
null
;
var
widthElem
=
chain
.
Where
((
p
)
=>
p
.
Width
!=
null
&&
p
.
Width
!=
SvgUnit
.
None
).
FirstOrDefault
();
var
heightElem
=
chain
.
Where
((
p
)
=>
p
.
Height
!=
null
&&
p
.
Height
!=
SvgUnit
.
None
).
FirstOrDefault
();
if
(
widthElem
==
null
&&
heightElem
==
null
)
return
null
;
try
{
if
(
this
.
PatternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
Boundable
(
renderingElement
);
var
viewBoxElem
=
chain
.
Where
((
p
)
=>
p
.
ViewBox
!=
null
&&
p
.
ViewBox
!=
SvgViewBox
.
Empty
).
FirstOrDefault
();
var
viewBox
=
viewBoxElem
==
null
?
SvgViewBox
.
Empty
:
viewBoxElem
.
ViewBox
;
var
xElem
=
chain
.
Where
((
p
)
=>
p
.
X
!=
null
&&
p
.
X
!=
SvgUnit
.
None
).
FirstOrDefault
();
var
yElem
=
chain
.
Where
((
p
)
=>
p
.
Y
!=
null
&&
p
.
Y
!=
SvgUnit
.
None
).
FirstOrDefault
();
var
xUnit
=
xElem
==
null
?
SvgUnit
.
Empty
:
xElem
.
X
;
var
yUnit
=
yElem
==
null
?
SvgUnit
.
Empty
:
yElem
.
Y
;
float
width
=
this
.
_width
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
);
float
height
=
this
.
_height
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
);
var
patternUnitElem
=
chain
.
Where
((
p
)
=>
p
.
PatternUnits
!=
SvgCoordinateUnits
.
Inherit
).
FirstOrDefault
();
var
patternUnits
=
(
patternUnitElem
==
null
?
SvgCoordinateUnits
.
ObjectBoundingBox
:
patternUnitElem
.
PatternUnits
);
var
patternContentUnitElem
=
chain
.
Where
((
p
)
=>
p
.
PatternContentUnits
!=
SvgCoordinateUnits
.
Inherit
).
FirstOrDefault
();
var
patternContentUnits
=
(
patternContentUnitElem
==
null
?
SvgCoordinateUnits
.
UserSpaceOnUse
:
patternContentUnitElem
.
PatternContentUnits
);
Matrix
patternMatrix
=
new
Matrix
();
// Apply a translate if needed
if
(
this
.
_x
.
Value
>
0.0f
||
this
.
_y
.
Value
>
0.0f
)
try
{
float
x
=
this
.
_x
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
HorizontalOffset
,
this
);
float
y
=
this
.
_y
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
VerticalOffset
,
this
);
if
(
patternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
SetBoundable
(
renderingElement
);
patternMatrix
.
Translate
(
x
+
-
1.0f
,
y
+
-
1.0f
);
}
else
using
(
var
patternMatrix
=
new
Matrix
())
{
patternMatrix
.
Translate
(-
1
,
-
1
);
}
var
bounds
=
renderer
.
GetBoundable
().
Bounds
;
var
xScale
=
(
patternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Width
:
1
);
var
yScale
=
(
patternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Height
:
1
);
if
(
this
.
ViewBox
.
Height
>
0
||
this
.
ViewBox
.
Width
>
0
)
{
patternMatrix
.
Scale
(
this
.
Width
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
)
/
this
.
ViewBox
.
Width
,
this
.
Height
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
)
/
this
.
ViewBox
.
Height
);
}
float
x
=
xScale
*
NormalizeUnit
(
xUnit
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
);
float
y
=
yScale
*
NormalizeUnit
(
yUnit
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
);
float
width
=
xScale
*
NormalizeUnit
(
widthElem
.
Width
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
);
float
height
=
yScale
*
NormalizeUnit
(
heightElem
.
Height
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
);
// Apply a scale if needed
patternMatrix
.
Scale
((
patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Width
:
1
)
*
(
viewBox
.
Width
>
0
?
width
/
viewBox
.
Width
:
1
),
(
patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Height
:
1
)
*
(
viewBox
.
Height
>
0
?
height
/
viewBox
.
Height
:
1
),
MatrixOrder
.
Prepend
);
Bitmap
image
=
new
Bitmap
((
int
)
width
,
(
int
)
height
);
using
(
SvgRendere
r
iRenderer
=
SvgRenderer
.
FromImage
(
image
))
using
(
va
r
iRenderer
=
SvgRenderer
.
FromImage
(
image
))
{
iRenderer
.
Boundable
((
_patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
?
new
GenericBoundable
(
0
,
0
,
width
,
height
)
:
renderer
.
Boundable
());
iRenderer
.
Set
Boundable
((
_patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
?
new
GenericBoundable
(
0
,
0
,
width
,
height
)
:
renderer
.
Get
Boundable
());
iRenderer
.
Transform
=
patternMatrix
;
iRenderer
.
CompositingQuality
=
CompositingQuality
.
HighQuality
;
iRenderer
.
SmoothingMode
=
SmoothingMode
.
AntiAlias
;
iRenderer
.
PixelOffsetMode
=
PixelOffsetMode
.
Half
;
iRenderer
.
SetClip
(
new
Region
(
new
RectangleF
(
0
,
0
,
viewBox
.
Width
>
0
?
viewBox
.
Width
:
width
,
viewBox
.
Height
>
0
?
viewBox
.
Height
:
height
)));
foreach
(
SvgElement
child
in
t
hi
s
.
Children
)
foreach
(
SvgElement
child
in
c
hi
ldElem
.
Children
)
{
child
.
RenderElement
(
iRenderer
);
}
iRenderer
.
Save
();
}
image
.
Save
(
string
.
Format
(
@"C:\test{0:D3}.png"
,
imgNumber
++));
TextureBrush
textureBrush
=
new
TextureBrush
(
image
);
var
brushTransform
=
EffectivePatternTransform
.
Clone
();
brushTransform
.
Translate
(
x
,
y
,
MatrixOrder
.
Append
);
textureBrush
.
Transform
=
brushTransform
;
return
textureBrush
;
}
}
finally
{
if
(
this
.
PatternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
PopBoundable
();
}
}
private
static
int
imgNumber
=
0
;
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgPatternServer
>();
...
...
Source/Painting/SvgRadialGradientServer.cs
View file @
780b5150
using
System
;
using
System.Diagnostics
;
using
System.Drawing
;
using
System.Collections.Generic
;
using
System.Drawing.Drawing2D
;
using
System.Linq
;
...
...
@@ -95,88 +96,207 @@ namespace Svg
Radius
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50F
);
}
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
SvgRenderer
renderer
,
float
opacity
)
private
object
_lockObj
=
new
Object
();
private
SvgUnit
NormalizeUnit
(
SvgUnit
orig
)
{
return
(
orig
.
Type
==
SvgUnitType
.
Percentage
&&
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
new
SvgUnit
(
SvgUnitType
.
User
,
orig
.
Value
/
100
)
:
orig
);
}
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
ISvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
LoadStops
(
renderingElement
);
try
{
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
Boundable
(
renderingElement
);
var
origin
=
renderer
.
Boundable
().
Location
;
var
centerPoint
=
CalculateCenterPoint
(
renderer
,
origin
);
var
focalPoint
=
CalculateFocalPoint
(
renderer
,
origin
);
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
SetBoundable
(
renderingElement
);
var
specifiedRadius
=
CalculateRadius
(
renderer
);
var
effectiveRadius
=
CalculateEffectiveRadius
(
renderingElement
,
centerPoint
,
specifiedRadius
);
// Calculate the path and transform it appropriately
var
center
=
new
PointF
(
NormalizeUnit
(
CenterX
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
),
NormalizeUnit
(
CenterY
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
));
var
focals
=
new
PointF
[]
{
new
PointF
(
NormalizeUnit
(
FocalX
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
),
NormalizeUnit
(
FocalY
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
))
};
var
specifiedRadius
=
NormalizeUnit
(
Radius
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
this
);
var
path
=
new
GraphicsPath
();
path
.
AddEllipse
(
center
.
X
-
specifiedRadius
,
center
.
Y
-
specifiedRadius
,
specifiedRadius
*
2
,
specifiedRadius
*
2
);
var
brush
=
new
PathGradientBrush
(
CreateGraphicsPath
(
origin
,
centerPoint
,
e
ffective
R
adi
us
)
)
using
(
var
transform
=
E
ffective
Gr
adi
entTransform
)
{
InterpolationColors
=
CalculateColorBlend
(
renderer
,
opacity
,
specifiedRadius
,
effectiveRadius
),
CenterPoint
=
focalPoint
};
var
bounds
=
renderer
.
GetBoundable
().
Bounds
;
transform
.
Translate
(
bounds
.
X
,
bounds
.
Y
,
MatrixOrder
.
Prepend
);
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
{
transform
.
Scale
(
bounds
.
Width
,
bounds
.
Height
,
MatrixOrder
.
Prepend
);
}
path
.
Transform
(
transform
);
transform
.
TransformPoints
(
focals
);
}
Debug
.
Assert
(
brush
.
Rectangle
.
Contains
(
renderingElement
.
Bounds
),
"Brush rectangle does not contain rendering element bounds!"
);
return
brush
;
// Calculate any required scaling
var
scaleBounds
=
RectangleF
.
Inflate
(
renderingElement
.
Bounds
,
renderingElement
.
StrokeWidth
,
renderingElement
.
StrokeWidth
);
var
scale
=
CalcScale
(
scaleBounds
,
path
);
// Not ideal, but this makes sure that the rest of the shape gets properly filled or drawn
if
(
scale
>
1.0f
&&
SpreadMethod
==
SvgGradientSpreadMethod
.
Pad
)
{
var
stop
=
Stops
.
Last
();
var
origColor
=
stop
.
GetColor
(
renderingElement
);
var
renderColor
=
System
.
Drawing
.
Color
.
FromArgb
((
int
)(
opacity
*
stop
.
GetOpacity
()
*
255
),
origColor
);
var
origClip
=
renderer
.
GetClip
();
try
{
using
(
var
solidBrush
=
new
SolidBrush
(
renderColor
))
{
var
newClip
=
origClip
.
Clone
();
newClip
.
Exclude
(
path
);
renderer
.
SetClip
(
newClip
);
var
renderPath
=
(
GraphicsPath
)
renderingElement
.
Path
(
renderer
);
if
(
forStroke
)
{
using
(
var
pen
=
new
Pen
(
solidBrush
,
renderingElement
.
StrokeWidth
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
renderingElement
)))
{
renderer
.
DrawPath
(
pen
,
renderPath
);
}
}
else
{
renderer
.
FillPath
(
solidBrush
,
renderPath
);
}
}
}
finally
{
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
PopBoundable
(
);
renderer
.
SetClip
(
origClip
);
}
}
private
PointF
CalculateCenterPoint
(
SvgRenderer
renderer
,
PointF
origin
)
// Get the color blend and any tweak to the scaling
var
blend
=
CalculateColorBlend
(
renderer
,
opacity
,
scale
,
out
scale
);
// Transform the path based on the scaling
var
gradBounds
=
path
.
GetBounds
();
var
transCenter
=
new
PointF
(
gradBounds
.
Left
+
gradBounds
.
Width
/
2
,
gradBounds
.
Top
+
gradBounds
.
Height
/
2
);
using
(
var
scaleMat
=
new
Matrix
())
{
var
deviceCenterX
=
origin
.
X
+
CenterX
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
HorizontalOffset
,
this
);
var
deviceCenterY
=
origin
.
Y
+
CenterY
.
ToDeviceV
al
u
e
(
renderer
,
UnitRenderingType
.
VerticalOffset
,
this
);
var
transformedCenterPoint
=
TransformPoint
(
new
PointF
(
deviceCenterX
,
deviceCenterY
)
);
return
transformedCenterPoint
;
scaleMat
.
Translate
(-
1
*
transCenter
.
X
,
-
1
*
transCenter
.
Y
,
MatrixOrder
.
Append
);
scaleMat
.
Sc
ale
(
scale
,
scale
,
MatrixOrder
.
Append
);
scaleMat
.
Translate
(
transCenter
.
X
,
transCenter
.
Y
,
MatrixOrder
.
Append
);
path
.
Transform
(
scaleMat
)
;
}
private
PointF
CalculateFocalPoint
(
SvgRenderer
renderer
,
PointF
origin
)
// calculate the brush
var
brush
=
new
PathGradientBrush
(
path
);
brush
.
CenterPoint
=
focals
[
0
];
brush
.
InterpolationColors
=
blend
;
return
brush
;
}
finally
{
var
deviceFocalX
=
origin
.
X
+
FocalX
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
HorizontalOffset
,
this
);
var
deviceFocalY
=
origin
.
Y
+
FocalY
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
VerticalOffset
,
this
);
var
transformedFocalPoint
=
TransformPoint
(
new
PointF
(
deviceFocalX
,
deviceFocalY
));
return
transformedFocalPoint
;
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
PopBoundable
();
}
}
private
float
CalculateRadius
(
SvgRenderer
renderer
)
/// <summary>
/// Determine how much (approximately) the path must be scaled to contain the rectangle
/// </summary>
/// <param name="bounds">Bounds that the path must contain</param>
/// <param name="path">Path of the gradient</param>
/// <returns>Scale factor</returns>
/// <remarks>
/// This method continually transforms the rectangle (fewer points) until it is contained by the path
/// and returns the result of the search. The scale factor is set to a constant 95%
/// </remarks>
private
float
CalcScale
(
RectangleF
bounds
,
GraphicsPath
path
)
{
var
points
=
new
PointF
[]
{
new
PointF
(
bounds
.
Left
,
bounds
.
Top
),
new
PointF
(
bounds
.
Right
,
bounds
.
Top
),
new
PointF
(
bounds
.
Right
,
bounds
.
Bottom
),
new
PointF
(
bounds
.
Left
,
bounds
.
Bottom
)
};
var
pathBounds
=
path
.
GetBounds
();
var
pathCenter
=
new
PointF
(
pathBounds
.
X
+
pathBounds
.
Width
/
2
,
pathBounds
.
Y
+
pathBounds
.
Height
/
2
);
using
(
var
transform
=
new
Matrix
())
{
transform
.
Translate
(-
1
*
pathCenter
.
X
,
-
1
*
pathCenter
.
Y
,
MatrixOrder
.
Append
);
transform
.
Scale
(.
95f
,
.
95f
,
MatrixOrder
.
Append
);
transform
.
Translate
(
pathCenter
.
X
,
pathCenter
.
Y
,
MatrixOrder
.
Append
);
var
boundsTest
=
RectangleF
.
Inflate
(
bounds
,
0
,
0
);
while
(!(
path
.
IsVisible
(
points
[
0
])
&&
path
.
IsVisible
(
points
[
1
])
&&
path
.
IsVisible
(
points
[
2
])
&&
path
.
IsVisible
(
points
[
3
])))
{
var
radius
=
Radius
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
this
);
var
transformRadiusVector
=
TransformVector
(
new
PointF
(
radius
,
0
));
var
transformedRadius
=
CalculateLength
(
transformRadiusVector
);
return
transformedRadius
;
transform
.
TransformPoints
(
points
);
}
}
return
bounds
.
Height
/
(
points
[
2
].
Y
-
points
[
1
].
Y
);
}
//New plan:
// scale the outer rectangle to always encompass ellipse
// cut the ellipse in half (either vertical or horizontal)
// determine the region on each side of the ellipse
private
static
IEnumerable
<
GraphicsPath
>
GetDifference
(
RectangleF
subject
,
GraphicsPath
clip
)
{
var
clipFlat
=
(
GraphicsPath
)
clip
.
Clone
();
clipFlat
.
Flatten
();
var
clipBounds
=
clipFlat
.
GetBounds
();
var
bounds
=
RectangleF
.
Union
(
subject
,
clipBounds
);
bounds
.
Inflate
(
bounds
.
Width
*
.
3f
,
bounds
.
Height
*
0.3f
);
private
float
CalculateEffectiveRadius
(
ISvgBoundable
boundable
,
PointF
centerPoint
,
float
specifiedRadius
)
var
clipMidPoint
=
new
PointF
((
clipBounds
.
Left
+
clipBounds
.
Right
)
/
2
,
(
clipBounds
.
Top
+
clipBounds
.
Bottom
)
/
2
);
var
leftPoints
=
new
List
<
PointF
>();
var
rightPoints
=
new
List
<
PointF
>();
foreach
(
var
pt
in
clipFlat
.
PathPoints
)
{
if
(
pt
.
X
<=
clipMidPoint
.
X
)
{
if
(
SpreadMethod
!=
SvgGradientSpreadMethod
.
Pad
)
leftPoints
.
Add
(
pt
);
}
else
{
return
specifiedRadius
;
rightPoints
.
Add
(
pt
);
}
}
leftPoints
.
Sort
((
p
,
q
)
=>
p
.
Y
.
CompareTo
(
q
.
Y
));
rightPoints
.
Sort
((
p
,
q
)
=>
p
.
Y
.
CompareTo
(
q
.
Y
));
var
topLeft
=
new
PointF
(
boundable
.
Bounds
.
Left
,
boundable
.
Bounds
.
Top
);
var
topRight
=
new
PointF
(
boundable
.
Bounds
.
Right
,
boundable
.
Bounds
.
Top
);
var
bottomRight
=
new
PointF
(
boundable
.
Bounds
.
Right
,
boundable
.
Bounds
.
Bottom
);
var
bottomLeft
=
new
PointF
(
boundable
.
Bounds
.
Left
,
boundable
.
Bounds
.
Bottom
);
var
point
=
new
PointF
((
leftPoints
.
Last
().
X
+
rightPoints
.
Last
().
X
)
/
2
,
(
leftPoints
.
Last
().
Y
+
rightPoints
.
Last
().
Y
)
/
2
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
point
=
new
PointF
(
point
.
X
,
bounds
.
Bottom
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
var
effectiveRadius
=
(
float
)
Math
.
Ceiling
(
Math
.
Max
(
Math
.
Max
(
CalculateDistance
(
centerPoint
,
topLeft
),
CalculateDistance
(
centerPoint
,
topRight
)
),
Math
.
Max
(
CalculateDistance
(
centerPoint
,
bottomRight
),
CalculateDistance
(
centerPoint
,
bottomLeft
)
)
)
);
leftPoints
.
Add
(
new
PointF
(
bounds
.
Left
,
bounds
.
Bottom
));
leftPoints
.
Add
(
new
PointF
(
bounds
.
Left
,
bounds
.
Top
));
rightPoints
.
Add
(
new
PointF
(
bounds
.
Right
,
bounds
.
Bottom
));
rightPoints
.
Add
(
new
PointF
(
bounds
.
Right
,
bounds
.
Top
));
point
=
new
PointF
((
leftPoints
.
First
().
X
+
rightPoints
.
First
().
X
)
/
2
,
bounds
.
Top
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
point
=
new
PointF
(
point
.
X
,
(
leftPoints
.
First
().
Y
+
rightPoints
.
First
().
Y
)
/
2
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
effectiveRadius
=
Math
.
Max
(
effectiveRadius
,
specifiedRadius
);
var
path
=
new
GraphicsPath
(
FillMode
.
Winding
);
path
.
AddPolygon
(
leftPoints
.
ToArray
());
yield
return
path
;
return
effectiveRadius
;
path
.
Reset
();
path
.
AddPolygon
(
rightPoints
.
ToArray
());
yield
return
path
;
}
private
static
GraphicsPath
CreateGraphicsPath
(
PointF
origin
,
PointF
centerPoint
,
float
effectiveRadius
)
...
...
@@ -193,22 +313,75 @@ namespace Svg
return
path
;
}
private
ColorBlend
CalculateColorBlend
(
SvgRenderer
renderer
,
float
opacity
,
float
s
pecifiedRadius
,
float
effectiveRadius
)
private
ColorBlend
CalculateColorBlend
(
I
SvgRenderer
renderer
,
float
opacity
,
float
s
cale
,
out
float
outScale
)
{
var
colorBlend
=
GetColorBlend
(
renderer
,
opacity
,
true
);
float
newScale
;
List
<
float
>
pos
;
List
<
Color
>
colors
;
if
(
specifiedRadius
>=
effectiveRadius
)
outScale
=
scale
;
if
(
scale
>
1
)
{
return
colorBlend
;
switch
(
this
.
SpreadMethod
)
{
case
SvgGradientSpreadMethod
.
Reflect
:
newScale
=
(
float
)
Math
.
Ceiling
(
scale
);
pos
=
(
from
p
in
colorBlend
.
Positions
select
1
+
(
p
-
1
)
/
newScale
).
ToList
();
colors
=
colorBlend
.
Colors
.
ToList
();
for
(
var
i
=
1
;
i
<
newScale
;
i
++)
{
if
(
i
%
2
==
1
)
{
for
(
int
j
=
1
;
j
<
colorBlend
.
Positions
.
Length
;
j
++)
{
pos
.
Insert
(
0
,
(
newScale
-
i
-
1
)
/
newScale
+
1
-
colorBlend
.
Positions
[
j
]);
colors
.
Insert
(
0
,
colorBlend
.
Colors
[
j
]);
}
}
else
{
for
(
int
j
=
0
;
j
<
colorBlend
.
Positions
.
Length
-
1
;
j
++)
{
pos
.
Insert
(
j
,
(
newScale
-
i
-
1
)
/
newScale
+
colorBlend
.
Positions
[
j
]);
colors
.
Insert
(
j
,
colorBlend
.
Colors
[
j
]);
}
}
}
for
(
var
i
=
0
;
i
<
colorBlend
.
Positions
.
Length
-
1
;
i
++)
colorBlend
.
Positions
=
pos
.
ToArray
();
colorBlend
.
Colors
=
colors
.
ToArray
();
outScale
=
newScale
;
break
;
case
SvgGradientSpreadMethod
.
Repeat
:
newScale
=
(
float
)
Math
.
Ceiling
(
scale
);
pos
=
(
from
p
in
colorBlend
.
Positions
select
p
/
newScale
).
ToList
();
colors
=
colorBlend
.
Colors
.
ToList
();
for
(
var
i
=
1
;
i
<
newScale
;
i
++)
{
colorBlend
.
Positions
[
i
]
=
1
-
(
specifiedRadius
/
effectiveRadius
)
*
(
1
-
colorBlend
.
Positions
[
i
]);
pos
.
AddRange
(
from
p
in
colorBlend
.
Positions
select
(
i
+
(
p
<=
0
?
0.001f
:
p
))
/
newScale
);
colors
.
AddRange
(
colorBlend
.
Colors
);
}
colorBlend
.
Positions
=
new
[]
{
0F
}.
Concat
(
colorBlend
.
Positions
).
ToArray
();
colorBlend
.
Colors
=
new
[]
{
colorBlend
.
Colors
.
First
()
}.
Concat
(
colorBlend
.
Colors
).
ToArray
();
colorBlend
.
Positions
=
pos
.
ToArray
();
colorBlend
.
Colors
=
colors
.
ToArray
();
outScale
=
newScale
;
break
;
default
:
outScale
=
1.0f
;
//for (var i = 0; i < colorBlend.Positions.Length - 1; i++)
//{
// colorBlend.Positions[i] = 1 - (1 - colorBlend.Positions[i]) / scale;
//}
//colorBlend.Positions = new[] { 0F }.Concat(colorBlend.Positions).ToArray();
//colorBlend.Colors = new[] { colorBlend.Colors.First() }.Concat(colorBlend.Colors).ToArray();
break
;
}
}
return
colorBlend
;
}
...
...
Source/Paths/CoordinateParser.cs
0 → 100644
View file @
780b5150
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Globalization
;
namespace
Svg
{
internal
class
CoordinateParser
{
private
enum
NumState
{
invalid
,
separator
,
prefix
,
integer
,
decPlace
,
fraction
,
exponent
,
expPrefix
,
expValue
}
private
string
_coords
;
private
int
_pos
=
0
;
private
NumState
_currState
=
NumState
.
separator
;
private
NumState
_newState
=
NumState
.
separator
;
private
int
i
=
0
;
private
bool
_parseWorked
=
true
;
public
int
Position
{
get
{
return
_pos
;
}
}
public
CoordinateParser
(
string
coords
)
{
_coords
=
coords
;
if
(
string
.
IsNullOrEmpty
(
_coords
))
_parseWorked
=
false
;
if
(
char
.
IsLetter
(
coords
[
0
]))
i
++;
}
public
bool
HasMore
{
get
{
return
_parseWorked
;
}
}
private
bool
MarkState
(
bool
state
)
{
_parseWorked
=
state
;
i
++;
return
state
;
}
public
bool
TryGetBool
(
out
bool
result
)
{
while
(
i
<
_coords
.
Length
&&
_parseWorked
)
{
switch
(
_currState
)
{
case
NumState
.
separator
:
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
if
(
_coords
[
i
]
==
'0'
)
{
result
=
false
;
_newState
=
NumState
.
separator
;
_pos
=
i
+
1
;
return
MarkState
(
true
);
}
else
if
(
_coords
[
i
]
==
'1'
)
{
result
=
true
;
_newState
=
NumState
.
separator
;
_pos
=
i
+
1
;
return
MarkState
(
true
);
}
else
{
result
=
false
;
return
MarkState
(
false
);
}
break
;
default
:
result
=
false
;
return
MarkState
(
false
);
}
i
++;
}
result
=
false
;
return
MarkState
(
false
);
}
public
bool
TryGetFloat
(
out
float
result
)
{
while
(
i
<
_coords
.
Length
&&
_parseWorked
)
{
switch
(
_currState
)
{
case
NumState
.
separator
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
integer
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
prefix
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
integer
;
}
else
if
(
_coords
[
i
]
==
'.'
)
{
_newState
=
NumState
.
decPlace
;
}
else
{
_newState
=
NumState
.
invalid
;
}
break
;
case
NumState
.
integer
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
integer
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'E'
:
case
'e'
:
_newState
=
NumState
.
exponent
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
decPlace
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
fraction
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'E'
:
case
'e'
:
_newState
=
NumState
.
exponent
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
fraction
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
fraction
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'E'
:
case
'e'
:
_newState
=
NumState
.
exponent
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
exponent
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
expValue
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
invalid
;
}
else
{
switch
(
_coords
[
i
])
{
case
'+'
:
case
'-'
:
_newState
=
NumState
.
expPrefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
expPrefix
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
expValue
;
}
else
{
_newState
=
NumState
.
invalid
;
}
break
;
case
NumState
.
expValue
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
expValue
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
}
if
(
_newState
<
_currState
)
{
result
=
float
.
Parse
(
_coords
.
Substring
(
_pos
,
i
-
_pos
),
NumberStyles
.
Float
,
CultureInfo
.
InvariantCulture
);
_pos
=
i
;
_currState
=
_newState
;
return
MarkState
(
true
);
}
else
if
(
_newState
!=
_currState
&&
_currState
==
NumState
.
separator
)
{
_pos
=
i
;
}
if
(
_newState
==
NumState
.
invalid
)
{
result
=
float
.
MinValue
;
return
MarkState
(
false
);
}
_currState
=
_newState
;
i
++;
}
if
(
_currState
==
NumState
.
separator
||
!
_parseWorked
||
_pos
>=
_coords
.
Length
)
{
result
=
float
.
MinValue
;
return
MarkState
(
false
);
}
else
{
result
=
float
.
Parse
(
_coords
.
Substring
(
_pos
,
_coords
.
Length
-
_pos
),
NumberStyles
.
Float
,
CultureInfo
.
InvariantCulture
);
_pos
=
_coords
.
Length
;
return
MarkState
(
true
);
}
}
private
static
bool
IsCoordSeparator
(
char
value
)
{
switch
(
value
)
{
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
case
','
:
return
true
;
}
return
false
;
}
}
}
Source/Paths/SvgPath.cs
View file @
780b5150
...
...
@@ -38,9 +38,9 @@ namespace Svg
/// Gets or sets the length of the path.
/// </summary>
[
SvgAttribute
(
"pathLength"
)]
public
in
t
PathLength
public
floa
t
PathLength
{
get
{
return
this
.
Attributes
.
GetAttribute
<
in
t
>(
"pathLength"
);
}
get
{
return
this
.
Attributes
.
GetAttribute
<
floa
t
>(
"pathLength"
);
}
set
{
this
.
Attributes
[
"pathLength"
]
=
value
;
}
}
...
...
@@ -81,7 +81,7 @@ namespace Svg
/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
public
override
GraphicsPath
Path
(
SvgRenderer
renderer
)
public
override
GraphicsPath
Path
(
I
SvgRenderer
renderer
)
{
if
(
this
.
_path
==
null
||
this
.
IsPathDirty
)
{
...
...
@@ -131,24 +131,13 @@ namespace Svg
}
/// <summary>
/// Renders the stroke of the <see cref="SvgVisualElement"/> to the specified <see cref="SvgRenderer"/>
/// Renders the stroke of the <see cref="SvgVisualElement"/> to the specified <see cref="
I
SvgRenderer"/>
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected
internal
override
void
RenderStroke
(
SvgRenderer
renderer
)
/// <param name="renderer">The <see cref="
I
SvgRenderer"/> object to render to.</param>
protected
internal
override
bool
RenderStroke
(
I
SvgRenderer
renderer
)
{
if
(
this
.
Stroke
!=
null
)
{
float
strokeWidth
=
this
.
StrokeWidth
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
this
);
using
(
Pen
pen
=
new
Pen
(
this
.
Stroke
.
GetBrush
(
this
,
renderer
,
this
.
StrokeOpacity
),
strokeWidth
))
{
if
(
this
.
StrokeDashArray
!=
null
&&
this
.
StrokeDashArray
.
Count
>
0
)
{
/* divide by stroke width - GDI behaviour that I don't quite understand yet.*/
pen
.
DashPattern
=
this
.
StrokeDashArray
.
ConvertAll
(
u
=>
u
.
Value
/
((
strokeWidth
<=
0
)
?
1
:
strokeWidth
)).
ToArray
();
}
var
result
=
base
.
RenderStroke
(
renderer
);
var
path
=
this
.
Path
(
renderer
);
renderer
.
DrawPath
(
pen
,
path
);
if
(
this
.
MarkerStart
!=
null
)
{
...
...
@@ -168,8 +157,8 @@ namespace Svg
SvgMarker
marker
=
this
.
OwnerDocument
.
GetElementById
<
SvgMarker
>(
this
.
MarkerEnd
.
ToString
());
marker
.
RenderMarker
(
renderer
,
this
,
path
.
PathPoints
[
path
.
PathPoints
.
Length
-
1
],
path
.
PathPoints
[
path
.
PathPoints
.
Length
-
2
],
path
.
PathPoints
[
path
.
PathPoints
.
Length
-
1
]);
}
}
}
return
result
;
}
public
override
SvgElement
DeepCopy
()
...
...
Prev
1
2
3
4
5
6
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment