html2canvas解决图片偏移并下载

<div id="certificateContent"></div>

<div class = '.getImg'></div>

var main = {

init: function() {

main.setListener();

},

//设置监听事件

setListener: function() {

var btnShare = $(".getImg");

btnShare.click(function() {

main.html2Canvas();

});

},

//获取像素密度

getPixelRatio: function(context) {

var backingStore = context.backingStorePixelRatio ||

context.webkitBackingStorePixelRatio ||

context.mozBackingStorePixelRatio ||

context.msBackingStorePixelRatio ||

context.oBackingStorePixelRatio ||

context.backingStorePixelRatio || 1;

return (window.devicePixelRatio || 1) / backingStore;

},

//绘制dom 元素,生成截图canvas

html2Canvas: function() {

var shareContent = $("#certificateContent")[0]; // 需要绘制的部分的 (原生)dom 对象 ,注意容器的宽度不要使用百分比,使用固定宽度,避免缩放问题

var width = shareContent.offsetWidth; // 获取(原生)dom 宽度

var height = shareContent.offsetHeight; // 获取(原生)dom 高

var offsetTop = shareContent.offsetTop; //元素距离顶部的偏移量

console.log(width, height);

var canvas = document.createElement('canvas'); //创建canvas 对象

var context = canvas.getContext('2d');

var scaleBy = main.getPixelRatio(context); //获取像素密度的方法 (也可以采用自定义缩放比例)

canvas.width = width * scaleBy; //这里 由于绘制的dom 为固定宽度,居中,所以没有偏移

canvas.height = (height + offsetTop) * scaleBy; // 注意高度问题,由于顶部有个距离所以要加上顶部的距离,解决图像高度偏移问题

context.scale(scaleBy, scaleBy);

var opts = {

//allowTaint: true, //允许加载跨域的图片

tainttest: true, //检测每张图片都已经加载完成

scale: scaleBy, // 添加的scale 参数

canvas: canvas, //自定义 canvas

logging: true, //日志开关,发布的时候记得改成false

width: width, //dom 原始宽度

height: height, //dom 原始高度

y: 170,

allowTaint: false,

useCORS: false

};

html2canvas(shareContent, opts).then(function(canvas) {

this.imgmap = canvas.toDataURL()

if (window.navigator.msSaveOrOpenBlob) {

var bstr = atob(this.imgmap.split(',')[1])

var n = bstr.length

var u8arr = new Uint8Array(n)

while (n--) {

u8arr[n] = bstr.charCodeAt(n)

}

var blob = new Blob([u8arr])

window.navigator.msSaveOrOpenBlob(blob, '个人证书' + '.' + 'png')

} else {

// 这里就按照chrome等新版浏览器来处理

const a = document.createElement('a')

a.href = this.imgmap

a.setAttribute('download', 'chart-download')

a.click()

}

});

}

};

main.init();

//https://www.cnblogs.com/lipengze/p/11512039.html  手机端示例
前言
首先做个自我介绍,我是成都某企业的一名刚刚入行约一年的前端,在之前的开发过程中,遇到了问题,也解决了问题,
但是在下一次解决相同问题的时候,只对这个问题有一丝丝的印象,还需要从新去查找,于是,我注册了segmemtfault,
便于搜集我的问题总结,以及将踩坑经验分享给每一个开发人员,好了,闲话不多说。
需求
需求:要求能够实现根据后端返回的数据生成一张image,便于用户将图片分享到朋友或者朋友圈,取得用户的关注。
开始踩坑
一.html2canvas对于跨域图片,转换的时候会将跨域图片识别为空白。
问题分析:
既然是由于跨域引起的问题,那我们让资源不跨域不就可以访问了吗?
解决办法:
将图片放置服务器,通过nginx进行代理资源,前端访问图片便不涉及到跨域问题。

二.html2canvas动态加载内容,通过canvas转换出来的数据,图片为空
问题分析:
内容是动态加载进来的,转换肯定是在请求完毕之后再去转换,但是在请求完毕之后去转换,按理说所需要的所有数据都已经到达前端,应该可以转换,经过思考,发现图片内容从后台读取需要一定时间去解析,才能够完整的将图片资源展示出来,html2canvas是将页面上显示的dom元素,经过解析将dom画在canvas上在转换为image图片格式。
解决办法:
1.让html2canvas转换代码等待一定时间,在进行转换操作,可进行转换。代码如下图所示

clipboard.png

2.当全部的图片数据都加载完毕之后,在执行转换操作。(本人建议第二种,更保险)

clipboard.png

三.html2canvas转换的base64位图不能被ios8以上版本所识别。会呈现出整个截图页面空白
问题分析:
这个问题的起因,应该是html2canvas对高版本的ios不支持(自我感觉),这个问题我很是头疼,当时根本没有对ios进行测试。客户使用的时候发现了这个问题,没法。想办法解决。百度说是由于ios不能识别base64的前缀,于是我试过将图片的前缀去除,但发现没反应。还是无用。思来想去感觉html2canvas坑太多了。填都填不完。于是。
解决办法:
我采用了另一款插件,dom-to-image,弄上去没有问题了。

clipboard.png

四.dom-to-image运用上去,在ios上能够出现内容了,但发现存在一个问题,部分图片内容,第一次进行公众号网页加载,没有正确显示,要在次进入才会显示,此bug同样是ios8以上版本
问题分析:
这一个问题我没有找到问题所在,一脸懵,不过最终还是得到了解决。
解决办法:
运用dom-to-imagede toSvg方式完美解决问题。

clipboard.png

五.离成功只有一步之遥了,使用了svg之后安卓手机不能将图片分享给朋友。识别不了
问题分析:
安卓能识别jpeg但不能识别svg矢量图片
解决办法:
自己手写咯。判断手机为安卓还是ios。

clipboard.png

六.所有的问题都已解决,我兴奋的跑去借了个果5,拿来测试,发现网页的背景图片不见了。
问题分析:
我长按两秒左右又是正常显示了,故图片是已经完美转换成功,可能是因为图片在转换过程中,没有完美适配到4.0寸的屏幕,
解决办法:
模拟长按事件,解决bug,这个方式可能不太好,但也是一种解决方式。

总结
躺过的坑都是我的经验,分享的同时我又加固了一遍。解决实际问题的思路,在过了一遍,对我帮助很棒。

代码参考

复制代码
//判断手机为安卓还是ios  安卓html2canvas方法  ios系统dom-to-image方法        
$(".code").click(function() {
    var u = navigator.userAgent;
    var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
    var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
    if(isiOS) {
        window.location.href = "mycodeios.html"
    } else if(isAndroid) {
        window.location.href = "mycode.html"
    }
})
复制代码
安卓html2canvas方法

复制代码
<!DOCTYPE html>
<html lang="zh">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
        <title>分享</title>
        <link rel="stylesheet" type="text/css" href="css/reset.css" />
        <style type="text/css">
            /*头部*/
            
            body {
                background: #FFFFFF;
                height: 0 !important;
            }
            
            .container {
                max-width: 750px;
                min-width: 32px;
                margin: 0 auto;
                background: #FFFFFF;
            }
            
            .zhe {
                position: fixed;
                max-width: 750px;
                min-width: 32px;
                width: 100%;
                height: 100%;
                background: #45A196;
                z-index: 9;
            }
            
            .imge {
                position: absolute;
                max-width: 750px;
                min-width: 32px;
                width: 90%;
                height: 100%;
                margin: 0% 5%;
                z-index: 99;
                /*background: url(codeimg/code.jpg) no-repeat;*/
                /*background-size: contain;*/
            }
            
            .left {
                position: absolute;
                left: 12%;
                top: 70%;
                color: #FFFFFF;
                font-size: 26px;
                letter-spacing: 5px;
            }
            
            .bottom {
                position: absolute;
                right: 38%;
                top: 65%;
            }
            
            .codebotom {
                position: absolute;
                padding: 10px;
                background: #FFFFFF;
                width: 90px;
                height: 90px;
            }
            
            .butright_img {
                position: absolute;
                width: 80px;
                height: 80px;
                margin: 5px;
                top: 0px;
                left: 0px;
            }
            
            .textbottom {
                position: absolute;
                width: 40px;
                letter-spacing: 5px;
                color: #FFFFFF;
                top: 20px;
                left: -45px;
            }
            
            .butright {
                position: absolute;
                bottom: 50px;
                right: 15%;
                color: #4BA59B;
                padding: 10px 20%;
                border-radius: 3px;
                z-index: 9999;
                color: #ffffff;
                text-align: center;
            }
            
            .image {
                display: block;
                max-width: 750px;
                min-width: 32px;
                width: 100%;
                position: absolute;
                top: 0px;
                left: 0px;
                background: #FFFFFF;
                z-index: 9999;
            }
        </style>
    </head>

    <body>
        <div class="container">
            <!--二维码-->
            <div class="zhe"></div>
            <div class="imge">
                <div style="position: absolute; top: 0px; left: 0px;">
                    <img src="codeimg/code.jpg" />
                </div>
                <div style="width: 100%;height: 100%; position: relative;">
                    <div class="left state"></div>
                    <div class="bottom">
                        <div class="textbottom">扫码立即注册</div>
                        <div class="codebotom">
                            <div id="qrcode" class="butright_img"></div>
                        </div>
                    </div>
                </div>
                <div>
                    <div class="butright">长按保存图片</div>
                </div>
            </div>
            <div class="image" style="display: block;">

            </div>

        </div>
    </body>
    <script src="js/config.js"></script>
    <script src="js/jquery-2.1.4.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/fenxiang.js" type="text/javascript" charset="utf-8"></script>
    <script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
    <!--二维码-->
    <script src="js/jquery.qrcode.logo.min.js" type="text/javascript" charset="utf-8"></script>
    <!--html2canvas图片-->
    <script type="application/javascript" src="http://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
    <script type="text/javascript">
        //  倒计时  
        $(function() {
            var openid_list = eval(decodeURIComponent(localStorage.getItem("openid")))
            var openid = openid_list[1]
            var access_token = openid_list[0]

            window.history.pushState(null, null, "#");
            window.addEventListener('popstate', function(e) {
                window.location.href = 'my.html'
            }, false);

            //创建二维码
            function createQRCode(id, url, width, height, src) {
                $('#' + id).empty();
                jQuery('#' + id).qrcode({
                    render: 'canvas',
                    text: url,
                    width: width, //二维码的宽度  
                    height: height, //二维码的高度  
                    imgWidth: width / 6, //图片宽
                    imgHeight: height / 6, //图片高
                    src: src //图片中央的二维码
                });
            }
            var url = 'https://api.gzkny.com/h5/aa.html?openid=' + openid;
            createQRCode("qrcode", url, 80, 80, "image/follow.jpg");

            // 使用html2canvas 转换html为canvas 安卓html2canvas方法
            function downloadForJS() {   
                html2canvas(document.body, {
                    useCORS: true,
                    logging: true
                }).then(function(canvas) {
                    var imgUri = canvas.toDataURL().replace("image/png", "image/octet-stream"); // 获取生成的图片的url  
                    //    $('.zhe').hide()
                    //    $('.imge').hide()
                    $('.image').html('<img src="' + imgUri + '"/>')
                });
            }

            // 获取数据
            $.ajax({
                method: 'GET',
                url: window.BASE_URL + 'api/v1/member/get',
                contentType: 'application/x-www-form-urlencoded',
                async: true,
                dataType: "json",
                data: {
                    access_token: access_token,
                },
                success: function(data) {
                    console.log(data)
                    if(data.error == 'success') {
                        $('.state').html(data.data.username)
                        downloadForJS()
                    }
                }
            });

        })
    </script>

</html>
复制代码
ios系统dom-to-image方法(css样式一定要自己写   避免图片失效)

复制代码
<!DOCTYPE html>
<html lang="zh">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>分享</title>
        <script src="js/jquery-2.1.4.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript" src="js/dom-to-image.js"></script>
        <script type="text/javascript" src="js/FileSaver.js"></script>
        <style type="text/css">
            /*头部*/
            * {
                margin: 0px;
                padding: 0px;
            }
            
            body {
                background: #45A196;
                width: 100%;
                height: 100%;
            }
            
            .container {
                max-width: 750px;
                min-width: 32px;
                margin: 0 auto;
                position: relative;
            }
            
            .imge {
                position: relative;
                max-width: 750px;
                min-width: 32px;
                width: 100%;
                height: 100%;
                z-index: 99;
            }
            
            .left {
                position: absolute;
                left: 12%;
                margin-top: 116%;
                color: #FFFFFF;
                font-size: 26px;
                letter-spacing: 5px;
            }
            
            .bottom {
                position: absolute;
            }
            
            .codebotom {
                position: absolute;
                background: #FFFFFF;
                width: 90px;
                height: 90px;
            }
            
            .butright_img {
                position: absolute;
                width: 80px;
                height: 80px;
                margin: 5px;
                top: 0px;
                left: 0px;
            }
            
            .textbottom {
                position: absolute;
                width: 50px;
                letter-spacing: 5px;
                color: #FFFFFF;
                top: 15px;
                left: -45px;
            }
            
            .butright {
                position: fixed;
                bottom: 0px;
                right: 40%;
                z-index: 9999;
                color: #ffffff;
            }
            
            .image {
                display: block;
                max-width: 750px;
                min-width: 32px;
                width: 100%;
                position: absolute;
                top: 0px;
                left: 0px;
                background: #FFFFFF;
                z-index: 9999;
            }
        </style>
    </head>

    <body>
        <div id="container">
            <div class="container">
                <div class="imge">
                    <img style="width: 100% ; position: absolute;" src="codeimg/code.jpg" />
                    <div class="left state"></div>
                    <div style=" position: absolute;right: 38%; margin-top: 110%;">
                        <div class="bottom">
                            <div class="textbottom">扫码立即注册</div>
                            <div class="codebotom">
                                <div id="qrcode" class="butright_img"></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="butright">长按保存图片</div>
        </div>
        <div class="bot" style="position: fixed; z-index: 9999999999999999; background: #4BA59B;"></div>

    </body>
    <!--二维码-->
    <script src="js/jquery.qrcode.logo.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/config.js"></script>
    <script type="text/javascript">
        $(function() {
            var openid_list = eval(decodeURIComponent(localStorage.getItem("openid")))
            var openid = openid_list[1]
            var access_token = openid_list[0]

            window.history.pushState(null, null, "#");
            window.addEventListener('popstate', function(e) {
                window.location.href = 'my.html'
            }, false);

            //创建二维码
            function createQRCode(id, url, width, height, src) {
                $('#' + id).empty();
                jQuery('#' + id).qrcode({
                    render: 'canvas',
                    text: url,
                    width: width, //二维码的宽度  
                    height: height, //二维码的高度  
                    imgWidth: width / 6, //图片宽
                    imgHeight: height / 6, //图片高
                    src: src //图片中央的二维码
                });
            }
            var url = 'https://api.gzkny.com/h5/aa.html?openid=' + openid;
            createQRCode("qrcode", url, 80, 80, "image/follow.jpg");

            //            ios系统dom-to-image方法    
            function downloadForJS() {
                domtoimage.toSvg(document.getElementById('container'))
                    .then(function(dataUrl) {
                        /* do something */
                        var img = new Image();
                        img.src = dataUrl;
                        $('.container').hide()
                        //    console.log(dataUrl)
                        //    document.body.appendChild(img);
                        $('.bot').html(img)
                    });
            }

            //    禁止屏幕滑动
            function bodyScroll(event) {
                event.preventDefault();
            }
            document.body.addEventListener('touchmove', bodyScroll, false);
            $('body').css({
                'position': 'fixed',
                "width": "100%"
            });

            //  获取数据
            $.ajax({
                method: 'GET',
                url: window.BASE_URL + 'api/v1/member/get',
                contentType: 'application/x-www-form-urlencoded',
                async: true,
                dataType: "json",
                data: {
                    access_token: access_token,
                },
                success: function(data) {
                    console.log(data)
                    if(data.error == 'success') {
                        $('.state').html(data.data.username)
                        downloadForJS()
                    }
                }
            });

        })
    </script>

</html>
复制代码
 

如果真的不知道将来要做什么,索性就先做好眼前的事情。只要今天比昨天过得好,就是进步。长此以往,时间自然会还你一个意想不到的未来。
生活像一个杯子。一开始,里面是空的,之后,要看你怎么对待它。如果你只往不如意的方面想,那么你最终辉得到一杯苦水。如果你往好的方面想,那么你最终会得到一杯清泉。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值