在Firefox中,使用createObjectURL img.src时onload事件不会触发

4

我有以下代码。在Chrome中,它完全正常,符合预期。然而,在Firefox中,它只记录“CONVERT”,但从未记录“LOADED”。没有JS错误或任何东西。onload事件根本没有触发。我似乎在Google或Stackoverflow上找不到太多信息。很多人说已缓存的图像不会触发onload事件,但这些图像不应该被缓存,即使它们被缓存,我也无法进行缓存破坏(正确吗?)

  flattenImage: function(file, callback){
    // Safari uses webkitURL
    var URL = window.URL || window.webkitURL;
    var canPreformat = !!(window.Blob && window.Uint8Array && URL && URL.createObjectURL);

    // If we have all features we need to preformat on the client and the image
    // isn't already flattened (jpeg), DO IT
    if (canPreformat && !file.type.test(/jpe?g/i)) {
      console.log('CONVERT');
      var thiz = this;
      var c = document.createElement('canvas');
      var ctx = c.getContext('2d');
      var img = new Image;
      // Makes a blob URL from the file given.
      img.onload = function() {
        console.log('LOADED');
        c.width = this.width;
        c.height = this.height;

        // Take the img that was added and copy it to the canvas
        ctx.drawImage(img, 0, 0);

        // Put the image on top of everything else
        ctx.globalCompositeOperation = 'destination-atop';

        // Any transparency should become white (instead of the default black)
        ctx.fillStyle = "#fff";
        ctx.fillRect(0, 0, this.width, this.height);

        // Save canvas as a base64'd jpeg
        var dataURL = c.toDataURL("image/jpeg");

        // The following blob lines take the base64 encoded image and then
        // convert it to a jpeg "file". This allows us to do a real file
        // upload rather than needing to send a base64 string.
        var blobBin = atob(dataURL.split(',')[1]);
        var array = [];
        for(var i = 0; i < blobBin.length; i++) {
          array.push(blobBin.charCodeAt(i));
        }
        callback.call(thiz, new Blob([new Uint8Array(array)], {type: 'image/jpeg'}));
      }
      img.src = URL.createObjectURL(file);
    }
    // If we don't have all the features just return the same file given to us
    else {
      console.log('NOPE')
      callback.call(this, file);
    }
  }

好的,这似乎是Firefox中的一个错误。我也在使用来自Blob的URL,并且即使在DOM中加载,load事件仍然无法触发。我已经向Firefox提交了几个与Blob相关的问题报告,所以这可能是另一个问题。 - joseeight
这个知道了还不错/不好 ;) 你有什么解决方法的想法吗? - Oscar Godson
你在尝试做什么?对我来说似乎不太清楚。 - joseeight
@joseeight 请看下面我的回答,我是如何解决这个问题的。无论如何,这段代码是为了在上传到文件存储服务之前将图像压平(即删除层和透明度)。问题是,当它调整大小像gif/png这样的图像时,它会出现问题,反转颜色并使alpha通道变黑。 - Oscar Godson
刚刚有一个错误报告,FYI:https://bugzilla.mozilla.org/show_bug.cgi?id=952179 - joseeight
显示剩余6条评论
1个回答

3
我通过不使用createObjectURL而是使用FileReader解决了这个问题,代码如下:
flattenImage: function(file, callback){
    // Safari uses webkitURL
    var URL = window.URL || window.webkitURL;
    var canPreformat = !!(window.FileReader && window.Blob && window.Uint8Array);

    // If we have all features we need to preformat on the client and the image
    // isn't already flattened (jpeg), DO IT
    if (canPreformat && !file.type.test(/jpe?g/i)) {
      console.log('CONVERT');
      var thiz = this;
      var c = document.createElement('canvas');
      var ctx = c.getContext('2d');

      var reader = new FileReader();
      var img = new Image;

      // Once the image is loaded from FileReader set the src of the image to
      // the base64'd result. This will trigger the img.onload
      reader.onload = function (ev) {
        img.src = ev.target.result;
      };

      // Makes a blob URL from the file given.
      img.onload = function() {
        console.log('LOADED');
        c.width = this.width;
        c.height = this.height;

        // Take the img that was added and copy it to the canvas
        ctx.drawImage(img, 0, 0);

        // Put the image on top of everything else
        ctx.globalCompositeOperation = 'destination-atop';

        // Any transparency should become white (instead of the default black)
        ctx.fillStyle = "#fff";
        ctx.fillRect(0, 0, this.width, this.height);

        // Save canvas as a base64'd jpeg
        var dataURL = c.toDataURL("image/jpeg");

        // The following blob lines take the base64 encoded image and then
        // convert it to a jpeg "file". This allows us to do a real file
        // upload rather than needing to send a base64 string.
        var blobBin = atob(dataURL.split(',')[1]);
        var array = [];
        for(var i = 0; i < blobBin.length; i++) {
          array.push(blobBin.charCodeAt(i));
        }
        callback.call(thiz, new Blob([new Uint8Array(array)], {type: 'image/jpeg'}));
      }
      reader.readAsDataURL(file);
    }
    // If we don't have all the features just return the same file given to us
    else {
      callback.call(this, file);
    }
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接