277 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
		
		
			
		
	
	
			277 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
|  | /** | ||
|  |  * covert canvas to image | ||
|  |  * and save the image file | ||
|  |  */ | ||
|  | 
 | ||
|  | var Canvas2Image = function () { | ||
|  | 
 | ||
|  | 	// check if support sth.
 | ||
|  | 	var $support = function () { | ||
|  | 		var canvas = document.createElement('canvas'), | ||
|  | 			ctx = canvas.getContext('2d'); | ||
|  | 
 | ||
|  | 		return { | ||
|  | 			canvas: !!ctx, | ||
|  | 			imageData: !!ctx.getImageData, | ||
|  | 			dataURL: !!canvas.toDataURL, | ||
|  | 			btoa: !!window.btoa | ||
|  | 		}; | ||
|  | 	}(); | ||
|  | 
 | ||
|  | 	var downloadMime = 'image/octet-stream'; | ||
|  | 
 | ||
|  | 	function scaleCanvas (canvas, width, height) { | ||
|  | 		var w = canvas.width, | ||
|  | 			h = canvas.height; | ||
|  | 		if (width == undefined) { | ||
|  | 			width = w; | ||
|  | 		} | ||
|  | 		if (height == undefined) { | ||
|  | 			height = h; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		var retCanvas = document.createElement('canvas'); | ||
|  | 		var retCtx = retCanvas.getContext('2d'); | ||
|  | 		retCanvas.width = width; | ||
|  | 		retCanvas.height = height; | ||
|  | 		retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height); | ||
|  | 		return retCanvas; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function getDataURL (canvas, type, width, height) { | ||
|  | 		canvas = scaleCanvas(canvas, width, height); | ||
|  | 		return canvas.toDataURL(type); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function saveFile (strData,filename) { | ||
|  | 		var save_link = document.createElement('a'); | ||
|  | 		save_link.href = strData; | ||
|  | 		save_link.download = filename; | ||
|  | 		var event = new MouseEvent('click',{"bubbles":false, "cancelable":false}); | ||
|  | 		save_link.dispatchEvent(event); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	function genImage(strData) { | ||
|  | 		var img = document.createElement('img'); | ||
|  | 		img.src = strData; | ||
|  | 		return img; | ||
|  | 	} | ||
|  | 	function fixType (type) { | ||
|  | 		type = type.toLowerCase().replace(/jpg/i, 'jpeg'); | ||
|  | 		var r = type.match(/png|jpeg|bmp|gif/)[0]; | ||
|  | 		return 'image/' + r; | ||
|  | 	} | ||
|  | 	function encodeData (data) { | ||
|  | 		if (!window.btoa) { throw 'btoa undefined' } | ||
|  | 		var str = ''; | ||
|  | 		if (typeof data == 'string') { | ||
|  | 			str = data; | ||
|  | 		} else { | ||
|  | 			for (var i = 0; i < data.length; i ++) { | ||
|  | 				str += String.fromCharCode(data[i]); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return btoa(str); | ||
|  | 	} | ||
|  | 	function getImageData (canvas) { | ||
|  | 		var w = canvas.width, | ||
|  | 			h = canvas.height; | ||
|  | 		return canvas.getContext('2d').getImageData(0, 0, w, h); | ||
|  | 	} | ||
|  | 	function makeURI (strData, type) { | ||
|  | 		return 'data:' + type + ';base64,' + strData; | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * create bitmap image | ||
|  | 	 * 按照规则生成图片响应头和响应体 | ||
|  | 	 */ | ||
|  | 	var genBitmapImage = function (oData) { | ||
|  | 
 | ||
|  | 		//
 | ||
|  | 		// BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
 | ||
|  | 		// BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
 | ||
|  | 		//
 | ||
|  | 
 | ||
|  | 		var biWidth  = oData.width; | ||
|  | 		var biHeight	= oData.height; | ||
|  | 		var biSizeImage = biWidth * biHeight * 3; | ||
|  | 		var bfSize  = biSizeImage + 54; // total header size = 54 bytes
 | ||
|  | 
 | ||
|  | 		//
 | ||
|  | 		//  typedef struct tagBITMAPFILEHEADER {
 | ||
|  | 		//  	WORD bfType;
 | ||
|  | 		//  	DWORD bfSize;
 | ||
|  | 		//  	WORD bfReserved1;
 | ||
|  | 		//  	WORD bfReserved2;
 | ||
|  | 		//  	DWORD bfOffBits;
 | ||
|  | 		//  } BITMAPFILEHEADER;
 | ||
|  | 		//
 | ||
|  | 		var BITMAPFILEHEADER = [ | ||
|  | 			// WORD bfType -- The file type signature; must be "BM"
 | ||
|  | 			0x42, 0x4D, | ||
|  | 			// DWORD bfSize -- The size, in bytes, of the bitmap file
 | ||
|  | 			bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff, | ||
|  | 			// WORD bfReserved1 -- Reserved; must be zero
 | ||
|  | 			0, 0, | ||
|  | 			// WORD bfReserved2 -- Reserved; must be zero
 | ||
|  | 			0, 0, | ||
|  | 			// DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
 | ||
|  | 			54, 0, 0, 0 | ||
|  | 		]; | ||
|  | 
 | ||
|  | 		//
 | ||
|  | 		//  typedef struct tagBITMAPINFOHEADER {
 | ||
|  | 		//  	DWORD biSize;
 | ||
|  | 		//  	LONG  biWidth;
 | ||
|  | 		//  	LONG  biHeight;
 | ||
|  | 		//  	WORD  biPlanes;
 | ||
|  | 		//  	WORD  biBitCount;
 | ||
|  | 		//  	DWORD biCompression;
 | ||
|  | 		//  	DWORD biSizeImage;
 | ||
|  | 		//  	LONG  biXPelsPerMeter;
 | ||
|  | 		//  	LONG  biYPelsPerMeter;
 | ||
|  | 		//  	DWORD biClrUsed;
 | ||
|  | 		//  	DWORD biClrImportant;
 | ||
|  | 		//  } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
 | ||
|  | 		//
 | ||
|  | 		var BITMAPINFOHEADER = [ | ||
|  | 			// DWORD biSize -- The number of bytes required by the structure
 | ||
|  | 			40, 0, 0, 0, | ||
|  | 			// LONG biWidth -- The width of the bitmap, in pixels
 | ||
|  | 			biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff, | ||
|  | 			// LONG biHeight -- The height of the bitmap, in pixels
 | ||
|  | 			biHeight & 0xff, biHeight >> 8  & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff, | ||
|  | 			// WORD biPlanes -- The number of planes for the target device. This value must be set to 1
 | ||
|  | 			1, 0, | ||
|  | 			// WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
 | ||
|  | 			// has a maximum of 2^24 colors (16777216, Truecolor)
 | ||
|  | 			24, 0, | ||
|  | 			// DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
 | ||
|  | 			0, 0, 0, 0, | ||
|  | 			// DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
 | ||
|  | 			biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff, | ||
|  | 			// LONG biXPelsPerMeter, unused
 | ||
|  | 			0,0,0,0, | ||
|  | 			// LONG biYPelsPerMeter, unused
 | ||
|  | 			0,0,0,0, | ||
|  | 			// DWORD biClrUsed, the number of color indexes of palette, unused
 | ||
|  | 			0,0,0,0, | ||
|  | 			// DWORD biClrImportant, unused
 | ||
|  | 			0,0,0,0 | ||
|  | 		]; | ||
|  | 
 | ||
|  | 		var iPadding = (4 - ((biWidth * 3) % 4)) % 4; | ||
|  | 
 | ||
|  | 		var aImgData = oData.data; | ||
|  | 
 | ||
|  | 		var strPixelData = ''; | ||
|  | 		var biWidth4 = biWidth<<2; | ||
|  | 		var y = biHeight; | ||
|  | 		var fromCharCode = String.fromCharCode; | ||
|  | 
 | ||
|  | 		do { | ||
|  | 			var iOffsetY = biWidth4*(y-1); | ||
|  | 			var strPixelRow = ''; | ||
|  | 			for (var x = 0; x < biWidth; x++) { | ||
|  | 				var iOffsetX = x<<2; | ||
|  | 				strPixelRow += fromCharCode(aImgData[iOffsetY+iOffsetX+2]) + | ||
|  | 							   fromCharCode(aImgData[iOffsetY+iOffsetX+1]) + | ||
|  | 							   fromCharCode(aImgData[iOffsetY+iOffsetX]); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			for (var c = 0; c < iPadding; c++) { | ||
|  | 				strPixelRow += String.fromCharCode(0); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			strPixelData += strPixelRow; | ||
|  | 		} while (--y); | ||
|  | 
 | ||
|  | 		var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData); | ||
|  | 
 | ||
|  | 		return strEncoded; | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	 | ||
|  | 	/** | ||
|  | 	 * [saveAsImage] | ||
|  | 	 * @param  {[obj]} canvas   [canvasElement] | ||
|  | 	 * @param  {[Number]} width    [optional] png width | ||
|  | 	 * @param  {[Number]} height   [optional] png height | ||
|  | 	 * @param  {[String]} type     [image type] | ||
|  | 	 * @param  {[String]} filename [image filename] | ||
|  | 	 * @return {[type]}          [description] | ||
|  | 	 */ | ||
|  | 	var saveAsImage = function (canvas, width, height, type,filename) { | ||
|  | 		if ($support.canvas && $support.dataURL) { | ||
|  | 			if (typeof canvas == "string") { canvas = document.getElementById(canvas); } | ||
|  | 			if (type == undefined) { type = 'png'; } | ||
|  | 			filename = filename == undefined||filename.length === 0 ?Date.now()+'.'+type: filename+'.'+type | ||
|  | 			type = fixType(type); | ||
|  | 
 | ||
|  | 			if (/bmp/.test(type)) { | ||
|  | 				var data = getImageData(scaleCanvas(canvas, width, height)); | ||
|  | 				var strData = genBitmapImage(data); | ||
|  | 
 | ||
|  | 				saveFile(makeURI(strData, downloadMimedownloadMime),filename); | ||
|  | 			} else { | ||
|  | 				var strData = getDataURL(canvas, type, width, height); | ||
|  | 				saveFile(strData.replace(type, downloadMime),filename); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	var convertToImage = function (canvas, width, height, type) { | ||
|  | 		if ($support.canvas && $support.dataURL) { | ||
|  | 			if (typeof canvas == "string") { canvas = document.getElementById(canvas); } | ||
|  | 			if (type == undefined) { type = 'png'; } | ||
|  | 			type = fixType(type); | ||
|  | 
 | ||
|  | 			if (/bmp/.test(type)) { | ||
|  | 				var data = getImageData(scaleCanvas(canvas, width, height)); | ||
|  | 				var strData = genBitmapImage(data); | ||
|  | 				return genImage(makeURI(strData, 'image/bmp')); | ||
|  | 			} else { | ||
|  | 				var strData = getDataURL(canvas, type, width, height); | ||
|  | 				return genImage(strData); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	}; | ||
|  | 
 | ||
|  | 
 | ||
|  | 	return { | ||
|  | 		saveAsImage: saveAsImage, | ||
|  | 		saveAsPNG: function (canvas, width, height, fileName) { | ||
|  | 			return saveAsImage(canvas, width, height, 'png',fileName); | ||
|  | 		}, | ||
|  | 		saveAsJPEG: function (canvas, width, height, fileName) { | ||
|  | 			return saveAsImage(canvas, width, height, 'jpeg',fileName); | ||
|  | 		}, | ||
|  | 		saveAsGIF: function (canvas, width, height, fileName) { | ||
|  | 			return saveAsImage(canvas, width, height, 'gif',fileName); | ||
|  | 		}, | ||
|  | 		saveAsBMP: function (canvas, width, height, fileName) { | ||
|  | 			return saveAsImage(canvas, width, height, 'bmp',fileName); | ||
|  | 		}, | ||
|  | 
 | ||
|  | 		convertToImage: convertToImage, | ||
|  | 		convertToPNG: function (canvas, width, height) { | ||
|  | 			return convertToImage(canvas, width, height, 'png'); | ||
|  | 		}, | ||
|  | 		convertToJPEG: function (canvas, width, height) { | ||
|  | 			return convertToImage(canvas, width, height, 'jpeg'); | ||
|  | 		}, | ||
|  | 		convertToGIF: function (canvas, width, height) { | ||
|  | 			return convertToImage(canvas, width, height, 'gif'); | ||
|  | 		}, | ||
|  | 		convertToBMP: function (canvas, width, height) { | ||
|  | 			return convertToImage(canvas, width, height, 'bmp'); | ||
|  | 		} | ||
|  | 	}; | ||
|  | 
 | ||
|  | }(); | ||
|  | 
 | ||
|  | export default Canvas2Image |