在Javascript中同步加载base64编码的图像

Synchronous loading of Base64-encoded images in Javascript

本文关键字:编码 图像 base64 加载 Javascript 同步      更新时间:2023-09-26

我有一组~200个base64编码的png(都来自一个共享的JSON文件),我想直接加载在一个循环作为WebGL纹理,而不必诉诸回调/事件处理程序(更简单的代码和更少的事件处理开销)。在Javascript中有办法做到这一点吗?

我知道加载base64编码图像的规范方法是通过数据uri。但似乎设置Image对象的src属性实际上并不解码图像数据,而只是排队异步加载(这意味着上传Image对象作为WebGL纹理后设置src属性失败;设置一个onload处理程序,上传纹理成功)。

为什么?为什么要同步进行呢?浏览器中的JavaScript不是为同步运行而设计的。你会冻结浏览器,并可能出现"此脚本执行时间过长"的对话框。

这并不难做异步,所以为什么不这样做呢?

var loadTextureFromImage = function(url, callback) {
   // use cyan as the default color.
   var initialColor = new Uint8Array([0,255,255,255]);
   // make a texture with 1x1 pixels so we can use the texture immediately
   // while we wait for the image to load
   var tex = gl.createTexture();
   gl.bindTexture(gl.TEXTURE_2D, tex);
   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, 
                 gl.RGBA, gl.UNSIGNED_BYTE, initialColor); 
   var img = new Image();
   img.onload = function() {
      gl.bindTexture(gl.TEXTURE_2D, tex);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
      callback(img);
   };
   return tex;
};
var loadTexturesFromImages(listOfImages, callback) {
   var numLeftToDownload = listOfImages.length;
   var checkFinished = function() {
     --numLeftToDownload;
     if (numLeftToDownload == 0 && callback) {
       callback();
     }
   };
   return listOfImages.map(function(url) {
     return loadTexturesFromImage(url, checkFinished);
   });
};
下面是使用上面 函数的一些代码
var imagesToLoad = [
   "http://foo.com/image1.jpg",
   "http://foo.com/image2.jpg",
   "data:image/png;base64,iVBORw0KG...",
];
var textures = loadTexturesFromImages(imagesToLoad);

现在你可以开始渲染了。它们都将以青色渲染,并在下载/解码时更新为图像。

如果你想等待,直到它们全部下载,然后提供一个回调到loadTexturesFromImages

我猜你的问题的简短答案是,"不,你不能同步解码图像"。长一点的答案是,如果你想同步解码它们,你必须自己解码它们。但现在你又回到了上面提到的问题。也就是说,你会冻结浏览器,你的用户可能会收到一个对话框,询问他们是否想要终止脚本。