简体   繁体   English

HTML5画布图像过滤器滞后(JavaScript)

[英]HTML5 Canvas Image Filter Lags (JavaScript)

I'm attempting to load a full-screen background image onto a canvas, then apply an image filter to it, but have a few questions. 我试图将全屏背景图像加载到画布上,然后对其应用图像过滤器,但是有几个问题。 I'm running into severe performance issues, but only when resizing the window. 我遇到了严重的性能问题,但仅限于调整窗口大小时。 Basically, my code attempts to keep the canvas/image matching the screen dimensions (which works well). 基本上,我的代码尝试使画布/图像保持与屏幕尺寸匹配(效果很好)。

UPDATE CANVAS METHOD: 更新画布方法:

The updateCanvas method is called on load to initially create/load the image object and place it on the canvas. 加载时调用updateCanvas方法,以最初创建/加载图像对象并将其放置在画布上。 If a filter is selected, it calls the filter method. 如果选择了过滤器,它将调用过滤器方法。 It accepts the onResize argument, which is passed on window resize to scale the canvas/image. 它接受onResize参数,该参数在窗口调整大小时传递以缩放画布/图像。 MAIN refers to an object used for referencing elements. MAIN是指用于引用元素的对象。

updateCanvas:function(onResize){ 
        // SETUP VARIABLES
    var img=new Image(), 
            $this=Main.currentOBJ, // REFERENCE FOR .DATA
            objData=$this.data, 
            canvas=Main.OBJ.$Canvas[0], 
        ctx=canvas.getContext("2d"), 
            winW=$(window).width(), winH=$(window).height();

   // SOURCE CAN BE SET IN .DATA OR DEFAULT
   img.src=(objData.bg_pic_src!=='') ? objData.bg_pic_src : Main.ConSRC;

   // LOAD THE IMAGE OBJECT
   img.onload=function(){ 
       var imgW=img.width, imgH=img.height, 
           ratio=imgW/imgH, newW=winW, newH=Math.round(newW/ratio);

       // SETUP IMAGE PROPORTIONS
       if(newH < winH){ var newH=winH, newW=Math.round(newH*ratio); }; 

       // WHEN RESIZING THE BROWSER 
       if(!onResize){ // INTIAL DRAW
          Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'});  
          ctx.drawImage(img,0,0,newW,newH);

          // APPLY FILTERS
      if(objData.bg_pic_filter > 0){ 
             Main.canvasFilter(ctx,newW,newH); // FILTER METHOD
      }else{ 
             Main.OBJ.$OverlayPic.animate({opacity:parseFloat(objData.bg_pic_opacity,10)},
        {duration:objData.bg_pic_speed_in,queue:false}); 
          };
    }else{ // RESIZING
         Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'});  
         ctx.drawImage(img,0,0,newW,newH);

         if(objData.bg_pic_filter > 0){ 
             Main.canvasFilter(ctx,newW,newH); // FILTER METHOD
         };     
    };
};

The Canvas Filter Method: If an image filter is to be applied to the background image, the canvasFilter method is called from the canvasUpdate method. 画布过滤器方法:如果要将图像过滤器应用于背景图像,则从canvasUpdate方法调用canvasFilter方法。

canvasFilter:function(ctx,width,height){ 
      // SETUP VARIABLES
      var objData=Main.currentOBJ.data, 
      canvasWidth=width, canvasHeight=height,
      imgdata=ctx.getImageData(0, 0, canvasWidth, canvasHeight), 
      pix=imgdata.data, l=pix.length;

     // APPLY THE CORRECT LOOP DEPENDING UPON THE FILTER NUMBER 
     switch(objData.bg_pic_filter){
     case 1: ... break;
     case 2: 
         for(var i=l; i>0; i-=4){ 
             var cacher=pix[i+2]; 
             pix[i]=pix[i+1]; 
             pix[i+1]=cacher; 
             pix[i+2]=cacher; 
             pix[i+3]=cacher;
         }; 
     break;
    };          

     // APPLY THE FILER & FADE IN THE BACKGROUND
     ctx.putImageData(imgdata, 0, 0);
     Main.OBJ.$OverlayPic.fadeTo(parseInt(objData.bg_pic_speed_in,10),    
         parseFloat(objData.bg_pic_opacity,10));
};

All of this works, and the initial draw/filter are quite fast. 所有这些工作,并且初始绘制/过滤非常快。 However, when I resize the window it's very sluggish. 但是,当我调整窗口大小时,它非常缓慢。 I've temporarily gotten around this by putting in a throttler, which just sets a timer to avoid firing the above functions too quickly. 我暂时通过安装一个调节器来解决这个问题,调节器只是设置了一个计时器,以避免太快地启动上述功能。 This helps slightly, but will keep the background image in place (displaying open solid background areas around the image) until the throttler timer kicks in and fires the methods - resizing the canvas/image and applying the filter. 这会有所帮助,但会保持背景图像就位(在图像周围显示开放的纯色背景区域),直到油门计时器启动并触发方法-调整画布/图像的大小并应用滤镜。

Questions: 问题:

  1. Is there a faster way? 有没有更快的方法? I've read about using Typed Arrays/Bitwise for pixel manipulation loops, but it seems that support is horrible for this. 我已经读过有关将类型化数组/按位用于像素操纵循环的信息,但似乎对此的支持令人恐惧。 I've also looked into CSS3 filters to accomplish the same thing, but again, support is horrible. 我也研究过CSS3过滤器来完成同样的事情,但同样,支持也很糟糕。 So, would this be the only approach to full-screen background image filters with "modern browser" compatibility? 那么,这是否是具有“现代浏览器”兼容性的全屏背景图像滤镜的唯一方法?

  2. The updateCanvas method is creating a new image object each time, I'm thinking that this might be a bottleneck, but am unsure, and also unsure of how to get around it? updateCanvas方法每次都会创建一个新的图像对象,我认为这可能是一个瓶颈,但是不确定,也不确定如何解决它?

  3. I've read others using a separate canvas as a buffer? 我读过别人使用单独的画布作为缓冲区吗? Would this actually increase performance in my situation? 在我的情况下,这实际上会提高性能吗?

  4. I'm really thinking there's a major logic issue in my code somewhere. 我真的在想我的代码中某个地方存在主要的逻辑问题。 It just doesn't make sense to me that I would need to loop through all of the pixel information more than once, but this is the only way I've gotten it to work. 对于我来说,我需要多次遍历所有像素信息只是没有意义,但这是我使它起作用的唯一方法。 Isn't there a way I can draw it/apply the filter once, then on resize, just adjust the dimensions without having to redraw/reloop/reapply the filter? 有没有一种方法可以绘制/应用滤镜一次,然后在调整大小时仅调整尺寸而无需重新绘制/重新套环/重新应用滤镜? I would think that it would maintain the filtered image, but if I remove the call to the canvasFilter method on window resize, it completely removes the filter effect. 我认为它会保留过滤的图像,但是如果我删除对窗口调整大小的canvasFilter方法的调用,它将完全删除过滤效果。

  5. I've yet to use memoization techniques as I've never quite understood it, and never quite understand where/when to use it. 我还没有使用过记忆技术,因为我从未完全了解它,也从未完全了解过在何处/何时使用它。 But, essentially, if I have a function that is returning the same results again and again (such as the canvasFilter method) can I memoize to increase performance - or would it be difference because it's pulling different pixel information after the window has resized? 但是,从本质上讲,如果我有一个函数一次又一次返回相同的结果(例如canvasFilter方法),我可以记住以提高性能吗?或者会有所不同,因为在调整窗口大小之后,它会提取不同的像素信息吗?

  6. I've also heard that a webGL render might help with this? 我还听说过webGL渲染可能对此有所帮助? Might be way off as I don't know anything about webGL. 可能还有一段距离,因为我对webGL一无所知。

So sorry for the loooonng question, but hopefully this covers some topics that others can benefit from as well. 非常抱歉这个loooonng问题,但是希望它涵盖了一些其他主题也可以从中受益的主题。 Any suggestions/tips would be much appreciated. 任何建议/提示将不胜感激。 Thanks! 谢谢! :) :)

Since it sounds like your image is mostly static, an approach you might want to try is using good old css. 由于听起来您的图像基本上是静态的,因此您可能想尝试的方法是使用旧的CSS。

The key trick here is using background-size:cover. 这里的关键技巧是使用background-size:cover。 See: http://css-tricks.com/perfect-full-page-background-image/ 参见: http : //css-tricks.com/perfect-full-page-background-image/

So in broad terms: 因此,从广义上讲:

  1. Load your image 载入图片
  2. Apply your filter in a canvas. 将滤镜应用到画布中。 (The canvas doesn't even need to be attached to the page). (画布甚至不需要附加到页面上)。
  3. Export your canvas data as a url via: ctx.toDataUrl("image/png"); 通过以下ctx.toDataUrl("image/png");将画布数据导出为url: ctx.toDataUrl("image/png");
  4. Add the style to your container element or the body: background-size:cover;background:url('data:image/png;yourcanvasdata'); 将样式添加到容器元素或正文中: background-size:cover;background:url('data:image/png;yourcanvasdata');
  5. Animate the opacity of the container element/body via js or the css transition property 通过js或CSS过渡属性对容器元素/主体的不透明度进行动画处理

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM