I’ve been interested in creating “glitched” graphics using web technologies for some time. While the canvas API has pixel-level control over bitmaps, yesterday I realized that a fairly simple aspect of the API could be used to create glitch effects.

Gaining Images In Canvas

First, we start with a <canvas> element, as shown in the related CodePen demo:

<canvas id="portrait" width="200" height="400"></canvas>

Note that the initial dimensions of the tag are arbitrary; they’ll be altered with the to come.

This is supplemented with some :

body { 
  background: #000;
}
canvas { 
  display: block;
  margin: 0 auto;
  width: 60%;
}

The JavaScript for drawing in the canvas is divided into two broad steps. First, we load a referenced bitmap:

var img = new Image();
img.src = "nastya.jpg";
img.onload = function() {
  draw(this);
};

Once the image is fully loaded, we draw it onto the canvas using a draw function. First, we ensure that the canvas is the same dimension as our loaded image:

function draw(img) {
  var portrait = document.getElementById("portrait");
  var canvas = portrait.getContext("2d");
  portrait.setAttribute("width", img.width);
  portrait.setAttribute("height", img.height);
  …
}

Under normal circumstances, a bitmap image would be “mapped” to a canvas drawing space one-to-one: that is, the full height and width of the image would be pasted into the same area of the sized canvas, from its top left corner (0 0) to its bottom right. The syntax would look something like this:

canvas.drawImage(img, 0, 0, img.width, img.height, 
    0, 0, portrait.width, porttrait.height);

However, there’s nothing that says we have to take the entire image and map it onto the entire canvas in one go. We could take repeated slices of the source image, and map them using a displaced horizontal value onto the canvas. To start that process, we need two variables: the number of slices, and a value for the maximum horizontal offset. Continuing inside the function:

var verticalSlices = Math.round(img.height / 20);
var maxHorizOffset = 20;

The slices are drawn inside a for loop:

for (var i = 0; i < verticalSlices; i++)  {
    var horizOffset = getRandom(-Math.abs(maxHorizOffset), maxHorizOffset);
    canvas.drawImage(img, 
    0, 
    i * verticalSlices, 
    img.width, 
    i * verticalSlices + verticalSlices, 
    horizOffset, i * verticalSlices, 
    img.width, 
    i * verticalSlices + verticalSlices);
}

horizOffset references another function for getting a random value between two numbers. Note that the function call will potentially return negative values, moving the slice to the left:

function getRandom(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

This creates the random glitched effect you can see in the demo at the top of this article.

Conclusion

Variations of this same technique can be used dynamically: for example, mapping HTML5 video from two different streams onto a <canvas> to create a before-and-after video comparator.

Somewhat ironically, most visual glitches effects are borrowed from the misfiring of analog technology, such as the reception on an old television, transferred into a digital realm. I’ll be exploring more effects like this using web technologies in future articles.

Photograph by Sean Archer, used under a Creative Commons license

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/amoGNX