Saturday, December 11, 2010

Comicbook.js - Release 0.3

For my 0.3 release of comicbook.js I've attempted to optimize the combination of closepixelate.js and video by writing the image to a canvas in memory then copying the image over to the main canvas when the write was finished. View the demo here.

Using the function renderToCanvas() allows me to buffer the write and return the result

  renderToCanvas: function (self, renderOptions, width, height, renderFunction) {
    var buffer = document.createElement('canvas');
    buffer.width = width;
    buffer.height = height;
    renderFunction(buffer.getContext('2d'), renderOptions, self);
    return buffer;
  }

var cached = this.renderToCanvas(
                self,
                renderOptions,
                this.c1.width,
                this.c1.height,
                function (ctx, renderOptions, self) {               
                    var imgData = self.ctx1.getImageData(0, 0, self.c1.width, self.c1.height);//.data;
                    self.ctx1.clearRect( 0, 0, self.c1.width, self.c1.height);
                    for (var i=0, len = renderOptions.length; i < len; i++) {
                     var opts = renderOptions[i],
                          res = opts.resolution,
                          // option defaults
                          size = opts.size || res,
                          alpha = opts.alpha || 1,
                          offset = opts.offset || 0,
                          offsetX = 0,
                          offsetY = 0,
                          cols = self.c1.width / res + 1,
                          rows = self.c1.height / res + 1,
                          halfSize = size / 2,
                          diamondSize = size / Math.SQRT2,
                          halfDiamondSize = diamondSize / 2;

                    offsetX = offsetY = offset;
                   
                     for ( var row = 0; row < rows; row++ ) {
                        var y = ( row - 0.5 ) * res + offsetY,
                          // normalize y so shapes around edges get color
                          pixelY = Math.max( Math.min( y, self.c1.height-1), 0);

                        for ( var col = 0; col < cols; col++ ) { 
                          var x = ( col - 0.5 ) * res + offsetX,
                                // normalize y so shapes around edges get color
                                pixelX = Math.max( Math.min( x, self.c1.width-1), 0),
                                pixelIndex = ( pixelX + pixelY * self.c1.width ) * 4,
                                red = imgData.data[ pixelIndex + 0 ],
                                green = imgData.data[ pixelIndex + 1 ],
                                blue = imgData.data[ pixelIndex + 2 ],
                                pixelAlpha = alpha * (imgData.data[ pixelIndex + 3 ] / 255);

                            ctx.fillStyle = 'rgba(' + red +','+ green +','+ blue +','+ pixelAlpha + ')';

                          switch ( opts.shape ) {
                             case 'circle' :
                                ctx.beginPath();
                                  ctx.arc ( x, y, halfSize, 0, self.PI2, true );
                                  ctx.fill();
                                ctx.closePath();
                                break;
                             case 'diamond' :
                                ctx.save();
                                  ctx.translate( x, y );
                                  ctx.rotate( self.PI1_4 );
                                  ctx.fillRect( -halfDiamondSize, -halfDiamondSize, diamondSize, diamondSize );
                                ctx.restore();
                                break;
                             default : // square           
                                ctx.fillRect( x - halfSize, y - halfSize, size, size );
                          } // switch       
                        } // col
                     } // row   
                  } // options
                }

this.ctx1.drawImage(cached, 0, 0);

This technique has definitely helped the performance. Another method of optimization that is probably more efficient is to eliminate the canvas draw functions altogether and create custom functions which modify the image data array directly.

I'm still stumped as to how to actually create the Halftone/Duotone effect which is pretty disappointing. Though the course is now over I'll continue working on this project on my own time.

No comments:

Post a Comment