diff --git a/src/pixie.nim b/src/pixie.nim index d6eb77e..6fc8608 100644 --- a/src/pixie.nim +++ b/src/pixie.nim @@ -28,7 +28,7 @@ proc decodeImage*(data: string): Image {.raises: [PixieError].} = decodeBmp(data) elif data.len > 5 and (data.readStr(0, 5) == xmlSignature or data.readStr(0, 4) == svgSignature): - decodeSvg(data) + newImage(parseSvg(data)) elif data.len > 6 and data.readStr(0, 6) in gifSignatures: decodeGif(data) elif data.len > (14+8) and data.readStr(0, 4) == qoiSignature: diff --git a/src/pixie/fileformats/svg.nim b/src/pixie/fileformats/svg.nim index 5bb9cdf..168ad1f 100644 --- a/src/pixie/fileformats/svg.nim +++ b/src/pixie/fileformats/svg.nim @@ -12,6 +12,7 @@ const type Svg* = ref object + width*, height*: int elements: seq[(Path, SvgProperties)] linearGradients: Table[string, LinearGradient] @@ -498,10 +499,10 @@ proc parseSvgElement( else: raise newException(PixieError, "Unsupported SVG tag: " & node.tag) -proc decodeSvg*( +proc parseSvg*( data: string | XmlNode, width = 0, height = 0 -): Image {.raises: [PixieError].} = - ## Render SVG XML and return the image. Defaults to the SVG's view box size. +): Svg {.raises: [PixieError].} = + ## Parse SVG XML. Defaults to the SVG's view box size. try: let root = parseXml(data) if root.tag != "svg": @@ -518,26 +519,38 @@ proc decodeSvg*( var rootProps = initSvgProperties() rootProps = root.parseSvgProperties(rootProps) + if viewBoxMinX != 0 or viewBoxMinY != 0: let viewBoxMin = vec2(-viewBoxMinX.float32, -viewBoxMinY.float32) rootprops.transform = rootprops.transform * translate(viewBoxMin) + result = Svg() + if width == 0 and height == 0: # Default to the view box size - result = newImage(viewBoxWidth, viewBoxHeight) + result.width = viewBoxWidth + result.height = viewBoxHeight else: - result = newImage(width, height) + result.width = width + result.height = height let scaleX = width.float32 / viewBoxWidth.float32 scaleY = height.float32 / viewBoxHeight.float32 rootprops.transform = rootprops.transform * scale(vec2(scaleX, scaleY)) - let svg = Svg() - var propertiesStack = @[rootProps] for node in root.items: - svg.elements.add node.parseSvgElement(svg, propertiesStack) + result.elements.add node.parseSvgElement(result, propertiesStack) + except PixieError as e: + raise e + except: + raise currentExceptionAsPixieError() +proc newImage*(svg: Svg): Image {.raises: [PixieError].} = + ## Render SVG and return the image. + result = newImage(svg.width, svg.height) + + try: for (path, props) in svg.elements: if props.display and props.opacity > 0: if props.fill != "none": @@ -580,4 +593,4 @@ proc decodeSvg*( except PixieError as e: raise e except: - raise newException(PixieError, "Unable to load SVG") + raise currentExceptionAsPixieError() diff --git a/tests/benchmark_svg.nim b/tests/benchmark_svg.nim index c158d6d..cde9a8a 100644 --- a/tests/benchmark_svg.nim +++ b/tests/benchmark_svg.nim @@ -2,5 +2,5 @@ import benchy, pixie/fileformats/svg let data = readFile("tests/fileformats/svg/Ghostscript_Tiger.svg") -timeIt "svg decode": - discard decodeSvg(data) +timeIt "svg parse + render": + discard newImage(parseSvg(data)) diff --git a/tests/megatest_emoji.nim b/tests/megatest_emoji.nim index 1e8d69d..7b594de 100644 --- a/tests/megatest_emoji.nim +++ b/tests/megatest_emoji.nim @@ -35,7 +35,7 @@ proc renderEmojiSet(index: int) = let (_, name, _) = splitFile(filePath) var image: Image try: - image = decodeSvg(readFile(filePath), width, height) + image = newImage(parseSvg(readFile(filePath), width, height)) except PixieError: echo &"Failed decoding {name}" image = newImage(width, height) diff --git a/tests/megatest_icons.nim b/tests/megatest_icons.nim index 185a6ec..bd8b838 100644 --- a/tests/megatest_icons.nim +++ b/tests/megatest_icons.nim @@ -38,7 +38,7 @@ proc renderIconSet(index: int) = for filePath in walkFiles(iconSet.path): let (_, name, _) = splitFile(filePath) - image = decodeSvg(readFile(filePath), width, height) + image = newImage(parseSvg(readFile(filePath), width, height)) images.add((name, image)) diff --git a/tests/test_svg.nim b/tests/test_svg.nim index c9f6d43..e31e449 100644 --- a/tests/test_svg.nim +++ b/tests/test_svg.nim @@ -26,9 +26,8 @@ proc doDiff(rendered: Image, name: string) = diffImage.writeFile(&"tests/fileformats/svg/diffs/{name}.png") for file in files: - doDiff(decodeSvg(readFile(&"tests/fileformats/svg/{file}.svg")), file) + doDiff(readImage(&"tests/fileformats/svg/{file}.svg"), file) -doDiff( - decodeSvg(readFile("tests/fileformats/svg/accessibility-outline.svg"), 512, 512), - "accessibility-outline" -) +block: + let svg = parseSvg(readFile("tests/fileformats/svg/accessibility-outline.svg"), 512, 512) + doDiff(newImage(svg), "accessibility-outline")