diff --git a/src/renderers/Canvas.js b/src/renderers/Canvas.js
new file mode 100644
index 0000000..87574a0
--- /dev/null
+++ b/src/renderers/Canvas.js
@@ -0,0 +1,226 @@
+/*
+  html2canvas @VERSION@ <http://html2canvas.hertzen.com>
+  Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
+  http://www.twitter.com/niklasvh
+
+  Released under MIT License
+*/
+
+
+html2canvas.Renderer.Canvas = function( options ) {
+
+    options = options || {};
+    
+    var doc = document,
+    canvas = options.canvas || doc.createElement('canvas'),
+    usingFlashcanvas = false,
+    _createCalled = false,
+    canvasReadyToDraw = false,
+    methods,
+    flashMaxSize = 2880; // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
+
+    
+    if (canvas.getContext){
+        html2canvas.log("html2canvas: Renderer: using canvas renderer");
+        canvasReadyToDraw = true;
+    } else if ( options.flashcanvas !== undefined ){
+        usingFlashcanvas = true;
+        html2canvas.log("html2canvas: Renderer: canvas not available, using flashcanvas");
+        var script = doc.createElement("script");
+        script.src = options.flashcanvas;
+                
+        script.onload = (function(script, func){
+            var intervalFunc; 
+    
+            if (script.onload === undefined) {
+                // IE lack of support for script onload
+                                
+                if( script.onreadystatechange !== undefined ) {
+                                    
+                    intervalFunc = function() {
+                        if (script.readyState !== "loaded" && script.readyState !== "complete") {
+                            window.setTimeout( intervalFunc, 250 );
+                                    
+                        } else {
+                            // it is loaded
+                            func();
+                                    
+                        }
+              
+                    };
+                                    
+                    window.setTimeout( intervalFunc, 250 );
+
+                } else {
+                    html2canvas.log("html2canvas: Renderer: Can't track when flashcanvas is loaded");
+                }
+                                
+            } else {
+                return func;
+            }
+                            
+        })(script, function(){
+                    
+            if (typeof window.FlashCanvas !== "undefined") {
+                html2canvas.log("html2canvas: Renderer: Flashcanvas initialized");
+                window.FlashCanvas.initElement( canvas );
+                
+                canvasReadyToDraw = true;
+                if ( _createCalled !== false ) {
+                    methods._create.apply( null, _createCalled );
+                }
+            }
+        });
+                
+        doc.body.appendChild( script );
+
+    }       
+
+    methods = {
+        _create: function( zStack, options, doc, queue, _html2canvas ) {
+            
+            if ( !canvasReadyToDraw ) {
+                _createCalled = arguments;
+                return canvas;
+            }
+            
+            var ctx = canvas.getContext("2d"),
+            storageContext,
+            i,
+            queueLen,
+            a,
+            newCanvas,
+            bounds,
+            testCanvas = document.createElement("canvas"),
+            hasCTX = ( testCanvas.getContext !== undefined ),
+            storageLen,
+            renderItem,
+            testctx = ( hasCTX ) ? testCanvas.getContext("2d") : {},
+            safeImages = [],
+            fstyle;
+            
+            canvas.width = canvas.style.width = (!usingFlashcanvas) ? options.width || zStack.ctx.width : Math.min(flashMaxSize, (options.width || zStack.ctx.width) );
+            canvas.height = canvas.style.height = (!usingFlashcanvas) ? options.height || zStack.ctx.height : Math.min(flashMaxSize, (options.height || zStack.ctx.height) );
+   
+            fstyle = ctx.fillStyle;
+            ctx.fillStyle = zStack.backgroundColor;
+            ctx.fillRect(0, 0, canvas.width, canvas.height);
+            ctx.fillStyle = fstyle;
+
+            for (i = 0, queueLen = queue.length; i < queueLen; i+=1){
+            
+                storageContext = queue.splice(0, 1)[0];
+                storageContext.canvasPosition = storageContext.canvasPosition || {};   
+           
+                //this.canvasRenderContext(storageContext,parentctx);           
+
+                // set common settings for canvas
+                ctx.textBaseline = "bottom";
+   
+                if (storageContext.clip){
+                    ctx.save();
+                    ctx.beginPath();
+                    // console.log(storageContext);
+                    ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
+                    ctx.clip();
+        
+                }
+        
+                if (storageContext.ctx.storage){
+               
+                    for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
+                    
+                        renderItem = storageContext.ctx.storage[a];
+                    
+                    
+                        switch(renderItem.type){
+                            case "variable":
+                                ctx[renderItem.name] = renderItem['arguments'];              
+                                break;
+                            case "function":
+                                if (renderItem.name === "fillRect") {
+                                
+                                    if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize  && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
+                                        ctx.fillRect.apply( ctx, renderItem['arguments'] );
+                                    }
+                                }else if(renderItem.name === "fillText") {
+                                    if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize  && renderItem['arguments'][2] < flashMaxSize) {
+                                        ctx.fillText.apply( ctx, renderItem['arguments'] );
+                                    }
+                                }else if(renderItem.name === "drawImage") {
+ 
+                                    if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){    
+                                        if ( hasCTX && options.taintTest ) {
+                                            if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
+                                                testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
+                                                try {
+                                                    testctx.getImageData( 0, 0, 1, 1 );
+                                                } catch(e) {      
+                                                    testCanvas = doc.createElement("canvas");
+                                                    testctx = testCanvas.getContext("2d");
+                                                    continue;
+                                                }
+                                          
+                                                safeImages.push( renderItem['arguments'][ 0 ].src );
+                                        
+                                            }
+                                        }
+                                        ctx.drawImage.apply( ctx, renderItem['arguments'] );                                   
+                                    }      
+                                }
+                       
+  
+                                break;
+                            default:
+                               
+                        }
+            
+                    }
+
+                }  
+                if (storageContext.clip){
+                    ctx.restore();
+                }
+    
+
+       
+   
+            }
+            h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
+        
+            queueLen = options.elements.length;
+
+            if (queueLen === 1) {
+                if (typeof options.elements[ 0 ] === "object" && options.elements[ 0 ].nodeName !== "BODY" && usingFlashcanvas === false) {
+                    // crop image to the bounds of selected (single) element
+                    bounds = _html2canvas.Util.Bounds( options.elements[ 0 ] );
+                    newCanvas = doc.createElement('canvas');
+                    newCanvas.width = bounds.width;
+                    newCanvas.height = bounds.height;
+                    ctx = newCanvas.getContext("2d");
+                
+                    ctx.drawImage( canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height );
+                    canvas = null;
+                    return newCanvas;
+                }
+            } /*else {
+        // TODO clip and resize multiple elements
+        
+            for ( i = 0; i < queueLen; i+=1 ) {
+                if (options.elements[ i ] instanceof Element) {
+                
+                }
+              
+            }
+        }
+        */
+       
+       
+        
+            return canvas;
+        }
+    }
+    
+    return methods;
+
+};
\ No newline at end of file