Created
December 10, 2009 10:55
-
-
Save saikat/253272 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @import <AppKit/CPView.j> | |
| @import "base64.j" | |
| /* | |
| * Canvas2Image v0.1 | |
| * Copyright (c) 2008 Jacob Seidelin, [email protected] | |
| * MIT License [http://www.opensource.org/licenses/mit-license.php] | |
| */ | |
| /******* Canvas2Image code starts here *******/ | |
| var Canvas2Image = (function() { | |
| // check if we have canvas support | |
| var bHasCanvas = false; | |
| var oCanvas = document.createElement("canvas"); | |
| if (oCanvas.getContext("2d")) { | |
| bHasCanvas = true; | |
| } | |
| // no canvas, bail out. | |
| if (!bHasCanvas) { | |
| return { | |
| saveAsBMP : function(){}, | |
| saveAsPNG : function(){}, | |
| saveAsJPEG : function(){} | |
| } | |
| } | |
| var bHasImageData = !!(oCanvas.getContext("2d").getImageData); | |
| var bHasDataURL = !!(oCanvas.toDataURL); | |
| var bHasBase64 = !!(window.btoa); | |
| var strDownloadMime = "image/octet-stream"; | |
| // ok, we're good | |
| var readCanvasData = function(oCanvas) { | |
| var iWidth = parseInt(oCanvas.width); | |
| var 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 strData = ""; | |
| if (typeof data == "string") { | |
| strData = data; | |
| } else { | |
| var aData = data; | |
| for (var i=0;i<aData.length;i++) { | |
| strData += String.fromCharCode(aData[i]); | |
| } | |
| } | |
| return btoa(strData); | |
| } | |
| // creates a base64 encoded string containing BMP data | |
| // takes an imagedata object as argument | |
| var createBMP = function(oData) { | |
| var aHeader = []; | |
| var iWidth = oData.width; | |
| var iHeight = oData.height; | |
| aHeader.push(0x42); // magic 1 | |
| aHeader.push(0x4D); | |
| var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes | |
| aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); | |
| aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); | |
| aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); | |
| aHeader.push(iFileSize % 256); | |
| aHeader.push(0); // reserved | |
| aHeader.push(0); | |
| aHeader.push(0); // reserved | |
| aHeader.push(0); | |
| aHeader.push(54); // dataoffset | |
| aHeader.push(0); | |
| aHeader.push(0); | |
| aHeader.push(0); | |
| var aInfoHeader = []; | |
| aInfoHeader.push(40); // info header size | |
| aInfoHeader.push(0); | |
| aInfoHeader.push(0); | |
| aInfoHeader.push(0); | |
| var iImageWidth = iWidth; | |
| aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); | |
| aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); | |
| aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); | |
| aInfoHeader.push(iImageWidth % 256); | |
| var iImageHeight = iHeight; | |
| aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); | |
| aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); | |
| aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); | |
| aInfoHeader.push(iImageHeight % 256); | |
| aInfoHeader.push(1); // num of planes | |
| aInfoHeader.push(0); | |
| aInfoHeader.push(24); // num of bits per pixel | |
| aInfoHeader.push(0); | |
| aInfoHeader.push(0); // compression = none | |
| aInfoHeader.push(0); | |
| aInfoHeader.push(0); | |
| aInfoHeader.push(0); | |
| var iDataSize = iWidth*iHeight*3; | |
| aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); | |
| aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); | |
| aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); | |
| aInfoHeader.push(iDataSize % 256); | |
| for (var i=0;i<16;i++) { | |
| aInfoHeader.push(0); // these bytes not used | |
| } | |
| var iPadding = (4 - ((iWidth * 3) % 4)) % 4; | |
| var aImgData = oData.data; | |
| var strPixelData = ""; | |
| var y = iHeight; | |
| do { | |
| var iOffsetY = iWidth*(y-1)*4; | |
| var strPixelRow = ""; | |
| for (var x=0;x<iWidth;x++) { | |
| var iOffsetX = 4*x; | |
| strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]); | |
| strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]); | |
| strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]); | |
| } | |
| for (var c=0;c<iPadding;c++) { | |
| strPixelRow += String.fromCharCode(0); | |
| } | |
| strPixelData += strPixelRow; | |
| } while (--y); | |
| var strEncoded = encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData); | |
| return strEncoded; | |
| } | |
| // sends the generated file to the client | |
| var saveFile = function(strData) { | |
| document.location.href = strData; | |
| } | |
| var makeDataURI = function(strData, strMime) { | |
| return "data:" + strMime + ";base64," + strData; | |
| } | |
| // generates a <img> 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); | |
| var strData = oScaledCanvas.toDataURL("image/png"); | |
| if (bReturnImg) { | |
| return makeImageObject(strData); | |
| } else { | |
| saveFile(strData.replace("image/png", strDownloadMime)); | |
| } | |
| return true; | |
| }, | |
| saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) { | |
| if (!bHasDataURL) { | |
| return false; | |
| } | |
| var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight); | |
| var strMime = "image/jpeg"; | |
| var 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(strData.replace(strMime, strDownloadMime)); | |
| } | |
| return true; | |
| }, | |
| saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) { | |
| if (!(bHasImageData && bHasBase64)) { | |
| return false; | |
| } | |
| var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight); | |
| var oData = readCanvasData(oScaledCanvas); | |
| var strImgData = createBMP(oData); | |
| if (bReturnImg) { | |
| return makeImageObject(makeDataURI(strImgData, "image/bmp")); | |
| } else { | |
| saveFile(makeDataURI(strImgData, strDownloadMime)); | |
| } | |
| return true; | |
| } | |
| }; | |
| })(); | |
| /******* Canvas2Image code ends here *******/ | |
| @implementation CPView(Export) { } | |
| - (DOMElement)exportToHTML | |
| { | |
| var clonedElement = _DOMElement.cloneNode(true), | |
| canvasElements = _DOMElement.getElementsByTagName("canvas"), | |
| clonedCanvasElements = clonedElement.getElementsByTagName("canvas"), | |
| count = canvasElements.length; | |
| while (count--) { | |
| var replacementImage = Canvas2Image.saveAsPNG(canvasElements[count], true); | |
| replacementImage.style.top = "0px"; | |
| replacementImage.style.left = "0px"; | |
| replacementImage.style.padding = "0px"; | |
| replacementImage.style.margin = "0px"; | |
| replacementImage.style.zIndex = -100; | |
| replacementImage.style.overflow = "hidden"; | |
| replacementImage.style.position = "absolute"; | |
| replacementImage.style.visibility = "visible"; | |
| clonedCanvasElements[count].parentNode.replaceChild(replacementImage, clonedCanvasElements[count]); | |
| } | |
| return clonedElement; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment