/* * Canvas2Image v0.1 * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com * MIT License [http://www.opensource.org/licenses/mit-license.php] */ var Canvas2Image = (function() { // check if we have canvas support var oCanvas = document.createElement("canvas"), sc = String.fromCharCode, strDownloadMime = "image/octet-stream", bReplaceDownloadMime = false; // no canvas, bail out. if (!oCanvas.getContext) { return { saveAsBMP : function(){}, saveAsPNG : function(){}, saveAsJPEG : function(){} } } var bHasImageData = !!(oCanvas.getContext("2d").getImageData), bHasDataURL = !!(oCanvas.toDataURL), bHasBase64 = !!(window.btoa); // ok, we're good var readCanvasData = function(oCanvas) { var iWidth = parseInt(oCanvas.width), iHeight = parseInt(oCanvas.height); return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight); } // base64 encodes either a string or an array of charcodes var encodeData = function(data) { var i, aData, strData = ""; if (typeof data == "string") { strData = data; } else { aData = data; for (i = 0; i < aData.length; i++) { strData += sc(aData[i]); } } return btoa(strData); } // creates a base64 encoded string containing BMP data takes an imagedata object as argument var createBMP = function(oData) { var strHeader = '', iWidth = oData.width, iHeight = oData.height; strHeader += 'BM'; var iFileSize = iWidth*iHeight*4 + 54; // total header size = 54 bytes strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); strHeader += sc(iFileSize % 256); strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset strHeader += sc(40, 0, 0, 0); // info header size var iImageWidth = iWidth; strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); strHeader += sc(iImageWidth % 256); var iImageHeight = iHeight; strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); strHeader += sc(iImageHeight % 256); strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel strHeader += sc(0, 0, 0, 0); // compression = none var iDataSize = iWidth*iHeight*4; strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); strHeader += sc(iDataSize % 256); strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used var aImgData = oData.data, strPixelData = "", c, x, y = iHeight, iOffsetX, iOffsetY, strPixelRow; do { iOffsetY = iWidth*(y-1)*4; strPixelRow = ""; for (x = 0; x < iWidth; x++) { iOffsetX = 4*x; strPixelRow += sc( aImgData[iOffsetY + iOffsetX + 2], // B aImgData[iOffsetY + iOffsetX + 1], // G aImgData[iOffsetY + iOffsetX], // R aImgData[iOffsetY + iOffsetX + 3] // A ); } strPixelData += strPixelRow; } while (--y); return encodeData(strHeader + strPixelData); } // sends the generated file to the client var saveFile = function(strData) { if (!window.open(strData)) { document.location.href = strData; } } var makeDataURI = function(strData, strMime) { return "data:" + strMime + ";base64," + strData; } // generates a object containing the imagedata var makeImageObject = function(strSource) { var oImgElement = document.createElement("img"); oImgElement.src = strSource; return oImgElement; } var scaleCanvas = function(oCanvas, iWidth, iHeight) { if (iWidth && iHeight) { var oSaveCanvas = document.createElement("canvas"); oSaveCanvas.width = iWidth; oSaveCanvas.height = iHeight; oSaveCanvas.style.width = iWidth+"px"; oSaveCanvas.style.height = iHeight+"px"; var oSaveCtx = oSaveCanvas.getContext("2d"); oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth); return oSaveCanvas; } return oCanvas; } return { saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) { if (!bHasDataURL) return false; var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight), strMime = "image/png", strData = oScaledCanvas.toDataURL(strMime); if (bReturnImg) { return makeImageObject(strData); } else { saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData); } return true; }, saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) { if (!bHasDataURL) return false; var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight), strMime = "image/jpeg", strData = oScaledCanvas.toDataURL(strMime); // check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false if (strData.indexOf(strMime) != 5) return false; if (bReturnImg) { return makeImageObject(strData); } else { saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData); } return true; }, saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) { if (!(bHasDataURL && bHasImageData && bHasBase64)) return false; var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight), strMime = "image/bmp", oData = readCanvasData(oScaledCanvas), strImgData = createBMP(oData); if (bReturnImg) { return makeImageObject(makeDataURI(strImgData, strMime)); } else { saveFile(makeDataURI(strImgData, strMime)); } return true; } }; })();