Including embedded PNG images in SVG export specified using data: urls

Hi,

I cannot manage to export image data to SVG.

I have a diagram with pictures (PNG). Because of other constraints, all the images are embedded directly in the node data, so that all the graph data is self-contained.

Example:

 {
            "key": "_invmult",
            "category": "",
            "source": "data:image/png;base64,iVBORw0KGgoAAAANSUhEU

Then the template looks like this:

let PIC = go.GraphObject.make(go.Picture, { 
                    maxSize: new go.Size(24, 24), ...
                },
                new go.Binding("source", "source"),
                new go.Binding("visible", "source", function (label) {
                    return !!label;
                }),
            )

When I do the SVG exporting the images are not included.

I read this sample: SVG Data URL | GoJS
in which an auxiliary function is used to embed an external link as a data: URL.
In my case the source is already a data: URL so I would expect it to work.

However, there is no image element generated in the SVG.

More context: I am using Puppeteer to render server-side SVGs (not sure if relevant).
I know the images are loaded correctly because I save a page screenshot and the images appear correctly.

thanks,
A.

I just modified that SVG Data URL sample so that the Picture.source property got a “data:” URL rather than the usual reference to an image file.

Then I also modified the call to Diagram.makeSvg to be:

    var svg = myDiagram.makeSvg({
      elementFinished: (graphobject, svgelement) => {
        if (!(graphobject instanceof go.Picture)) return;
        const pic = graphobject;
        if (pic.source.startsWith("data:")) {
          svgelement.setAttribute('href', pic.source);
        } else {
          toDataURL(svgelement.href.baseVal, (dataUrl) => {
            svgelement.setAttribute('href', dataUrl);
          });
        }
      }
    });

The resulting SVG images did have the data URL:

<image x="0" y="0" width="55" height="55" xlink:href="data:image/png;base64,...

But then it occurred to me that you don’t need to use that elementFinished option on Diagram.makeSvg at all. Sure enough, after commenting it out, the resulting SVG still looked correct and had the data URL embedded.

So I cannot explain your situation.

I can confirm that, for the same model, it works fine when running in a regular browser, but it doesn’t work when run in puppeteer.

Puppeteer can visualize the image internally, as seen from this page screenshot:

However, the SVG produced by GOJS does not contain an <image> tag at all.

<svg width="802px" height="402px" viewBox="0 0 802 402" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: block; letter-spacing: normal; word-spacing: normal; width: 802px; height: 402px;"><g clip-path="url(#mainClip1239)"><g class="gojs-diagram" transform="matrix(1, 0, 0, 1, 316, 171)"><g transform="matrix(1, 0, 0, 1, 16.657015484993813, 11.135874432747718)" data-class-name="Link" data-key="_fun_f_1-_sum-_fun_f_1_f_1__sum_f_1" data-from-key="_fun_f_1" data-from-port-id="f_1" data-to-key="_sum" data-to-port-id="f_1"><path stroke="#096e19" fill="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" d="M 0,0 L 5.421492257503093,0 Q 10.842984515006187,0 10.842984515006187,5.4214922575030915 L 10.842984515006187,8.317937216373858 Q 10.842984515006187,16.635874432747713 19.160921731380043,16.635874432747713 L 57.17889659573698,16.635874432747713" transform="matrix(1, 0, 0, 1, 0.5, 0.5)"></path></g><g transform="matrix(1, 0, 0, 1, 16.790217084114907, 35.52065023268293)" data-class-name="Link" data-key="_fun_f_2-_sum-_fun_f_2_f_2__sum_f_2" data-from-key="_fun_f_2" data-from-port-id="f_2" data-to-key="_sum" data-to-port-id="f_2"><path stroke="#096e19" fill="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" d="M 0,8.88697306556022 L 5.354891457942546,8.88697306556022 Q 10.709782915885093,8.88697306556022 10.709782915885093,14.241864523502763 L 10.709782915885093,16.433161416438644 Q 10.709782915885093,23.979349767317068 18.255971266763517,23.979349767317068 L 40.70978291588509,23.979349767317068 Q 50.70978291588509,23.979349767317068 50.70978291588509,13.979349767317068 L 50.70978291588509,3.1679560403653966 Q 50.70978291588509,0 53.87773895625049,0 L 57.045694996615886,0" transform="matrix(1, 0, 0, 1, 0.5, 0.5)"></path></g><g transform="matrix(1, 0, 0, 1, 97.8359120807308, 27.771748865495432)" data-class-name="Link" data-key="_sum-_res_r-_sum__result__res_r_r" data-from-key="_sum" data-from-port-id="_result" data-to-key="_res_r" data-to-port-id="r"><path stroke="#800400" fill="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="3,3" stroke-dashoffset="0" d="M 0,3.87445068359375 L 8.062774658203125,3.87445068359375 Q 10,3.87445068359375 10,1.937225341796875 L 10,1.937225341796875 Q 10,0 11.937225341796875,0 L 57.04569499661591,0" transform="matrix(1, 0, 0, 1, 0.5, 0.5)"></path></g><g transform="matrix(1, 0, 0, 1, 65.05164083326889, 3.113026934439783)" data-class-name="Group" data-key=""><g transform="matrix(1, 0, 0, 1, 0, 7.7489013671875)"><path stroke="black" fill="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" d="M 10,0 L 31.56854249492381,0 C 36.04569499661588,0 41.56854249492381,5.522847498307936 41.56854249492381,10 L 41.56854249492381,31.568542494923804 C 41.56854249492381,36.045694996615865 36.04569499661588,41.568542494923804 31.56854249492381,41.568542494923804 L 10,41.568542494923804 C 5.522847498307936,41.568542494923804 0,36.045694996615865 0,31.568542494923804 L 0,10 C 0,5.522847498307936 5.522847498307936,0 10,0 z" transform="matrix(1, 0, 0, 1, 0.5, 0.5)"></path><g transform="matrix(1, 0, 0, 1, 6.022847498307938, 6.022847498307932)"></g></g></g><g transform="matrix(1, 0, 0, 1, 0.13320159912109375, 0)" data-class-name="Node" data-key="_fun_f_1"><g transform="matrix(1, 0, 0, 1, 2.761423749153969, 2.761423749153968)"><g transform="matrix(1, 0, 0, 1, 0, 0)" data-port-id="f_1" data-item-index="0"><text x="4.26239013671875" y="5.811676025390625" style="font: 5pt  STIX Two Math, STIX Two Text, Cambria, serif" text-anchor="end" fill="#096e19" transform="matrix(1, 0, 0, 1, 5, 5)">f₁</text></g></g></g><g transform="matrix(1, 0, 0, 1, 0, 33.27174886549543)" data-class-name="Node" data-key="_fun_f_2"><g transform="matrix(1, 0, 0, 1, 2.761423749153969, 2.761423749153968)"><g transform="matrix(1, 0, 0, 1, 0, 0)" data-port-id="f_2" data-item-index="0"><text x="4.5287933349609375" y="5.811676025390625" style="font: 5pt  STIX Two Math, STIX Two Text, Cambria, serif" text-anchor="end" fill="#096e19" transform="matrix(1, 0, 0, 1, 5, 5)">f₂</text></g></g></g><g transform="matrix(1, 0, 0, 1, 152.62018332819272, 16.635874432747716)" data-class-name="Node" data-key="_res_r"><g transform="matrix(1, 0, 0, 1, 2.761423749153968, 2.761423749153968)"><g transform="matrix(1, 0, 0, 1, 0, 0)" data-port-id="r" data-item-index="0"><text x="0" y="5.811676025390625" style="font: 5pt  STIX Two Math, STIX Two Text, Cambria, serif" text-anchor="start" fill="#800400" transform="matrix(1, 0, 0, 1, 5, 5)">r</text></g></g></g><g transform="matrix(1, 0, 0, 1, 71.07448833157683, 16.884775799935216)" data-class-name="Node" data-key="_sum"><g transform="matrix(1, 0, 0, 1, 0, 0)"><g transform="matrix(1, 0, 0, 1, 0, 0)"><path stroke="black" fill="white" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" d="M 5,0 L 24.522847498307936,0 C 26.76142374915397,0 29.522847498307936,2.761423749153968 29.522847498307936,5 L 29.522847498307936,24.522847498307936 C 29.522847498307936,26.76142374915397 26.76142374915397,29.522847498307936 24.522847498307936,29.522847498307936 L 5,29.522847498307936 C 2.761423749153968,29.522847498307936 0,26.76142374915397 0,24.522847498307936 L 0,5 C 0,2.761423749153968 2.761423749153968,0 5,0 z" transform="matrix(1, 0, 0, 1, 0.5, 0.5)"></path><g transform="matrix(1, 0, 0, 1, 3.261423749153968, 3.261423749153968)"><g transform="matrix(1, 0, 0, 1, 0, 4.2510986328125)"><g transform="matrix(1, 0, 0, 1, 0, 0)" data-port-id="f_1" data-item-index="0"></g><g transform="matrix(1, 0, 0, 1, 0, 7.7489013671875)" data-port-id="f_2" data-item-index="1"></g></g><g class="gojs-ts"></g><g transform="matrix(1, 0, 0, 1, 24, 8.12554931640625)"><g transform="matrix(1, 0, 0, 1, 0, 0)" data-port-id="_result" data-item-index="0"></g></g></g></g><g class="gojs-ts"></g></g></g></g><g transform="matrix(1, 0, 0, 1, 316, 171)"></g></g><clipPath id="mainClip1239"><rect x="0" y="0" width="802px" height="402px"></rect></clipPath></svg>

I’m trying to reproduce the problem. Precisely which version of GoJS are you using?

I am using

https://unpkg.com/gojs

(modifying the puppeteer example on the website)

@walter I can send you a complete reproducible example via e-mail, but I prefer not to post it here publicly.

Sure, just send it to GoJS at our domain, nwoods.com.