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:

You solutioned this ? i am meetting the problem too。i am getting the ArrayBuffer but it can’t be as a show in website tag

can glb export *.ai file ?

Its been long time i worked on the project, but i gonna start again.
I ended up customising importer and exporter (to save) … this helps me in finer managing of image/media data, like storing them seperately also having a Uri of each image (which guessing you want to use in a image tag) …

This is the way i would do it :slightly_smiling_face:

Thank you also , The code worked!! in image tag

				Promise.all(bufferPromises).then((buffers) => {  
					var arrayBufferView = new Uint8Array( buffers[0]);
					var blob = new Blob( [ arrayBufferView ], { type: "image/png" } );
					var urlCreator = window.URL || window.webkitURL;
					var imageUrl = urlCreator.createObjectURL( blob );
					var image = document.getElementById('image');
					image.src = imageUrl;  
				});

Hello,
I am trying to do something similar, when I load my model everything is fine with all materials,
My need is to get the path || the data of all the images related to the specific material (map, normalMap, etc …), if I try this snipped I get an error and if I check that no bufferView is present inside “parser.json.images”, only

  • first name
  • mime type
  • uri
    but without any association

I’m loading the Gltf model compressed with draco and generated with blender

Can you guys help me to get it done?
Thanks in advice
C