Alf*_*ang 2 html javascript canvas image-processing web-worker
我现在正在处理客户端选择图像。
我想对该图像执行两个操作,并输出 base64 编码的字符串。
所以现在我将在主脚本中执行以下操作:
$(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;
});
});Run Code Online (Sandbox Code Playgroud)
<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" />Run Code Online (Sandbox Code Playgroud)
但是,我的代码仍然可以在移动设备上运行,而上述过程(调整大小和压缩)无法很快完成。它会导致 GUI 停止响应片刻。
我希望该过程在另一个线程中工作,使用 web worker。所以它不会阻塞UI,所以用户体验会更好。
现在问题来了,网络工作者似乎无法处理画布,我该如何解决这个问题?
一些事件驱动的编码
遗憾的是,Web 工作者还没有准备好提供浏览器支持。
对toDataURL网络工作者的有限支持意味着需要另一种解决方案。请参阅页面中间的MDN Web Worker API (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
};
Run Code Online (Sandbox Code Playgroud)
setTimeout允许当前调用退出,释放调用堆栈并允许 UI 在 DOM 上获取其手套。我给了 10ms,我个人会从 0ms 开始,因为调用堆栈访问没有被阻止,但我很安全
运气好的话,问题会大大减少。如果它仍然是不可接受的延迟,那么我可以查看 CPU 配置文件,看看是否无法通过针对瓶颈找到解决方案。我的猜测是toDataURL负载所在的位置。如果是,一个可能的解决方案是找到一个用 javascript 编写的 JPG 编码器,它可以转换为事件驱动的编码器。
问题不在于处理数据需要多长时间,而在于您阻塞 UI 的时间。