Canvas2Image

covert canvas to image and save the image file

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/460904/1155383/Canvas2Image.js

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

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址