Graphics.DrawSVG method

In my current line of work, SVG images forms a critical part of our production environment.

So much so that I’ve started an open source project that extends the Xojo Graphics object with a DrawSVG method. This method is still work in progress, but all the basic elements, together with transformations are already implemented.

Thanks for everyone that has unselfishly shared their expertise and code samples to get this project off the ground.

I’m currently working on the PATH element, which some of you might know to be a heavily used element of SVG. So don’t expect SVG’s that relies on this element to render correctly just yet. I hope to eventually grow this project into a full implementation of SVG 1.1.

Using the method in your own projects is very easy. Just copy the DrawSVG module from the project found at the link below to your own project, and your Graphics object will have a brand new DrawSVG method. You use it exactly how you would use the DrawPicture method, except that you need to supply SVG XML for drawing instead of a Picture object.

Sub Paint(g As Graphics, areas() As REALbasic.Rect)
    g.DrawSVG "Some SVG XML", 100, 100
End Sub

Like I mentioned, this project is still work in progress, and you will find that there are still lots of missing features. I’m committed however to improve the feature set on a daily basis.

If there are any particular SVG images that you need rendered with this method, that currently doesn’t render with the method as it stands now, you are more than welcome to private message me with the sample SVG (or even post it in this conversation for general discussion). This will help me prioritize which features to attend to first.

If you are a Mac or a Linux user, I would love to hear if the module works on these platforms. All my work is done on Windows and I haven’t had time yet to test it on these platforms.

https://github.com/Zoclee/xojo-drawsvg

Here is a screenshot of some test SVGs that the method can already render successfully:

It’s funny how these things work out… I just wrote an SVG to PDF converter today as I wanted to use some SVG vectors in my Xojo application.

Once I finish my current project, I’ll tart it up and stick it out there too.

I have a lot of SVG that are plain black. On the web it’s easy to simply style their color with a CSS Property. I currently use PNG’s on the desktop version of my app but I would love to switch it over to the vectors for a number of reasons (i.e. retina, resource management, memory). Is setting the penColor sufficient for this? I’m sure I could hack a way into the SVG’s XML and replace colors if need be, but wasn’t sure if this would work “out of the box” so to speak. (?)

@Alwyn Bester
just for curiosity

why did you define pointXY, when exists REALbasic.Point (and in the new framework xojo.Core.Point) ?

Unfortunately not. I think you will have to hack the XML, because the color of the polygons and lines are determined in their style tags in the XML, and not by the ForeColor of the graphics object.

I do plan to add support for CSS style sheets soon, so at least if your objects uses style classes, you can change the colors of all the objects at one single point in the file.

Looks like pretty much none of my SVG’s are rending (they all render fine in the WebApp).

They’re all pretty similar.
Here are a few examples:

<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"> <g id="Layer_2"> <path d="M39.3,11.2c0.8-1.2,1.5-2.4,2.3-3.6c0.6-1,0.5-2.4,0.7-3.6c-1.1,0.5-2.2,1-3.3,1.6c-0.2,0.1-0.4,0.4-0.5,0.7 c-0.6,0.8-1.3,1.5-1.9,2.3C33.1,5.7,28.8,4,24,4C13,4,4,13,4,24c0,11,9,20,20,20s20-9,20-20C44,19.1,42.2,14.7,39.3,11.2z M24,40.6 c-9.1,0-16.5-7.4-16.5-16.5S14.9,7.5,24,7.5c3.9,0,7.5,1.4,10.3,3.7c-3.8,4.6-7.7,9.2-11.7,14c-1.8-2-3.3-3.7-4.7-5.4 c-1.5-1.7-3.2-2.5-5.1-0.8c-1.8,1.7-1.3,3.5,0.2,5.3c2.3,2.7,4.5,5.4,6.8,8c2.1,2.4,4.5,2.3,6.3-0.3c3.8-5.9,7.6-11.7,11.3-17.6 c2,2.7,3.2,6.1,3.2,9.7C40.5,33.1,33.1,40.6,24,40.6z"/> </g> </svg>

[code]<?xml version="1.0" encoding="utf-8"?>



	<rect id="Strike" x="21.9" y="-2.2" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 57.7202 24.1135)" width="4" height="52.5"/>
<g id="Body">
	<path id="BodyTop" d="M37.9,29.6c0-3.8,0-6.8,0-7.6c0-7.8-6.2-14-14-14c-2.2,0-4.2,0.6-6.2,1.4L37.9,29.6z"/>
	<path id="BodyBottom" d="M14.5,11.8C11.7,14.4,9.8,18,9.8,22c0,0.8,0,4.6,0,9l-4,4.6V38h34.8L14.5,11.8z"/>
</g>
[/code]

<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"> <g id="Layer_2"> <g> <path d="M32.7,7.2c-3.5-2-5.4-1-5.4-1l-6.8,12.2l-7.8,14l0.6,9.5l8.4-4.5l7.8-14l6.8-12.2C36.4,11.3,36.2,9.1,32.7,7.2z M20.9,36.6l-3.2,2.1c-0.5-0.5-1-0.9-1.8-1.4c-0.8-0.5-1.5-0.7-2.1-0.8l0.1-3.8L20.9,36.6z"/> </g> </g> </svg>

Brock,
How do you get an xml file from an svg image file?

Thanks.

[quote=228799:@Brock Nash]Looks like pretty much none of my SVG’s are rending (they all render fine in the WebApp).

They’re all pretty similar.
Here are a few examples:[/quote]

I’ll look into these for you.

There is still a lot of work to get things tweaked to work with all SVGs. Will let you know as soon as I made some progress on getting these fixed for you.

Just open the SVG file with any text editor. I prefer to use Notepad++.

SVG files are stored as XML text.

[quote=228793:@Antonio Rinaldi]just for curiosity

why did you define pointXY, when exists REALbasic.Point (and in the new framework xojo.Core.Point) ?[/quote]

For no reason other than I didn’t know about the REALbasic.Point class. I’ve updated the project to rather use the REALbasic.Point class.

When all the issues are sorted out with the current module, then I will start to port the project to the new framework. For now though I just want to first get everything perfect for the old framework.

If you have any other suggestions about the code, please send 'em through :slight_smile:

Cool. We can change some ideas on how to implement things. Looks like the paths and arcs are going to get pretty hairy.

That would be awesome! :slight_smile:

Also it would be nice if the “g.DrawSVG” event took a width and a height as well as the x and y property.
What does it currently do? Does it ratio it across the remaining space? The point of a vector is typically that you can scale the image without losing quality, but I’m not sure how to achieve that currently.

The g.DrawSVG method now has the optional w1 and h1 properties, exactly like the g,DrawPicture method. I’ve already pushed the new code to GitHub.

DrawSVG(svg As String, x As Integer, y As Integer, w1 As Integer = -10000, h1 As Integer = -10000)

Absolutely, quality is preserved no matter how large you size the picture. Basically, transformation matrices are created for translation, scaling, rotation and skewing, which is passed down recursively to each element that needs to be drawn.

For example, to implement the width and height properties all I had to do was add the following code in the DrawSVG method:

            mulMatrix = initScaleMatrix(w1 / w, h1 / h)
            matrix = matrixMultiply(matrix, mulMatrix)

This creates a scaling matrix and “adds” it to the other transformations already stored in the matrix variable. All child elements will now be drawn with the new scale being applied to them.

Not sure if this makes any sense?

I had a quick look at your sample SVGs. They all required path elements that I’m still busy implementing. I hope to get most of it done during the next few days. That would be why nothing renders at the moment when you try to draw them. Will post here when I have these implemented.

@Alwyn Bester - This looks great. Can you give a rotation sample? I dusted off my gamekit a couple of days ago and will see how this performs once I dig in to it a bit.

Rotation is super easy with SVG.

For example, let’s say you have a SVG with a blue rectangle shape in it:

<svg width="100" height="100">
    <rect width="50" height="50" x="25" y="25" style="fill:blue;" />
</svg>

This rectangle’s center point is at (50,50)… (x + half of it’s with, y + half of it’s height).

To rotate this square 30 degrees around it’s center point, we simply add a transform attribute to the rect tag:

<svg width="100" height="100">
    <rect width="50" height="50" x="25" y="25" style="fill:blue;" transform="rotate(30, 50, 50);" />
</svg>

To rotate this square 30 degrees around point (20, 40), we simply change the rotate call as follow:

<svg width="100" height="100">
    <rect width="50" height="50" x="25" y="25" style="fill:blue;" transform="rotate(30, 20, 40);" />
</svg>

The nice thing about working with SVG XML is that we can do some nice animation effects by manipulating the XML elements directly.

This example shows how easy it is to create a spinning rectangle using SVG and the timer control:

Animation Demo

I’ve always found W3Schools.com and excellent resource for SVG information.

Nice. Have you written any games with your kit?

Brock,

Some good news for you…

There is still a known issue when trying to use the DrawSVG width and height parameters with SVG images that has a viewbox defined (like your test images), but I will get that fixed eventually.

If anyone else has SVG images that currently does not render correctly, please send them to me so that I can investigate why. There are still a few features I need to implement, but the DrawSVG is slowly becoming useful for most people’s needs.

Here is another SVG I got to render correctly this morning, which was a more complicated one:

Brock, I hope you don’t mind, I’ve added your test images to the test folder on GitHub?

[quote=228802:@Richard Summers]Brock,
How do you get an xml file from an svg image file?
[/quote]
SVG is an XML file. Just open it in a text editor :slight_smile: