Set image as texture from JSZip

Hey i’m currently trying to set a image, which i unzipped with JSZip as a texture of my material.

But im failing to set the image blob as content in the Texture.

Here’s what i have so far:

Ui.prototype.handleZipFile = function(data) {
    var that = this;
    JSZip.loadAsync(data).then(function(zip) {
        zip.file("Skin_B.png").async("arraybuffer").then(function(content) {
            var blob = new Blob([content], {'type': 'image/png'});
            var img = document.createElement('img');
            img.width = 256;
            img.height = 256;
            img.style.position = 'absolute';
            img.style.top = '0px';
            img.style.left = '256px';
            img.src = URL.createObjectURL(blob);
            document.body.appendChild(img);
            
            var texture = new pc.Texture(that.app.graphicsDevice);
            texture.setSource(URL.createObjectURL(blob));
            
            that.base.resource.diffuseMap = texture;
            that.base.resource.update();
        });
        //zip.forEach(function (relativePath, zipEntry) {
        //    console.log(zipEntry);
        //});
    }, function (e) {
        console.log("Error reading " + f.name + ": " + e.message);
    });
};

The texture does correctly show up in the img element i’m creating for debug purposes. But when updating the material it just shows black.

Also i’m not sure if i should just create and set the texture directly as i’m doing right now. Or should add the texture to the asset registry.

Well sometimes you just have to have a look at the docs.

setSource: Set the pixel data of the texture from a canvas, image, video DOM element. If the texture is a cubemap, the supplied source must be an array of 6 canvases, images or videos.

This works:

Ui.prototype.handleZipFile = function(data) {
    var that = this;
    JSZip.loadAsync(data).then(function(zip) {
        zip.file("Skin_B.png").async("arraybuffer").then(function(content) {
            var blob = new Blob([content], {'type': 'image/png'});
            var img = document.createElement('img');
            img.width = 256;
            img.height = 256;
            img.style.position = 'absolute';
            img.style.top = '0px';
            img.style.left = '256px';
            img.onload = function () {
                var texture = new pc.Texture(that.app.graphicsDevice);
                texture.setSource(img);

                that.base.resource.diffuseMap = texture;
                that.base.resource.update();
            };
            img.src = URL.createObjectURL(blob);
            document.body.appendChild(img);
        });
        //zip.forEach(function (relativePath, zipEntry) {
        //    console.log(zipEntry);
        //});
    }, function (e) {
        console.log("Error reading " + f.name + ": " + e.message);
    });
};

Is this the supposed way to handle it?

It will probably be easier to use the asset registry’s loadByUrl function

var url = URL.createObjectURL(blob);
app.assets.loadFromUrl(url, "texture", function (err, asset) {
    var texture = asset.resource;
});

Also, remember to call URL.revokeObjectURL() when loading is done.

4 Likes

If the asset is created by the asset registry, can i then directly revoke the object URL or keeps the asset registry a reference to it?

Like so:

var url = URL.createObjectURL(blob);
app.assets.loadFromUrl(url, "texture", function (err, asset) {
    URL.revokeObjectURL(url);
    var texture = asset.resource;
});

You can directly revoke it IIRC.