Juce::image support for svg files for sprite / filmstrip functionality

I am trying to make a custom component based on an image sprite. My image is an SVG file. I am able to display my complete SVG correctly using a juce::Drawable object or a DrawableImage object. However the juce graphics object expects an Image to draw part of the image based on examples on this forum.

I have tried loading my SVG in an image object. But it does not seem to display the image. Things work fine for a PNG.

So here is my question - Does juce::Image support SVG files and is there any place in the documentation where the supported formats are mentioned?

Curiously, Drawable is the only thing in Juce that can parse SVG files, Image or ImageFileFormat do not handle it. Through the years, there has been some discussion that the SVG parsing should be separated from the Drawables, but it has not yet happened.

Thats a shame. But I am happy this was not something I was doing wrong. I believe the trend is to use more and more vector images, so it will be good if JUCE adds more SVG support.

This may not help, but if your SVG is a simple path, you can use the Drawable to turn it into a juce::Path and then draw that any place you can draw a path, apply transforms to it, etc.

std::unique_ptr<Drawable> createDrawableFromSVG (const char* data)
{
    auto xml = parseXML (data);
    jassert (xml != nullptr);
    return Drawable::createFromSVG (*xml);
}

Example using it to draw a triangle on a ComboBox:

        std::unique_ptr<Drawable> d = createDrawableFromSVG(BinaryData::triangleDown_svg);
        Path p = d->getOutlineAsPath();
        p.applyTransform (AffineTransform::scale(0.8f));
        p.applyTransform (AffineTransform::translation((float) bounds.getWidth() - 10, (float) (buttonH / 2) - 1));
        
        g.setColour(box.findColour(ComboBox::arrowColourId).withMultipliedAlpha(box.isEnabled() ? 1.0f : ad->disabledIncDecAlpha));
        g.fillPath(p);

It’s probably not useful for complex SVGs, but I thought I’d mention it. :slight_smile:

I believe that’s because of the implicit distinction between vector images (SVG, handled with Drawable), and raster/bitmap images (handled with Image)

To @RagsInRags : it’s fairly easy to obtain an Image from a Drawable. Create an empty Image of the desired size, then create a Graphics object on it (that’s necessary for drawing onto the empty image), then use any of the Drawable::draw...() functions to draw the Drawable onto the Graphics (which in turn will paint it onto the underlying Image that you created).

2 Likes

Thanks yfede. for now I have managed to create simple controls based on the Drawable and completed by UI.

I thought the whole point of SVG was to have the image scaled. With your approach, I assume I will need to update the Image on resize?. Will check it out at the next logical point.

Ah yes, the procedure I described is for obtaining a bitmap picture of known fixed size from a Drawable.

If you want to use Drawables to render resizable Components, I believe the best approach is to do so by overriding their paint() function or the virtual methods provided by the LookAndFeel that deal with drawing the kind of Component you want.

In both cases, those methods receive a reference to a Graphics object, and you can use that as the first argument for all the Drawable::draw...() functions that you can call to draw the Drawables directly inside the Component area, at its current size.