jkuhlmann / cgltf

:diamond_shape_with_a_dot_inside: Single-file glTF 2.0 loader and writer written in C99

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The reference information regarding the use of cgltf_load_buffer_base64 is unclear

b1skit opened this issue · comments

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.