How to get texture file bytes embedded in GLB after loading it in the scene via GLTFLoader?

Hello,

I’m trying to access textures image files that are embedded inside a GLB file.
The model, material and texture loads successfully and is visible in the scene, but how can I access the texture image file from a material of a model in the GLB file?
I’m accessing the image property of the material like this: material.map.image. This image has a src property which just contains a reference to an blob object url. And I’m unable to access the blob data via that url, it always results in file not found error.
Please note I’m trying to get the actual image file bytes, including content type and instead of just the image data bytes (so drawing the texture to a canvas and reading pixel data from it wouldn’t be sufficient).

Any idea how I would get to this data?
Maybe I could access the gltf image data via the GLTFLoader and its parse function, but then I would have to re-link it to the correct reference…

Something like this should work:

loader.load('model.glb', (gltf) => {
  const parser = gltf.parser;
  const bufferPromises = parser.json.images.map((imageDef) => {
    return parser.getDependency('bufferView', imageDef.bufferView));
  });
  Promise.all(bufferPromises).then((buffers) => {
    console.log(buffers); // Array<ArrayBuffer>
  });
});

The Blob URLs don’t work because GLTFLoader revokes them after it’s done loading to clean up resources: https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/GLTFLoader.js#L2077.

1 Like

Thank you @donmccurdy , this worked!!!

I was facing the exact problem and did get the issue but was not able to get the solution. Did not want to copy the image data and reencode!
Just for information:

  1. how do we associate the image in the scene to the buffer we got here???

  2. the buffers are encoded jpeg/png data … right? (just checked … it is)
    imageDef.name for name
    imageDef.mimeType for mime type
    imageDef.bufferView for index of the buffer
    [for others facing the issue]

  3. Why does the gltf loader does this i.e. revoke URI?
    How exactly does the renderer get the image data, if the image is revoked of uri?

  4. will be doing

    var blob = new Blob( [ parser.getDependency(‘bufferView’, imageDef.bufferView)) ], { type: imageDef.mimeType } );
    sourceURI = URL.createObjectURL( blob );

and resetting the images after getting the scene, any other way to work on it?

how do we associate the image in the scene to the buffer we got here???

Revoking the URI does not destroy the image data. Once the image has been loaded the URI is not needed, and can be cleaned up.

how do we associate the image in the scene to the buffer we got here?

If you want a Texture to put into the scene, then you’ll have an easier time requesting that from the parser rather than an ArrayBuffer:

console.log( parser.json.textures );
const texture = await parser.getDependency( 'texture', 0 /* textureIndex */ );

Or, if you have a URI from a Blob:

const sourceURI = URL.createObjectURL( blob );
const texture = new TextureLoader().load( sourceURI );
texture.flipY = false;

The first example is easier, because it will configure the texture for you. Otherwise you need to set flipY and perhaps other settings, which require some knowledge beforehand.

I mean i wanted the link between Texture and the encoded image(s) … getting texture using getDependency, you get a fully initialized Texture with direct link to image(s) (which only has decoded image data bites), actual encoded image is lost after parsing

so one way is to turn off revokeURL :grin:, by commenting it out in GLTFImporter, so now we have aa working URI which helps in giving the relationship between texture and images and the image file data itself after the parsing.

The scene would have to be exported again and this relation ha to be maintained externally again (as images dont have uuid),

as it is now if we export using gltf or toJSON, and if there are two textures using one image, we would eventually get two images in export one for each textures, which is an issue for here.

just an update:
there are three images in the glt file, but when imported to a scene there are 5 different URI,
i did check the images uri, while they are 5 different urls but the actual content of two of those are repeated.
Also when i see the number of textures i see 3 different texture but when converted to scene there are 5, two extra (based on uuid)

Should i move it to a different thread?

You’ll need to share a demo or complete code to reproduce this, I don’t know what you’re asking sorry.

ok, let me see if i can make a demo
Thanks for the help otherwise tho :slightly_smiling_face: