zoukankan      html  css  js  c++  java
  • 使用canvas给图片添加水印, canvas转换base64,,canvas,图片,base64等转换成二进制文档流的方法,并将合成的图片上传到服务器,

    一,前端合成带水印的图片

      一般来说,生成带水印的图片由后端生成,但不乏有时候需要前端来处理。当然,前端处理图片一般不建议,一方面js的处理图片的方法不全,二是有些老版本的浏览器对canvas的支持度不够。

    下面我们就说说,利用canvas 生成带水印的图片。

    1、我们要实现一下效果

    2、创建一个canvas

    var canvas = document.createElement('canvas');
            var time = new Date();
            var logoCanvas =time+'  '+'http://www.cnblogs.com/zuoan-oopp'; // 水印
            var context = canvas.getContext('2d');

    3,绘制图片

    var imgUpload = new Image();
            imgUpload.src =src;
            imgUpload.onload = function () {
                
                context.drawImage(imgUpload, 0, 0,imgUpload.width,imgUpload.height,0,0,imgWidth,imgHeight);
    }

    4,按照1024*768的比例压缩图片

    var width = imgUpload.width;
                var height= imgUpload.height;
                var scale,imgWidth,imgHeight;  // 缩放比 ,按照1024*768缩放
               
                if(width>height){  // 横着拍
                    if(width>1024){   //宽大于1024
                        scale = 1024/width;
                        imgWidth =1024;
                        imgHeight = height*scale;  // 算出按照宽1024,的等比压缩后的高
                        if(imgHeight>768){        // 若高>768,算出等比768缩放的宽
                            scale = 768/imgHeight;
                            imgHeight = 768;
                            imgWidth = imgWidth*scale;
                        }
                    }else{
                        imgWidth = width;
                        imgHeight = height
                    }
                }else{     // 纵着拍的或者正方形
                    if(height>1024){ // 高大于1024
                        scale = 1024/height;
                        imgHeight =1024;
                        imgWidth = width*scale;  // 算出按照宽1024,的等比压缩后的高
                        if(imgWidth>768){        // 若高>768,算出等比768缩放的宽
                            scale = 768/imgWidth;
                            imgWidth = 768;
                            imgHeight = imgHeight*scale;
                        }
                    }else{
                        imgWidth = width;
                        imgHeight = height
                    }
                }

    5,给canvas添加背景和水印

    canvas.height = imgHeight+60;  // 给canvas 赋值高度
                context.save();
                context.fillStyle = "green";
                context.fillRect(0,0,imgWidth,imgHeight+60);  // 绘制图片的背景
                context.restore();
                context.save();
                context.font="100px PingFangSC-Regular microsoft yahei";
                context.fillStyle = "#000";
                context.restore();

    6,如果水印文字太长要换行,代码如下:

    for(let i=0;i<logoCanvas.length;i++){  // 字数换行
                    lineWidth+=context.measureText(logoCanvas[i]).width; 
                    if(lineWidth>canvas.width-20){ 
                        context.fillText(logoCanvas.substring(lastSubStrIndex,i),10,initHeight);//绘制截取部分
                        initHeight+=20;//20为字体的高度
                        height+=20;
                        lineWidth=0;
                        lastSubStrIndex=i;
                    } 
                    if(i==logoCanvas.length-1){//绘制剩余部分
                        context.fillText(logoCanvas.substring(lastSubStrIndex,i+1),10,initHeight);
                    }
                }

    7,canvas转换成base64位,以图片的形式展示

    var url=canvas.toDataURL("image/jpg", 0.8);   // canvas转换成base64位
                var newImg = new Image(); 
                newImg.src = url;
                newImg.onload = function() {
                    document.getElementById('imgUpload').append(newImg);
                };

    注意:toDataURL函数可能会出现跨域的问题,请在同一个服务器下操作


    二,图片上传

     1,图片上传到服务器要转换成文档流(二进制blob)的形式。所以无论上传canvas,还是img,要先转换成文档流

     2、canvas 转换成文档流,利用toBlob方法转换

    canvas.toBlob(function(blob) {
                //创建forme
                var form = new FormData();
                form.append('file', blob); 
                $.POST(url, {
                            data:formData,
                            processData: false,
                            contentType: false,
                            
                    }).done(function(data) {
                        console.log('回调函数')
                    }).fail((data,textStatus)=>{
                        console.log('失败函数')
                    })
            });

    注意:次方法兼容性不太好,,低版本的chrome不支持,安卓4.4.2版本都不支持(只测了这一个版本),各浏览器的兼容性如下:

     3,canvas 直接转换成文档流兼容性不太好,但是这个功能又必须做,怎么办,,,那么我们就换种方式,,使用base64位上传。

    4,除了base64位上传,还想使用blob二进制文档流上传,怎么办。。。我们可以使用window对象提供的atob函数

    5、WindowOrWorkerGlobalScope.atob()函数用来解码一个已经被base-64编码过的数据。你可以使用 window.btoa() 方法来编码一个可能在传输过程中出现问题的数据,并且在接受数据之后,使用 window.atob() 方法来将数据解码。

    6,将base64位转换成blob,这样就可以避免低版本的chrome不支持了。

    url = url.replace("data:image/png;base64,", "");
            var blob = b64toBlob(src);
            var formData = new FormData();
            formData.append("file",blob);
            $.POST(url, {
                data:formData,
                processData: false,
                contentType: false,
            }).done(function(data) {
                console.log('回调函数')
            }).fail((data,textStatus)=>{
                console.log('失败函数')
            })
            // 将base64位转换成blob
            function b64toBlob(b64Data, contentType, sliceSize) {
                contentType = contentType || '';
                sliceSize = sliceSize || 512;
    
                var byteCharacters = atob(b64Data);
                var byteArrays = [];
    
                for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
                    var slice = byteCharacters.slice(offset, offset + sliceSize);
    
                    var byteNumbers = new Array(slice.length);
                    for (var i = 0; i < slice.length; i++) {
                        byteNumbers[i] = slice.charCodeAt(i);
                    }
    
                    var byteArray = new Uint8Array(byteNumbers);
    
                    byteArrays.push(byteArray);
                }
    
                var blob = new Blob(byteArrays, {type: contentType});
                return blob;
            }

    ablob兼容性如下:

     三,源代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>合成水印</title>
        <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
        <style type="text/css">
            *{margin:0;padding:0;}
            .content{
                display:block;
                margin: 30px;
            }
            .content:after{
                content: "";
                display:block;
                clear:both;
            }
            .content li{
                float: left;
                margin-left:30px;
                list-style: none;
            }
            .img-wrap{
                display:-webkit-box;
                -webkit-box-align:center;
                -webkit-box-pack: center;
                500px;
                height:400px;
                
            }
            .img-wrap img{
                max- 100%;
                max-height:100%;
            }
            .img-wrap canvas{
                max- 100%;
                max-height:100%;
            }
        </style>
    </head>
    <body>
        <ul class="content">
            <li>
                <p>原图</p>
                <div class="img-wrap">
                    <img src="2.jpg"/>
                </div>
            </li>
            <li>
                <p>加水印的canvas</p>
                <div id="imgContent" class="img-wrap"></div>
            </li>
            <li>
                <p>加水印的img</p>
                <div id="imgUpload" class="img-wrap"></div>
            </li>
        </ul>
        <script type="text/javascript">
            var src = $('img').attr('src');
            var canvas = document.createElement('canvas');
            var time = new Date();
            var logoCanvas =time+'  '+'http://www.cnblogs.com/zuoan-oopp'; // 水印
            var context = canvas.getContext('2d');
            
            // 这是上传图像
            var imgUpload = new Image();
            imgUpload.src =src;
            imgUpload.onload = function () {
                // 绘制
                var width = imgUpload.width;
                var height= imgUpload.height;
                var scale,imgWidth,imgHeight;  // 缩放比 ,按照1024*768缩放
               
                if(width>height){  // 横着拍
                    if(width>1024){   //宽大于1024
                        scale = 1024/width;
                        imgWidth =1024;
                        imgHeight = height*scale;  // 算出按照宽1024,的等比压缩后的高
                        if(imgHeight>768){        // 若高>768,算出等比768缩放的宽
                            scale = 768/imgHeight;
                            imgHeight = 768;
                            imgWidth = imgWidth*scale;
                        }
                    }else{
                        imgWidth = width;
                        imgHeight = height
                    }
                }else{     // 纵着拍的或者正方形
                    if(height>1024){ // 高大于1024
                        scale = 1024/height;
                        imgHeight =1024;
                        imgWidth = width*scale;  // 算出按照宽1024,的等比压缩后的高
                        if(imgWidth>768){        // 若高>768,算出等比768缩放的宽
                            scale = 768/imgWidth;
                            imgWidth = 768;
                            imgHeight = imgHeight*scale;
                        }
                    }else{
                        imgWidth = width;
                        imgHeight = height
                    }
                }
                canvas.width = imgWidth;    // geicanvas赋值宽度
                canvas.height = imgHeight+60;  // 给canvas 赋值高度
                context.save();
                context.fillStyle = "green";
                context.fillRect(0,0,imgWidth,imgHeight+60);  // 绘制图片的背景
                context.restore();
                context.save();
                context.font="100px PingFangSC-Regular microsoft yahei";
                context.fillStyle = "#000";
                context.restore();
    
                context.drawImage(imgUpload, 0, 0,imgUpload.width,imgUpload.height,0,0,imgWidth,imgHeight);
                var lineWidth = 0
                var initHeight=imgHeight+30;//绘制字体距离canvas顶部初始的高度
                var lastSubStrIndex= 0; //每次开始截取的字符串的索引     
                for(let i=0;i<logoCanvas.length;i++){  // 字数换行
                    lineWidth+=context.measureText(logoCanvas[i]).width; 
                    if(lineWidth>canvas.width-20){ 
                        context.fillText(logoCanvas.substring(lastSubStrIndex,i),10,initHeight);//绘制截取部分
                        initHeight+=20;//20为字体的高度
                        height+=20;
                        lineWidth=0;
                        lastSubStrIndex=i;
                    } 
                    if(i==logoCanvas.length-1){//绘制剩余部分
                        context.fillText(logoCanvas.substring(lastSubStrIndex,i+1),10,initHeight);
                    }
                }
                var url=canvas.toDataURL("image/jpg", 0.8);   // canvas转换成base64位
                var newImg = new Image(); 
                newImg.src = url;
                newImg.onload = function() {
                    document.getElementById('imgUpload').append(newImg);
                };
                document.getElementById('imgContent').append(canvas);  // 将canvas绘制的图片存放在imgContent里
            };
            canvas.toBlob(function(blob) {
                //创建forme
                var form = new FormData();
                form.append('file', blob); 
                $.POST(url, {
                            data:formData,
                            processData: false,
                            contentType: false,
                            
                    }).done(function(data) {
                        console.log('回调函数')
                    }).fail((data,textStatus)=>{
                        console.log('失败函数')
                    })
            });
    
            url = url.replace("data:image/png;base64,", "");
            var blob = b64toBlob(src);
            var formData = new FormData();
            formData.append("file",blob);
            $.POST(url, {
                data:formData,
                processData: false,
                contentType: false,
            }).done(function(data) {
                console.log('回调函数')
            }).fail((data,textStatus)=>{
                console.log('失败函数')
            })
            // 将base64位转换成blob
            function b64toBlob(b64Data, contentType, sliceSize) {
                contentType = contentType || '';
                sliceSize = sliceSize || 512;
    
                var byteCharacters = atob(b64Data);
                var byteArrays = [];
    
                for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
                    var slice = byteCharacters.slice(offset, offset + sliceSize);
    
                    var byteNumbers = new Array(slice.length);
                    for (var i = 0; i < slice.length; i++) {
                        byteNumbers[i] = slice.charCodeAt(i);
                    }
    
                    var byteArray = new Uint8Array(byteNumbers);
    
                    byteArrays.push(byteArray);
                }
    
                var blob = new Blob(byteArrays, {type: contentType});
                return blob;
            }
        </script>
    </body>
    </html>

    四,参考文档

     1、https://developer.mozilla.org/zh-CN/docs/Web/API/WindowBase64/atob

     2、https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toBlob

  • 相关阅读:
    Python
    QinQ 技术解析
    TLS/SSL 协议
    TLS/SSL 协议
    TLS/SSL 协议
    排序算法之基本排序算法(冒泡、插入、选择)
    Spring Boot 学习笔记--手写版
    mysql -- collection一对多查询
    mybatis 批量操作增删改查
    easyUI之datagrid绑定后端返回数据的两种方式
  • 原文地址:https://www.cnblogs.com/zuoan-oopp/p/8006524.html
Copyright © 2011-2022 走看看