Loading local images as texture

Hello there,

I need a way to open a local html file and display Babylon content like textures and gltf meshes inside it. I dont want to open the html file with a local webserver if possible. I know it is not possible to access local files because you run into CORs errors because of browser security, but I can display multiple local images as img tag inside my html file and I wont run into CORs problems.

This piece of code displays the correct image when I open the html file
<img :src="require('@/assets/Map.png')" alt="">

When I try to load the texture through an assetmanager I get the error: “Error while trying to load image” which is caused by CORs.
assetManager.addTextureTask("Texture1", require('@/assets/Map.png'));

Can someone explain why I wont get CORs problems when I try to display the img inside html but as soon as I use the same img in babylon I get errors?

Thanks in advance

cors errors would mean they are served from a different server than the app is running on.

@sebavan
Sadly, Mixing protocols is considered different origins since chrome 76. For ex, if you right click a html file and copy the url path and then paste it into a browser, some browser apis stop working. Fetch for sure, i think dynamic import and worker modules too, among others.

@Simon_Weck
Are you loading babylon from a cdn? Mixing http/https with (implicit) file protocol loading is probably a no go.

You can definitely make this work though. Babylon accepts objects not just string urls so you can get a reference to it whatever way you find easiest. If all else fails, you can manually inline the assets as string base64 data uris. Ive been meaning to test some things in electron related to using file protocols, maybe i will work on that later and report back. (I have been using electron’s loadFile api to develop for years)

Notes for future me:
.Local caching using IndexedDB
. Using rel="preload" with SceneLoader

1 Like

There is Chrome extension - Allow CORS: Access-Control-Allow-Origin - Chrome Web Store - which may solve somehow your problem.

@jeremy-coleman
I load Babylon through npm. Base64 is possible but I have a lot of files I have to integrate and converting them all takes too much time.

@labris
Thats a good fallback but I try to make it work without any extra software

Is there is a way creating the Babylon Texture out of the html img tag, beacuse the html img tag can load the img?

img tags do not follow the exact same policy.

CORS despite being a tad annoying are for the best. You should simply either allow cors on your server or place the resources under the same endpoint.

1 Like

Hello!
I’d like to add some information. If you create the img tag dynamically you have to set CORS rules on your server as @sebavan mentioned and you need to set the crossOrigin property on the img tag as follows:

const texture = new BABYLON.DynamicTexture("dynamicTexture", { width, height }, scene);
const textureContext = texture.getContext();

const img= new Image();
img.crossOrigin = "anonymous"
img.src = 'https://playgrounds.babylonjs.xyz/bjs-logo.png';
img.onload = function () {
  //Add image to dynamic texture
  textureContext.drawImage(img, x, y);
}

If you are on Apache just add this to your .htaccess file in the directory you want to access without CORS:

Header set Access-Control-Allow-Origin "*"
1 Like

Hes not using a server:)

@Simon_Weck
Curious, what is your use case? Im guessing an art installation or secure/offline data dashboard? Or just like a pi at your home? Importantly, Is your device connected to the internet?

I thought opening chrome with --disable-web-security should disable cors constraints, but i just tried it and it doesnt. Also note that some command line args to chromium make the changes permanent, and you definitely dont want that as a permanent setting. Electron has a setting when you create your window to disable web security, sandboxing, etc. Electron is actually probably a better choice than chrome for what you’re trying to do.

Still trying though.
Currently trying to use a meta tag in head to define a csp manually, something like <meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'unsafe-inline'; img-src *; ">

Iframes also have a .csp property you can use.

Notes:
directives
.Content Security Policy Level 3
values?

.Fetch Standard
request properties

1 Like

Btw, anyone interested can use this node script to open chrome on windows at least. copy paste into a file and run it with node from the command prompt

function open(fd) {
  fd = fd || "index.html"
  try {
    require("child_process").exec("start chrome " + require("path").resolve(fd))
  } catch (e) {
    console.log(e)
  }
}
//or wherever the index file is
open("./src/index.html")

Basically the problem is that you can’t use data from an image, even if the image works in the dom.

Ex 1

<img src="assets//images/dark_rock.png" id="dark_rock"/>

This renders in the dom without error when using file protocol.

However, if you document.getElementById(“canvas”) without a crossorigin attribute and then try to use the elements data to draw, you will get this error: (getImageData is the function trying to do the draw). The data is marked “tainted”, which means it came from another origin and is unsafe.

Ex 2

<img src="assets//images/dark_rock.png" id="dark_rock" crossorigin="anonymous"/>

After adding the crossorigin attribute, the image does not render at all in the dom because of protocol error from (implicitly) using the file protocol.
Also, the script to extract the image data does not work at all because the image never had any to begin with. So, you get this error:

Maybe there is a setting that will allow use of “tainted” data? Do service workers work on file protocol in chrome? like, could we intercept response and save data to local storage? Kinda feeling like this is a hard no, and just use electron, a web server, or inline data uris though. Maybe it could work by bundling it all up into a .glb? Definitely a lot of extra effort in the workflow though :\

2 Likes

I also tried something similar to this and got the same problems… I also tried opening chrome with disabled web security but it somehow didnt work for me either.

My usecase is that I have a client who needs the application offline and if possible without installing any extra software. They dont really understand Computers and stuff, installing something is always problematic.

The solution I shipped now is a batch script that installes a npm https server and runs it. But the client needs to manually install nodjs before he can run the script, thats already too complicated for some people…

NSIS might be good for your use case: NSIS Wiki (sourceforge.io). You can use it to create an installer that runs every other installer the user needs, so they only have to keep clicking “next” xD

I know you said you didn’t want to start a server on the machine… but how about one in the browser?
This is a Chrome Extension that does the job: https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=en