canvas2image.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Canvas2Image v0.1
  3. * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk
  4. * MIT License [http://www.opensource.org/licenses/mit-license.php]
  5. */
  6. var Canvas2Image = (function() {
  7. // check if we have canvas support
  8. var bHasCanvas = false;
  9. var oCanvas = document.createElement("canvas");
  10. if (oCanvas.getContext("2d")) {
  11. bHasCanvas = true;
  12. }
  13. // no canvas, bail out.
  14. if (!bHasCanvas) {
  15. return {
  16. saveAsBMP : function(){},
  17. saveAsPNG : function(){},
  18. saveAsJPEG : function(){}
  19. }
  20. }
  21. var bHasImageData = !!(oCanvas.getContext("2d").getImageData);
  22. var bHasDataURL = !!(oCanvas.toDataURL);
  23. var bHasBase64 = !!(window.btoa);
  24. var strDownloadMime = "image/octet-stream";
  25. // ok, we're good
  26. var readCanvasData = function(oCanvas) {
  27. var iWidth = parseInt(oCanvas.width);
  28. var iHeight = parseInt(oCanvas.height);
  29. return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight);
  30. }
  31. // base64 encodes either a string or an array of charcodes
  32. var encodeData = function(data) {
  33. var strData = "";
  34. if (typeof data == "string") {
  35. strData = data;
  36. } else {
  37. var aData = data;
  38. for (var i=0;i<aData.length;i++) {
  39. strData += String.fromCharCode(aData[i]);
  40. }
  41. }
  42. return btoa(strData);
  43. }
  44. // creates a base64 encoded string containing BMP data
  45. // takes an imagedata object as argument
  46. var createBMP = function(oData) {
  47. var aHeader = [];
  48. var iWidth = oData.width;
  49. var iHeight = oData.height;
  50. aHeader.push(0x42); // magic 1
  51. aHeader.push(0x4D);
  52. var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes
  53. aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
  54. aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
  55. aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
  56. aHeader.push(iFileSize % 256);
  57. aHeader.push(0); // reserved
  58. aHeader.push(0);
  59. aHeader.push(0); // reserved
  60. aHeader.push(0);
  61. aHeader.push(54); // dataoffset
  62. aHeader.push(0);
  63. aHeader.push(0);
  64. aHeader.push(0);
  65. var aInfoHeader = [];
  66. aInfoHeader.push(40); // info header size
  67. aInfoHeader.push(0);
  68. aInfoHeader.push(0);
  69. aInfoHeader.push(0);
  70. var iImageWidth = iWidth;
  71. aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
  72. aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
  73. aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
  74. aInfoHeader.push(iImageWidth % 256);
  75. var iImageHeight = iHeight;
  76. aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
  77. aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
  78. aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
  79. aInfoHeader.push(iImageHeight % 256);
  80. aInfoHeader.push(1); // num of planes
  81. aInfoHeader.push(0);
  82. aInfoHeader.push(24); // num of bits per pixel
  83. aInfoHeader.push(0);
  84. aInfoHeader.push(0); // compression = none
  85. aInfoHeader.push(0);
  86. aInfoHeader.push(0);
  87. aInfoHeader.push(0);
  88. var iDataSize = iWidth*iHeight*3;
  89. aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
  90. aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
  91. aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
  92. aInfoHeader.push(iDataSize % 256);
  93. for (var i=0;i<16;i++) {
  94. aInfoHeader.push(0); // these bytes not used
  95. }
  96. var iPadding = (4 - ((iWidth * 3) % 4)) % 4;
  97. var aImgData = oData.data;
  98. var strPixelData = "";
  99. var y = iHeight;
  100. do {
  101. var iOffsetY = iWidth*(y-1)*4;
  102. var strPixelRow = "";
  103. for (var x=0;x<iWidth;x++) {
  104. var iOffsetX = 4*x;
  105. strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);
  106. strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);
  107. strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);
  108. }
  109. for (var c=0;c<iPadding;c++) {
  110. strPixelRow += String.fromCharCode(0);
  111. }
  112. strPixelData += strPixelRow;
  113. } while (--y);
  114. var strEncoded = encodeData(aHeader.concat(aInfoHeader)) + encodeData(strPixelData);
  115. return strEncoded;
  116. }
  117. // sends the generated file to the client
  118. var saveFile = function(strData) {
  119. document.location.href = strData;
  120. }
  121. var makeDataURI = function(strData, strMime) {
  122. return "data:" + strMime + ";base64," + strData;
  123. }
  124. // generates a <img> object containing the imagedata
  125. var makeImageObject = function(strSource) {
  126. var oImgElement = document.createElement("img");
  127. oImgElement.src = strSource;
  128. return oImgElement;
  129. }
  130. var scaleCanvas = function(oCanvas, iWidth, iHeight) {
  131. if (iWidth && iHeight) {
  132. var oSaveCanvas = document.createElement("canvas");
  133. oSaveCanvas.width = iWidth;
  134. oSaveCanvas.height = iHeight;
  135. oSaveCanvas.style.width = iWidth+"px";
  136. oSaveCanvas.style.height = iHeight+"px";
  137. var oSaveCtx = oSaveCanvas.getContext("2d");
  138. oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iHeight);
  139. return oSaveCanvas;
  140. }
  141. return oCanvas;
  142. }
  143. return {
  144. saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {
  145. if (!bHasDataURL) {
  146. return false;
  147. }
  148. var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
  149. var strData = oScaledCanvas.toDataURL("image/png");
  150. if (bReturnImg) {
  151. return makeImageObject(strData);
  152. } else {
  153. saveFile(strData.replace("image/png", strDownloadMime));
  154. }
  155. return true;
  156. },
  157. saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {
  158. if (!bHasDataURL) {
  159. return false;
  160. }
  161. var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
  162. var strMime = "image/jpeg";
  163. var strData = oScaledCanvas.toDataURL(strMime);
  164. // check if browser actually supports jpeg by looking for the mime type in the data uri.
  165. // if not, return false
  166. if (strData.indexOf(strMime) != 5) {
  167. return false;
  168. }
  169. if (bReturnImg) {
  170. return makeImageObject(strData);
  171. } else {
  172. saveFile(strData.replace(strMime, strDownloadMime));
  173. }
  174. return true;
  175. },
  176. saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {
  177. if (!(bHasImageData && bHasBase64)) {
  178. return false;
  179. }
  180. var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight);
  181. var oData = readCanvasData(oScaledCanvas);
  182. var strImgData = createBMP(oData);
  183. if (bReturnImg) {
  184. return makeImageObject(makeDataURI(strImgData, "image/bmp"));
  185. } else {
  186. saveFile(makeDataURI(strImgData, strDownloadMime));
  187. }
  188. return true;
  189. }
  190. };
  191. })();