Graphics.DrawSVG method

The DrawSVG method now raises an SVGException on detected errors. There are three types of exceptions at this point:

1: Expected path command: …
2: Feature not yet implemented: …
3: Malformed SVG XML.

The first exception is raised when incorrect path data is provided with the path element (or at this point it might also be raised with partially implemented commands). The second exception is raised in places where features still need to be implemented. And the third exception is raised when the SVG XML is malformed.

I’ll expand on these exceptions as work continues on the DrawSVG method. Any suggestions on how the exception handling might be improved are welcome.

Just FYI, the Tiger image that was so popular when svg was first available does not render in your library. I found a copy of the it here…

https://commons.m.wikimedia.org/wiki/File:Ghostscript_Tiger.svg

Thanks Greg, I’ve added the tiger to the list of test images.

On a quick run I see it throws the “Expected path command” event. This indicates that one of that path commands are not yet fully implemented.

Will look into this.

…and the tiger renders :slight_smile: Just get the latest version of DrawSVG from GitHub.

There is one snag though, it takes about 5 seconds to render. For real-time animation and graphics this is obviously not sufficient.

I have 2 more important SVG elements to implement: arc paths and base64 encoded bitmap images. When I’ve complete these two features I will spend a decent amount of time optimizing the existing code for better speed performances.

Until then, the one workaround I can recommend if you need to use large or very complicated SVG images (such as the tiger) in your application, is to render the SVG to a Picture at the start of the application, and then rather use the DrawPicture method to render the picture in real-time thereafter.

For basic SVG images you should be able to render it in real-time though.

Graphics.DrawSVG now has a sister… WebGraphics.DrawSVG.

Work still continues on Graphics.DrawSVG… almost done with the path arc command.

Hi Alwyn,

congratulations for your SVG method. I want to use it in my project but I don’t know how to get your xojo project with the SVG module from GitHub. I have downloaded ‘DrawSVG.xojo_project’ file but when I open it in Xojo, the projet is empty.

Could you help me and link the SVG project in other platform, please? (i.e. dropbox)

Thank you very much.
Sergio

Hi Sergio,

Try using the Download ZIP button on the main DrawSVG project page on GitHub. This will download the whole project and everything that’s needed to run it in a single zip file.

Then simply extract the zip file, and try to open the project. Please let me know if you are still having difficulty opening the project with the zip.

Keep in mind, DrawSVG is still work in progress, and although it should render most SVGs, if you do find any SVG’s that doesn’t render correctly, please send through to me so that I can have look.

The Download ZIP button is located at the bottom of the column on the right…

Hi Alwyn,

I could download the Zip file and extract the example project. I have opened several SVG files and it works perfectly but I have found a little mistake with an specific SVG file: https://www.dropbox.com/s/r4zn4rjgejjktf5/StepProgress.svg?dl=0. If I load this SVG file in your xojo example, I can see the SVG draw but without resolution:

Low resolution:
Low resolution

Here you have the previous SVG imagen loaded in Artboard Software:

SVG in Artboard

As you can see there is a great difference in the resolution (I have used a mac book pro with retina display).

Thank you very much,
Sergio

Good to hear you got it working Sergio, and thank you for the feedback.

I’ve added your SVG to the list of test files, and will look into it.

My goal with DrawSVG is to first get it working, then get it perfect. I work on it almost daily so I hope that in good time it will mature into something useful for everyone.

Here is a little roadmap for what I’ve got planned for DrawSVG.

  • Complete the path arc command.
  • Support for rounded rectangle corners.
  • Optimize for speed.
  • Support for dashed lines.
  • Support for line end-points.
  • Refactor code for speed and quality.
  • Look into the possibility of using platform specific declares for rendering.

While working on this roadmap, I will also continue to look into issues pointed out by users.

Ok… the quality issues with the text in your sample SVG is now fixed Sergio. You can just download the latest version of DrawSVG from GitHub.

I’ve noticed one other issue, in that the line widths are not drawn exactly the same. This is a known issue, that I will look at once the path arc command is completed.

Is there a way to know upfront what the dimensions are going to be?

So before g.DrawSVG(SvgXML, 0, 0) ?

I don’t know anything about SVG but:

  • I picked a random example from your test project ‘test_00032.svg’.
  • Set the dimensions to 600*346 (obviously, this needs to be dynamic with correct aspect ratio. Canvas size or whatever)
  • Then changed the paint event of the test project to:
  // Dimensions.
  Dim Width As Integer = 600
  Dim Height As Integer = 346
  
  // Pick a Smoothfactor
  Dim SmoothFactor As Double = 2
  Do Until Width * SmoothFactor > 1600 // Some large number. Bigger is better but slower.
    SmoothFactor = SmoothFactor + 0.5
  Loop
  
  // Set
  Width = Width * SmoothFactor
  Height = Height * SmoothFactor
  
  // Scratch pic
  Dim tmpPic As New Picture(Width, Height)
  Dim tmpG As Graphics = tmpPic.Graphics

  // Draw SVG
  tmpG.DrawSVG(SvgXML, 0, 0, Width, Height)
  
  // Draw Picture
  g.DrawPicture(tmpPic, 0, 0, Width / SmoothFactor, Height / SmoothFactor, 0, 0, Width, Height)

That made it look smoother/sharper.
First one is the demo. Second with above change:

and the tiger:

Just a suggestion. :slight_smile:

Perhaps an optional quality parameter to make the rendering smooth would help? The higher the quality the slower, but it will look better.

I tried to replace all my graphics with vectors but the quality issue is currently preventing a full switch.

[quote=233178:@Marco Hof]I picked a random example from your test project ‘test_00032.svg’.
Set the dimensions to 600*346 (obviously, this needs to be dynamic with correct aspect ratio. Canvas size or whatever)
Then changed the paint event of the test project to:[/quote]

This is a fantastic enhancement to the rendering code Marco. I will definitely build in your smoothing factor today. I’ve been racking my brain on how Webkit get’s their SVG images to look so smooth, and your code hits the hammer on the nail.

[quote=233172:@Marco Hof]Is there a way to know upfront what the dimensions are going to be?
So before g.DrawSVG(SvgXML, 0, 0) ?[/quote]

If I build in your smoothing mechanism directly into the DrawSVG method, will you still have the need to get the dimensions of a SVG?

If so, I can add a GetSVGDimensions method for us that extracts the width and height from the SVG string.

[quote=233208:@Brock Nash]Perhaps an optional quality parameter to make the rendering smooth would help? The higher the quality the slower, but it will look better.

I tried to replace all my graphics with vectors but the quality issue is currently preventing a full switch.[/quote]

I hope when we apply Marco’s smoothing algorithm that the DrawSVG method that we will be one step closer to make DrawSVG usable in your projects Brock.

Let me build in the smooth factor, and then we can perhaps discuss afterward if we need to add an optional quality parameter. I would like to first see if we can get the rendering fast enough without having to have to degrade the quality of the final image at all.

Your thoughts Brock?

Glad you can use it. :slight_smile:
I don’t think you will notice much of a speed difference when using the smoothing. The svg drawing takes most time and the ‘Do Until’ keeps things a bit under control. Really large canvas drawings are slow (and the smoothing will make it worse) but to do at least a bit of smoothing, I picked a minimum (2) value.
If you set it to 1, it just skips smoothing of larger drawings.

I asked for the size (or better yet, the aspect ratio) upfront so the pics can be cached more easily.
For example, if you load the tiger in your demo project, try to resize the window. That’s pretty much not workable.

Now if you do something like:

    If itIsTheSameSvg Then

      // Draw Cache Picture
      g.DrawPicture(CachePicture, 0, 0, Width / SmoothFactor, Height / SmoothFactor, 0, 0, CachePicture.Width, CachePicture.Height)
    
    Else

        // Scratch pic
      Dim tmpPic As New Picture(Width, Height)
      Dim tmpG As Graphics = tmpPic.Graphics

      // Draw SVG
      tmpG.DrawSVG(SvgXML, 0, 0, Width, Height)

      // Draw svgPicture
      g.DrawPicture(tmpPic, 0, 0, Width / SmoothFactor, Height / SmoothFactor, 0, 0, Width, Height)
     
      // Store Cache Pic
     CachePicture = tmpPic

    End If

(more or less)

That way, you only have to do the actual drawing once. CachePicture should always resize properly (and fast) because the CachePicture is the larger picture that was used for smoothing.

Caching is definitely a good way to ensure a smooth user experience. Even if we do get SVG rendering to a decent speed for large images, complex and large SVG drawings will never be as fast as a pre-rendered bitmap image.

True.
(I think… I never used svg images before. :slight_smile: )

I have one other suggestion though. :slight_smile:
Wouldn’t it be easier to make it so that your class can be called with the svg folderitem as parameter and it just returns the picture? That way, the user can do whatever he wants with it. He can then also handle the caching himself.

Absolutely. I will make provision for such a feature.

Agreed, much better that the user implements his/her caching in a way that is fitting for his/her particular application.