SvgDocument.Draw() gives a null reference exception

Apr 30, 2012 at 1:30 PM
Edited Apr 30, 2012 at 1:32 PM

I'm attempting to save an SVG file via a handler to a .png file. At the moment my code appears to give me a null reference exception when I try to call 'Draw()' on the SvgDocument, but the document appears correctly formed.

My code at the moment looks like this (inside a handler):

[code]var oDoc = Svg.SvgDocument.Open(new System.IO.MemoryStream(System.Text.ASCIIEncoding.Default.GetBytes(context.Request.Params["svg"])));

oDoc.Draw().Save(@"c:\temp\somit.png", ImageFormat.Png);[/code]

My input svg seems sane, but the Draw method doesn't seem too happy. Any ideas on where to look with this one?

The stack trace is below:

Object reference not set to an instance of an object.<br><br> at Svg.SvgUnit.ToDeviceValue(ISvgStylable styleOwner, Boolean vertical)
at Svg.SvgUnit.ToDeviceValue(ISvgStylable styleOwner)
at Svg.SvgUnit.ToDeviceValue()
at Svg.SvgRectangle.get_Path()
at Svg.SvgGraphicsElement.Render(SvgRenderer renderer)
at Svg.SvgRectangle.Render(SvgRenderer renderer)
at Svg.SvgElement.RenderChildren(SvgRenderer renderer)
at Svg.SvgElement.Render(SvgRenderer renderer)
at Svg.SvgDocument.Draw()
at SVGHandler.ProcessRequest(HttpContext context) in c:\Applications\Document\SVGHandler.ashx:line 28
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

My svg string, taken directly from 'context.Request.Params["svg"]' is below:

<?xml version="1.0" standalone="yes"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="1184px" height="365px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><defs></defs><rect width="100%" height="100%" fill="#fff" fill-opacity="0" stroke="none" /><path d="M 176.5 293L 176.5 10M 170 293.5L 177 293.5M 170 252.5L 177 252.5M 170 212.5L 177 212.5M 170 171.5L 177 171.5M 170 131.5L 177 131.5M 170 90.5L 177 90.5M 170 50.5L 177 50.5M 170 10.5L 177 10.5" fill="none" stroke="#444" stroke-width="1" z-index="0" transform="matrix(1,0,0,1,0,0)" /><text x="149" y="293" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="149" dy="3">0.0</tspan></text><text x="142" y="252" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="142" dy="3">20.0</tspan></text><text x="142" y="212" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="142" dy="3">40.0</tspan></text><text x="142" y="171" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="142" dy="3">60.0</tspan></text><text x="142" y="131" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="142" dy="3">80.0</tspan></text><text x="135" y="90" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="135" dy="3">100.0</tspan></text><text x="135" y="50" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="135" dy="3">120.0</tspan></text><text x="135" y="9" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="135" dy="3">140.0</tspan></text><text x="0" y="0" font-size="22" font-family="Arial" fill="#222" transform="matrix(0,-1,1,0,115.5,180.5)" ><tspan x="" dy="5.5">Hours</tspan></text><path d="M 176.5 252.5L 1172.5 252.5M 176.5 212.5L 1172.5 212.5M 176.5 171.5L 1172.5 171.5M 176.5 131.5L 1172.5 131.5M 176.5 90.5L 1172.5 90.5M 176.5 50.5L 1172.5 50.5" fill="none" stroke="#ccc" stroke-width="1" z-index="0" transform="matrix(1,0,0,1,0,0)" /><rect x="187" y="50" width="89" height="243" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="187" y="50" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="187" y="30" width="89" height="20" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><path d="M 176 293.5L 1174 293.5M 231.5 293L 231.5 300M 329.5 293L 329.5 300M 428.5 293L 428.5 300M 527.5 293L 527.5 300M 625.5 293L 625.5 300M 724.5 293L 724.5 300M 822.5 293L 822.5 300M 921.5 293L 921.5 300M 1020.5 293L 1020.5 300M 1118.5 293L 1118.5 300" fill="none" stroke="#444" stroke-width="1" z-index="0" transform="matrix(1,0,0,1,0,0)" /><text x="200" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="200" dy="3">04/05/2012</tspan></text><text x="298" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="298" dy="3">11/05/2012</tspan></text><text x="397" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="397" dy="3">18/05/2012</tspan></text><text x="496" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="496" dy="3">25/05/2012</tspan></text><text x="594" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="594" dy="3">01/06/2012</tspan></text><text x="693" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="693" dy="3">08/06/2012</tspan></text><text x="791" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="791" dy="3">15/06/2012</tspan></text><text x="890" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="890" dy="3">22/06/2012</tspan></text><text x="989" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="989" dy="3">29/06/2012</tspan></text><text x="1087" y="312.5" font-size="12" font-family="Arial" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="1087" dy="3">06/07/2012</tspan></text><text x="0" y="0" font-size="22" font-family="Arial" fill="#222" transform="matrix(1,0,0,1,611.5,347.6)" ><tspan x="" dy="5.5">Week Ending</tspan></text><path d="M 231.5 292.5L 231.5 11.5M 329.5 292.5L 329.5 11.5M 428.5 292.5L 428.5 11.5M 527.5 292.5L 527.5 11.5M 625.5 292.5L 625.5 11.5M 724.5 292.5L 724.5 11.5M 822.5 292.5L 822.5 11.5M 921.5 292.5L 921.5 11.5M 1020.5 292.5L 1020.5 11.5M 1118.5 292.5L 1118.5 11.5" fill="none" stroke="#ccc" stroke-width="1" z-index="0" transform="matrix(1,0,0,1,0,0)" /><rect x="285" y="172" width="89" height="121" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="285" y="172" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="285" y="156" width="89" height="16" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="384" y="142" width="89" height="151" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="384" y="142" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="384" y="122" width="89" height="20" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="483" y="114" width="89" height="179" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="483" y="114" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="483" y="94" width="89" height="20" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="581" y="77" width="89" height="216" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="581" y="77" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="581" y="61" width="89" height="16" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="680" y="159" width="89" height="134" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="680" y="159" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="680" y="139" width="89" height="20" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="779" y="81" width="89" height="212" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="779" y="81" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="779" y="12" width="89" height="69" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="877" y="146" width="89" height="147" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="877" y="146" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="877" y="77" width="89" height="69" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="976" y="146" width="89" height="147" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="976" y="146" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="976" y="77" width="89" height="69" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="1075" y="116" width="89" height="177" fill="#104bd6" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="1075" y="116" width="89" height="0" fill="#0edc32" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="1075" y="47" width="89" height="69" fill="#e60005" fill-opacity="0.5" stroke="black" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="9.5" y="103.5" width="80" height="95" fill="#FFF" stroke="#000" stroke-width="1" transform="matrix(1,0,0,1,0,0)" /><rect x="0" y="-8.5" width="62" height="20.5" fill="#FFF" transform="matrix(1,0,0,1,15,114)" /><rect x="0" y="-8.5" width="70" height="20.5" fill="#FFF" transform="matrix(1,0,0,1,15,142)" /><rect x="0" y="-8.5" width="69.5" height="20.5" fill="#FFF" transform="matrix(1,0,0,1,15,170)" /><text x="35" y="120" font-size="12" font-family="Helvetica, sans-serif" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="35" dy="3">Definite</tspan></text><rect x="0" y="0" width="12" height="12" fill="#104bd6" transform="matrix(1,0,0,1,15,114)" /><text x="35" y="148" font-size="12" font-family="Helvetica, sans-serif" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="35" dy="3">Probable</tspan></text><rect x="0" y="0" width="12" height="12" fill="#0edc32" transform="matrix(1,0,0,1,15,142)" /><text x="35" y="176" font-size="12" font-family="Helvetica, sans-serif" fill="#000" transform="matrix(1,0,0,1,0,0)" ><tspan x="35" dy="3">Prospect</tspan></text><rect x="0" y="0" width="12" height="12" fill="#e60005" transform="matrix(1,0,0,1,15,170)" /></svg>

Coordinator
May 1, 2012 at 7:22 AM

Hey dougajmcdonald,

I'll look into this when I'm back at my machine, but by looking at the issue I wonder if the width and height being set to 100% might be the issue. I'm not suggesting this is invalid SVG but I don't recall if this is supported.

You may want to try and set the width and height to pixel values on the root <rect/> to see if this resolves the issue (as a temp option).

Scriv

 

May 1, 2012 at 8:26 AM

Hi Scriv,

In an effort to sort this one I grabbed the latest version of the source, rather than the 0.5.2 download in the downloads section and I'm no longer getting this issue.

I am now however getting a different issue, in that the image is produced happily without any of the text. Is there anything wrong with how the text elements are formed in the SVG as far as you can see?

The rest of the image is absolutely fine, I've updated my code to fire the image as an attachment, in case this would make any difference. Here is my ProcessRequest() method in my handler:

    public void ProcessRequest (HttpContext context) {

        var opDoc = Svg.SvgDocument.Open(new System.IO.MemoryStream(System.Text.ASCIIEncoding.Default.GetBytes(context.Request.Params["svg"])));
        
        byte[] opData = null;

        using (MemoryStream opMemStream = new MemoryStream())
        {
            opDoc.Draw().Save(opMemStream, ImageFormat.Png);

            opData = opMemStream.ToArray();
        }

        context.Response.Clear();

        context.Response.AppendHeader("Content-disposition", "attachment; filename=ChartDownload.png");              
        
        context.Response.OutputStream.Write(opData, 0, opData.Length);                

        context.Response.Flush();

        context.Response.End();            
            
    }
May 11, 2012 at 1:12 PM

Ok, I did some more digging on this one and curtosy of a colleague we've worked out that the <tspan> tags are what's causing the issue here.

For the time being, we've adjusted our generation code to remove those tags, but it would be great if the renderer could cope with those.

If we amend the code to handle it (not sure we'll have time right now), I'll post the updated code back here,

Cheers,

Doug

May 12, 2012 at 2:54 AM

Hi Doug,

I think the reason why tspan does not work is that text element does not render its children. I add below in SvgText.cs to do this:

        protected override void Render(SvgRenderer renderer)
        {
            this.PushTransforms(renderer);
            this.SetClip(renderer);
            if (this.Children.Count != 0) base.RenderChildren(renderer); else base.Render(renderer);
            this.ResetClip(renderer);
            this.PopTransforms(renderer);
        }

Besides, I found the properties dx and dy  for tspan were not defined, need to add them and change X/Y properties in SvgTextSpan.cs as below:

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override SvgUnit X
        {
            get { return ((base.X.Type == SvgUnitType.None) ? new SvgUnit(ParentNode.X.Type, ParentNode.X.Value + DX.Value) : new SvgUnit(base.X.Type, base.X.Value + DX.Value)); }
            set { base.X = value; }
        }

        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override SvgUnit Y
        {
            get { return ((base.Y.Type == SvgUnitType.None) ? new SvgUnit(ParentNode.Y.Type, ParentNode.Y.Value + DY.Value) : new SvgUnit(base.Y.Type, base.Y.Value + DY.Value)); }
            set { base.Y = value; }
        }

        public SvgUnit DX { get; set; }
        public SvgUnit DY { get; set; }
        private SvgText ParentNode { get { return (SvgText) Parent; } }

I tried the the example you attached above. It seems to work well. You may try to see if it is what you want.

Vincent

May 13, 2012 at 2:31 PM

Hi Vincent,

Thanks very much for the render override and property definition examples. I've implimented them into my local version (based on 63210) but I seem to hit a null reference exception when calling 'Save()' within 'Draw()' inside SvgDocument.

Object reference not set to an instance of an object.

at System.Drawing.Graphics.set_Transform(Matrix value) at Svg.SvgRenderer.set_Transform(Matrix value) in C:\Applications\SVGRenderer\Source\SvgRenderer.cs:line 123 at Svg.SvgElement.PopTransforms(SvgRenderer renderer) in C:\Applications\SVGRenderer\Source\SvgElement.cs:line 170 at Svg.SvgText.Render(SvgRenderer renderer) in C:\Applications\SVGRenderer\Source\Text\SvgText.cs:line 291 at Svg.SvgElement.RenderChildren(SvgRenderer renderer) in C:\Applications\SVGRenderer\Source\SvgElement.cs:line 372 at Svg.SvgText.Render(SvgRenderer renderer) in C:\Applications\SVGRenderer\Source\Text\SvgText.cs:line 289 at Svg.SvgElement.RenderChildren(SvgRenderer renderer) in C:\Applications\SVGRenderer\Source\SvgElement.cs:line 372 at Svg.SvgElement.Render(SvgRenderer renderer) in C:\Applications\SVGRenderer\Source\SvgElement.cs:line 360 at Svg.SvgDocument.Draw() in C:\Applications\SVGRenderer\Source\SvgDocument.cs:line 342 at SVGHandler.ProcessRequest(HttpContext context) in c:\Applications\Document\SVGHandler.ashx:line 28 at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

 

I had a go inserting some null checks in the PopTransforms functions and in the X/Y override property and I can get past the null reference exception by altering the 'DX.Value' to (if(DX == null ? 0.0F : DX.Value)) but then I drop the majority of the chart in the output!

Were there any other changes you made to get things working your end?

Cheers,

Doug

May 16, 2012 at 11:20 AM

Hi Doug,

Lots of bug fixed but not yet in the released version. I am not sure what the problem you encountered. One possible cause could be that in push/pop transform functions, the original version did not really use a stack to keep the matrix graphics. That could cause null reference for nested push/pop when it is set to null after pop. I changed it in Svgelement.cs:

        //private Matrix _graphicsMatrix;
        private Stack _graphicsMatrixStack = new Stack(); // 1.02

//-----
protected internal virtual void PushTransforms(SvgRenderer renderer)
        {
            //_graphicsMatrix = renderer.Transform;
            _graphicsMatrixStack.Push(renderer.Transform); // 1.02

//------
protected internal virtual void PopTransforms(SvgRenderer renderer)
        {
            //renderer.Transform = _graphicsMatrix;
            renderer.Transform = _graphicsMatrixStack.Pop(); // 1.02
            //_graphicsMatrix = null;
        }

 

You may try it. I had also uploaded my complete local version (patch ID: 12212, with a viewer included). Try it if you like. (Note: this version is not an official released one, only for my own purpose, for your reference only, no garantee...) 

Vincent

 

Sep 10, 2012 at 4:19 AM

Hi Doug or Vincent,

Were you ever able to get this working?  I ran into the same series of errors.  The recommended code changes at the end didn't resolve for me the issue of the exported chart having no text.

Thanks,

Jaime