Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The reference information regarding the use of cgltf_load_buffer_base64 is unclear #194

Open
b1skit opened this issue Dec 25, 2022 · 0 comments

Comments

@b1skit
Copy link

b1skit commented Dec 25, 2022

The "Reference" section at the head of cgltf.h states:

 * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options,
 * cgltf_size size, const char* base64, void** out_data)` decodes
 * base64-encoded data content. Used internally by `cgltf_load_buffers()`.
 * This is useful when decoding data URIs in images.

This information is incomplete, and doesn't fully explain the usage of this function. Calling this function requires computation of some parameter values that are not immediately obvious to the user.

Google's filament parseDataUri function demonstrates successful usage of this function to load base64 texture data embedded in a URI:

 // Parses a data URI and returns a blob that gets malloc'd in cgltf, which the caller must free.  
// (implementation snarfed from meshoptimizer)  
static const uint8_t* parseDataUri(const char* uri, std::string* mimeType, size_t* psize) {  
    if (strncmp(uri, "data:", 5) != 0) {  
        return nullptr;  
    }  
    const char* comma = strchr(uri, ',');  
    if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0) {
        const char* base64 = comma + 1;
        const size_t base64Size = strlen(base64);
        size_t size = base64Size - base64Size / 4;
        if (base64Size >= 2) {
            size -= base64[base64Size - 2] == '=';
            size -= base64[base64Size - 1] == '=';
        }
        void* data = 0;
        cgltf_options options = {};
        cgltf_result result = cgltf_load_buffer_base64(&options, size, base64, &data);
        if (result != cgltf_result_success) {
            return nullptr;
        }
        *mimeType = std::string(uri + 5, comma - 7);
        *psize = size;
        return (const uint8_t*) data;
    }
    return nullptr;
}

For reference, their implementation of parseDataUri can be found here (line 285):
https://github.com/google/filament/blob/676694e4589dca55c1cdbbb669cf3dba0e2b576f/libs/gltfio/src/ResourceLoader.cpp

Notice how calling cgltf_load_buffer_base64 requires

  • offsetting a pointer to the first character following a ',' (comma character) (const char* base64)
  • Computing the length of the string following this pointer (base64Size)
  • Dividing base64Size by 4 (size)
  • Decrementing size based on the existence of '=' characters at specific locations in the uri string

This operations may be straightforward to users with knowledge of base64 encoding, but for others (such as myself) it's difficult to use.

As a solution, I'd recommend a combination of the following:

  • Update the documentation in the "Reference" section of cgltf.h to provide explicit instructions for decoding base64 data embedded in a uri using cgltf_load_buffer_base64, and/or a demonstration of this usage
  • Writing a helper function to handle the computation of these values automatically, allowing users to pass the provided raw uri string directly into a function that unpacks the data for them

I'd offer to do this myself, but unfortunately I'm not familiar with base64 and only figured out how to use this feature by cribbing from the filament example above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant