调整大小&压缩Web Worker中的图像。我可以用帆布吗?

时间:2015-11-28 10:23:39

标签: javascript html5 image-processing canvas web-worker

化背景

我现在正在处理客户选择图片。

我想对该图像执行两个操作,并输出base64编码的字符串。

  1. 如果图像尺寸的宽度或高度大于1000,请调整其大小。
  2. 使用质量为0.5的jpeg压缩图像。
  3. 所以现在我将在主脚本中执行以下操作:

    
    
    $(function() {
    
      $('#upload').change(function() {
    
        var URL = window.URL || window.webkitURL;
    
        var imgURL = URL.createObjectURL(this.files[0]);
    
        var img = new Image();
    
        img.onload = function() {
    
          var canvas = document.createElement('canvas');
          var ctx = canvas.getContext('2d');
          var w0 = img.width;
          var h0 = img.height;
          var w1 = Math.min(w0, 1000);
          var h1 = h0 / w0 * w1;
    
          canvas.width = w1;
          canvas.height = h1;
    
          ctx.drawImage(img, 0, 0, w0, h0,
            0, 0, canvas.width, canvas.height);
    
          // Here, the result is ready, 
          var data_src = canvas.toDataURL('image/jpeg', 0.5);
          $('#img').attr('src', data_src);
    
          URL.revokeObjectURL(imgURL);
        };
    
        img.src = imgURL;
    
      });
    
    });
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <input id="upload" type="file" accept="image/*" />
    <img id="img" />
    &#13;
    &#13;
    &#13;

    问题

    但是,我的代码仍可在移动设备上运行,上述过程(调整大小和压缩)无法很快解决。它会导致GUI停止响应片刻。

    我希望使用web worker在另一个线程中运行该过程。因此它不会阻止用户界面,因此用户体验会更好。

    现在出现了问题,似乎网络工作者无法处理画布,我该如何解决这个问题?

1 个答案:

答案 0 :(得分:4)

某些事件驱动的编码

可悲的是,Web工作者还没有准备好浏览器支持。

网络工作者对toDataURL的有限支持意味着需要另一种解决方案。请参阅页面中间的MDN web worker APIs (ImageData),目前只适用于Firefox。

查看您的onload,您可以通过一次阻止拨打onload来完成所有繁重的工作。您在创建新画布,获取其上下文,缩放和toDataURL(不知道revokeObjectURL做什么)的过程中阻止了UI。在发生这种情况时,您需要让UI接听几个电话。所以一个小事件驱动的处理将有助于减少故障,如果不让它不明显。

尝试按如下方式重写onload函数。

// have added some debugging code that would be useful to know if
// this does not solve the problem. Uncomment it and use it to see where
// the big delay is.
img.onload = function () {
    var canvas, ctx, w, h, dataSrc, delay; // hosit vars just for readability as the following functions will close over them
                                    // Just for the uninitiated in closure.
    // var now, CPUProfile = [];  // debug code 
    delay = 10; // 0 could work just as well and save you 20-30ms
    function revokeObject() { // not sure what this does but playing it safe
        // as an event.
        // now = performance.now(); // debug code
        URL.revokeObjectURL(imgURL);
        //CPUProfile.push(performance.now()-now); // debug code
        // setTimeout( function () { CPUProfile.forEach ( time => console.log(time)), 0);
    }
    function decodeImage() {
        // now = performance.now(); // debug code
        $('#img').attr('src', dataSrc);
        setTimeout(revokeObject, delay); // gives the UI a second chance to get something done.
        //CPUProfile.push(performance.now()-now); // debug code
    }
    function encodeImage() {
        // now = performance.now(); // debug code
        dataSrc = canvas.toDataURL('image/jpeg', 0.5);
        setTimeout(decodeImage, delay); // gives the UI a second chance to get something done.
        //CPUProfile.push(performance.now()-now); // debug code
    }
    function scaleImage() {
        // now = performance.now(); // debug code
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        setTimeout(encodeImage, delay); // gives the UI a second chance to get something done.
        //CPUProfile.push(performance.now()-now); // debug code
    }
    // now = performance.now(); // debug code
    canvas = document.createElement('canvas');
    ctx = canvas.getContext('2d');
    w = Math.min(img.width, 1000);
    h = img.height / img.width * w;
    canvas.width = w;
    canvas.height = h;
    setTimeout(scaleImage, delay); // gives the UI a chance to get something done.
    //CPUProfile.push(performance.now()-now); // debug code
};

setTimeout允许当前调用退出,释放调用堆栈并允许UI在DOM上获取其手势。我给了10ms,个人我会以0ms开始,因为调用堆栈访问没有被阻止,但我正在安全地玩它

幸运的是,问题将大大减少。如果它仍然是一个不可接受的延迟,那么我可以查看CPU配置文件,看看是否找不到通过针对瓶颈找到解决方案。我的猜测是toDataURL是负载的位置。如果是,可能的解决方案是找到用javascript编写的JPG编码器,该编码器可以转换为事件驱动的编码器。

问题不在于处理数据需要多长时间,而在于您阻止UI的时间。