Home > Back-end >  Get average color of image without sacrificing lazy loading
Get average color of image without sacrificing lazy loading

Time:03-08

Here is just an example of what I'm trying to achieve. example of getting color from image

So I looked online on how to get the average color of an image and the solution I found works pretty well. The only problem is that it doesn't work well when you decide to lazy load the images.

For the purpose of this question, here is a basic HTML structure with images.

<div id="block">
    <img id="img"  src="http://localhost:90/avg-color-of-img/Archive.jpg">
</div>

<div id="block">
    <img id="img"  src="http://localhost:90/avg-color-of-img/Archive.jpg">
</div>

<div id="block">
    <img id="img"  src="http://localhost:90/avg-color-of-img/Archive.jpg">
</div>

And here is the javascript that picks the average color from the images:

function averageColor(imageElement) {
    // Create the canavs element
    var canvas = document.createElement('canvas'),

    // Get the 2D context of the canvas
    context
        = canvas.getContext &&
        canvas.getContext('2d'),
        imgData, width, height,
        length,
 
        // Define variables for storing
        // the individual red, blue and
        // green colors
        rgb = { r: 0, g: 0, b: 0 },

        // Define variable for the 
        // total number of colors
        count = 0;
 
    // Set the height and width equal
    // to that of the canvas and the image
    height = canvas.height =
        imageElement.naturalHeight ||
        imageElement.offsetHeight ||
        imageElement.height;
    width = canvas.width =
        imageElement.naturalWidth ||
        imageElement.offsetWidth ||
        imageElement.width;
 
    // Draw the image to the canvas
    context.drawImage(imageElement, 0, 0);
 
    // Get the data of the image
    imgData = context.getImageData(
            0, 0, width, height);

    // Get the length of image data object
    length = imgData.data.length;

    for (var i = 0; i < length; i  = 4) {
        // Sum all values of red colour
        rgb.r  = imgData.data[i];

        // Sum all values of green colour
        rgb.g  = imgData.data[i   1];

        // Sum all values of blue colour
        rgb.b  = imgData.data[i   2];

        // Increment the total number of
        // values of rgb colours
        count  ;
    }

    // Find the average of red
    rgb.r = Math.floor(rgb.r / count);

    // Find the average of green
    rgb.g = Math.floor(rgb.g / count);

    // Find the average of blue
    rgb.b = Math.floor(rgb.b / count);

    return rgb;
}
// Function to set the background color of the second div as 
// calculated average color of image
var rgb;
var imgg = document.getElementsByClassName("cimg");
var blocks = document.getElementsByClassName("block");
var i;
for (i = 0; i < imgg.length; i  ) {
    rgb = averageColor(imgg[I]);

    blocks[i].style.backgroundColor =
        'rgb('   rgb.r   ','
          rgb.g   ','
          rgb.b   ')';
}

Everything worked fine until I decided to use 'lazysizes' to lazyload the images.

For the lazy loading to work I had to use data-src to get the images instead of the regular src attribute and now because there isn't an image in the src attribute, the code to pick the average color doesn't work well.

Please is there any possible way to lazy load images and still get their average color? Thanks :)

CodePudding user response:

You can create a load event listener for each image, so once each image loads you get the color. Your code can be written thus:

var imgg = document.getElementsByClassName("cimg");
var blocks = document.getElementsByClassName("block");
for (var i = 0; i < imgg.length; i  ) {
    setColor(i);
}

function setColor(i) {
  var $img = imgg[i];
  // once the lazy-loaded image loads:
  $img.addEventListener("load", e => {
    // get average color and set
    var rgb = averageColor($img);
    blocks[i].style.backgroundColor =
          'rgb('   rgb.r   ','
            rgb.g   ','
            rgb.b   ')';
  });
}
  • Related