Dynamically Animating Hue Shift on Canvas Image

1.4k Views Asked by At

I'm still relatively new to working with the canvas tag. What I've done so far is draw an image to the canvas. My goal is to have a fake night/day animation that cycles repeatedly.

I've exhausted quite a few different avenues (SVG, CSS3 filters, etc) and think that canvas pixel manipulation is the best route in my case. I'm trying to:

  1. Loop through all pixels in the image
  2. Select a certain color range
  3. Adjust to new color
  4. Update the canvas

Here's the code I have so far:

function gameLoop(){
        requestAnimationFrame(gameLoop);        

        ////////////////////////////////////////////////////////////////
        // LOOP PIXEL DATA - PIXEL'S RGBA IS STORED IN SEQUENTIAL ARRAYS
        ////////////////////////////////////////////////////////////////
        for(var i=0; i<data.length; i+=4){
            red=data[i+0];
            green=data[i+1];
            blue=data[i+2];
            alpha=data[i+3];

            // GET HUE BY CONVERTING TO HSL
            var hsl=rgbToHsl(red, green, blue);
            var hue=hsl.h*360;

            // CHANGE SET COLORRANGE TO NEW COLORSHIFT
            if(hue>colorRangeStart && hue<colorRangeEnd){
                var newRgb=hslToRgb(hsl.h+colorShift, hsl.s, hsl.l);
                data[i+0]=newRgb.r;
                data[i+1]=newRgb.g;
                data[i+2]=newRgb.b;
                data[i+3]=255;
            };
        };

        // UPDATE CANVAS
        ctx.putImageData(imgData, 0, 0);        
    };

The code works and selects a hue ranges and shifts it once, but is incredibly laggy. The canvas dimensions are roughly 500x1024.

My questions:

  1. Is it possible to improve performance?
  2. Is there a better way to perform a defined hue shift animation?

Thanks!

1

There are 1 best solutions below

3
On BEST ANSWER

It's hard to do this real-time using high quality HSL conversion. Been there done that, so I came up with a quantized approach which allow you to do this in real-time.

You can find the solution here (GPL3.0 licensed):
https://github.com/epistemex/FastHSL2RGB

Example of usage can be found here (MIT license) incl. demo:
https://github.com/epistemex/HueWheel

Apologies for referencing my own solutions here, but the inner workings (the how to's) is too extensive to present in a simple form here and both of these are free to use for anything..

The key points are in any case:

  • Quantize the range you want to use (don't use full 360 degrees and not floating points for lightness etc.)
  • Cache the values in a 3D array (initial setup using web workers or use rough values)
  • Quantize the input values so they fit in the range of the inner 3D array
  • Process the bitmap using these values

It is not accurate but good enough for animations (or previews which is what I wrote it for).

There are other techniques such as pre-caching the complete processed bitmap for key positions, then interpolate the colors between those instead. This, of course, requires much more memory but is a fast way.

Hope this helps!