預約系統 IOS / Android Windows

canvas2image.js 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /**
  2. * covert canvas to image
  3. * and save the image file
  4. */
  5. const Canvas2Image = (function () {
  6. // check if support sth.
  7. const $support = (function () {
  8. const canvas = document.createElement("canvas"),
  9. ctx = canvas.getContext("2d");
  10. return {
  11. canvas: !!ctx,
  12. imageData: !!ctx.getImageData,
  13. dataURL: !!canvas.toDataURL,
  14. btoa: !!window.btoa,
  15. };
  16. })();
  17. const downloadMime = "image/octet-stream";
  18. function scaleCanvas(canvas, width, height) {
  19. const w = canvas.width,
  20. h = canvas.height;
  21. if (width === undefined) {
  22. width = w;
  23. }
  24. if (height === undefined) {
  25. height = h;
  26. }
  27. let retCanvas = document.createElement("canvas");
  28. let retCtx = retCanvas.getContext("2d");
  29. retCanvas.width = width;
  30. retCanvas.height = height;
  31. retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height);
  32. return retCanvas;
  33. }
  34. function getDataURL(canvas, type, width, height) {
  35. canvas = scaleCanvas(canvas, width, height);
  36. return canvas.toDataURL(type);
  37. }
  38. // save file to local with file name and file type
  39. function saveFile(strData, fileType, fileName = "name") {
  40. // document.location.href = strData;
  41. let saveLink = document.createElement("a");
  42. // download file name
  43. saveLink.download = fileName + "." + fileType;
  44. // download file data
  45. saveLink.href = strData;
  46. // start download
  47. saveLink.click();
  48. }
  49. function genImage(strData) {
  50. let img = document.createElement("img");
  51. img.src = strData;
  52. return img;
  53. }
  54. function fixType(type) {
  55. type = type.toLowerCase().replace(/jpg/i, "jpeg");
  56. const r = type.match(/png|jpeg|bmp|gif/)[0];
  57. return "image/" + r;
  58. }
  59. function encodeData(data) {
  60. if (!window.btoa) {
  61. // eslint-disable-next-line no-throw-literal
  62. throw "btoa undefined";
  63. }
  64. let str = "";
  65. if (typeof data == "string") {
  66. str = data;
  67. } else {
  68. for (let i = 0; i < data.length; i++) {
  69. str += String.fromCharCode(data[i]);
  70. }
  71. }
  72. return btoa(str);
  73. }
  74. function getImageData(canvas) {
  75. const w = canvas.width,
  76. h = canvas.height;
  77. return canvas.getContext("2d").getImageData(0, 0, w, h);
  78. }
  79. function makeURI(strData, type) {
  80. return "data:" + type + ";base64," + strData;
  81. }
  82. /**
  83. * create bitmap image
  84. * 按照规则生成图片响应头和响应体
  85. */
  86. const genBitmapImage = function (oData) {
  87. //
  88. // BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
  89. // BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
  90. //
  91. const biWidth = oData.width;
  92. const biHeight = oData.height;
  93. const biSizeImage = biWidth * biHeight * 3;
  94. const bfSize = biSizeImage + 54; // total header size = 54 bytes
  95. //
  96. // typedef struct tagBITMAPFILEHEADER {
  97. // WORD bfType;
  98. // DWORD bfSize;
  99. // WORD bfReserved1;
  100. // WORD bfReserved2;
  101. // DWORD bfOffBits;
  102. // } BITMAPFILEHEADER;
  103. //
  104. const BITMAPFILEHEADER = [
  105. // WORD bfType -- The file type signature; must be "BM"
  106. 0x42,
  107. 0x4d,
  108. // DWORD bfSize -- The size, in bytes, of the bitmap file
  109. bfSize & 0xff,
  110. (bfSize >> 8) & 0xff,
  111. (bfSize >> 16) & 0xff,
  112. (bfSize >> 24) & 0xff,
  113. // WORD bfReserved1 -- Reserved; must be zero
  114. 0,
  115. 0,
  116. // WORD bfReserved2 -- Reserved; must be zero
  117. 0,
  118. 0,
  119. // DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
  120. 54,
  121. 0,
  122. 0,
  123. 0,
  124. ];
  125. //
  126. // typedef struct tagBITMAPINFOHEADER {
  127. // DWORD biSize;
  128. // LONG biWidth;
  129. // LONG biHeight;
  130. // WORD biPlanes;
  131. // WORD biBitCount;
  132. // DWORD biCompression;
  133. // DWORD biSizeImage;
  134. // LONG biXPelsPerMeter;
  135. // LONG biYPelsPerMeter;
  136. // DWORD biClrUsed;
  137. // DWORD biClrImportant;
  138. // } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
  139. //
  140. const BITMAPINFOHEADER = [
  141. // DWORD biSize -- The number of bytes required by the structure
  142. 40,
  143. 0,
  144. 0,
  145. 0,
  146. // LONG biWidth -- The width of the bitmap, in pixels
  147. biWidth & 0xff,
  148. (biWidth >> 8) & 0xff,
  149. (biWidth >> 16) & 0xff,
  150. (biWidth >> 24) & 0xff,
  151. // LONG biHeight -- The height of the bitmap, in pixels
  152. biHeight & 0xff,
  153. (biHeight >> 8) & 0xff,
  154. (biHeight >> 16) & 0xff,
  155. (biHeight >> 24) & 0xff,
  156. // WORD biPlanes -- The number of planes for the target device. This value must be set to 1
  157. 1,
  158. 0,
  159. // WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
  160. // has a maximum of 2^24 colors (16777216, Truecolor)
  161. 24,
  162. 0,
  163. // DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
  164. 0,
  165. 0,
  166. 0,
  167. 0,
  168. // DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
  169. biSizeImage & 0xff,
  170. (biSizeImage >> 8) & 0xff,
  171. (biSizeImage >> 16) & 0xff,
  172. (biSizeImage >> 24) & 0xff,
  173. // LONG biXPelsPerMeter, unused
  174. 0,
  175. 0,
  176. 0,
  177. 0,
  178. // LONG biYPelsPerMeter, unused
  179. 0,
  180. 0,
  181. 0,
  182. 0,
  183. // DWORD biClrUsed, the number of color indexes of palette, unused
  184. 0,
  185. 0,
  186. 0,
  187. 0,
  188. // DWORD biClrImportant, unused
  189. 0,
  190. 0,
  191. 0,
  192. 0,
  193. ];
  194. const iPadding = (4 - ((biWidth * 3) % 4)) % 4;
  195. const aImgData = oData.data;
  196. let strPixelData = "";
  197. const biWidth4 = biWidth << 2;
  198. let y = biHeight;
  199. const fromCharCode = String.fromCharCode;
  200. do {
  201. const iOffsetY = biWidth4 * (y - 1);
  202. let strPixelRow = "";
  203. for (let x = 0; x < biWidth; x++) {
  204. const iOffsetX = x << 2;
  205. strPixelRow +=
  206. fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) +
  207. fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) +
  208. fromCharCode(aImgData[iOffsetY + iOffsetX]);
  209. }
  210. for (let c = 0; c < iPadding; c++) {
  211. strPixelRow += String.fromCharCode(0);
  212. }
  213. strPixelData += strPixelRow;
  214. } while (--y);
  215. return (
  216. encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) +
  217. encodeData(strPixelData)
  218. );
  219. };
  220. /**
  221. * saveAsImage
  222. * @param canvas canvasElement
  223. * @param width {String} image type
  224. * @param height {Number} [optional] png width
  225. * @param type {string} [optional] png height
  226. * @param fileName {String} image name
  227. */
  228. const saveAsImage = function (canvas, width, height, type, fileName) {
  229. // save file type
  230. const fileType = type;
  231. if ($support.canvas && $support.dataURL) {
  232. if (typeof canvas == "string") {
  233. canvas = document.getElementById(canvas);
  234. }
  235. if (type === undefined) {
  236. type = "png";
  237. }
  238. type = fixType(type);
  239. if (/bmp/.test(type)) {
  240. const data = getImageData(scaleCanvas(canvas, width, height));
  241. const strData = genBitmapImage(data);
  242. // use new parameter: fileType
  243. saveFile(makeURI(strData, downloadMime), fileType, fileName);
  244. } else {
  245. const strData = getDataURL(canvas, type, width, height);
  246. // use new parameter: fileType
  247. saveFile(strData.replace(type, downloadMime), fileType, fileName);
  248. }
  249. }
  250. };
  251. const convertToImage = function (canvas, width, height, type) {
  252. if ($support.canvas && $support.dataURL) {
  253. if (typeof canvas == "string") {
  254. canvas = document.getElementById(canvas);
  255. }
  256. if (type === undefined) {
  257. type = "png";
  258. }
  259. type = fixType(type);
  260. if (/bmp/.test(type)) {
  261. const data = getImageData(scaleCanvas(canvas, width, height));
  262. const strData = genBitmapImage(data);
  263. return genImage(makeURI(strData, "image/bmp"));
  264. } else {
  265. const strData = getDataURL(canvas, type, width, height);
  266. return genImage(strData);
  267. }
  268. }
  269. };
  270. return {
  271. saveAsImage: saveAsImage,
  272. saveAsPNG: function (canvas, width, height, fileName) {
  273. return saveAsImage(canvas, width, height, "png", fileName);
  274. },
  275. saveAsJPEG: function (canvas, width, height, fileName) {
  276. return saveAsImage(canvas, width, height, "jpeg", fileName);
  277. },
  278. saveAsGIF: function (canvas, width, height, fileName) {
  279. return saveAsImage(canvas, width, height, "gif", fileName);
  280. },
  281. saveAsBMP: function (canvas, width, height, fileName) {
  282. return saveAsImage(canvas, width, height, "bmp", fileName);
  283. },
  284. convertToImage: convertToImage,
  285. convertToPNG: function (canvas, width, height) {
  286. return convertToImage(canvas, width, height, "png");
  287. },
  288. convertToJPEG: function (canvas, width, height) {
  289. return convertToImage(canvas, width, height, "jpeg");
  290. },
  291. convertToGIF: function (canvas, width, height) {
  292. return convertToImage(canvas, width, height, "gif");
  293. },
  294. convertToBMP: function (canvas, width, height) {
  295. return convertToImage(canvas, width, height, "bmp");
  296. },
  297. };
  298. })();