Canvas blending not working

409 views Asked by At

While running a code for a blending between image and background, I couldn't solve why isn't working. I'm doing it with canvas blending 'cause it have more cross browsing compatibility than css3 background-blend-mode but I stock on a problem rendering it, as you will see on the snippet below the images didn't blends at all... I'm an amateur with javascript so I'm maybe missing something.

  var canvas=document.getElementById("header_photo");
  var ctx=canvas.getContext("2d");
  var cw=canvas.width;
  var ch=canvas.height;
    ctx.globalCompositeOperation = "source-over";

  var img = new Image();
  img.onload = start;
  img.src = "https://i.stack.imgur.com/Yfi8y.jpg";

  var images = new Image();
  images.onload = starting;
  images.src = "https://i.stack.imgur.com/Ut7Wk.jpg";

  function start(){

    var c1=scaleIt(img,1);

    canvas.width=c1.width/1;
    canvas.height=c1.height/1;
    ctx.drawImage(c1,0,0);
    ctx.globalCompositeOperation = 'multiply';

  }

  function starting(){

    var c1=scaleIt(images,1);

    canvas.width=c1.width/1;
    canvas.height=c1.height/1;
    ctx.drawImage(c1,0,0);

  }

  function scaleIt(source,scaleFactor){
    var c=document.createElement('canvas');
    var ctx=c.getContext('2d');
    var w=source.width*scaleFactor;
    var h=source.height*scaleFactor;
    c.width=w;
    c.height=h;
    ctx.drawImage(source,0,0,w,h);
    ctx.globalCompositeOperation = 'source-out';
    return(c);
  } 
html, body {
  height: 100%;
  overflow-x: hidden; }

header {
  width: 100%;
  height: 100%; }
  header #header_photo {
    width: 100%;
    height: auto;
    position: absolute;
    opacity: 1; }
<header>
  <canvas id="header_photo"></canvas>
</header>

1

There are 1 answers

2
Kaiido On BEST ANSWER

The main problem you are facing is that setting the canvas width or height properties does reset the whole context's properties (including gCO, and what has been drawn to it previously).

Also note that the way you are doing it doesn't assure in which order start or starting will fire. So you may end up with unwanted results. You should rather create a single start function that will be triggered only when both images have loaded.

var canvas = document.getElementById("header_photo");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.globalCompositeOperation = "source-over";

var img = new Image();
img.onload = loadHandler;
img.src = "https://i.stack.imgur.com/Yfi8y.jpg";

var images = new Image();
images.onload = loadHandler;
images.src = "https://i.stack.imgur.com/Ut7Wk.jpg";

var loaded = 0;
function loadHandler(){
   if(++loaded == 2){
      start();
     }
   }

function start() {
  var c1 = scaleIt(img, 1);
  var c2 = scaleIt(images, 1);
  canvas.width = c1.width / 1;
  canvas.height = c1.height / 1;
  ctx.drawImage(c1, 0, 0);
  ctx.globalCompositeOperation = 'multiply';
  // here don't resize the main canvas, but use drawImage sizing options
  ctx.drawImage(c2, 0, 0, c1.width, c1.height);
}


function scaleIt(source, scaleFactor) {
  var c = document.createElement('canvas');
  var ctx = c.getContext('2d');
  var w = source.width * scaleFactor;
  var h = source.height * scaleFactor;
  c.width = w;
  c.height = h;
  ctx.drawImage(source, 0, 0, w, h);
  ctx.globalCompositeOperation = 'source-out';
  return (c);
}
html,
body {
  height: 100%;
  overflow-x: hidden;
}
header {
  width: 100%;
  height: 100%;
}
header #header_photo {
  width: 100%;
  height: auto;
  position: absolute;
  opacity: 1;
}
<header>
  <canvas id="header_photo"></canvas>
</header>