Create A Halftone Effect On Video

Category: Javascript | May 7, 2018
Author:Louis Hoebregts
Views Total:461 views
Official Page:Go to website
Last Update:May 7, 2018
License:MIT

Preview:

Create A Halftone Effect On Video

Description:

Makes use of JavaScript and HTML5 canvas to create a fancy halftone mask effect on your HTML5 video.

How to use it:

Embed an HTML5 video into the page.

<video src="sample.mp4" loop muted autoplay crossorigin="anonymous"></video>

Create an empty canvas on which you want to render the halftone effect.

<canvas class="scene"></canvas>

The main JavaScript to render the halftone effect on the HTML5 video.

const v = document.querySelector('video');
const canvas = document.querySelector('canvas.scene');
const ctx = canvas.getContext('2d');
let width = canvas.offsetWidth;
let height = canvas.offsetHeight;
canvas.width = width;
canvas.height = height;

window.addEventListener('resize', () => {
  width = canvas.offsetWidth;
  height = canvas.offsetHeight;
  fakeSize = Math.min(100,  Math.ceil(window.innerWidth / 12));
  pRatio = width / fakeSize;
  canvas.width = width;
  canvas.height = height;
  fakeCanvas.width = fakeSize;
  fakeCanvas.height = fakeSize;
  videoParameters();
  createPoints();
});

const videoParameters = () => {
  v._opts = {
    left: 0,
    top: 0,
    width: 0,
    height: 0
  };
  v._opts.width = width;
  v._opts.ratio = (width / v.offsetWidth);
  v._opts.height = v.offsetHeight * v._opts.ratio;
  v._opts.left = (width - v._opts.width) /2;
  v._opts.top = (width - v._opts.height) /2;
};

const fakeCanvas = document.createElement('canvas');
const fakeCtx = fakeCanvas.getContext('2d');
let fakeSize = Math.ceil(window.innerWidth / 12);
let pRatio = width / fakeSize;
fakeCanvas.width = fakeSize;
fakeCanvas.height = fakeSize;
const getPoints = () => {
  fakeCtx.clearRect(0, 0, fakeSize, fakeSize);
  fakeCtx.fillStyle = 'white';
  fakeCtx.fillRect(0, 0, fakeSize, fakeSize);
  fakeCtx.drawImage(canvas, 0, 0, fakeSize, fakeSize);
  
  const canvasData = fakeCtx.getImageData(0, 0, fakeSize, fakeSize).data;
  
  for (let x = 0; x < fakeSize; x++) {
    for (let y = 0; y < fakeSize; y++) {
      const p = points[x * fakeSize + y];
      const red = canvasData[(y * fakeSize + x) * 4 + 0] / 255;
      const green = canvasData[(y * fakeSize + x) * 4 + 1] / 255;
      const blue = canvasData[(y * fakeSize + x) * 4 + 2] / 255;
      
      const gray = (red * 0.2126 + green * 0.7152 + blue * 0.0722);
      const radius = 1 - gray;
      p.r += (radius * pRatio - p.r) * 0.1;
    }
  }
};

let points = [];
const createPoints = () => {
  points = [];
  for (let x = 0; x < fakeSize; x++) {
      for (let y = 0; y < fakeSize; y++) {
        const point = {
          x: x * pRatio,
          y: y * pRatio,
          r: 0
        };
        points.push(point);
    }
  }
}

const render = () => {
  window.requestAnimationFrame(render);
  
  ctx.clearRect(0, 0, width, height);
  ctx.drawImage(v, v._opts.left, v._opts.top, v._opts.width, v._opts.height);
  getPoints();
  
  ctx.clearRect(0, 0, width, height);
  // Draw the points
  for (let i = 0; i < points.length; i++) {
    const p = points[i];
    if (p.r > 0) {
      if (i%2 === 0) {
        ctx.fillRect(p.x - p.r, p.y - p.r, p.r, p.r);
      } else {
        ctx.fillRect(p.x - p.r + pRatio *0.5, p.y - p.r, p.r, p.r);
      }
    }
  }

};

videoParameters();
v.addEventListener('canplay', () => {
  createPoints();
  window.requestAnimationFrame(render);
}, {
  once: true
});

// Handle user webcam
const startWebcam = (stream) => {
  v.src = window.URL.createObjectURL(stream);
  v.addEventListener('canplay', () => {
    videoParameters();
  }, {
    once: true
  });
}
navigator.getUserMedia = navigator.getUserMedia ||
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia;
if (navigator.getUserMedia) {       
    navigator.getUserMedia({video: true}, startWebcam, (error) => {console.log(error)});
}

You Might Be Interested In:


Leave a Reply