Search code examples
javascriptcanvasmaskantialiasinggoogle-swiffy

How Swiffy antialias canvas?


I don't understand how swiffy succefully antialias clipping mask when it exports a flash animation that contains mask.

Here is my exemple :

I tried a lot of things, including draw a 200% canvas then scale it down, adding more points when I draw my mask, but no way to get a clean mask in my canvas.

How does swiffy ? It just turn me crazy.

Thanks. :)


Solution

  • Instead of using clip() you can draw the clipping path into an off-screen canvas and use that as a "matte", or rather, an alpha mask.

    Now you can use the mask with various composite modes to get anti-aliased edges. Draw in the background you want to clip, set a composite mode (operator) and draw in mask. Depending on operator you can cut out center or the surroundings (destination-in is typical equivalent to using clip() though).

    Note: demo below is only useful in Chrome/Opera as Firefox/IE already apply anti-aliasing to the clip mask - here's a snapshot showing the difference:

    A snapshot

    var ctxC = document.getElementById("clip").getContext("2d");
    var ctxM = document.getElementById("mask").getContext("2d");
    var w = ctxC.canvas.width, h = ctxC.canvas.height;
    var img = new Image();
    img.onload = demo;
    img.src = "http://i.imgur.com/s9ksOb1.jpg";
    
    function demo() {
      
      // define a clip path
      ctxC.save();
      createPath(ctxC);
      ctxC.clip();
      ctxC.drawImage(this, 0, 0, w, h);
      ctxC.restore();
      
      // create a "matte" / alpha mask
      var matte = document.createElement("canvas"),
          ctx = matte.getContext("2d");
      matte.width = w;
      matte.height = h;
    
      // fill the path instead:
      createPath(ctx);
      ctx.fill(); // color doesn't matter, alpha does
      
      // now use composition to "clip"
      ctxM.drawImage(this, 0, 0, w, h);  // draw image
      ctxM.globalCompositeOperation = "destination-in"; // will keep bg where mask cover
      ctxM.drawImage(matte, 0, 0);
      ctxM.globalCompositeOperation = "source-over";    // default mode
      
      // zoom some details:
      zoom(ctxC);
      zoom(ctxM);
    }
    
    function createPath(ctx) {
      var r = 88;
      ctx.beginPath();
      ctx.moveTo(100 + r, 90);
      ctx.arc(100,90,r, 0, 6.28);
    }
    
    function zoom(ctx) {
      ctx.imageSmoothingEnabled =
        ctx.webkitImageSmoothingEnabled =
        ctx.mozImageSmoothingEnabled = false;
      ctx.drawImage(ctx.canvas, 10, 10, 100, 100,  70,0, 400, 400);
    }
    html, body {margin:4px 0 0 4px;overflow:hidden}
    canvas{background:#000;border:1px solid #000;margin:0 1px 0 0}
    <canvas id="clip" height=180></canvas>
    <canvas id="mask" height=180></canvas>