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,否则背景图片导不出来。

代码:



/**

 * Created by tengri on 2016-5-9.
 */


/**
 * 导出类
 * @param content  要导出的内容
 * @constructor
 */
function Export2Image(content,opts){
    this.exportObj = typeof(content) == "string" ? document.getElementById(content) : content;
    if(!this.exportObj) throw new Error("导出内容对象只能传递ID和DOM对象");
    this.opts = opts || {};
    if(this.exportObj.nodeName !="CANVAS"){
        this.exportType = "html2Image";
        this.canvas = document.createElement("canvas");
        this.canvas.style.display = "none";
        //如果没有设置宽度和高度,实际是多大就导出多大
        this.canvas.width = this.opts.width || this.exportObj.scrollWidth + 10;
        this.canvas.height = this.opts.height || this.exportObj.scrollHeight + 10;
    }else{
        this.exportType = "canvas2Image";
        this.canvas = this.exportObj;
    }
    if(this.opts.width && this.opts.height){
        this.actualWidth = this.opts.width;
        this.actualHeight = this.opts.height;
    }
    this.type =  this.opts.type || "png";
    this.fileName = (this.opts.name || new Date().getTime()) + "." + this.type;
    this.init();
    return this;
}


/**
 * 初始化
 */
Export2Image.prototype.init = function(){
    this._fixType();
}


Export2Image.prototype._encodeData = function(data){
    if(!window.btoa) throw "btoa undefined";
    var strDtata = "";
    if(typeof(data) !="string"){
        for(var i = 0 ; i < data.length;i++){
            strDtata +=String.fromCharCode(data[i]);
        }
    }else{
        strDtata = data;
    }
    return window.btoa(strDtata);
};


/**
 * 根据配置生成固定大小图片
 * @param width
 * @param height
 */
Export2Image.prototype._scaleCanvas = function(width,height){
    var w = this.canvas.width;
    var h = this.canvas.height;
    width = width || w;
    height = height  || h;


    var newCanvas = document.createElement("canvas");
    newCanvas.width = width;
    newCanvas.height = height;
    var ctx = newCanvas.getContext("2d");
    ctx.drawImage(this.canvas,0,0,w,h,0,0,width,height);
    this.canvas = newCanvas;
};


/**
 * 获取canvas的Dataurl
 */
Export2Image.prototype._getDataURL = function(){
    return this.canvas.toDataURL(this.type);
};
/**
 * 获取导出图片类型
 * @private
 */
Export2Image.prototype._fixType = function(){
    var type = this.type.toLocaleLowerCase().replace(/jpg/i,"jpeg");
    var res = type.match(/png|jpeg|bmp|gif/)[0];
    this.type = "image/" + res;
};


/**
 * 获取数据
 */
Export2Image.prototype.getData = function(){
    if(this.actualWidth && this.actualHeight){
        this._scaleCanvas(this.actualWidth,this.actualHeight);
    }
    var strData = "";
    if (/bmp/.test(this.type)) {
        var data = this._getImageData();
        strData = this._getBitmapImage(data);
    } else {
        strData = this._getDataURL();
    }
    return strData;
}


/**
 * 普通图片获取
 * @private
 */
Export2Image.prototype._getImageData = function(){
    var w = this.canvas.width, h = this.canvas.height;
    return this.canvas.getContext('2d').getImageData(0, 0, w, h);
};


/**
 * 位图获取
 * @private
 */
Export2Image.prototype._getBitmapImage = function(oData){
    var aHeader = [];


    var iWidth = oData.width;
    var iHeight = oData.height;


    aHeader.push(0x42); // magic 1
    aHeader.push(0x4D);


    var iFileSize = iWidth*iHeight*3 + 54; // total header size = 54 bytes
    aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
    aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
    aHeader.push(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
    aHeader.push(iFileSize % 256);


    aHeader.push(0); // reserved
    aHeader.push(0);
    aHeader.push(0); // reserved
    aHeader.push(0);


    aHeader.push(54); // dataoffset
    aHeader.push(0);
    aHeader.push(0);
    aHeader.push(0);


    var aInfoHeader = [];
    aInfoHeader.push(40); // info header size
    aInfoHeader.push(0);
    aInfoHeader.push(0);
    aInfoHeader.push(0);


    var iImageWidth = iWidth;
    aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
    aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
    aInfoHeader.push(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
    aInfoHeader.push(iImageWidth % 256);


    var iImageHeight = iHeight;
    aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
    aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
    aInfoHeader.push(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
    aInfoHeader.push(iImageHeight % 256);


    aInfoHeader.push(1); // num of planes
    aInfoHeader.push(0);


    aInfoHeader.push(24); // num of bits per pixel
    aInfoHeader.push(0);


    aInfoHeader.push(0); // compression = none
    aInfoHeader.push(0);
    aInfoHeader.push(0);
    aInfoHeader.push(0);


    var iDataSize = iWidth*iHeight*3;
    aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
    aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
    aInfoHeader.push(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
    aInfoHeader.push(iDataSize % 256);


    for (var i=0;i<16;i++) {
        aInfoHeader.push(0);    // these bytes not used
    }


    var iPadding = (4 - ((iWidth * 3) % 4)) % 4;


    var aImgData = oData.data;


    var strPixelData = "";
    var y = iHeight;
    do {
        var iOffsetY = iWidth*(y-1)*4;
        var strPixelRow = "";
        for (var x=0;x<iWidth;x++) {
            var iOffsetX = 4*x;


            strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);
            strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);
            strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);
        }
        for (var c=0;c<iPadding;c++) {
            strPixelRow += String.fromCharCode(0);
        }
        strPixelData += strPixelRow;
    } while (--y);


    var strEncoded = this._encodeData(aHeader.concat(aInfoHeader)) + this._encodeData(strPixelData);


    return  this._makeDataURI(strEncoded);
};


Export2Image.prototype._makeDataURI = function(strData){
    return "data:" + this.type + ";base64," + strData;
}


/**
 * 保存
 * @param data
 * @param fileName
 * @private
 */
Export2Image.prototype._saveFile = function(data,fileName){
    try{
        //TODO:IE浏览器
         new ActiveXObject("Microsoft.XMLHTTP");
        var oImg = document.createElement("img");
        oImg.src = data;
        oImg.onload = function(){
            myWindow=window.open('','_blank','width=800,height=600');
            myWindow.document.write("<img src='"+data+"'>")
            myWindow.focus()
        }
    }catch(e){
         var saveLink = document.createElementNS("http://www.w3.org/1999/xhtml","a");
        saveLink.href = data;
        saveLink.download = fileName;
        var event = document.createEvent("MouseEvents");
        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
        saveLink.dispatchEvent(event);
    }


};


Export2Image.prototype.exportPic = function(){
    if(this.exportType == "html2Image"){
        if(typeof(html2canvas) !="function"){
            alert("需要引入html2canvas.js库文件");
            return;
        }
        var that = this;
        html2canvas(this.exportObj, {
            onrendered: function(canvas) {
                that.canvas = canvas;
                var data = that.getData();
                var imgData = data.replace(that.type,'image/octet-stream');
                that._saveFile(imgData,that.fileName);
            }
        });
    }else{
        var data = this.getData();
        var imgData = data.replace(this.type,'image/octet-stream');
        this._saveFile(imgData,this.fileName);
    }


};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值