我正在尝试制作一个jquery插件,它通过画布过滤图像。我在此链接中找到了一些过滤器代码
https://www.script-tutorials.com/demos/118/index.html
问题在于我在应用对比度,灰度效果时它们工作正常而不是挂起浏览器,运行平稳,但是当我对大尺寸图像使用模糊效果时,例如' 2000x3000',浏览器被绞死。
这是我的插件代码(仅适用于模糊)::
(function ($) {
$.fn.canfilter = function (options) {
var thisobg = $(this);
var canvas = document.createElement('canvas');
thisobg.empty();
thisobg.append(canvas);
var context;
var iW = $(".cropped").find('img').innerWidth(); // image width
var iH = $(".cropped").find('img').innerHeight(); // image height
var p1 = 0.99;
var p2 = 0.99;
var p3 = 0.99;
var er = 0; // extra red
var eg = 0; // extra green
var eb = 0; // extra blue
var iBlurRate = 0;
var func = 'color'; // last used function
if (options === 'blur1') {
resetToBlur1();
}
else if (options === 'blur2') {
resetToBlur2();
}
else {
//do default action
}
// ------------------------- blur ---------------------
function Blur() {
func = 'blur'; // last used function
var imgObj = new Image();
imgObj.src = $(".cropped").find('img').attr('src');//$("#image").attr('src');
canvas.width = iW;
canvas.height = iH;
context = canvas.getContext('2d');
context.drawImage(imgObj, 0, 0, iW, iH);
var imgd = context.getImageData(0, 0, iW, iH);
var data = imgd.data;
for (br = 0; br < iBlurRate; br += 1) {
for (var i = 0, n = data.length; i < n; i += 4) {
iMW = 4 * iW;
iSumOpacity = iSumRed = iSumGreen = iSumBlue = 0;
iCnt = 0;
// data of close pixels (from all 8 surrounding pixels)
aCloseData = [
i - iMW - 4, i - iMW, i - iMW + 4, // top pixels
i - 4, i + 4, // middle pixels
i + iMW - 4, i + iMW, i + iMW + 4 // bottom pixels
];
// calculating Sum value of all close pixels
for (e = 0; e < aCloseData.length; e += 1) {
if (aCloseData[e] >= 0 && aCloseData[e] <= data.length - 3) {
iSumOpacity += data[aCloseData[e]];
iSumRed += data[aCloseData[e] + 1];
iSumGreen += data[aCloseData[e] + 2];
iSumBlue += data[aCloseData[e] + 3];
iCnt += 1;
}
}
// apply average values
data[i] = (iSumOpacity / iCnt) * p1 + er;
data[i + 1] = (iSumRed / iCnt) * p2 + eg;
data[i + 2] = (iSumGreen / iCnt) * p3 + eb;
data[i + 3] = (iSumBlue / iCnt);
}
}
context.putImageData(imgd, 0, 0);
}
function resetToBlur1() {
p1 = 1;
p2 = 1;
p3 = 1;
er = eg = eb = 0;
iBlurRate = 1;
Blur();
}
// -- blur 2
function resetToBlur2() {
p1 = 1;
p2 = 1;
p3 = 1;
er = eg = eb = 0;
iBlurRate = 4;
Blur();
}
// ------------------------- // blur ---------------------
};
}(jQuery));
以下是HTML代码:
<div class="cropped">
<img id="croppedImg" src="03bc52c30e5eea81e4e816364fe4249a.jpg" alt=""/>
</div>
<div id="panel">
<!-- viewable canvas -->
</div>
<input type="button" id="blur1" value="Blur1" />
<input type="button" id="blur2" value="Blur2" />
并在脚本::
$("#blur1").click(function(){
$("#panel").filter('blur1');
});
$("#blur2").click(function(){
$("#panel").filter('blur2');
});
我需要一个简单的模糊代码,它不会挂起浏览器。请给我一个解决方案。
由于
答案 0 :(得分:0)
我不会过多地介绍你的代码,但让我们从一个与你的问题无关的重要事情开始:你不是在将图像绘制到画布上之前等待图像已加载。这可能适用于某些UA,但在其他UA上肯定会失败。
现在,对模糊问题。
在大图像上自己做模糊效果会很慢,因为你必须在所有像素上多次迭代,有this lib,这样做很好,但也可能会挂起浏览器。 / p>
因此,您可能希望在工作室中运行算法,以便在进行计算时不冻结主页面,但这仍然会很慢:
var img = new Image();
img.onload = init;
img.crossOrigin = 'anonymous';
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/John_William_Waterhouse_A_Mermaid.jpg/800px-John_William_Waterhouse_A_Mermaid.jpg";
function initWorker() {
var worker_file = new Blob([worker_script.textContent]);
var worker_url = URL.createObjectURL(worker_file);
return new Worker(worker_url);
}
function init() {
var worker = initWorker();
var c = document.createElement('canvas');
var ctx = c.getContext('2d');
c.width = canvas.width = img.width;
c.height = canvas.height = img.height;
var visibleCtx = canvas.getContext('2d');
var amount = 2;
var blur = 5;
worker.onmessage = function(e) {
visibleCtx.putImageData(e.data, 0, 0);
blur += amount;
if (blur > 10 || blur <= 0) {
amount *= -1;
}
blurImage(blur);
};
function blurImage(blurRate) {
var imageData = ctx.getImageData(0, 0, c.width, c.height);
worker.postMessage({
imageData: imageData,
blurRate: blurRate
}, [imageData.data.buffer]);
}
ctx.drawImage(img, 0, 0);
blurImage(blur);
}
<canvas id="canvas"></canvas>
<script type="worker-script" id="worker_script">
onmessage = function(event){
var d = event.data;
var imgData = d.imageData.data.length ?
d.imageData : new ImageData(d.imageData.data, d.imageData.width, d.imageData.height);
self.postMessage(Blur(imgData, d.blurRate), [imgData.data.buffer]);
};
function Blur(imgd, iBlurRate){
var p1 = 1;
p2 = 1;
p3 = 1;
er = eg = eb = 0;
var iW = imgd.width;
var data = imgd.data;
for (var br = 0; br < iBlurRate; br += 1) {
for (var i = 0, n = data.length; i < n; i += 4) {
iMW = 4 * iW;
iSumOpacity = iSumRed = iSumGreen = iSumBlue = 0;
iCnt = 0;
// data of close pixels (from all 8 surrounding pixels)
aCloseData = [
i - iMW - 4, i - iMW, i - iMW + 4, // top pixels
i - 4, i + 4, // middle pixels
i + iMW - 4, i + iMW, i + iMW + 4 // bottom pixels
];
// calculating Sum value of all close pixels
for (e = 0; e < aCloseData.length; e += 1) {
if (aCloseData[e] >= 0 && aCloseData[e] <= data.length - 3) {
iSumOpacity += data[aCloseData[e]];
iSumRed += data[aCloseData[e] + 1];
iSumGreen += data[aCloseData[e] + 2];
iSumBlue += data[aCloseData[e] + 3];
iCnt += 1;
}
}
// apply average values
data[i] = (iSumOpacity / iCnt) * p1 + er;
data[i + 1] = (iSumRed / iCnt) * p2 + eg;
data[i + 2] = (iSumGreen / iCnt) * p3 + eb;
data[i + 3] = (iSumBlue / iCnt);
}
}
return imgd;
}
</script>
但是,最好的解决方案是使用ctx.filter
属性。浏览器将在GPU上进行模糊处理:
var img = new Image();
img.onload = init;
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/55/John_William_Waterhouse_A_Mermaid.jpg/800px-John_William_Waterhouse_A_Mermaid.jpg"
var ctx = c.getContext('2d');
if(ctx.filter !== 'none'){
console.warn("your browser doesn't support the filter property," +
"we should fallback to the getImageData + worker solution");
throw 'not-supported';
}
var blur = 5;
var amount = .4;
function init(){
c.width = this.width;
c.height = this.height;
draw();
}
function draw(){
blur = blur + amount;
if(blur > 20 || blur <=0){
amount *= -1;
}
ctx.filter = 'blur('+blur+'px)';
ctx.drawImage(img, 0, 0);
requestAnimationFrame(draw);
}
<canvas id="c"></canvas>