html页面、canvas导出图片
背景:项目现场提出将一个html做的图形页面导出为一张图片的需求,在网上搜了一下,发现都不是很全面,所以综合了很多大神的帖子,自己再次封装,以适用项目需求。
所需js库:html2canvas.js(https://github.com/niklasvh/html2canvas); Export2Image.js(自己封装),其中new Export2Image(htmlDom,[opts]).export()是执行导出命令。opts = {width:400,height:400,type:"png",fname:"downloadName"}为可选参数。
注意:在使用过程中,发现一个问题,dom背景图片千万不能设置background-size:contain/conver,否则背景图片导不出来。
代码:
1 /** 2 * Created by tengri on 2016-5-9. 3 */ 4 5 /** 6 * 导出类 7 * @param content 要导出的内容 8 * @constructor 9 */ 10 function Export2Image(content,opts){ 11 this.exportObj = typeof(content) == "string" ? document.getElementById(content) : content; 12 if(!this.exportObj) throw new Error("导出内容对象只能传递ID和DOM对象"); 13 this.opts = opts || {}; 14 if(this.exportObj.nodeName !="CANVAS"){ 15 this.exportType = "html2Image"; 16 this.canvas = document.createElement("canvas"); 17 this.canvas.style.display = "none"; 18 //如果没有设置宽度和高度,实际是多大就导出多大 19 this.canvas.width = this.opts.width || this.exportObj.scrollWidth + 10; 20 this.canvas.height = this.opts.height || this.exportObj.scrollHeight + 10; 21 }else{ 22 this.exportType = "canvas2Image"; 23 this.canvas = this.exportObj; 24 } 25 if(this.opts.width && this.opts.height){ 26 this.actualWidth = this.opts.width; 27 this.actualHeight = this.opts.height; 28 } 29 this.type = this.opts.type || "png"; 30 this.fileName = (this.opts.name || new Date().getTime()) + "." + this.type; 31 this.init(); 32 return this; 33 } 34 35 /** 36 * 初始化 37 */ 38 Export2Image.prototype.init = function(){ 39 this._fixType(); 40 } 41 42 Export2Image.prototype._encodeData = function(data){ 43 if(!window.btoa) throw "btoa undefined"; 44 var strDtata = ""; 45 if(typeof(data) !="string"){ 46 for(var i = 0 ; i < data.length;i++){ 47 strDtata +=String.fromCharCode(data[i]); 48 } 49 }else{ 50 strDtata = data; 51 } 52 return window.btoa(strDtata); 53 }; 54 55 /** 56 * 根据配置生成固定大小图片 57 * @param width 58 * @param height 59 */ 60 Export2Image.prototype._scaleCanvas = function(width,height){ 61 var w = this.canvas.width; 62 var h = this.canvas.height; 63 width = width || w; 64 height = height || h; 65 66 var newCanvas = document.createElement("canvas"); 67 newCanvas.width = width; 68 newCanvas.height = height; 69 var ctx = newCanvas.getContext("2d"); 70 ctx.drawImage(this.canvas,0,0,w,h,0,0,width,height); 71 this.canvas = newCanvas; 72 }; 73 74 /** 75 * 获取canvas的Dataurl 76 */ 77 Export2Image.prototype._getDataURL = function(){ 78 return this.canvas.toDataURL(this.type); 79 }; 80 /** 81 * 获取导出图片类型 82 * @private 83 */ 84 Export2Image.prototype._fixType = function(){ 85 var type = this.type.toLocaleLowerCase().replace(/jpg/i,"jpeg"); 86 var res = type.match(/png|jpeg|bmp|gif/)[0]; 87 this.type = "image/" + res; 88 }; 89 90 /** 91 * 获取数据 92 */ 93 Export2Image.prototype.getData = function(){ 94 if(this.actualWidth && this.actualHeight){ 95 this._scaleCanvas(this.actualWidth,this.actualHeight); 96 } 97 var strData = ""; 98 if (/bmp/.test(this.type)) { 99 var data = this._getImageData(); 100 strData = this._getBitmapImage(data); 101 } else { 102 strData = this._getDataURL(); 103 } 104 return strData; 105 } 106 107 /** 108 * 普通图片获取 109 * @private 110 */ 111 Export2Image.prototype._getImageData = function(){ 112 var w = this.canvas.width, h = this.canvas.height; 113 return this.canvas.getContext('2d').getImageData(0, 0, w, h); 114 }; 115 116 /** 117 * 位图获取 118 * @private 119 */ 120 Export2Image.prototype._getBitmapImage = function(oData){ 121 var aHeader = []; 122 123 var iWidth = oData.width; 124 var iHeight = oData.height; 125 126 aHeader.push(0x42); // magic 1 127 aHeader.push(0x4D); 128 129 var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes 130 aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); 131 aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); 132 aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256); 133 aHeader.push(iFileSize % 256); 134 135 aHeader.push(0); // reserved 136 aHeader.push(0); 137 aHeader.push(0); // reserved 138 aHeader.push(0); 139 140 aHeader.push(54); // dataoffset 141 aHeader.push(0); 142 aHeader.push(0); 143 aHeader.push(0); 144 145 var aInfoHeader = []; 146 aInfoHeader.push(40); // info header size 147 aInfoHeader.push(0); 148 aInfoHeader.push(0); 149 aInfoHeader.push(0); 150 151 var iImageWidth = iWidth; 152 aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); 153 aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); 154 aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256); 155 aInfoHeader.push(iImageWidth % 256); 156 157 var iImageHeight = iHeight; 158 aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); 159 aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); 160 aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256); 161 aInfoHeader.push(iImageHeight % 256); 162 163 aInfoHeader.push(1); // num of planes 164 aInfoHeader.push(0); 165 166 aInfoHeader.push(24); // num of bits per pixel 167 aInfoHeader.push(0); 168 169 aInfoHeader.push(0); // compression = none 170 aInfoHeader.push(0); 171 aInfoHeader.push(0); 172 aInfoHeader.push(0); 173 174 var iDataSize = iWidth*iHeight*3; 175 aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); 176 aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); 177 aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256); 178 aInfoHeader.push(iDataSize % 256); 179 180 for (var i=0;i<16;i++) { 181 aInfoHeader.push(0); // these bytes not used 182 } 183 184 var iPadding = (4 - ((iWidth * 3) % 4)) % 4; 185 186 var aImgData = oData.data; 187 188 var strPixelData = ""; 189 var y = iHeight; 190 do { 191 var iOffsetY = iWidth*(y-1)*4; 192 var strPixelRow = ""; 193 for (var x=0;x<iWidth;x++) { 194 var iOffsetX = 4*x; 195 196 strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]); 197 strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]); 198 strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]); 199 } 200 for (var c=0;c<iPadding;c++) { 201 strPixelRow += String.fromCharCode(0); 202 } 203 strPixelData += strPixelRow; 204 } while (--y); 205 206 var strEncoded = this._encodeData(aHeader.concat(aInfoHeader)) + this._encodeData(strPixelData); 207 208 return this._makeDataURI(strEncoded); 209 }; 210 211 Export2Image.prototype._makeDataURI = function(strData){ 212 return "data:" + this.type + ";base64," + strData; 213 } 214 215 /** 216 * 保存 217 * @param data 218 * @param fileName 219 * @private 220 */ 221 Export2Image.prototype._saveFile = function(data,fileName){ 222 try{ 223 //TODO:IE浏览器 224 new ActiveXObject("Microsoft.XMLHTTP"); 225 var oImg = document.createElement("img"); 226 oImg.src = data; 227 oImg.onload = function(){ 228 myWindow=window.open('','_blank','width=800,height=600'); 229 myWindow.document.write("<img src='"+data+"'>") 230 myWindow.focus() 231 } 232 }catch(e){ 233 var saveLink = document.createElementNS("http://www.w3.org/1999/xhtml","a"); 234 saveLink.href = data; 235 saveLink.download = fileName; 236 var event = document.createEvent("MouseEvents"); 237 event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); 238 saveLink.dispatchEvent(event); 239 } 240 241 }; 242 243 Export2Image.prototype.exportPic = function(){ 244 if(this.exportType == "html2Image"){ 245 if(typeof(html2canvas) !="function"){ 246 alert("需要引入html2canvas.js库文件"); 247 return; 248 } 249 var that = this; 250 html2canvas(this.exportObj, { 251 onrendered: function(canvas) { 252 that.canvas = canvas; 253 var data = that.getData(); 254 var imgData = data.replace(that.type,'image/octet-stream'); 255 that._saveFile(imgData,that.fileName); 256 } 257 }); 258 }else{ 259 var data = this.getData(); 260 var imgData = data.replace(this.type,'image/octet-stream'); 261 this._saveFile(imgData,this.fileName); 262 } 263 264 };
1 <html> 2 <meta http-equiv="X-UA-Compatible" content="chrome=1"> 3 <meta charset="utf-8"> 4 <head> 5 <title>dom页面导出为图片</title> 6 <style type="text/css"> 7 #wrap{ 8 width:400px; 9 height:300px; 10 line-height:300px; 11 font-family: "Courier New", Courier, monospace; 12 font-size: 18px; 13 text-align: center; 14 border: 1px solid #ccc; 15 background-image: url("img/a.jpg"); 16 overflow: auto; 17 } 18 19 </style> 20 </head> 21 <body> 22 <div id="wrap">这是DOM元素,相当于项目中的图形所在的div 23 </div> 24 <input type="button" value="html导出图片" onclick="htmlExportHandler();"/><br><hr/> 25 <canvas id="myCanvas" width="600" height="400" style="background:yellowgreen"></canvas> 26 <input type="button" value="canvas导出图片" onclick="canvasExportHandler();"/><br><hr/> 27 28 </body> 29 </html> 30 <script type="text/javascript" src="js/html5.js"></script> 31 <script type="text/javascript" src="js/html2canvas.js"></script> 32 <script type="text/javascript" src="js/Export2Image.js"></script> 33 <script> 34 35 36 window.onload = function() { 37 var canvas = document.getElementById("myCanvas"); 38 var ctx=canvas.getContext('2d'); 39 ctx.fillStyle='#FF0000'; 40 ctx.fillRect(10,10,200,100); 41 42 }; 43 44 function htmlExportHandler(){ 45 var oContent = document.getElementById("wrap"); 46 new Export2Image(oContent,{type:"bmp",name:"html导出文件"}).export(); 47 } 48 49 function canvasExportHandler(){ 50 new Export2Image("myCanvas").export(); 51 } 52 53 </script>