Binary Resource Tutorial

Hello! Are there any resources for learning how to access and use assets that are bundled together as binary data (specifically in visual studio if that matters).
I see quite a few references to using BinaryData but I haven’t run into any clear examples and I don’t see it mentioned in the JUCE: Class Index so maybe it’s depreciated?

I’m sure I’m overlooking them or I’m using the wrong words in my google searches
Thanks

A couple threads.

These resources are added in the Projucer which creates the BinaryData h/cpp to access in code.

https://juce.com/discover/stories/projucer-manual

See; 5.2 File Explorer Folder Settings

Binary Resource - The file is added as a binary resource in your executable. Counts towards your platform-specific binary app size limits.

Thanks @TeotiGraphix

I believe I was missing some fundamental aspects of BinaryData that were just assumed knowledge. After tracking down some example usage, I have a better understanding of BinaryData and how to use it. I’ll add these notes here for any future-self’s that aren’t sure where to start.

First off, BinaryData is code generated by the Projucer based on files that the user has added and checked the “Binary Resources” option in the Projucer’s File Explorer. Therefore, BinaryData is NOT a JUCE module and that explains why there is no API documentation for it in the JUCE Class Index.

It does have some standard variables and functions available though

// Number of elements in the namedResourceList and originalFileNames arrays.
const int namedResourceListSize = 33; // value depends on # of files you've added

// Points to the start of a list of resource names.
extern const char* namedResourceList[];

// Points to the start of a list of resource filenames.
extern const char* originalFilenames[];

// If you provide the name of one of the binary resource variables above, this function will
// return the corresponding data and its size (or a null pointer if the name isn't found).
const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes);

// If you provide the name of one of the binary resource variables above, this function will
// return the corresponding original, non-mangled filename (or a null pointer if the name isn't found).
const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8);

You don’t have to explicitly import BinaryData. just access the variables and functions directly.

ie,

char* firstItem = BinaryData::namedResourceList[0];
// or 
char* firstItem = BinaryData::example_test_txt
3 Likes

Sorry to bump this old post. I generated my BinaryData using the BindaryBuilder and the created BinaryData.h file does not contain the definitions of namedResourceListSize, namedResourceList, originalFilenames, getNamedResource and getNamedReourceOriginalFilename but it only contains the definitions of the assets that I added and their size. Why are those definitions missing?

Taking a quick look at the code, those don’t get added by BinaryBuilder, they are added by Projucer when it creates the BinaryData files. There is a class, called ResourceFile (in extras\Build\juce_build_tools\utils\juce_BinaryResourceFile.cpp) which does all the heavy lifting. I don’t know what is best practice to generate that code if you aren’t using Projucer, so I can’t offer more than the results of my detective work.

That’s what I noticed too when looking at the BinaryBuilder source code. I’m still using the Projucer but I’d like to switch to CMake sometime, so it would be nice if the BinaryData generated with the 2 methods would be identical, I wonder why that’s not the case.

1 Like

I wondered that exact thing when looking into this. Best of luck. I want to move to cmake too, so I hope there is a solution. If nothing else, since the source code is available, one could write their own tool. :nerd_face:

I haven’t tried it yet, but there is a juce_add_binary_data module for CMake that might do the trick. Otherwise the functionalities should be in juce_BinaryResourceFile.h/cpp and can just be replicated.

2 Likes

Just out of interest, what real-world uses cases do you have for those name lists and functions taking the file name? All the time working with binary data I always accessed the assets directly like e.g.

auto fooImage = juce::ImageFileFormat::loadFrom (BinaryData::foo_png, BinaryData::foo_pngSize);
auto barImage = juce::ImageFileFormat::loadFrom (BinaryData::bar_png, BinaryData::bar_pngSize);

I was figuring out how to write a cross platform presets. While checking out some open source projects I noticed those lists and functions used to loop through the presets I guess stored in the BinaryData.

Ah I see. We usually take a hand written std::map for stuff like that.

Example code modern C++ 20 features

struct PresetManager
{
    static inline const std::map<std::string_view, std::span<const char>> presets
    {
        {"Preset 1", { BinaryData::preset1_bin, size_t (BinaryData::preset1_binSize) }},
        {"Preset 2", { BinaryData::preset2_bin, size_t (BinaryData::preset2_binSize) }},
        {"Preset 3", { BinaryData::preset3_bin, size_t (BinaryData::preset3_binSize) }}
    };

    static std::span<const char> getPresetWithName (std::string_view name)
    {
        return presets.at (name);
    }

    static void printAllPresets()
    {
        for (const auto& [name, data] : presets)
            std::cout << name << std::endl;
    }
};

I think it’s reasonable to keep a list like that up to date manually and using containers like e.g. std::map here gives you a lot of convenient functionality out of the box. Note that the code above could of course be rewritten using some JUCE classes – this was just a quick sketch that should compile on compiler explorer