separate parsing from rendering
This commit is contained in:
parent
d334daf812
commit
b79a31fabf
1 changed files with 32 additions and 19 deletions
|
@ -11,10 +11,6 @@ const
|
||||||
svgSignature* = "<svg"
|
svgSignature* = "<svg"
|
||||||
|
|
||||||
type
|
type
|
||||||
LinearGradient = object
|
|
||||||
x1, y1, x2, y2: float32
|
|
||||||
stops: seq[ColorStop]
|
|
||||||
|
|
||||||
SvgProperties = object
|
SvgProperties = object
|
||||||
display: bool
|
display: bool
|
||||||
fillRule: WindingRule
|
fillRule: WindingRule
|
||||||
|
@ -30,6 +26,13 @@ type
|
||||||
opacity, strokeOpacity: float32
|
opacity, strokeOpacity: float32
|
||||||
linearGradients: TableRef[string, LinearGradient]
|
linearGradients: TableRef[string, LinearGradient]
|
||||||
|
|
||||||
|
RenderMode = enum
|
||||||
|
Fill, Stroke
|
||||||
|
|
||||||
|
LinearGradient = object
|
||||||
|
x1, y1, x2, y2: float32
|
||||||
|
stops: seq[ColorStop]
|
||||||
|
|
||||||
template failInvalid() =
|
template failInvalid() =
|
||||||
raise newException(PixieError, "Invalid SVG data")
|
raise newException(PixieError, "Invalid SVG data")
|
||||||
|
|
||||||
|
@ -316,13 +319,13 @@ proc parseSvgProperties(node: XmlNode, inherited: SvgProperties): SvgProperties
|
||||||
else:
|
else:
|
||||||
failInvalidTransform(transform)
|
failInvalidTransform(transform)
|
||||||
|
|
||||||
proc fill(img: Image, props: SvgProperties, path: Path) {.inline.} =
|
proc fill(img: Image, path: Path, props: SvgProperties) =
|
||||||
if props.display and props.opacity > 0:
|
if props.display and props.opacity > 0:
|
||||||
let paint = newPaint(props.fill)
|
let paint = newPaint(props.fill)
|
||||||
paint.opacity = paint.opacity * props.opacity
|
paint.opacity = paint.opacity * props.opacity
|
||||||
img.fillPath(path, paint, props.transform, props.fillRule)
|
img.fillPath(path, paint, props.transform, props.fillRule)
|
||||||
|
|
||||||
proc stroke(img: Image, props: SvgProperties, path: Path) {.inline.} =
|
proc stroke(img: Image, path: Path, props: SvgProperties) =
|
||||||
if props.display and props.opacity > 0:
|
if props.display and props.opacity > 0:
|
||||||
let paint = newPaint(props.stroke)
|
let paint = newPaint(props.stroke)
|
||||||
paint.color.a *= (props.opacity * props.strokeOpacity)
|
paint.color.a *= (props.opacity * props.strokeOpacity)
|
||||||
|
@ -337,7 +340,9 @@ proc stroke(img: Image, props: SvgProperties, path: Path) {.inline.} =
|
||||||
dashes = props.strokeDashArray
|
dashes = props.strokeDashArray
|
||||||
)
|
)
|
||||||
|
|
||||||
proc draw(img: Image, node: XmlNode, propertiesStack: var seq[SvgProperties]) =
|
proc parseSvgElement(
|
||||||
|
node: XmlNode, propertiesStack: var seq[SvgProperties]
|
||||||
|
): seq[(Path, RenderMode, SvgProperties)] =
|
||||||
if node.kind != xnElement:
|
if node.kind != xnElement:
|
||||||
# Skip <!-- comments -->
|
# Skip <!-- comments -->
|
||||||
return
|
return
|
||||||
|
@ -354,7 +359,7 @@ proc draw(img: Image, node: XmlNode, propertiesStack: var seq[SvgProperties]) =
|
||||||
let props = node.parseSvgProperties(propertiesStack[^1])
|
let props = node.parseSvgProperties(propertiesStack[^1])
|
||||||
propertiesStack.add(props)
|
propertiesStack.add(props)
|
||||||
for child in node:
|
for child in node:
|
||||||
img.draw(child, propertiesStack)
|
result.add child.parseSvgElement(propertiesStack)
|
||||||
discard propertiesStack.pop()
|
discard propertiesStack.pop()
|
||||||
|
|
||||||
of "path":
|
of "path":
|
||||||
|
@ -363,9 +368,9 @@ proc draw(img: Image, node: XmlNode, propertiesStack: var seq[SvgProperties]) =
|
||||||
props = node.parseSvgProperties(propertiesStack[^1])
|
props = node.parseSvgProperties(propertiesStack[^1])
|
||||||
path = parsePath(d)
|
path = parsePath(d)
|
||||||
|
|
||||||
img.fill(props, path)
|
result.add (path, Fill, props)
|
||||||
if props.shouldStroke:
|
if props.shouldStroke:
|
||||||
img.stroke(props, path)
|
result.add (path, Stroke, props)
|
||||||
|
|
||||||
of "line":
|
of "line":
|
||||||
let
|
let
|
||||||
|
@ -380,7 +385,7 @@ proc draw(img: Image, node: XmlNode, propertiesStack: var seq[SvgProperties]) =
|
||||||
path.lineTo(x2, y2)
|
path.lineTo(x2, y2)
|
||||||
|
|
||||||
if props.shouldStroke:
|
if props.shouldStroke:
|
||||||
img.stroke(props, path)
|
result.add (path, Stroke, props)
|
||||||
|
|
||||||
of "polyline", "polygon":
|
of "polyline", "polygon":
|
||||||
let
|
let
|
||||||
|
@ -413,10 +418,10 @@ proc draw(img: Image, node: XmlNode, propertiesStack: var seq[SvgProperties]) =
|
||||||
# and fill or not
|
# and fill or not
|
||||||
if node.tag == "polygon":
|
if node.tag == "polygon":
|
||||||
path.closePath()
|
path.closePath()
|
||||||
img.fill(props, path)
|
result.add (path, Fill, props)
|
||||||
|
|
||||||
if props.shouldStroke:
|
if props.shouldStroke:
|
||||||
img.stroke(props, path)
|
result.add (path, Stroke, props)
|
||||||
|
|
||||||
of "rect":
|
of "rect":
|
||||||
let
|
let
|
||||||
|
@ -454,9 +459,9 @@ proc draw(img: Image, node: XmlNode, propertiesStack: var seq[SvgProperties]) =
|
||||||
else:
|
else:
|
||||||
path.rect(x, y, width, height)
|
path.rect(x, y, width, height)
|
||||||
|
|
||||||
img.fill(props, path)
|
result.add (path, Fill, props)
|
||||||
if props.shouldStroke:
|
if props.shouldStroke:
|
||||||
img.stroke(props, path)
|
result.add (path, Stroke, props)
|
||||||
|
|
||||||
of "circle", "ellipse":
|
of "circle", "ellipse":
|
||||||
let
|
let
|
||||||
|
@ -475,9 +480,9 @@ proc draw(img: Image, node: XmlNode, propertiesStack: var seq[SvgProperties]) =
|
||||||
let path = newPath()
|
let path = newPath()
|
||||||
path.ellipse(cx, cy, rx, ry)
|
path.ellipse(cx, cy, rx, ry)
|
||||||
|
|
||||||
img.fill(props, path)
|
result.add (path, Fill, props)
|
||||||
if props.shouldStroke:
|
if props.shouldStroke:
|
||||||
img.stroke(props, path)
|
result.add (path, Stroke, props)
|
||||||
|
|
||||||
of "radialGradient":
|
of "radialGradient":
|
||||||
discard
|
discard
|
||||||
|
@ -578,9 +583,17 @@ proc decodeSvg*(
|
||||||
scaleY = height.float32 / viewBoxHeight.float32
|
scaleY = height.float32 / viewBoxHeight.float32
|
||||||
rootprops.transform = rootprops.transform * scale(vec2(scaleX, scaleY))
|
rootprops.transform = rootprops.transform * scale(vec2(scaleX, scaleY))
|
||||||
|
|
||||||
var propertiesStack = @[rootProps]
|
var
|
||||||
|
propertiesStack = @[rootProps]
|
||||||
|
renderInfos: seq[(Path, RenderMode, SvgProperties)]
|
||||||
for node in root.items:
|
for node in root.items:
|
||||||
result.draw(node, propertiesStack)
|
renderInfos.add node.parseSvgElement(propertiesStack)
|
||||||
|
for (path, mode, props) in renderInfos:
|
||||||
|
case mode:
|
||||||
|
of Fill:
|
||||||
|
result.fill(path, props)
|
||||||
|
of Stroke:
|
||||||
|
result.stroke(path, props)
|
||||||
except PixieError as e:
|
except PixieError as e:
|
||||||
raise e
|
raise e
|
||||||
except:
|
except:
|
||||||
|
|
Loading…
Reference in a new issue