Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions tests/tester.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1247,3 +1247,48 @@ TEST_CASE("empty-images-not-written", "[issue-495]") {
// WriteImageData should be invoked for both images
CHECK(counter == 2);
}

TEST_CASE("images-data-uri-lost", "[issue-497]") {
std::string err;
std::string warn;
tinygltf::Model model;
tinygltf::TinyGLTF ctx;

// First, load a model that has images
tinygltf::Model modelWithExternalURIs;
bool ok = ctx.LoadASCIIFromFile(&modelWithExternalURIs, &err, &warn, "../models/Cube/Cube.gltf");
REQUIRE(ok);
REQUIRE(err.empty());
REQUIRE(warn.empty());

// Write as GLB and embed the images as data URIs
ok = ctx.WriteGltfSceneToFile(&modelWithExternalURIs, "issue-497.glb", true, true, false, true);
REQUIRE(ok);

// Now load the GLB with the data URI images.
// Use a custom image loader that does not load any image data.
ctx.SetImageLoader(LoadImageData, nullptr);
ok = ctx.LoadBinaryFromFile(&model, &err, &warn, "issue-497.glb");
REQUIRE(ok);
REQUIRE(err.empty());
REQUIRE(warn.empty());

// Now check the images of the model
CHECK(model.images.size() == 2);
for (const auto& image : model.images) {
// No data loaded or decoded
CHECK(image.image.empty());
// The URI is kept
CHECK_FALSE(image.uri.empty());
// The URI should be a data URI
CHECK(image.uri.find("data:") == 0);
}

// Now write the model with the data URIs
int counter = 0;
ctx.SetImageWriter(WriteImageData, &counter);
ok = ctx.WriteGltfSceneToFile(&model, "issue-497-data-uris.gltf");
CHECK(ok);
// WriteImageData should not have been invoked for the data URIs
CHECK(counter == 0);
}
31 changes: 21 additions & 10 deletions tiny_gltf.h
Original file line number Diff line number Diff line change
Expand Up @@ -3293,15 +3293,17 @@ static bool UpdateImageObject(const Image &image, std::string &baseDir,
void *user_data, std::string *out_uri) {
std::string filename;
std::string ext;
// If image has uri, use it as a filename
if (image.uri.size()) {
std::string decoded_uri;
if (!uri_cb->decode(image.uri, &decoded_uri, uri_cb->user_data)) {
// A decode failure results in a failure to write the gltf.
return false;
// If image has a uri, and it is not a data uri, use it as filename
if (!image.uri.empty()) {
if (!IsDataURI(image.uri)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we can end up here with a data URI, so protect against that case

std::string decoded_uri;
if (!uri_cb->decode(image.uri, &decoded_uri, uri_cb->user_data)) {
// A decode failure results in a failure to write the gltf.
return false;
}
filename = GetBaseFilename(decoded_uri);
ext = GetFilePathExtension(filename);
}
filename = GetBaseFilename(decoded_uri);
ext = GetFilePathExtension(filename);
} else if (image.bufferView != -1) {
// If there's no URI and the data exists in a buffer,
// don't change properties or write images
Expand Down Expand Up @@ -4442,8 +4444,17 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
return false;
}

return LoadImageData(image, image_idx, err, warn, 0, 0, &img.at(0),
static_cast<int>(img.size()), load_image_user_data);
bool ok = LoadImageData(image, image_idx, err, warn, 0, 0, &img.at(0),
static_cast<int>(img.size()), load_image_user_data);

// If the image is encoded as data URI, and the actual image data was
// not extracted, then we keep the original data URI that holds all
// the data.
if (IsDataURI(uri) && ok && image->image.empty()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the uri only if the data has not been loaded. Otherwise we have it in memory twice.

image->uri = uri;
}

return ok;
}

static bool ParseTexture(Texture *texture, std::string *err,
Expand Down