javascripthtmlcanvastextgenerative-art

JavaScript canvas, manually cloning a canvas onto another generates a weird pattern


I'm trying to make a text effect similar to the effect found at the bottom of this article

enter image description here

My proposed approach is:

  1. Make two canvasses, one is visible, the other is invisible I use this as a buffer.
  2. Draw some text on the buffer canvas
  3. Loop over getImageData pixels
  4. if pixel alpha is not equal to zero (when there is a pixel drawn on the canvas buffer) with a small chance, ie 2%, draw a randomly generated circle with cool effecs at that pixel on the visible canvas.

I'm having trouble at step 4. With the code below, I'm trying to replicate the text on the second canvas, in full red. Instead I get this weird picture.

result

code

// create the canvas to replicate the buffer text on.
var draw = new Drawing(true);

var bufferText = function (size, textFont) {
  // set the font to Georgia if it isn't defined
  textFont = textFont || "Georgia";
  // create a new canvas buffer, true means that it's visible on the screen
  // Note, Drawing is a small library I wrote, it's just a wrapper over the canvas API
  // it creates a new canvas and adds some functions to the context
  // it doesn't change any of the original functions
  var buffer = new Drawing(true);
  // context is just a small wrapper library I wrote to make the canvas API a little more bearable. 
  with (buffer.context) {
    font = util.format("{size}px {font}", {size: size, font: textFont});
    fillText("Hi there", 0, size);
  }
  // get the imagedata and store the actual pixels array in data
  var imageData = buffer.context.getImageData(0, 0, buffer.canvas.width, buffer.canvas.height);
  var data = imageData.data;
  var index, alpha, x, y;
  // loop over the pixels
  for (x = 0; x < imageData.width; x++) {
    for (y = 0; y < imageData.height; y++) {
      index = x * y * 4;
      alpha = data[index + 3];
      // if the alpha is not equal to 0, draw a red pixel at (x, y)
      if (alpha !== 0) {
        with (draw.context) {
          dot(x/4, y/4, {fillColor: "red"})
        }
      }
    }
  }
};

bufferText(20);

Note that here, my buffer is actually visible to show where the red pixels are supposed to go compared to where they actually go.

I'm really confused by this problem.

If anybody knows an alternative approach, that's very welcome too.


Solution

  • replace this...

    index = x * y * 4;
    

    with...

    index = (imageData.width * y) + x;
    

    the rest is good :)