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
2462bf13
Commit
2462bf13
authored
Jul 15, 2014
by
Tebjan Halm
Browse files
Merge pull request #85 from articulate/GradientTransform
Gradient Improvements
parents
e71c9d97
3987f281
Changes
12
Hide whitespace changes
Inline
Side-by-side
Source/Basic Shapes/SvgVisualElement.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Xml
;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
System.Xml.Serialization
;
using
System.ComponentModel
;
using
System.Diagnostics
;
namespace
Svg
{
/// <summary>
/// The class that all SVG elements should derive from when they are to be rendered.
/// </summary>
public
abstract
partial
class
SvgVisualElement
:
SvgElement
,
ISvgStylable
,
ISvgClipable
public
abstract
partial
class
SvgVisualElement
:
SvgElement
,
ISvgBoundable
,
ISvgStylable
,
ISvgClipable
{
private
bool
_dirty
;
private
bool
_requiresSmoothRendering
;
...
...
@@ -23,6 +17,23 @@ namespace Svg
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
public
abstract
GraphicsPath
Path
{
get
;
protected
set
;
}
PointF
ISvgBoundable
.
Location
{
get
{
return
Bounds
.
Location
;
}
}
SizeF
ISvgBoundable
.
Size
{
get
{
return
Bounds
.
Size
;
}
}
/// <summary>
/// Gets the bounds of the element.
/// </summary>
...
...
@@ -61,15 +72,15 @@ namespace Svg
set
{
this
.
Attributes
[
"clip-rule"
]
=
value
;
}
}
/// <summary>
/// Gets the associated <see cref="SvgClipPath"/> if one has been specified.
/// </summary>
[
SvgAttribute
(
"filter"
)]
public
virtual
Uri
Filter
{
get
{
return
this
.
Attributes
.
GetAttribute
<
Uri
>(
"filter"
);
}
set
{
this
.
Attributes
[
"filter"
]
=
value
;
}
}
/// <summary>
/// Gets the associated <see cref="SvgClipPath"/> if one has been specified.
/// </summary>
[
SvgAttribute
(
"filter"
)]
public
virtual
Uri
Filter
{
get
{
return
this
.
Attributes
.
GetAttribute
<
Uri
>(
"filter"
);
}
set
{
this
.
Attributes
[
"filter"
]
=
value
;
}
}
/// <summary>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
...
...
@@ -131,7 +142,7 @@ namespace Svg
{
if
(
brush
!=
null
)
{
this
.
Path
.
FillMode
=
this
.
FillRule
==
SvgFillRule
.
NonZero
?
FillMode
.
Winding
:
FillMode
.
Alternate
;
this
.
Path
.
FillMode
=
this
.
FillRule
==
SvgFillRule
.
NonZero
?
FillMode
.
Winding
:
FillMode
.
Alternate
;
renderer
.
FillPath
(
brush
,
this
.
Path
);
}
}
...
...
@@ -209,31 +220,31 @@ namespace Svg
this
.
ResetClip
(
renderer
);
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgVisualElement
;
newObj
.
ClipPath
=
this
.
ClipPath
;
newObj
.
ClipRule
=
this
.
ClipRule
;
newObj
.
Filter
=
this
.
Filter
;
newObj
.
Visible
=
this
.
Visible
;
if
(
this
.
Fill
!=
null
)
newObj
.
Fill
=
this
.
Fill
;
if
(
this
.
Stroke
!=
null
)
newObj
.
Stroke
=
this
.
Stroke
;
newObj
.
FillRule
=
this
.
FillRule
;
newObj
.
FillOpacity
=
this
.
FillOpacity
;
newObj
.
StrokeWidth
=
this
.
StrokeWidth
;
newObj
.
StrokeLineCap
=
this
.
StrokeLineCap
;
newObj
.
StrokeLineJoin
=
this
.
StrokeLineJoin
;
newObj
.
StrokeMiterLimit
=
this
.
StrokeMiterLimit
;
newObj
.
StrokeDashArray
=
this
.
StrokeDashArray
;
newObj
.
StrokeDashOffset
=
this
.
StrokeDashOffset
;
newObj
.
StrokeOpacity
=
this
.
StrokeOpacity
;
newObj
.
Opacity
=
this
.
Opacity
;
return
newObj
;
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgVisualElement
;
newObj
.
ClipPath
=
this
.
ClipPath
;
newObj
.
ClipRule
=
this
.
ClipRule
;
newObj
.
Filter
=
this
.
Filter
;
newObj
.
Visible
=
this
.
Visible
;
if
(
this
.
Fill
!=
null
)
newObj
.
Fill
=
this
.
Fill
;
if
(
this
.
Stroke
!=
null
)
newObj
.
Stroke
=
this
.
Stroke
;
newObj
.
FillRule
=
this
.
FillRule
;
newObj
.
FillOpacity
=
this
.
FillOpacity
;
newObj
.
StrokeWidth
=
this
.
StrokeWidth
;
newObj
.
StrokeLineCap
=
this
.
StrokeLineCap
;
newObj
.
StrokeLineJoin
=
this
.
StrokeLineJoin
;
newObj
.
StrokeMiterLimit
=
this
.
StrokeMiterLimit
;
newObj
.
StrokeDashArray
=
this
.
StrokeDashArray
;
newObj
.
StrokeDashOffset
=
this
.
StrokeDashOffset
;
newObj
.
StrokeOpacity
=
this
.
StrokeOpacity
;
newObj
.
Opacity
=
this
.
Opacity
;
return
newObj
;
}
}
}
\ No newline at end of file
Source/DataTypes/SvgUnit.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.ComponentModel
;
using
System.Web.UI.WebControls
;
using
System.Globalization
;
namespace
Svg
...
...
@@ -73,16 +70,16 @@ namespace Svg
/// Converts the current unit to one that can be used at render time.
/// </summary>
/// <returns>The representation of the current unit in a device value (usually pixels).</returns>
public
float
ToDeviceValue
(
ISvg
Stylable
styleOwner
)
public
float
ToDeviceValue
(
ISvg
Boundable
boundable
)
{
return
this
.
ToDeviceValue
(
styleOwner
,
false
);
return
this
.
ToDeviceValue
(
boundable
,
false
);
}
/// <summary>
/// Converts the current unit to one that can be used at render time.
/// </summary>
/// <returns>The representation of the current unit in a device value (usually pixels).</returns>
public
float
ToDeviceValue
(
ISvg
Stylable
styleOwner
,
bool
vertical
)
public
float
ToDeviceValue
(
ISvg
Boundable
boundable
,
bool
vertical
)
{
// If it's already been calculated
if
(
this
.
_deviceValue
.
HasValue
)
...
...
@@ -131,14 +128,14 @@ namespace Svg
break
;
case
SvgUnitType
.
Percentage
:
// Can't calculate if there is no style owner
if
(
styleOwner
==
null
)
if
(
boundable
==
null
)
{
_deviceValue
=
this
.
Value
;
break
;
}
// TODO : Support height percentages
System
.
Drawing
.
Rectangl
eF
size
=
styleOwner
.
Bounds
;
System
.
Drawing
.
Siz
eF
size
=
boundable
.
Bounds
.
Size
;
_deviceValue
=
(((
vertical
)
?
size
.
Height
:
size
.
Width
)
/
100
)
*
this
.
Value
;
break
;
default
:
...
...
@@ -165,43 +162,43 @@ namespace Svg
}
}
#
region
Equals
and
GetHashCode
implementation
public
override
bool
Equals
(
object
obj
)
{
if
(
obj
==
null
)
return
false
;
#
region
Equals
and
GetHashCode
implementation
public
override
bool
Equals
(
object
obj
)
{
if
(
obj
==
null
)
return
false
;
if
(!(
obj
.
GetType
()
==
typeof
(
SvgUnit
)))
return
false
;
var
unit
=
(
SvgUnit
)
obj
;
return
(
unit
.
Value
==
this
.
Value
&&
unit
.
Type
==
this
.
Type
);
}
public
bool
Equals
(
SvgUnit
other
)
{
return
this
.
_type
==
other
.
_type
&&
(
this
.
_value
==
other
.
_value
);
}
public
override
int
GetHashCode
()
{
int
hashCode
=
0
;
unchecked
{
hashCode
+=
1000000007
*
_type
.
GetHashCode
();
hashCode
+=
1000000009
*
_value
.
GetHashCode
();
hashCode
+=
1000000021
*
_isEmpty
.
GetHashCode
();
hashCode
+=
1000000033
*
_deviceValue
.
GetHashCode
();
}
return
hashCode
;
}
public
static
bool
operator
==(
SvgUnit
lhs
,
SvgUnit
rhs
)
{
return
lhs
.
Equals
(
rhs
);
}
public
static
bool
operator
!=(
SvgUnit
lhs
,
SvgUnit
rhs
)
{
return
!(
lhs
==
rhs
);
}
#
endregion
}
public
bool
Equals
(
SvgUnit
other
)
{
return
this
.
_type
==
other
.
_type
&&
(
this
.
_value
==
other
.
_value
);
}
public
override
int
GetHashCode
()
{
int
hashCode
=
0
;
unchecked
{
hashCode
+=
1000000007
*
_type
.
GetHashCode
();
hashCode
+=
1000000009
*
_value
.
GetHashCode
();
hashCode
+=
1000000021
*
_isEmpty
.
GetHashCode
();
hashCode
+=
1000000033
*
_deviceValue
.
GetHashCode
();
}
return
hashCode
;
}
public
static
bool
operator
==(
SvgUnit
lhs
,
SvgUnit
rhs
)
{
return
lhs
.
Equals
(
rhs
);
}
public
static
bool
operator
!=(
SvgUnit
lhs
,
SvgUnit
rhs
)
{
return
!(
lhs
==
rhs
);
}
#
endregion
public
override
string
ToString
()
{
...
...
Source/Document Structure/SvgFragment.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Xml
;
using
System.Drawing.Drawing2D
;
using
System.Drawing
;
using
System.
ComponentModel
;
using
System.
Drawing.Drawing2D
;
namespace
Svg
{
...
...
@@ -12,13 +8,37 @@ namespace Svg
/// An <see cref="SvgFragment"/> represents an SVG fragment that can be the root element or an embedded fragment of an SVG document.
/// </summary>
[
SvgElement
(
"svg"
)]
public
class
SvgFragment
:
SvgElement
,
ISvgViewPort
public
class
SvgFragment
:
SvgElement
,
ISvgViewPort
,
ISvgBoundable
{
/// <summary>
/// Gets the SVG namespace string.
/// </summary>
public
static
readonly
Uri
Namespace
=
new
Uri
(
"http://www.w3.org/2000/svg"
);
PointF
ISvgBoundable
.
Location
{
get
{
return
PointF
.
Empty
;
}
}
SizeF
ISvgBoundable
.
Size
{
get
{
return
GetDimensions
();
}
}
RectangleF
ISvgBoundable
.
Bounds
{
get
{
return
new
RectangleF
(((
ISvgBoundable
)
this
).
Location
,
((
ISvgBoundable
)
this
).
Size
);
}
}
private
SvgUnit
_x
;
private
SvgUnit
_y
;
...
...
@@ -28,15 +48,15 @@ namespace Svg
[
SvgAttribute
(
"x"
)]
public
SvgUnit
X
{
get
{
return
_x
;
}
set
{
if
(
_x
!=
value
)
{
_x
=
value
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"x"
,
Value
=
value
});
}
}
get
{
return
_x
;
}
set
{
if
(
_x
!=
value
)
{
_x
=
value
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"x"
,
Value
=
value
});
}
}
}
/// <summary>
...
...
@@ -45,15 +65,15 @@ namespace Svg
[
SvgAttribute
(
"y"
)]
public
SvgUnit
Y
{
get
{
return
_y
;
}
set
{
if
(
_y
!=
value
)
{
_y
=
value
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"y"
,
Value
=
value
});
}
}
get
{
return
_y
;
}
set
{
if
(
_y
!=
value
)
{
_y
=
value
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"y"
,
Value
=
value
});
}
}
}
/// <summary>
...
...
@@ -64,7 +84,7 @@ namespace Svg
public
SvgUnit
Width
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"width"
);
}
set
{
this
.
Attributes
[
"width"
]
=
value
;
}
set
{
this
.
Attributes
[
"width"
]
=
value
;
}
}
/// <summary>
...
...
@@ -75,15 +95,15 @@ namespace Svg
public
SvgUnit
Height
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"height"
);
}
set
{
this
.
Attributes
[
"height"
]
=
value
;
}
set
{
this
.
Attributes
[
"height"
]
=
value
;
}
}
[
SvgAttribute
(
"overflow"
)]
public
virtual
SvgOverflow
Overflow
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgOverflow
>(
"overflow"
);
}
set
{
this
.
Attributes
[
"overflow"
]
=
value
;
}
}
[
SvgAttribute
(
"overflow"
)]
public
virtual
SvgOverflow
Overflow
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgOverflow
>(
"overflow"
);
}
set
{
this
.
Attributes
[
"overflow"
]
=
value
;
}
}
/// <summary>
/// Gets or sets the viewport of the element.
...
...
@@ -100,11 +120,11 @@ namespace Svg
/// Gets or sets the aspect of the viewport.
/// </summary>
/// <value></value>
[
SvgAttribute
(
"preserveAspectRatio"
)]
[
SvgAttribute
(
"preserveAspectRatio"
)]
public
SvgAspectRatio
AspectRatio
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgAspectRatio
>(
"preserveAspectRatio"
);
}
set
{
this
.
Attributes
[
"preserveAspectRatio"
]
=
value
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgAspectRatio
>(
"preserveAspectRatio"
);
}
set
{
this
.
Attributes
[
"preserveAspectRatio"
]
=
value
;
}
}
/// <summary>
...
...
@@ -117,68 +137,68 @@ namespace Svg
if
(!
this
.
ViewBox
.
Equals
(
SvgViewBox
.
Empty
))
{
float
fScaleX
=
this
.
Width
.
ToDeviceValue
()
/
this
.
ViewBox
.
Width
;
float
fScaleY
=
this
.
Height
.
ToDeviceValue
()
/
this
.
ViewBox
.
Height
;
float
fMinX
=
-
this
.
ViewBox
.
MinX
;
float
fMinY
=
-
this
.
ViewBox
.
MinY
;
if
(
AspectRatio
.
Align
!=
SvgPreserveAspectRatio
.
none
)
{
if
(
AspectRatio
.
Slice
)
{
fScaleX
=
Math
.
Max
(
fScaleX
,
fScaleY
);
fScaleY
=
Math
.
Max
(
fScaleX
,
fScaleY
);
}
else
{
fScaleX
=
Math
.
Min
(
fScaleX
,
fScaleY
);
fScaleY
=
Math
.
Min
(
fScaleX
,
fScaleY
);
}
float
fViewMidX
=
(
this
.
ViewBox
.
Width
/
2
)
*
fScaleX
;
float
fViewMidY
=
(
this
.
ViewBox
.
Height
/
2
)
*
fScaleY
;
float
fMidX
=
this
.
Width
.
ToDeviceValue
()
/
2
;
float
fMidY
=
this
.
Height
.
ToDeviceValue
()
/
2
;
switch
(
AspectRatio
.
Align
)
{
case
SvgPreserveAspectRatio
.
xMinYMin
:
break
;
case
SvgPreserveAspectRatio
.
xMidYMin
:
fMinX
+=
(
fMidX
-
fViewMidX
)
/
fScaleX
;
break
;
case
SvgPreserveAspectRatio
.
xMaxYMin
:
fMinX
+=
(
this
.
Width
.
ToDeviceValue
()
/
fScaleX
)
-
this
.
ViewBox
.
Width
;
break
;
case
SvgPreserveAspectRatio
.
xMinYMid
:
fMinY
+=
(
fMidY
-
fViewMidY
)
/
fScaleY
;
break
;
case
SvgPreserveAspectRatio
.
xMidYMid
:
fMinX
+=
(
fMidX
-
fViewMidX
)
/
fScaleX
;
fMinY
+=
(
fMidY
-
fViewMidY
)
/
fScaleY
;
break
;
case
SvgPreserveAspectRatio
.
xMaxYMid
:
fMinX
+=
(
this
.
Width
.
ToDeviceValue
()
/
fScaleX
)
-
this
.
ViewBox
.
Width
;
fMinY
+=
(
fMidY
-
fViewMidY
)
/
fScaleY
;
break
;
case
SvgPreserveAspectRatio
.
xMinYMax
:
fMinY
+=
(
this
.
Height
.
ToDeviceValue
()
/
fScaleY
)
-
this
.
ViewBox
.
Height
;
break
;
case
SvgPreserveAspectRatio
.
xMidYMax
:
fMinX
+=
(
fMidX
-
fViewMidX
)
/
fScaleX
;
fMinY
+=
(
this
.
Height
.
ToDeviceValue
()
/
fScaleY
)
-
this
.
ViewBox
.
Height
;
break
;
case
SvgPreserveAspectRatio
.
xMaxYMax
:
fMinX
+=
(
this
.
Width
.
ToDeviceValue
()
/
fScaleX
)
-
this
.
ViewBox
.
Width
;
fMinY
+=
(
this
.
Height
.
ToDeviceValue
()
/
fScaleY
)
-
this
.
ViewBox
.
Height
;
break
;
default
:
break
;
}
}
renderer
.
TranslateTransform
(
_x
,
_y
);
renderer
.
TranslateTransform
(
fMinX
,
fMinY
);
renderer
.
ScaleTransform
(
fScaleX
,
fScaleY
);
float
fScaleX
=
this
.
Width
.
ToDeviceValue
(
this
,
false
)
/
this
.
ViewBox
.
Width
;
float
fScaleY
=
this
.
Height
.
ToDeviceValue
(
this
,
true
)
/
this
.
ViewBox
.
Height
;
float
fMinX
=
-
this
.
ViewBox
.
MinX
;
float
fMinY
=
-
this
.
ViewBox
.
MinY
;
if
(
AspectRatio
.
Align
!=
SvgPreserveAspectRatio
.
none
)
{
if
(
AspectRatio
.
Slice
)
{
fScaleX
=
Math
.
Max
(
fScaleX
,
fScaleY
);
fScaleY
=
Math
.
Max
(
fScaleX
,
fScaleY
);
}
else
{
fScaleX
=
Math
.
Min
(
fScaleX
,
fScaleY
);
fScaleY
=
Math
.
Min
(
fScaleX
,
fScaleY
);
}
float
fViewMidX
=
(
this
.
ViewBox
.
Width
/
2
)
*
fScaleX
;
float
fViewMidY
=
(
this
.
ViewBox
.
Height
/
2
)
*
fScaleY
;
float
fMidX
=
this
.
Width
.
ToDeviceValue
(
this
,
false
)
/
2
;
float
fMidY
=
this
.
Height
.
ToDeviceValue
(
this
,
true
)
/
2
;
switch
(
AspectRatio
.
Align
)
{
case
SvgPreserveAspectRatio
.
xMinYMin
:
break
;
case
SvgPreserveAspectRatio
.
xMidYMin
:
fMinX
+=
(
fMidX
-
fViewMidX
)
/
fScaleX
;
break
;
case
SvgPreserveAspectRatio
.
xMaxYMin
:
fMinX
+=
(
this
.
Width
.
ToDeviceValue
(
this
,
false
)
/
fScaleX
)
-
this
.
ViewBox
.
Width
;
break
;
case
SvgPreserveAspectRatio
.
xMinYMid
:
fMinY
+=
(
fMidY
-
fViewMidY
)
/
fScaleY
;
break
;
case
SvgPreserveAspectRatio
.
xMidYMid
:
fMinX
+=
(
fMidX
-
fViewMidX
)
/
fScaleX
;
fMinY
+=
(
fMidY
-
fViewMidY
)
/
fScaleY
;
break
;
case
SvgPreserveAspectRatio
.
xMaxYMid
:
fMinX
+=
(
this
.
Width
.
ToDeviceValue
(
this
,
false
)
/
fScaleX
)
-
this
.
ViewBox
.
Width
;
fMinY
+=
(
fMidY
-
fViewMidY
)
/
fScaleY
;
break
;
case
SvgPreserveAspectRatio
.
xMinYMax
:
fMinY
+=
(
this
.
Height
.
ToDeviceValue
(
this
,
true
)
/
fScaleY
)
-
this
.
ViewBox
.
Height
;
break
;
case
SvgPreserveAspectRatio
.
xMidYMax
:
fMinX
+=
(
fMidX
-
fViewMidX
)
/
fScaleX
;
fMinY
+=
(
this
.
Height
.
ToDeviceValue
(
this
,
true
)
/
fScaleY
)
-
this
.
ViewBox
.
Height
;
break
;
case
SvgPreserveAspectRatio
.
xMaxYMax
:
fMinX
+=
(
this
.
Width
.
ToDeviceValue
(
this
,
false
)
/
fScaleX
)
-
this
.
ViewBox
.
Width
;
fMinY
+=
(
this
.
Height
.
ToDeviceValue
(
this
,
true
)
/
fScaleY
)
-
this
.
ViewBox
.
Height
;
break
;
default
:
break
;
}
}
renderer
.
TranslateTransform
(
_x
,
_y
);
renderer
.
TranslateTransform
(
fMinX
,
fMinY
);
renderer
.
ScaleTransform
(
fScaleX
,
fScaleY
);
}
}
...
...
@@ -190,11 +210,11 @@ namespace Svg
{
get
{
var
path
=
new
GraphicsPath
();
var
path
=
new
GraphicsPath
();
AddPaths
(
this
,
path
);
AddPaths
(
this
,
path
);
return
path
;
return
path
;
}
}
...
...
@@ -204,10 +224,10 @@ namespace Svg
/// <value>The bounds.</value>
public
RectangleF
Bounds
{
get
{
return
this
.
Path
.
GetBounds
();
}
get
{
return
this
.
Path
.
GetBounds
();
}
}
/// <summary>
...
...
@@ -215,7 +235,7 @@ namespace Svg
/// </summary>
public
SvgFragment
()
{
_x
=
0.0f
;
_x
=
0.0f
;
_y
=
0.0f
;
this
.
Height
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
100.0f
);
this
.
Width
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
100.0f
);
...
...
@@ -223,21 +243,41 @@ namespace Svg
this
.
AspectRatio
=
new
SvgAspectRatio
(
SvgPreserveAspectRatio
.
xMidYMid
);
}
public
SizeF
GetDimensions
()
{
var
w
=
Width
.
ToDeviceValue
();
var
h
=
Height
.
ToDeviceValue
();
RectangleF
bounds
=
new
RectangleF
();
var
isWidthperc
=
Width
.
Type
==
SvgUnitType
.
Percentage
;
var
isHeightperc
=
Height
.
Type
==
SvgUnitType
.
Percentage
;
if
(
isWidthperc
||
isHeightperc
)
{
bounds
=
this
.
Bounds
;
//do just one call to the recursive bounds property
if
(
isWidthperc
)
w
=
(
bounds
.
Width
+
bounds
.
X
)
*
(
w
*
0.01f
);
if
(
isHeightperc
)
h
=
(
bounds
.
Height
+
bounds
.
Y
)
*
(
h
*
0.01f
);
}
return
new
SizeF
(
w
,
h
);
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgFragment
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgFragment
;
newObj
.
Height
=
this
.
Height
;
newObj
.
Width
=
this
.
Width
;
newObj
.
Overflow
=
this
.
Overflow
;
newObj
.
ViewBox
=
this
.
ViewBox
;
newObj
.
AspectRatio
=
this
.
AspectRatio
;
return
newObj
;
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgFragment
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgFragment
;
newObj
.
Height
=
this
.
Height
;
newObj
.
Width
=
this
.
Width
;
newObj
.
Overflow
=
this
.
Overflow
;
newObj
.
ViewBox
=
this
.
ViewBox
;
newObj
.
AspectRatio
=
this
.
AspectRatio
;
return
newObj
;
}
}
}
\ No newline at end of file
Source/Document Structure/SvgGroup.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Xml
;
using
System.Text
;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
System.Linq
;
using
Svg.Transforms
;
namespace
Svg
{
...
...
@@ -27,10 +21,10 @@ namespace Svg
{
get
{
//var path = new GraphicsPath();
//AddPaths(this, path);
//var path = new GraphicsPath();
//AddPaths(this, path);
return
GetPaths
(
this
);
return
GetPaths
(
this
);
}
protected
set
{
}
...
...
@@ -44,21 +38,29 @@ namespace Svg
{
get
{
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
{
var
r
=
new
RectangleF
();
foreach
(
var
c
in
this
.
Children
)
{
if
(
c
is
SvgVisualElement
)
{
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
// First it should check if rectangle is empty or it will return the wrong Bounds.
// This is because when the Rectangle is Empty, the Union method adds as if the first values where X=0, Y=0
if
(
r
.
IsEmpty
)
{
r
=
((
SvgVisualElement
)
c
).
Bounds
;
}
else
r
=
RectangleF
.
Union
(
r
,
((
SvgVisualElement
)
c
).
Bounds
);
{
var
childBounds
=
((
SvgVisualElement
)
c
).
Bounds
;
if
(!
childBounds
.
IsEmpty
)
{
r
=
RectangleF
.
Union
(
r
,
childBounds
);
}
}
}
}
return
r
;
}
return
r
;
}
}
...
...
@@ -78,18 +80,18 @@ namespace Svg
this
.
PopTransforms
(
renderer
);
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgGroup
>();
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgGroup
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgGroup
;
if
(
this
.
Fill
!=
null
)
newObj
.
Fill
=
this
.
Fill
.
DeepCopy
()
as
SvgPaintServer
;
return
newObj
;
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgGroup
;
if
(
this
.
Fill
!=
null
)
newObj
.
Fill
=
this
.
Fill
.
DeepCopy
()
as
SvgPaintServer
;
return
newObj
;
}
}
}
Source/Painting/ISvgBoundable.cs
0 → 100644
View file @
2462bf13
using
System.Drawing
;
namespace
Svg
{
public
interface
ISvgBoundable
{
PointF
Location
{
get
;
}
SizeF
Size
{
get
;
}
RectangleF
Bounds
{
get
;
}
}
}
\ No newline at end of file
Source/Painting/ISvgStylable.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
namespace
Svg
...
...
@@ -24,6 +20,5 @@ namespace Svg
SvgUnitCollection
StrokeDashArray
{
get
;
set
;
}
SvgUnit
StrokeDashOffset
{
get
;
set
;
}
GraphicsPath
Path
{
get
;
}
RectangleF
Bounds
{
get
;
}
}
}
\ No newline at end of file
Source/Painting/SvgGradientServer.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
Svg.Transforms
;
namespace
Svg
{
...
...
@@ -10,7 +12,7 @@ namespace Svg
public
abstract
class
SvgGradientServer
:
SvgPaintServer
{
private
SvgCoordinateUnits
_gradientUnits
;
private
SvgGradientSpreadMethod
_spreadMethod
=
SvgGradientSpreadMethod
.
Pad
;
private
SvgGradientSpreadMethod
_spreadMethod
;
private
SvgGradientServer
_inheritGradient
;
private
List
<
SvgGradientStop
>
_stops
;
...
...
@@ -20,6 +22,7 @@ namespace Svg
internal
SvgGradientServer
()
{
this
.
GradientUnits
=
SvgCoordinateUnits
.
ObjectBoundingBox
;
this
.
SpreadMethod
=
SvgGradientSpreadMethod
.
Pad
;
this
.
_stops
=
new
List
<
SvgGradientStop
>();
}
...
...
@@ -96,12 +99,39 @@ namespace Svg
}
}
[
SvgAttribute
(
"gradientTransform"
)]
public
SvgTransformCollection
GradientTransform
{
get
{
return
(
this
.
Attributes
.
GetAttribute
<
SvgTransformCollection
>(
"gradientTransform"
));
}
set
{
this
.
Attributes
[
"gradientTransform"
]
=
value
;
}
}
private
Matrix
EffectiveGradientTransform
{
get
{
var
transform
=
new
Matrix
();
if
(
GradientTransform
!=
null
)
{
transform
.
Multiply
(
GradientTransform
.
GetMatrix
());
}
return
transform
;
}
}
/// <summary>
/// Gets a <see cref="ColorBlend"/> representing the <see cref="SvgGradientServer"/>'s gradient stops.
/// </summary>
/// <param name="owner">The parent <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the colour blend.</param>
protected
ColorBlend
GetColo
u
rBlend
(
SvgVisualElement
owner
,
float
opacity
,
bool
radial
)
protected
ColorBlend
GetColorBlend
(
SvgVisualElement
owner
,
float
opacity
,
bool
radial
)
{
int
colourBlends
=
this
.
Stops
.
Count
;
bool
insertStart
=
false
;
...
...
@@ -201,16 +231,49 @@ namespace Svg
}
}
protected
ISvgBoundable
CalculateBoundable
(
SvgVisualElement
renderingElement
)
{
return
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
?
(
ISvgBoundable
)
renderingElement
:
renderingElement
.
OwnerDocument
;
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgGradientServer
;
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
));
}
protected
static
float
CalculateLength
(
PointF
vector
)
{
return
(
float
)
Math
.
Sqrt
(
Math
.
Pow
(
vector
.
X
,
2
)
+
Math
.
Pow
(
vector
.
Y
,
2
));
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgGradientServer
;
newObj
.
SpreadMethod
=
this
.
SpreadMethod
;
newObj
.
GradientUnits
=
this
.
GradientUnits
;
newObj
.
InheritGradient
=
this
.
InheritGradient
;
newObj
.
GradientUnits
=
this
.
GradientUnits
;
newObj
.
InheritGradient
=
this
.
InheritGradient
;
newObj
.
GradientTransform
=
this
.
GradientTransform
;
return
newObj
;
}
return
newObj
;
}
}
}
\ No newline at end of file
Source/Painting/SvgLinearGradientServer.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Drawing.Drawing2D
;
using
System.Diagnostics
;
using
System.Drawing
;
using
System.ComponentModel
;
using
System.Drawing.Drawing2D
;
using
System.Linq
;
namespace
Svg
{
[
SvgElement
(
"linearGradient"
)]
public
sealed
class
SvgLinearGradientServer
:
SvgGradientServer
{
private
SvgUnit
_x1
;
private
SvgUnit
_y1
;
private
SvgUnit
_x2
;
private
SvgUnit
_y2
;
[
DefaultValue
(
typeof
(
SvgUnit
),
"0"
),
SvgAttribute
(
"x1"
)]
[
SvgAttribute
(
"x1"
)]
public
SvgUnit
X1
{
get
{
return
this
.
_x1
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"x1"
);
}
set
{
this
.
_x1
=
value
;
Attributes
[
"x1"
]
=
value
;
}
}
[
DefaultValue
(
typeof
(
SvgUnit
),
"0"
),
SvgAttribute
(
"y1"
)]
[
SvgAttribute
(
"y1"
)]
public
SvgUnit
Y1
{
get
{
return
this
.
_y1
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"y1"
);
}
set
{
this
.
_y1
=
value
;
this
.
Attributes
[
"y1"
]
=
value
;
}
}
[
DefaultValue
(
typeof
(
SvgUnit
),
"0"
),
SvgAttribute
(
"x2"
)]
[
SvgAttribute
(
"x2"
)]
public
SvgUnit
X2
{
get
{
return
this
.
_x2
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"x2"
);
}
set
{
this
.
_x2
=
value
;
Attributes
[
"x2"
]
=
value
;
}
}
[
DefaultValue
(
typeof
(
SvgUnit
),
"0"
),
SvgAttribute
(
"y2"
)]
[
SvgAttribute
(
"y2"
)]
public
SvgUnit
Y2
{
get
{
return
this
.
_y2
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"y2"
);
}
set
{
this
.
_y2
=
value
;
this
.
Attributes
[
"y2"
]
=
value
;
}
}
private
bool
IsInvalid
{
get
{
// Need at least 2 colours to do the gradient fill
return
this
.
Stops
.
Count
<
2
;
}
}
public
SvgLinearGradientServer
()
{
this
.
_x1
=
new
SvgUnit
(
0.0f
);
this
.
_y1
=
new
SvgUnit
(
0.0f
);
this
.
_x2
=
new
SvgUnit
(
0.0f
);
this
.
_y2
=
new
SvgUnit
(
0.0f
);
X1
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
0F
);
Y1
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
0F
);
X2
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
100F
);
Y2
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
0F
);
}
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
float
opacity
)
{
if
(
IsInvalid
)
{
return
null
;
}
var
boundable
=
CalculateBoundable
(
renderingElement
);
var
specifiedStart
=
CalculateStart
(
boundable
);
var
specifiedEnd
=
CalculateEnd
(
boundable
);
var
effectiveStart
=
specifiedStart
;
var
effectiveEnd
=
specifiedEnd
;
if
(
NeedToExpandGradient
(
renderingElement
,
specifiedStart
,
specifiedEnd
))
{
var
expansion
=
ExpandGradient
(
renderingElement
,
specifiedStart
,
specifiedEnd
);
effectiveStart
=
expansion
.
Item1
;
effectiveEnd
=
expansion
.
Item2
;
}
return
new
LinearGradientBrush
(
effectiveStart
,
effectiveEnd
,
Color
.
Transparent
,
Color
.
Transparent
)
{
InterpolationColors
=
CalculateColorBlend
(
renderingElement
,
opacity
,
specifiedStart
,
effectiveStart
,
specifiedEnd
,
effectiveEnd
),
WrapMode
=
WrapMode
.
TileFlipX
};
}
private
PointF
CalculateStart
(
ISvgBoundable
boundable
)
{
return
TransformPoint
(
new
PointF
(
this
.
X1
.
ToDeviceValue
(
boundable
),
this
.
Y1
.
ToDeviceValue
(
boundable
,
true
)));
}
p
ublic
SvgPoint
Start
p
rivate
PointF
CalculateEnd
(
ISvgBoundable
boundable
)
{
get
{
return
new
Svg
Point
(
this
.
X
1
,
this
.
Y1
);
}
return
TransformPoint
(
new
Point
F
(
this
.
X
2
.
ToDeviceValue
(
boundable
),
this
.
Y2
.
ToDeviceValue
(
boundable
,
true
)));
}
p
ublic
SvgPoint
End
p
rivate
bool
NeedToExpandGradient
(
ISvgBoundable
boundable
,
PointF
specifiedStart
,
PointF
specified
End
)
{
get
{
return
new
SvgPoint
(
this
.
X2
,
this
.
Y2
);
}
return
SpreadMethod
==
SvgGradientSpreadMethod
.
Pad
&&
(
boundable
.
Bounds
.
Contains
(
specifiedStart
)
||
boundable
.
Bounds
.
Contains
(
specifiedEnd
));
}
p
ublic
override
Brush
GetBrush
(
SvgVisualElement
owner
,
float
opacity
)
p
rivate
Tuple
<
PointF
,
PointF
>
ExpandGradient
(
ISvgBoundable
boundable
,
PointF
specifiedStart
,
PointF
specifiedEnd
)
{
// Need at least 2 colours to do the gradient fill
if
(
this
.
Stops
.
Count
<
2
)
if
(!
NeedToExpandGradient
(
boundable
,
specifiedStart
,
specifiedEnd
))
{
return
null
;
Debug
.
Fail
(
"Unexpectedly expanding gradient when not needed!"
);
return
new
Tuple
<
PointF
,
PointF
>(
specifiedStart
,
specifiedEnd
);
}
PointF
start
;
PointF
end
;
RectangleF
bounds
=
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
?
owner
.
Bounds
:
owner
.
OwnerDocument
.
GetDimensions
();
var
specifiedLength
=
CalculateDistance
(
specifiedStart
,
specifiedEnd
);
var
specifiedUnitVector
=
new
PointF
((
specifiedEnd
.
X
-
specifiedStart
.
X
)
/
(
float
)
specifiedLength
,
(
specifiedEnd
.
Y
-
specifiedStart
.
Y
)
/
(
float
)
specifiedLength
);
var
effectiveStart
=
specifiedStart
;
var
effectiveEnd
=
specifiedEnd
;
var
elementDiagonal
=
(
float
)
CalculateDistance
(
new
PointF
(
boundable
.
Bounds
.
Left
,
boundable
.
Bounds
.
Top
),
new
PointF
(
boundable
.
Bounds
.
Right
,
boundable
.
Bounds
.
Bottom
));
var
expandedStart
=
MovePointAlongVector
(
effectiveStart
,
specifiedUnitVector
,
-
elementDiagonal
);
var
expandedEnd
=
MovePointAlongVector
(
effectiveEnd
,
specifiedUnitVector
,
elementDiagonal
);
var
intersectionPoints
=
new
LineF
(
expandedStart
.
X
,
expandedStart
.
Y
,
expandedEnd
.
X
,
expandedEnd
.
Y
).
Intersection
(
boundable
.
Bounds
);
// Have start/end points been set? If not the gradient is horizontal
if
(!
this
.
End
.
IsEmpty
())
if
(
boundable
.
Bounds
.
Contains
(
specifiedStart
))
{
// Get the points to work out an angle
if
(
this
.
Start
.
IsEmpty
())
{
start
=
bounds
.
Location
;
}
else
{
start
=
new
PointF
(
this
.
Start
.
X
.
ToDeviceValue
(
owner
),
this
.
Start
.
Y
.
ToDeviceValue
(
owner
,
true
));
}
effectiveStart
=
CalculateClosestIntersectionPoint
(
expandedStart
,
intersectionPoints
);
effectiveStart
=
MovePointAlongVector
(
effectiveStart
,
specifiedUnitVector
,
-
1
);
}
if
(
boundable
.
Bounds
.
Contains
(
specifiedEnd
))
{
effectiveEnd
=
CalculateClosestIntersectionPoint
(
effectiveEnd
,
intersectionPoints
);
effectiveEnd
=
MovePointAlongVector
(
effectiveEnd
,
specifiedUnitVector
,
1
);
}
return
new
Tuple
<
PointF
,
PointF
>(
effectiveStart
,
effectiveEnd
);
}
private
ColorBlend
CalculateColorBlend
(
SvgVisualElement
owner
,
float
opacity
,
PointF
specifiedStart
,
PointF
effectiveStart
,
PointF
specifiedEnd
,
PointF
effectiveEnd
)
{
var
colorBlend
=
GetColorBlend
(
owner
,
opacity
,
false
);
var
startDelta
=
CalculateDistance
(
specifiedStart
,
effectiveStart
);
var
endDelta
=
CalculateDistance
(
specifiedEnd
,
effectiveEnd
);
if
(!(
startDelta
>
0
)
&&
!(
endDelta
>
0
))
{
return
colorBlend
;
}
var
specifiedLength
=
CalculateDistance
(
specifiedStart
,
specifiedEnd
);
var
specifiedUnitVector
=
new
PointF
((
specifiedEnd
.
X
-
specifiedStart
.
X
)
/
(
float
)
specifiedLength
,
(
specifiedEnd
.
Y
-
specifiedStart
.
Y
)
/
(
float
)
specifiedLength
);
var
effectiveLength
=
CalculateDistance
(
effectiveStart
,
effectiveEnd
);
for
(
var
i
=
0
;
i
<
colorBlend
.
Positions
.
Length
;
i
++)
{
var
originalPoint
=
MovePointAlongVector
(
specifiedStart
,
specifiedUnitVector
,
(
float
)
specifiedLength
*
colorBlend
.
Positions
[
i
]);
float
x
=
(
this
.
End
.
X
.
IsEmpty
)
?
start
.
X
:
this
.
End
.
X
.
ToDeviceValue
(
owner
);
end
=
new
PointF
(
x
,
this
.
End
.
Y
.
ToDeviceValue
(
owner
,
true
));
var
distanceFromEffectiveStart
=
CalculateDistance
(
effectiveStart
,
originalPoint
);
colorBlend
.
Positions
[
i
]
=
(
float
)
Math
.
Max
(
0F
,
Math
.
Min
((
distanceFromEffectiveStart
/
effectiveLength
),
1.0F
));
}
if
(
startDelta
>
0
)
{
colorBlend
.
Positions
=
new
[]
{
0F
}.
Concat
(
colorBlend
.
Positions
).
ToArray
();
colorBlend
.
Colors
=
new
[]
{
colorBlend
.
Colors
.
First
()
}.
Concat
(
colorBlend
.
Colors
).
ToArray
();
}
else
if
(
endDelta
>
0
)
{
// Default: horizontal
start
=
bounds
.
Location
;
end
=
new
PointF
(
bounds
.
Right
,
bounds
.
Top
);
colorBlend
.
Positions
=
colorBlend
.
Positions
.
Concat
(
new
[]
{
1F
}).
ToArray
();
colorBlend
.
Colors
=
colorBlend
.
Colors
.
Concat
(
new
[]
{
colorBlend
.
Colors
.
Last
()
}).
ToArray
();
}
LinearGradientBrush
gradient
=
new
LinearGradientBrush
(
start
,
end
,
Color
.
Transparent
,
Color
.
Transparent
);
gradient
.
InterpolationColors
=
base
.
GetColourBlend
(
owner
,
opacity
,
false
);
return
colorBlend
;
}
private
static
PointF
CalculateClosestIntersectionPoint
(
PointF
sourcePoint
,
IList
<
PointF
>
targetPoints
)
{
Debug
.
Assert
(
targetPoints
.
Count
==
2
,
"Unexpected number of intersection points!"
);
return
CalculateDistance
(
sourcePoint
,
targetPoints
[
0
])
<
CalculateDistance
(
sourcePoint
,
targetPoints
[
1
])
?
targetPoints
[
0
]
:
targetPoints
[
1
];
}
private
static
PointF
MovePointAlongVector
(
PointF
start
,
PointF
unitVector
,
float
distance
)
{
return
start
+
new
SizeF
(
unitVector
.
X
*
distance
,
unitVector
.
Y
*
distance
);
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgLinearGradientServer
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgLinearGradientServer
;
newObj
.
X1
=
this
.
X1
;
newObj
.
Y1
=
this
.
Y1
;
newObj
.
X2
=
this
.
X2
;
newObj
.
Y2
=
this
.
Y2
;
return
newObj
;
// Needed to fix an issue where the gradient was being wrapped when though it had the correct bounds
gradient
.
WrapMode
=
WrapMode
.
TileFlipX
;
return
gradient
;
}
private
sealed
class
LineF
{
private
float
X1
{
get
;
set
;
}
private
float
Y1
{
get
;
set
;
}
private
float
X2
{
get
;
set
;
}
private
float
Y2
{
get
;
set
;
}
public
LineF
(
float
x1
,
float
y1
,
float
x2
,
float
y2
)
{
X1
=
x1
;
Y1
=
y1
;
X2
=
x2
;
Y2
=
y2
;
}
public
List
<
PointF
>
Intersection
(
RectangleF
rectangle
)
{
var
result
=
new
List
<
PointF
>();
AddIfIntersect
(
this
,
new
LineF
(
rectangle
.
X
,
rectangle
.
Y
,
rectangle
.
Right
,
rectangle
.
Y
),
result
);
AddIfIntersect
(
this
,
new
LineF
(
rectangle
.
Right
,
rectangle
.
Y
,
rectangle
.
Right
,
rectangle
.
Bottom
),
result
);
AddIfIntersect
(
this
,
new
LineF
(
rectangle
.
Right
,
rectangle
.
Bottom
,
rectangle
.
X
,
rectangle
.
Bottom
),
result
);
AddIfIntersect
(
this
,
new
LineF
(
rectangle
.
X
,
rectangle
.
Bottom
,
rectangle
.
X
,
rectangle
.
Y
),
result
);
return
result
;
}
private
PointF
?
Intersection
(
LineF
other
)
{
var
a1
=
Y2
-
Y1
;
var
b1
=
X1
-
X2
;
var
c1
=
X2
*
Y1
-
X1
*
Y2
;
var
r3
=
a1
*
other
.
X1
+
b1
*
other
.
Y1
+
c1
;
var
r4
=
a1
*
other
.
X2
+
b1
*
other
.
Y2
+
c1
;
if
(
r3
!=
0
&&
r4
!=
0
&&
Math
.
Sign
(
r3
)
==
Math
.
Sign
(
r4
))
{
return
null
;
}
var
a2
=
other
.
Y2
-
other
.
Y1
;
var
b2
=
other
.
X1
-
other
.
X2
;
var
c2
=
other
.
X2
*
other
.
Y1
-
other
.
X1
*
other
.
Y2
;
var
r1
=
a2
*
X1
+
b2
*
Y1
+
c2
;
var
r2
=
a2
*
X2
+
b2
*
Y2
+
c2
;
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgLinearGradientServer
>();
}
if
(
r1
!=
0
&&
r2
!=
0
&&
Math
.
Sign
(
r1
)
==
Math
.
Sign
(
r2
))
{
return
(
null
);
}
var
denom
=
a1
*
b2
-
a2
*
b1
;
if
(
denom
==
0
)
{
return
null
;
}
var
offset
=
denom
<
0
?
-
denom
/
2
:
denom
/
2
;
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgLinearGradientServer
;
newObj
.
X1
=
this
.
X1
;
newObj
.
Y1
=
this
.
Y1
;
newObj
.
X2
=
this
.
X2
;
newObj
.
Y2
=
this
.
Y2
;
return
newObj
;
var
num
=
b1
*
c2
-
b2
*
c1
;
var
x
=
(
num
<
0
?
num
-
offset
:
num
+
offset
)
/
denom
;
}
num
=
a2
*
c1
-
a1
*
c2
;
var
y
=
(
num
<
0
?
num
-
offset
:
num
+
offset
)
/
denom
;
return
new
PointF
(
x
,
y
);
}
private
static
void
AddIfIntersect
(
LineF
first
,
LineF
second
,
ICollection
<
PointF
>
result
)
{
var
intersection
=
first
.
Intersection
(
second
);
if
(
intersection
!=
null
)
{
result
.
Add
(
intersection
.
Value
);
}
}
}
}
}
\ No newline at end of file
Source/Painting/SvgMarker.cs
View file @
2462bf13
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Web
;
using
System.Xml
;
using
System.Xml.Serialization
;
using
System.Drawing.Drawing2D
;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
System.Linq
;
using
Svg.DataTypes
;
namespace
Svg
...
...
@@ -14,7 +9,7 @@ namespace Svg
[
SvgElement
(
"marker"
)]
public
class
SvgMarker
:
SvgVisualElement
,
ISvgViewPort
{
private
SvgOrient
_svgOrient
=
new
SvgOrient
();
private
SvgOrient
_svgOrient
=
new
SvgOrient
();
[
SvgAttribute
(
"refX"
)]
public
virtual
SvgUnit
RefX
...
...
@@ -31,68 +26,75 @@ namespace Svg
}
[
SvgAttribute
(
"orient"
)]
public
virtual
SvgOrient
Orient
{
get
{
return
_svgOrient
;
}
set
{
_svgOrient
=
value
;
}
}
[
SvgAttribute
(
"overflow"
)]
public
virtual
SvgOverflow
Overflow
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgOverflow
>(
"overflow"
);
}
set
{
this
.
Attributes
[
"overflow"
]
=
value
;
}
}
[
SvgAttribute
(
"viewBox"
)]
public
virtual
SvgViewBox
ViewBox
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgViewBox
>(
"viewBox"
);
}
set
{
this
.
Attributes
[
"viewBox"
]
=
value
;
}
}
[
SvgAttribute
(
"preserveAspectRatio"
)]
public
virtual
SvgAspectRatio
AspectRatio
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgAspectRatio
>(
"preserveAspectRatio"
);
}
set
{
this
.
Attributes
[
"preserveAspectRatio"
]
=
value
;
}
}
[
SvgAttribute
(
"markerWidth"
)]
public
virtual
SvgUnit
MarkerWidth
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"markerWidth"
);
}
set
{
this
.
Attributes
[
"markerWidth"
]
=
value
;
}
}
[
SvgAttribute
(
"markerHeight"
)]
public
virtual
SvgUnit
MarkerHeight
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"markerHeight"
);
}
set
{
this
.
Attributes
[
"markerHeight"
]
=
value
;
}
}
public
SvgMarker
()
{
MarkerUnits
=
SvgMarkerUnits
.
strokeWidth
;
MarkerHeight
=
3
;
MarkerWidth
=
3
;
Overflow
=
SvgOverflow
.
hidden
;
}
public
override
System
.
Drawing
.
Drawing2D
.
GraphicsPath
Path
[
SvgAttribute
(
"orient"
)]
public
virtual
SvgOrient
Orient
{
get
{
return
_svgOrient
;
}
set
{
_svgOrient
=
value
;
}
}
[
SvgAttribute
(
"overflow"
)]
public
virtual
SvgOverflow
Overflow
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgOverflow
>(
"overflow"
);
}
set
{
this
.
Attributes
[
"overflow"
]
=
value
;
}
}
[
SvgAttribute
(
"viewBox"
)]
public
virtual
SvgViewBox
ViewBox
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgViewBox
>(
"viewBox"
);
}
set
{
this
.
Attributes
[
"viewBox"
]
=
value
;
}
}
[
SvgAttribute
(
"preserveAspectRatio"
)]
public
virtual
SvgAspectRatio
AspectRatio
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgAspectRatio
>(
"preserveAspectRatio"
);
}
set
{
this
.
Attributes
[
"preserveAspectRatio"
]
=
value
;
}
}
[
SvgAttribute
(
"markerWidth"
)]
public
virtual
SvgUnit
MarkerWidth
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"markerWidth"
);
}
set
{
this
.
Attributes
[
"markerWidth"
]
=
value
;
}
}
[
SvgAttribute
(
"markerHeight"
)]
public
virtual
SvgUnit
MarkerHeight
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"markerHeight"
);
}
set
{
this
.
Attributes
[
"markerHeight"
]
=
value
;
}
}
[
SvgAttribute
(
"markerUnits"
)]
public
virtual
SvgMarkerUnits
MarkerUnits
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgMarkerUnits
>(
"markerUnits"
);
}
set
{
this
.
Attributes
[
"markerUnits"
]
=
value
;
}
}
public
SvgMarker
()
{
MarkerUnits
=
SvgMarkerUnits
.
strokeWidth
;
MarkerHeight
=
3
;
MarkerWidth
=
3
;
Overflow
=
SvgOverflow
.
hidden
;
}
public
override
System
.
Drawing
.
Drawing2D
.
GraphicsPath
Path
{
get
{
var
path
=
this
.
Children
.
FirstOrDefault
(
x
=>
x
is
SvgPath
);
if
(
path
!=
null
)
return
(
path
as
SvgPath
).
Path
;
return
null
;
var
path
=
this
.
Children
.
FirstOrDefault
(
x
=>
x
is
SvgPath
);
if
(
path
!=
null
)
return
(
path
as
SvgPath
).
Path
;
return
null
;
}
protected
set
{
...
...
@@ -104,172 +106,172 @@ namespace Svg
{
get
{
var
path
=
this
.
Path
;
if
(
path
!=
null
)
return
path
.
GetBounds
();
return
new
System
.
Drawing
.
RectangleF
();
var
path
=
this
.
Path
;
if
(
path
!=
null
)
return
path
.
GetBounds
();
return
new
System
.
Drawing
.
RectangleF
();
}
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgMarker
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgMarker
;
newObj
.
RefX
=
this
.
RefX
;
newObj
.
RefY
=
this
.
RefY
;
newObj
.
Orient
=
this
.
Orient
;
newObj
.
ViewBox
=
this
.
ViewBox
;
newObj
.
Overflow
=
this
.
Overflow
;
newObj
.
AspectRatio
=
this
.
AspectRatio
;
return
newObj
;
}
/// <summary>
/// Render this marker using the slope of the given line segment
/// </summary>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
float
fAngle1
=
(
float
)(
Math
.
Atan2
(
yDiff
,
xDiff
)
*
180.0
/
Math
.
PI
);
RenderPart2
(
fAngle1
,
pRenderer
,
pOwner
,
pRefPoint
);
}
/// <summary>
/// Render this marker using the average of the slopes of the two given line segments
/// </summary>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
/// <param name="pMarkerPoint3"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
,
PointF
pMarkerPoint3
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
float
fAngle1
=
(
float
)(
Math
.
Atan2
(
yDiff
,
xDiff
)
*
180.0
/
Math
.
PI
);
xDiff
=
pMarkerPoint3
.
X
-
pMarkerPoint2
.
X
;
yDiff
=
pMarkerPoint3
.
Y
-
pMarkerPoint2
.
Y
;
float
fAngle2
=
(
float
)(
Math
.
Atan2
(
yDiff
,
xDiff
)
*
180.0
/
Math
.
PI
);
RenderPart2
((
fAngle1
+
fAngle2
)
/
2
,
pRenderer
,
pOwner
,
pRefPoint
);
}
/// <summary>
/// Common code for rendering a marker once the orientation angle has been calculated
/// </summary>
/// <param name="fAngle"></param>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint"></param>
private
void
RenderPart2
(
float
fAngle
,
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pMarkerPoint
)
{
Pen
pRenderPen
=
CreatePen
(
pOwner
);
GraphicsPath
markerPath
=
GetClone
(
pOwner
);
Matrix
transMatrix
=
new
Matrix
();
transMatrix
.
Translate
(
pMarkerPoint
.
X
,
pMarkerPoint
.
Y
);
if
(
Orient
.
IsAuto
)
transMatrix
.
Rotate
(
fAngle
);
else
transMatrix
.
Rotate
(
Orient
.
Angle
);
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
transMatrix
.
Translate
(
AdjustForViewBoxWidth
(-
RefX
*
pOwner
.
StrokeWidth
),
AdjustForViewBoxHeight
(-
RefY
*
pOwner
.
StrokeWidth
));
break
;
case
SvgMarkerUnits
.
userSpaceOnUse
:
transMatrix
.
Translate
(-
RefX
,
-
RefY
);
break
;
}
markerPath
.
Transform
(
transMatrix
);
pRenderer
.
DrawPath
(
pRenderPen
,
markerPath
);
SvgPaintServer
pFill
=
Fill
;
SvgFillRule
pFillRule
=
FillRule
;
// TODO: What do we use the fill rule for?
float
fOpacity
=
FillOpacity
;
if
(
pFill
!=
null
)
{
Brush
pBrush
=
pFill
.
GetBrush
(
this
,
fOpacity
);
pRenderer
.
FillPath
(
pBrush
,
markerPath
);
pBrush
.
Dispose
();
}
pRenderPen
.
Dispose
();
markerPath
.
Dispose
();
transMatrix
.
Dispose
();
}
/// <summary>
/// Create a pen that can be used to render this marker
/// </summary>
/// <param name="pStroke"></param>
/// <returns></returns>
private
Pen
CreatePen
(
SvgPath
pPath
)
{
Brush
pBrush
=
pPath
.
Stroke
.
GetBrush
(
this
,
Opacity
);
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
return
(
new
Pen
(
pBrush
,
StrokeWidth
*
pPath
.
StrokeWidth
));
case
SvgMarkerUnits
.
userSpaceOnUse
:
return
(
new
Pen
(
pBrush
,
StrokeWidth
));
}
return
(
new
Pen
(
pBrush
,
StrokeWidth
));
}
/// <summary>
/// Get a clone of the current path, scaled for the stroke with
/// </summary>
/// <returns></returns>
private
GraphicsPath
GetClone
(
SvgPath
pPath
)
{
GraphicsPath
pRet
=
Path
.
Clone
()
as
GraphicsPath
;
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
Matrix
transMatrix
=
new
Matrix
();
transMatrix
.
Scale
(
AdjustForViewBoxWidth
(
pPath
.
StrokeWidth
),
AdjustForViewBoxHeight
(
pPath
.
StrokeWidth
));
pRet
.
Transform
(
transMatrix
);
break
;
case
SvgMarkerUnits
.
userSpaceOnUse
:
break
;
}
return
(
pRet
);
}
/// <summary>
/// Adjust the given value to account for the width of the viewbox in the viewport
/// </summary>
/// <param name="fWidth"></param>
/// <returns></returns>
private
float
AdjustForViewBoxWidth
(
float
fWidth
)
{
// TODO: We know this isn't correct
return
(
fWidth
/
ViewBox
.
Width
);
}
/// <summary>
/// Adjust the given value to account for the height of the viewbox in the viewport
/// </summary>
/// <param name="fWidth"></param>
/// <returns></returns>
private
float
AdjustForViewBoxHeight
(
float
fHeight
)
{
// TODO: We know this isn't correct
return
(
fHeight
/
ViewBox
.
Height
);
}
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgMarker
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgMarker
;
newObj
.
RefX
=
this
.
RefX
;
newObj
.
RefY
=
this
.
RefY
;
newObj
.
Orient
=
this
.
Orient
;
newObj
.
ViewBox
=
this
.
ViewBox
;
newObj
.
Overflow
=
this
.
Overflow
;
newObj
.
AspectRatio
=
this
.
AspectRatio
;
return
newObj
;
}
/// <summary>
/// Render this marker using the slope of the given line segment
/// </summary>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
float
fAngle1
=
(
float
)(
Math
.
Atan2
(
yDiff
,
xDiff
)
*
180.0
/
Math
.
PI
);
RenderPart2
(
fAngle1
,
pRenderer
,
pOwner
,
pRefPoint
);
}
/// <summary>
/// Render this marker using the average of the slopes of the two given line segments
/// </summary>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
/// <param name="pMarkerPoint3"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
,
PointF
pMarkerPoint3
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
float
fAngle1
=
(
float
)(
Math
.
Atan2
(
yDiff
,
xDiff
)
*
180.0
/
Math
.
PI
);
xDiff
=
pMarkerPoint3
.
X
-
pMarkerPoint2
.
X
;
yDiff
=
pMarkerPoint3
.
Y
-
pMarkerPoint2
.
Y
;
float
fAngle2
=
(
float
)(
Math
.
Atan2
(
yDiff
,
xDiff
)
*
180.0
/
Math
.
PI
);
RenderPart2
((
fAngle1
+
fAngle2
)
/
2
,
pRenderer
,
pOwner
,
pRefPoint
);
}
/// <summary>
/// Common code for rendering a marker once the orientation angle has been calculated
/// </summary>
/// <param name="fAngle"></param>
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint"></param>
private
void
RenderPart2
(
float
fAngle
,
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pMarkerPoint
)
{
Pen
pRenderPen
=
CreatePen
(
pOwner
);
GraphicsPath
markerPath
=
GetClone
(
pOwner
);
Matrix
transMatrix
=
new
Matrix
();
transMatrix
.
Translate
(
pMarkerPoint
.
X
,
pMarkerPoint
.
Y
);
if
(
Orient
.
IsAuto
)
transMatrix
.
Rotate
(
fAngle
);
else
transMatrix
.
Rotate
(
Orient
.
Angle
);
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
transMatrix
.
Translate
(
AdjustForViewBoxWidth
(-
RefX
*
pOwner
.
StrokeWidth
),
AdjustForViewBoxHeight
(-
RefY
*
pOwner
.
StrokeWidth
));
break
;
case
SvgMarkerUnits
.
userSpaceOnUse
:
transMatrix
.
Translate
(-
RefX
,
-
RefY
);
break
;
}
markerPath
.
Transform
(
transMatrix
);
pRenderer
.
DrawPath
(
pRenderPen
,
markerPath
);
SvgPaintServer
pFill
=
Fill
;
SvgFillRule
pFillRule
=
FillRule
;
// TODO: What do we use the fill rule for?
float
fOpacity
=
FillOpacity
;
if
(
pFill
!=
null
)
{
Brush
pBrush
=
pFill
.
GetBrush
(
this
,
fOpacity
);
pRenderer
.
FillPath
(
pBrush
,
markerPath
);
pBrush
.
Dispose
();
}
pRenderPen
.
Dispose
();
markerPath
.
Dispose
();
transMatrix
.
Dispose
();
}
/// <summary>
/// Create a pen that can be used to render this marker
/// </summary>
/// <param name="pStroke"></param>
/// <returns></returns>
private
Pen
CreatePen
(
SvgPath
pPath
)
{
Brush
pBrush
=
pPath
.
Stroke
.
GetBrush
(
this
,
Opacity
);
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
return
(
new
Pen
(
pBrush
,
StrokeWidth
*
pPath
.
StrokeWidth
));
case
SvgMarkerUnits
.
userSpaceOnUse
:
return
(
new
Pen
(
pBrush
,
StrokeWidth
));
}
return
(
new
Pen
(
pBrush
,
StrokeWidth
));
}
/// <summary>
/// Get a clone of the current path, scaled for the stroke with
/// </summary>
/// <returns></returns>
private
GraphicsPath
GetClone
(
SvgPath
pPath
)
{
GraphicsPath
pRet
=
Path
.
Clone
()
as
GraphicsPath
;
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
Matrix
transMatrix
=
new
Matrix
();
transMatrix
.
Scale
(
AdjustForViewBoxWidth
(
pPath
.
StrokeWidth
),
AdjustForViewBoxHeight
(
pPath
.
StrokeWidth
));
pRet
.
Transform
(
transMatrix
);
break
;
case
SvgMarkerUnits
.
userSpaceOnUse
:
break
;
}
return
(
pRet
);
}
/// <summary>
/// Adjust the given value to account for the width of the viewbox in the viewport
/// </summary>
/// <param name="fWidth"></param>
/// <returns></returns>
private
float
AdjustForViewBoxWidth
(
float
fWidth
)
{
// TODO: We know this isn't correct
return
(
fWidth
/
ViewBox
.
Width
);
}
/// <summary>
/// Adjust the given value to account for the height of the viewbox in the viewport
/// </summary>
/// <param name="fWidth"></param>
/// <returns></returns>
private
float
AdjustForViewBoxHeight
(
float
fHeight
)
{
// TODO: We know this isn't correct
return
(
fHeight
/
ViewBox
.
Height
);
}
}
}
\ No newline at end of file
Source/Painting/SvgRadialGradientServer.cs
View file @
2462bf13
using
System
;
using
System.Diagnostics
;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
System.Linq
;
namespace
Svg
{
...
...
@@ -9,22 +12,40 @@ namespace Svg
[
SvgAttribute
(
"cx"
)]
public
SvgUnit
CenterX
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"cx"
);
}
set
{
this
.
Attributes
[
"cx"
]
=
value
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"cx"
);
}
set
{
this
.
Attributes
[
"cx"
]
=
value
;
}
}
[
SvgAttribute
(
"cy"
)]
public
SvgUnit
CenterY
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"cy"
);
}
set
{
this
.
Attributes
[
"cy"
]
=
value
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"cy"
);
}
set
{
this
.
Attributes
[
"cy"
]
=
value
;
}
}
[
SvgAttribute
(
"r"
)]
public
SvgUnit
Radius
{
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"r"
);
}
set
{
this
.
Attributes
[
"r"
]
=
value
;
}
get
{
return
this
.
Attributes
.
GetAttribute
<
SvgUnit
>(
"r"
);
}
set
{
this
.
Attributes
[
"r"
]
=
value
;
}
}
[
SvgAttribute
(
"fx"
)]
...
...
@@ -41,8 +62,10 @@ namespace Svg
return
value
;
}
set
{
this
.
Attributes
[
"fx"
]
=
value
;
}
set
{
this
.
Attributes
[
"fx"
]
=
value
;
}
}
[
SvgAttribute
(
"fy"
)]
...
...
@@ -59,72 +82,150 @@ namespace Svg
return
value
;
}
set
{
this
.
Attributes
[
"fy"
]
=
value
;
}
set
{
this
.
Attributes
[
"fy"
]
=
value
;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgRadialGradientServer"/> class.
/// </summary>
public
SvgRadialGradientServer
()
{
//Apply default values of 50% to cX,cY and r
CenterX
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50
);
CenterY
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50
);
Radius
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50
);
CenterX
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50F
);
CenterY
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50F
);
Radius
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50F
);
}
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
float
opacity
)
{
float
radius
=
this
.
Radius
.
ToDeviceValue
(
renderingElement
);
var
origin
=
CalculateOrigin
(
renderingElement
);
var
centerPoint
=
CalculateCenterPoint
(
renderingElement
,
origin
);
var
focalPoint
=
CalculateFocalPoint
(
renderingElement
,
origin
);
var
specifiedRadius
=
CalculateRadius
(
renderingElement
);
var
effectiveRadius
=
CalculateEffectiveRadius
(
renderingElement
,
centerPoint
,
specifiedRadius
);
if
(
radius
<=
0
)
var
brush
=
new
PathGradientBrush
(
CreateGraphicsPath
(
origin
,
centerPoint
,
effectiveRadius
)
)
{
return
null
;
InterpolationColors
=
CalculateColorBlend
(
renderingElement
,
opacity
,
specifiedRadius
,
effectiveRadius
),
CenterPoint
=
focalPoint
};
Debug
.
Assert
(
brush
.
Rectangle
.
Contains
(
renderingElement
.
Bounds
),
"Brush rectangle does not contain rendering element bounds!"
);
return
brush
;
}
private
PointF
CalculateOrigin
(
SvgVisualElement
renderingElement
)
{
return
CalculateBoundable
(
renderingElement
).
Location
;
}
private
PointF
CalculateCenterPoint
(
ISvgBoundable
boundable
,
PointF
origin
)
{
var
deviceCenterX
=
origin
.
X
+
CenterX
.
ToDeviceValue
(
boundable
);
var
deviceCenterY
=
origin
.
Y
+
CenterY
.
ToDeviceValue
(
boundable
,
true
);
var
transformedCenterPoint
=
TransformPoint
(
new
PointF
(
deviceCenterX
,
deviceCenterY
));
return
transformedCenterPoint
;
}
private
PointF
CalculateFocalPoint
(
ISvgBoundable
boundable
,
PointF
origin
)
{
var
deviceFocalX
=
origin
.
X
+
FocalX
.
ToDeviceValue
(
boundable
);
var
deviceFocalY
=
origin
.
Y
+
FocalY
.
ToDeviceValue
(
boundable
,
true
);
var
transformedFocalPoint
=
TransformPoint
(
new
PointF
(
deviceFocalX
,
deviceFocalY
));
return
transformedFocalPoint
;
}
private
float
CalculateRadius
(
ISvgBoundable
boundable
)
{
var
radius
=
Radius
.
ToDeviceValue
(
boundable
);
var
transformRadiusVector
=
TransformVector
(
new
PointF
(
radius
,
0
));
var
transformedRadius
=
CalculateLength
(
transformRadiusVector
);
return
transformedRadius
;
}
private
float
CalculateEffectiveRadius
(
ISvgBoundable
boundable
,
PointF
centerPoint
,
float
specifiedRadius
)
{
if
(
SpreadMethod
!=
SvgGradientSpreadMethod
.
Pad
)
{
return
specifiedRadius
;
}
GraphicsPath
path
=
new
GraphicsPath
();
float
left
=
this
.
CenterX
.
ToDeviceValue
(
renderingElement
);
float
top
=
this
.
CenterY
.
ToDeviceValue
(
renderingElement
,
true
);
RectangleF
boundingBox
=
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
?
renderingElement
.
Bounds
:
renderingElement
.
OwnerDocument
.
GetDimensions
();
path
.
AddEllipse
(
boundingBox
.
Left
+
left
-
radius
,
boundingBox
.
Top
+
top
-
radius
,
radius
*
2
,
radius
*
2
);
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
effectiveRadius
=
(
float
)
Math
.
Ceiling
(
Math
.
Max
(
Math
.
Max
(
CalculateDistance
(
centerPoint
,
topLeft
),
CalculateDistance
(
centerPoint
,
topRight
)
),
Math
.
Max
(
CalculateDistance
(
centerPoint
,
bottomRight
),
CalculateDistance
(
centerPoint
,
bottomLeft
)
)
)
);
effectiveRadius
=
Math
.
Max
(
effectiveRadius
,
specifiedRadius
);
return
effectiveRadius
;
}
PathGradientBrush
brush
=
new
PathGradientBrush
(
path
);
ColorBlend
blend
=
base
.
GetColourBlend
(
renderingElement
,
opacity
,
true
);
private
static
GraphicsPath
CreateGraphicsPath
(
PointF
origin
,
PointF
centerPoint
,
float
effectiveRadius
)
{
var
path
=
new
GraphicsPath
();
brush
.
InterpolationColors
=
blend
;
brush
.
CenterPoint
=
new
PointF
(
boundingBox
.
Left
+
this
.
FocalX
.
ToDeviceValue
(
renderingElement
),
boundingBox
.
Top
+
this
.
FocalY
.
ToDeviceValue
(
renderingElement
,
true
));
path
.
AddEllipse
(
origin
.
X
+
centerPoint
.
X
-
effectiveRadius
,
origin
.
Y
+
centerPoint
.
Y
-
effectiveRadius
,
effectiveRadius
*
2
,
effectiveRadius
*
2
);
return
brus
h
;
return
pat
h
;
}
private
ColorBlend
CalculateColorBlend
(
SvgVisualElement
renderingElement
,
float
opacity
,
float
specifiedRadius
,
float
effectiveRadius
)
{
var
colorBlend
=
GetColorBlend
(
renderingElement
,
opacity
,
true
);
public
override
SvgElement
DeepCopy
(
)
{
return
DeepCopy
<
SvgRadialGradientServer
>()
;
}
if
(
specifiedRadius
>=
effectiveRadius
)
{
return
colorBlend
;
}
for
(
var
i
=
0
;
i
<
colorBlend
.
Positions
.
Length
-
1
;
i
++)
{
colorBlend
.
Positions
[
i
]
=
1
-
(
specifiedRadius
/
effectiveRadius
)
*
(
1
-
colorBlend
.
Positions
[
i
]);
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgRadialGradientServer
;
colorBlend
.
Positions
=
new
[]
{
0F
}.
Concat
(
colorBlend
.
Positions
).
ToArray
();
colorBlend
.
Colors
=
new
[]
{
colorBlend
.
Colors
.
First
()
}.
Concat
(
colorBlend
.
Colors
).
ToArray
();
newObj
.
CenterX
=
this
.
CenterX
;
newObj
.
CenterY
=
this
.
CenterY
;
newObj
.
Radius
=
this
.
Radius
;
newObj
.
FocalX
=
this
.
FocalX
;
newObj
.
FocalY
=
this
.
FocalY
;
return
colorBlend
;
}
return
newObj
;
}
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgRadialGradientServer
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgRadialGradientServer
;
newObj
.
CenterX
=
this
.
CenterX
;
newObj
.
CenterY
=
this
.
CenterY
;
newObj
.
Radius
=
this
.
Radius
;
newObj
.
FocalX
=
this
.
FocalX
;
newObj
.
FocalY
=
this
.
FocalY
;
return
newObj
;
}
}
}
\ No newline at end of file
Source/Svg.csproj
View file @
2462bf13
...
...
@@ -52,7 +52,7 @@
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "
>
<DebugType>
Full
</DebugType>
<Optimize>
false
</Optimize>
<OutputPath>
..\..\vvvv\public\common\src\thirdparty\
</OutputPath>
<OutputPath>
..\..\vvvv\public\common\src\thirdparty\
</OutputPath>
<DefineConstants>
TRACE;DEBUG;REFLECTION
</DefineConstants>
<ErrorReport>
prompt
</ErrorReport>
<WarningLevel>
4
</WarningLevel>
...
...
@@ -114,6 +114,7 @@
<Compile
Include=
"DataTypes\SvgViewBox.cs"
/>
<Compile
Include=
"Document Structure\SvgTitle.cs"
/>
<Compile
Include=
"Document Structure\SvgDocumentMetadata.cs"
/>
<Compile
Include=
"Painting\ISvgBoundable.cs"
/>
<Compile
Include=
"Painting\SvgMarker.cs"
/>
<Compile
Include=
"Document Structure\SvgDefinitionList.cs"
/>
<Compile
Include=
"Document Structure\SvgDescription.cs"
/>
...
...
Source/SvgDocument.cs
View file @
2462bf13
...
...
@@ -19,14 +19,12 @@ namespace Svg
public
static
readonly
int
PointsPerInch
=
96
;
private
SvgElementIdManager
_idManager
;
/// <summary>
/// Initializes a new instance of the <see cref="SvgDocument"/> class.
/// </summary>
public
SvgDocument
()
{
Ppi
=
PointsPerInch
;
Ppi
=
PointsPerInch
;
}
/// <summary>
...
...
@@ -53,7 +51,7 @@ namespace Svg
/// <param name="manager"></param>
public
void
OverwriteIdManager
(
SvgElementIdManager
manager
)
{
_idManager
=
manager
;
_idManager
=
manager
;
}
/// <summary>
...
...
@@ -293,25 +291,6 @@ namespace Svg
return
null
;
}
public
RectangleF
GetDimensions
()
{
var
w
=
Width
.
ToDeviceValue
();
var
h
=
Height
.
ToDeviceValue
();
RectangleF
bounds
=
new
RectangleF
();
var
isWidthperc
=
Width
.
Type
==
SvgUnitType
.
Percentage
;
var
isHeightperc
=
Height
.
Type
==
SvgUnitType
.
Percentage
;
if
(
isWidthperc
||
isHeightperc
)
{
bounds
=
this
.
Bounds
;
//do just one call to the recursive bounds property
if
(
isWidthperc
)
w
=
(
bounds
.
Width
+
bounds
.
X
)
*
(
w
*
0.01f
);
if
(
isHeightperc
)
h
=
(
bounds
.
Height
+
bounds
.
Y
)
*
(
h
*
0.01f
);
}
return
new
RectangleF
(
0
,
0
,
w
,
h
);
}
/// <summary>
/// Renders the <see cref="SvgDocument"/> to the specified <see cref="SvgRenderer"/>.
/// </summary>
...
...
@@ -413,6 +392,5 @@ namespace Svg
this
.
Write
(
fs
);
}
}
}
}
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