Google Instant Preview

This deserves more research and tests.

Renders

  • 2D transforms
  • border-radius, elliptical border-radius
  • text-shadow
  • gradients

Does not render

  • 3D transforms
  • Typekit or @font-face
  • canvas

desandro.com Google Instant Preview

sxsw.beercamp.com Google Instant Preview

desandro conan Google Instant Preview

rumpetroll Google Instant Preview

toDataURL & drawImage are totally cool

John Schulz continues to do my job for me.

@desandro re: [putImageData is a complete jerk] I don’t know if this has been suggested already, but use drawImage instead [http://jsfiddle.net/JFSIII/Ga5jf/]

John Schulz

The thing pulling it all together is converting the canvas into a data URL and using that as an image:

var img = new Image();
img.src = canvas2.toDataURL('image/png');
ctx2.drawImage(img, 30, 10);

Gonna have to give him a back rub one of these days.

putImageData is a complete jerk

Overwriting

Using canvas’ putImageData() method completely overwrites the pixels it replaces. Take a look.

var renderCanvasExamples = function() {
  var canvas1 = document.getElementById('two-square-example'),
      canvas2 = document.getElementById('put-image-data-example');
  
  if ( !(canvas1.getContext && canvas1.getContext('2d') ) ) {
    return;
  }
  
  var fillColor = 'hsla(0,100%,50%,.4)';
      strokeColor = 'hsla(240,100%,50%,.4)',
      // convienence function for rendering circles
      circle = function( ctx, x, y, radius ) {
        ctx.beginPath();
          ctx.arc ( x, y, radius, 0, Math.PI*2, true);
          ctx.fill();
          ctx.stroke();
        ctx.closePath();
      };
  
  // example 1 renders 3 circles
  var ctx1 = canvas1.getContext('2d');
  ctx1.fillStyle = fillColor;
  ctx1.strokeStyle = strokeColor;
  ctx1.lineWidth = 2;
  circle( ctx1,  60,  60, 50);
  circle( ctx1,  90,  70, 50);
  circle( ctx1, 120,  80, 50);

  // example 2 renders 1 circle, 
  // then uses `putImageData` to render the next 2
  var ctx2 = canvas2.getContext('2d')

  ctx2.fillStyle = fillColor;
  ctx2.strokeStyle = strokeColor;
  ctx2.lineWidth = 2;

  circle( ctx2,  60,  60, 50);

  // limit imgData to 100 x 100 pixels so Firefox can display
  var imgData = ctx2.getImageData(0, 0, 100, 100);
  ctx2.putImageData( imgData, 30, 10 );
  ctx2.putImageData( imgData, 60, 20 );

};

window.addEventListener( 'DOMContentLoaded', renderCanvasExamples, false);

Each canvas has a yellow background to exhibit transparency. The first canvas has the same three circles overlaid on top of each other. As their fillStyle color has partial opacity, the red color is built up.

The second example uses getImageData() to capture a snapshot of the current canvas context. That image is then re-rendered at an offset position. Instead of three circles overlapping one another, the area of the putImageData output blows out the pixels underneath.

Unaffected by manipulation methods

Neither translate() nor rotate() will have any effect on subsequent putImageData() calls.

Breaks Firefox if bleeds outside canvas bounds

Also of note is that Firefox with throw an error if the output of putImageData() extends outside the bounds of the canvas. In this example, I had to crop the dimension of getImageData() so the putImageData() output would fit inside the canvas. If I kept getImageData to the original canvas dimensions, Firefox returns with An invalid or illegal string was specified" code: "12.

jerk.

Collectively, this is all pretty disappointing, as putImageData had tremendous potential. It would be especially useful to use putImageData as a way of reproducing Photoshop layers, or brushes, or all sorts of wondrous techniques that will have to be hacked together.