1. 程式人生 > >使用canvas給圖片添加水印, canvas轉換base64,,canvas,圖片,base64等轉換成二進制文檔流的方法,並將合成的圖片上傳到服務器,

使用canvas給圖片添加水印, canvas轉換base64,,canvas,圖片,base64等轉換成二進制文檔流的方法,並將合成的圖片上傳到服務器,

web don 可能 work box rac return ros font

一,前端合成帶水印的圖片

一般來說,生成帶水印的圖片由後端生成,但不乏有時候需要前端來處理。當然,前端處理圖片一般不建議,一方面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;
            width:500px;
            height:400px;
            
        }
        .img-wrap img{
            max-width: 100%;
            max-height:100%;
        }
        .img-wrap canvas{
            max-width: 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

使用canvas給圖片添加水印, canvas轉換base64,,canvas,圖片,base64等轉換成二進制文檔流的方法,並將合成的圖片上傳到服務器,