Drawable::createFromSVG with text?



I am able to create and display a Drawable from my svg via Drawable::createFromSVG.

The Drawable seems to render correctly but without any text the svg contains.

The svg is created with Adobe Illustrator. I also checked to add a text with InkScape with the same result.

The text itself is nothing fancy:













or created dy Illustrator:


   transform="matrix(1 0 0 1 965.827 94.5257)"




I tried leaving out or changing the font-family. But no change.

Any idea whats going wrong here? Is svg text rendering supported at all?




No, SVG text rendering isn't supported - the spec for text rendering is huge, and I just didn't have time to implement it!


thanks, Jules,

yes, I figured by looking at the code. Maybe I implement a rudimentary text parser. I just need to place labels on my controls.

Speaking of controls: Currently parseSVGElement prevents the creation of a Drawable from a svg subtree by checking with hasTagNameIgnoringNamespace for a "svg" tag.

By using svg subtrees we can streamline the GUI creation by having the Graphic Designer placing all controls in a single svg, which then gets generically parsed by our software so that corresponding controls are created and attached.




Yes, but technically I don't think that a sub-tree of an SVG is valid SVG, so I think the parser is correct to reject it.. (My memory of the details of SVG is a bit vague though, so correct me if I'm wrong about that!)


I just start to dig into svg myself. You are probably right that not all subtree's are valid svgs itself. (i.e. if referencing "url"s=others parts of the svg), but when taking care it can work. Probably not a general feature though, so rejecting it is probably right.


I see that you already started a

Drawable* parseText (const XmlPath& xml)

and that the use of the Path class is prepared. Did you plan (or would you suggest) to render text as a path? Or the other way around can a path be used on DrawableText objects?

For rudimentary text support I thought of adding text as DrawableText. But I wouldnt see the use of the Path?


I guess that

Array <float> xCoords, yCoords, dxCoords, dyCoords;

getCoordList (xCoords, getInheritedAttribute (xml, "x"), true, true);
getCoordList (yCoords, getInheritedAttribute (xml, "y"), true, false);
getCoordList (dxCoords, getInheritedAttribute (xml, "dx"), true, true);
getCoordList (dyCoords, getInheritedAttribute (xml, "dy"), true, false);

retrieves the origins of the relative coords (if there are any) from parent objects?



OK. I have an implementation for my purpose.

Would you be interested in my implementation and how shoud/can I provide it to you?


One thing though: Currently I had to hardcode a font size factor:

It looks like the font size is not correctly translated. Its about 20% smaller than the InkScape fonts. It looks svg gives the size in Point. Maybe there is a translation to pixel needed?



Sounds interesting, I'd like to take a look at what you've done if you like.

Perhaps for fonts the method you were looking for is use Font::withPointHeight() ?


OK, after squinting on the svg specs I have to admit following really is only a starting point to display the specific Illustrator output my Graphic Designer is delivering to me (./modules/juce_gui_basics/drawables/juce_SVGParser.cpp):

    Drawable* parseText (const XmlPath& xml)
        Array <float> xCoords, yCoords, dxCoords, dyCoords;
        getCoordList (xCoords, getInheritedAttribute (xml, "x"), true, true);
        getCoordList (yCoords, getInheritedAttribute (xml, "y"), true, false);
        getCoordList (dxCoords, getInheritedAttribute (xml, "dx"), true, true);
        getCoordList (dyCoords, getInheritedAttribute (xml, "dy"), true, false);

        DrawableComposite* const drawable = new DrawableComposite();

        drawable->setComponentID (xml->getStringAttribute ("id"));

        //xxx not done text yet!
        forEachXmlChildElement (*xml, e)
            if (e->isTextElement())
                DrawableText* text = new DrawableText();
                String string = e->getText();
                Font font(
                    xml->getStringAttribute ("font-family", Font::getDefaultSansSerifFontName()).
                    xml->getStringAttribute ("font-style", Font::getDefaultStyle()).
                    xml->getDoubleAttribute ("font-size", 12)*1.2);
                text->setFont (font,true);
                float x = xml->getDoubleAttribute ("x",0);
                float y = xml->getDoubleAttribute ("y",0)-font.getAscent();
                if (xml->hasAttribute ("transform"))
                    AffineTransform transform = parseTransform (xml->getStringAttribute ("transform"));
                    text->setTransform (transform);
                    transform.transformPoint (x,y);
                if (xml->hasAttribute ("fill"))
                    text->setColour (Colour (0xff000000|
                        xml->getStringAttribute ("fill").trimCharactersAtStart("#").getHexValue32()));
                text->setBoundingBox (Rectangle<float> (x,y,font.getStringWidth (string),font.getHeight()));
                text->setText (string);
    e->getText()<<" ("<<x<<", "<<y<<", "<<
    font.getTypefaceName()<<", "<<
    font.getTypefaceStyle()<<", "<<
    font.getHeight()<<", "<<
//std::clog<<"x:";for(auto&coord:xCoords)std::clog<<coord<<", ";std::clog<<std::endl;
//std::clog<<"y:";for(auto&coord:yCoords)std::clog<<coord<<", ";std::clog<<std::endl;
//std::clog<<"dx:";for(auto&coord:dxCoords)std::clog<<coord<<", ";std::clog<<std::endl;
//std::clog<<"dy:";for(auto&coord:dyCoords)std::clog<<coord<<", ";std::clog<<std::endl;
                drawable->addAndMakeVisible (text);
            else if (e->hasTagNameIgnoringNamespace ("tspan"))
                drawable->addAndMakeVisible (parseText (xml.getChild (e)));
        return drawable;

One probably should take advantage of the existing parse path functions, but currently this only serves as a proof of concept to create my GUI. With advancing the GUI requirements this could advance as well. Also the parent coords are not used yet. Before putting in more effort I would like to hear if this is principal the right approach.




Well, it's a start, though I can immediately see lots of issues that would need to be fixed.. I don't have time to commit to it at the moment, but if you keep working on it, keep me posted!