想給頭像加國旗?何必@微信官方,@我就能夠啦

前言

前幾天你們都在朋友圈@微信官方,求賜一面國旗,沒有獲得微信官方的小盆友們,有沒有很失落呀~心血來潮的我,決定用js來寫一個給頭像加國旗的功能,而後我就送了本身一面國旗,事實證實,想要的東西仍是隻能靠本身的雙手去創造。哈哈哈,這雞湯灑的觸不及防~,迴歸正題,下面就一塊兒來看看我是怎麼實現的吧~~css

實現過程

理清思路

其實給頭像加國旗的實現原理很簡單,就是拿到你的圖片資源(就是你的頭像),用canvas繪製該圖片,而後在圖片的右下角再繪製一個小國旗,這樣基礎的功能就實現了。下面咱們來一步步實現給頭像加國旗的功能。源碼地址html

應評論區需求,我這裏貼一個代碼處理後的頭像的效果圖(圖像是有一個白色圓角邊框的,可能會與博客的白色背景重疊,審美不太好,湊合看哈~).vue

我把我開發該功能的整個思考流程梳理以下:web

  1. 建立input標籤,定義onchange事件,讀取圖片資源,拿到頭像的base64編碼;
  2. 建立canvas標籤,網上找一個國旗的圖片,一樣拿到該圖片的base64編碼,依次使用canvas的drawImage api把頭像和國旗繪製在特定位置。
  3. 直角的頭像和國旗太生硬,因而寫了個方法給頭像和國旗加了一個白色的圓角邊框。
  4. 寫死畫布的高度會致使圖片被拉伸,因此我但願固定畫布的寬度,畫布的高度根據圖片資深的寬高比,和已知的寬度,把按比例計算出來的高度設置爲畫布的高度。由於國旗的繪製區域是相對於畫布的右下角的位置,因此須要在畫布高度肯定以後(也就是頭像繪製完成以後)再進行繪製。
  5. 把canvas繪製好的圖片下載,編寫下載圖片的邏輯。

開始編碼

html代碼:canvas

<div>
  <div><button class="input-container">
      上傳頭像
      <input accept="image/gif,image/jpeg,image/png"
      class="file-input" id="fileInput" type="file" />
    </button>
  <button class="save-btn"  onclick="downLoad()">保存圖片</button>
  </div>
  <canvas id="canvas" class="canvas"></canvas>
</div>
複製代碼

js代碼:api

// 這一過程是定義一些可配置的參數,以便根據須要作修改
const options = {
  avatarImgX: 0,  // 頭像開始剪切的x座標
  avatarImgY: 0,  // 頭像開始剪切的y座標
  avatarX: 10,    // 畫布上頭像開始繪製的x座標
  avatarY: 10,    // 畫布上頭像開始繪製的y座標
  avatarWidth: 200,   // 畫布上要繪製的頭像的寬度
  avatarHeight: 200,  // 畫布上要繪製的頭像的寬度
  radius: 5,          // 頭像的圓角半徑
  
  guoqiRadius: 3,     // 國旗的圓角半徑
  guoqiX: 0,          // 國旗開始剪切的x座標
  guoqiY: 0,          // 國旗開始剪切的y座標
  guoqiWidth: 50,     // 畫布上要繪製的國旗的寬度
  guoqiHeight: 33,    // 畫布上要繪製的國旗的寬度
  // 存放的是國旗的base64編碼,源碼地址點開可查看完整的
  guoqi: ""           
}
// 定義一些常量
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const inputUpload = document.getElementById('fileInput');
// 定義input的onchange事件,經過fileReader拿到圖片的base64編碼
window.onload = function() {
  inputUpload.onchange = function uploadAvatar() {
    const file = this.files[0];
    if(file) {
      // 讀取圖片資源
      const fileReader = new FileReader();
      fileReader.readAsDataURL(file);
      fileReader.onload = function () {
       // 爲了保證圖片不失真,畫布的高度是根據上傳頭像的寬高比
       // 和options中定義好的繪製寬度計算出來的,
       // 因此須要把國旗的繪製放在頭像繪製完成後的回調函數中執行。
       function cb() {
         const param = {
           sx: options.guoqiX,
           sy: options.guoqiY,
           x: canvas.width - options.guoqiWidth - options.radius * 2,
           y: canvas.height - options.guoqiHeight - options.radius * 2,
           width: options.guoqiWidth,
           height: options.guoqiHeight
         }
         // 調用繪製圖片的工具函數,傳入所需參數
        drawAvatar(options.guoqi,cb, param.sx,param.sy,param.x,param.y,
        param.width,param.height, options.guoqiRadius)
      } 
      // 調用繪製圖片的工具函數,傳入所需參數
      drawAvatar(this.result,cb,options.avatarImgX,options.avatarImgY,
      options.avatarX,options.avatarY,options.avatarWidth,
      options.avatarHeight); 
  }
 }  
};
}
// 繪製圖片
function drawAvatar(imgSrc,cb, ...args) {
  let img = new Image();
  img.src = imgSrc;
  // 不少狀況下的圖片繪製的邏輯都會寫在onload裏面
  // 是由於一般的圖片資源都是網絡請求獲取的,
  // 咱們會要保證在資源加載完成後才能正確完成繪製。
  // 我這裏是直接使用的圖片的base64編碼,
  // 繪製圖片的邏輯也可不寫在onload函數裏
  img.onload = function () {
    args.splice(2, 0, img.width,img.height);
    // 繪製的是頭像,則計算並設置畫布的高度,清空input的值
    if(args[6] === options.avatarWidth) {
       args[7] = parseInt(args[6] / (img.width / img.height));
      canvas.width = args[6] + 20;
      canvas.height = args[7] + 20;
      inputUpload.value = '';
       }
    const r = args[8] || options.radius, x = args[4],
    y = args[5], w = args[6], h=args[7];
    ctx.drawImage(img, ...args);
    // 繪製圖像的圓角的函數
    drawRadius(x, y, w, h, r);
    // 繪製國旗
    typeof cb === 'function' && cb();
  }
  
}
// 繪製圖片圓角
function drawRadius(x,y,w,h,r) {
  ctx.beginPath();
  ctx.strokeStyle='white';
  ctx.fillStyle ='white'
  ctx.lineWidth= r;
  console.log(ctx.lineWidth);
  ctx.moveTo(x+r, y);
  ctx.arcTo(x+w, y, x+w, y+h, r);
  ctx.arcTo(x+w, y+h, x, y+h, r);
  ctx.arcTo(x, y+h, x, y, r);
  ctx.arcTo(x, y, x+w, y, r);
  ctx.stroke();
  ctx.closePath();
}
// 圖片下載,下載的原理就是建立a標籤,指向圖片的下載地址,
// 模擬觸發a標籤的點擊完成下載
function downLoad(url){
    let oA = document.createElement("a");
    oA.download = 'avatar';
    // 經過canvas.toDataURL方法生成圖片的下載地址 
    oA.href = saveAsPNG();
    document.body.appendChild(oA);
    oA.click();
    oA.remove(); // 下載以後把建立的元素刪除
}
// 保存成png格式的圖片,你這裏能夠選擇其餘格式的圖片保存
function saveAsPNG() {
    return canvas.toDataURL("image/png");
}
複製代碼

css代碼:微信

.save-btn, .input-container{
  border: none;
  box-shadow: none;
  width: 150px;
  padding: 10px;
  margin-bottom: 20px;
  margin-right: 20px;
  text-align: center;
  color: #fff;
  background-color: blue;
  border-radius: 5px;
  cursor: pointer;
}
.save-btn {
  background-color: #67c23a;
}
.input-container {
  background-color: #409eff;
  position: relative;
  .file-input {
    cursor: pointer;
    position: absolute;
    display: inline-block;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    opacity: 0;
  }
}
複製代碼

總結

到這兒,給頭像添加國旗的功能就完成了,不知道大家有沒有學會呢?代碼寫到這裏其實還有不少待完善的地方,例如國旗的素材,我選的這個國旗圖片很規矩,沒有太多的設計感,還能夠利用canvas的其餘api,讓生成的圖片更有趣,更好看,更天然。我今天的分享就到這兒了,有什麼疑惑或者建議可評論區留言給我奧~~,最後,祝咱們的祖國生日快樂~,國泰民安,繁榮富強,這盛世,如你所願!網絡

擴展閱讀

相關文章
相關標籤/搜索