Add SVG scale transform and non-zero / negative viewbox offset

This commit is contained in:
Joris Bontje 2021-04-21 15:26:09 +02:00
parent 101619a9e6
commit 2e93a75bb7
3 changed files with 50 additions and 1 deletions

16
examples/data/scale.svg Normal file
View file

@ -0,0 +1,16 @@
<svg viewBox="-50 -50 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- uniform scale -->
<circle cx="0" cy="0" r="10" fill="red"
transform="scale(4)" />
<!-- vertical scale -->
<circle cx="0" cy="0" r="10" fill="yellow"
transform="scale(1,4)" />
<!-- horizontal scale -->
<circle cx="0" cy="0" r="10" fill="pink"
transform="scale(4,1)" />
<!-- No scale -->
<circle cx="0" cy="0" r="10" fill="black" />
</svg>

After

Width:  |  Height:  |  Size: 459 B

12
examples/scale.nim Normal file
View file

@ -0,0 +1,12 @@
import pixie
let image = newImage(100, 100)
image.fill(rgba(255, 255, 255, 255))
let flower = readImage("examples/data/scale.svg")
image.draw(
flower
)
image.writeFile("examples/scale.png")

View file

@ -192,6 +192,21 @@ proc decodeCtx(inherited: Ctx, node: XmlNode): Ctx =
let center = vec2(cx, cy)
result.transform = result.transform *
translate(center) * rotate(angle) * translate(-center)
elif f.startsWith("scale("):
let
values =
if f.contains(","):
f[6 .. ^2].split(",")
else:
f[6 .. ^2].split(" ")
let
sx: float32 = parseFloat(values[0].strip())
sy: float32 =
if values.len > 1:
parseFloat(values[1].strip())
else:
sx
result.transform = result.transform * scale(vec2(sx, sy))
else:
failInvalidTransform(transform)
@ -348,12 +363,18 @@ proc decodeSvg*(data: string, width = 0, height = 0): Image =
let
viewBox = root.attr("viewBox")
box = viewBox.split(" ")
viewBoxMinX = parseInt(box[0])
viewBoxMinY= parseInt(box[1])
viewBoxWidth = parseInt(box[2])
viewBoxHeight = parseInt(box[3])
var rootCtx = initCtx()
rootCtx = decodeCtx(rootCtx, root)
if viewBoxMinX != 0 or viewBoxMinY != 0:
rootCtx.transform = rootCtx.transform * translate(
vec2(-viewBoxMinX.float32, -viewBoxMinY.float32))
if width == 0 and height == 0: # Default to the view box size
result = newImage(viewBoxWidth, viewBoxHeight)
else:
@ -362,7 +383,7 @@ proc decodeSvg*(data: string, width = 0, height = 0): Image =
let
scaleX = width.float32 / viewBoxWidth.float32
scaleY = height.float32 / viewBoxHeight.float32
rootCtx.transform = scale(vec2(scaleX, scaleY))
rootCtx.transform = rootCtx.transform * scale(vec2(scaleX, scaleY))
var ctxStack = @[rootCtx]
for node in root: