別再@官方啦,普天同慶加國旗

別再@官方啦,普天同慶加國旗

國慶就要來了!今年是新中國成立70週年,你們的熱情都很高漲。這不,我今天一翻朋友圈,被齊刷刷地帶國旗的頭像給刷屏了!javascript

不過還有些朋友不明就裏,還在不停地@微信官方,但願能自動給頭像加上一面國旗。然而等了半天,仍是毫無反應……css

 

固然,程序員朋友,也開始了一頓操做。前端

python 用 python-opencv 庫,直接調。java

go 用 image 庫,直接調。python

那麼前端呢? 我們前端不用庫,原生的 js + canvas  簡單快捷。程序員

1、思路分析web

    大體有兩種辦法能夠實現。canvas

  1.   使用 將圖片畫在 canvas 上面,而後經過 api 獲取 圖片的像素值,進行疊加,而後再寫入 canvas ,最後導出圖片。好處是:能夠對透明的圖像進行處理,自定義程度高。缺點:控制起來複雜度高,計算量大。
  2.    直接將兩張圖片分兩次畫在 canvas 上面,而後導出圖片 。 好處:簡單快捷。 缺點:透明圖像不能處理,可控性小。

這裏我採用第二種辦法,簡單點。。api

2、技術點微信

    一、  獲取畫布:

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

  

   二、將圖片畫入canvas

context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);  

 

 

  三、導出圖片

canvas.toDataURL("image/png");

 四、有了這些方法,咱們的圖片從哪裏來?

 經過  <input type="file" name="" id="flag" value="" /> 能拿到文件 file ,咱們只須要將 file 轉化爲 圖片的 url連接便可。

這裏有兩種辦法:一、使用 FileReader  讀取出 base64圖片,是一個異步操做。 二、使用 URL.createObjectURL 讀取出 blob 的協議連接,是一個同步操做。這裏咱們採用第二種辦法

 

3、正式開始

一、結構和樣式

 

<style type="text/css">
            * {
                padding: 0;
                margin: 0;
                font-size: 14px;
            }
 
            #box {
                width: 400px;
                height: 400px;
                border: 1px solid red;
                margin: 20px auto;
                position: relative;
            }
 
            #operate {
                text-align: center;
                ;
            }
 
            #operate p {
                margin-bottom: 6px;
            }
 
            input[type=file] {
                display: none;
            }
 
            label {
                display: inline-block;
                cursor: pointer;
                background: #38f;
                color: #fff;
                width: 102px;
                height: 38px;
                line-height: 38px;
                border-radius: 4px;
            }
 
        </style>

  

<div id="box">
            <canvas id="canvas" width="400" height="400"></canvas>
        </div>
        <div id="operate">
            <p><label><input type="file" name="" id="bg" value="" />選擇頭像</label></p>
            <p><label><input type="file" name="" id="flag" value="" />選擇上層</label></p>
			<p><label id="create">直接生成</label></p>
        </div>
        <a href="" download="logo.png" title="點擊下載" id="down">
            <img src="" id="result">
        </a>
    </body>

  

 

 二、js代碼以下

const canvas = document.getElementById("canvas"); //獲取canvas
        const ctx = canvas.getContext("2d"); //獲取畫布
        const baseW = 400; //頭像的最大寬高
        const flagW = 100;	//旗的最大寬高
        let bgConfig;		//畫 頭像的參數
        let flagConfig;		//畫  旗的參數
        document.getElementById("bg").onchange = async function() {
            const file = this.files[0];
            try {
                const img = await getImageObj(file);
                const rate = compress(img, baseW);
                bgConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h];
                drawn();
            } catch (e) {
                console.error(e);
            }
        };
 
        document.getElementById("flag").onchange = async function() {
            const file = this.files[0];
            try {
                const img = await getImageObj(file);
                const rate = compress(img, flagW);
                flagConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h];
                drawn();
            } catch (e) {
                console.error(e);
            }
        };
		//畫
        function drawn() {
            ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
            if (bgConfig) {
                ctx.drawImage(...bgConfig);
            }
            if (flagConfig) {
                ctx.drawImage(...flagConfig);
            }
        }
 
        //圖片壓縮,獲取等比縮放後的結果
        function compress(img, base) {
            let w = img.width;
            let h = img.height;
            if (img.width > img.height) {
                if (img.width > base) {
                    //要將寬度縮放
                    w = base;
                    h = (w / img.width) * img.height; // 新的 寬比 高 = 舊的寬比高  h / w = img.heigth/img.width  ;
                }
            } else {
                if (img.height > base) {
                    h = base;
                    w = (h / img.height) * img.width;
                }
            }
            return {
                w,
                h
            };
        }
		//經過 file 獲取到圖片對象
        function getImageObj(file) {
            const url = getObjectURL(file);
            const img = new Image();
            img.src = url;
            return new Promise((resolve, reject) => {
                img.onload = function() {
                    resolve(img);
                }
                img.onerror = function(e) {
                    reject(e);
                }
            });
        }
 
        //取得該文件的url
        function getObjectURL(file) {
            var url = null;
            if (window.createObjectURL != undefined) {
                url = window.createObjectURL(file);
            } else if (window.URL != undefined) {
                url = window.URL.createObjectURL(file);
            } else if (window.webkitURL != undefined) {
                url = window.webkitURL.createObjectURL(file);
            }
            return url;
        }
		//直接生成
		document.getElementById("create").onclick = function(){
		    exportImg({
		        x:0,
		        y:0,
		        w:canvas.clientWidth,
		        h:canvas.clientHeight,
		    });
		}
		//導出頭像的範圍
		 function startClip(area) {
			 var canvas = document.createElement("canvas");
			 canvas.width = area.w;
			 canvas.height = area.h;
			 var data = ctx.getImageData(area.x, area.y, area.w, area.h);
			 var context = canvas.getContext("2d");
			 context.putImageData(data, 0, 0);
			 return canvas.toDataURL("image/png");
		 }
		  //導出頭像,點擊能夠下載
		 function exportImg(clipArea){
			 var url = startClip(clipArea);
			 document.getElementById("result").src = url;
			 document.getElementById("down").href = url;
		 }

  

其中: bgConfig 存了 頭像的 logo 圖  ctx.drawImage 的參數。 flagConfig 存了 旗子 參數。

結果以下:

 

很顯然,這並非咱們要的效果,須要控制旗子的位置,也簡單。

調整  flagConfig 組數裏面的 5 和 6 的位置元素 值,即 x 、y ,例如:

flagConfig[5] = 100;
flagConfig[6] = 200;

  

爲了方便修改。增長兩個輸入框:

 

 在js 裏面增長以下代碼:

document.getElementById("posX").oninput = function() {
		    let val = Number(this.value) || 0;
		    flagConfig[5] = val;
		    drawn();
		}
		document.getElementById("posY").oninput = function() {
		    let val = Number(this.value) || 0;
		    flagConfig[6] = val;
		    drawn();
		}

  

大功告成:

 

 

 

4、問題

 覺得這樣就完了嗎?還早,,若是傳一張不規則的頭像,以下:

 

若是碰見這樣不規則的圖片,最後生成的圖片,會出現一片白邊。

不過,這可難不到程序員,截掉就能夠啦。

後面截取 canvas的代碼就不一 貼出來了,最後附近加入完整版的吧!

直接用鼠標截取想要的部分:

 

 

 

 

完整版源碼:

連接:https://pan.baidu.com/s/1c4Rj6zmILpJW-x5yjGtSzg 提取碼:ol0y

相關文章
相關標籤/搜索