小程序如何生成圖片保存到相冊

首先我們先來看看生成的圖片


微信圖片_20200830213420.png

廢話就不多說了施禾,我們來看看代碼的實(shí)現(xiàn)吧

<canvas style="width:100%;height:{{contentHeight}}px" canvas-id="myCanvas"></canvas>
data: {
   // canvas
    windowWidth: 0, //屏幕寬度
    windowHeight: 0, //屏幕高度
    contentHeight: 0, //內(nèi)容高度
    canvasUrl: '', //canvas李彪
    qrCode:
      'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1254162229,4079702590&fm=26&gp=0.jpg', //小程序碼https圖片路徑
    shopImg:
      'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1254162229,4079702590&fm=26&gp=0.jpg', //商品圖片
    sharePopup: false, //顯示分享彈窗
    goodsInfoImg: '', //轉(zhuǎn)換臨時(shí)圖片的商品圖片
    canvasTempFile: '' //canvas臨時(shí)圖片
}
 /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  onLoad: function(options) {
    var that = this
    that.setData({
      insideWidth: '100%'
    })
    //獲取設(shè)備信息高度脚线。計(jì)算出其他的高度等
    wx.getSystemInfo({
      success: function(res) {
        that.setData({
          windowWidth: res.windowWidth,
          windowHeight: res.windowHeight,
          boxWidth: res.windowWidth * 0.75, //分享圖片box寬度
          boxheight: res.windowWidth * (0.222 + 0.72 + 0.192) + 90, //分享圖片box高度
          boxPageY: res.windowWidth * 0.081, //boxY軸位置
          shadowWidth: res.windowWidth * 0.6, //陰影寬度
          shadowHeight: res.windowWidth * 0.78, //陰影高度
          imgPageY: res.windowWidth * 0.232 //商品圖片Y軸位置
          // codeWidth: res.windowWidth * 0.192, //小程序碼圖片寬度
          // codeHeight: res.windowWidth * 0.192, //小程序碼圖片高度
        })
      }
    })
    //網(wǎng)絡(luò)圖片轉(zhuǎn)為本地圖片,直接顯示網(wǎng)絡(luò)圖片的話真機(jī)不顯示
    that.getTempFile(that.data.shopImg)
  },

  //drawImage繪制的圖片需要通過getImageInfo/downloadFile獲取商品臨時(shí)圖片路徑
  getTempFile: function(url) {
    wx.showLoading({
      title: '圖片生成中'
    })
    let that = this
    wx.downloadFile({
      url: url,
      success: function(res) {
        that.setData({
          goodsInfoImg: res.tempFilePath
        })
        //繼續(xù)生成商品的小程序碼
        that.downloadSkuQrCode(that.data.qrCode)
      },
      fail: function(err) {
        wx.showToast({
          title: '下載商品圖片失敗,稍后重試邮绿!',
          icon: 'none',
          duration: 5000
        })
      }
    })
  },

  getData() {
    let that = this
    wx.getImageInfo({
      src: that.data.shopImg,
      success(res) {
        var imgsize = that.getimageSize(
          { width: res.width, height: res.height },
          that.data.shadowWidth,
          95
        )
        that.setData({
          imgWidth: imgsize.width,
          imgHeight: imgsize.height
        })
        that.createNewImg()
      }
    })
  },

  // 圖片適配(aspectFill)
  getimageSize: function(imageSize, w, h) {
    if (imageSize.width < w) {
      if (imageSize.height < h) {
        var scale1 = imageSize.height / imageSize.width
        var scale2 = h / imageSize.height
        if (scale1 > scale2) {
          imageSize.height = (imageSize.height / imageSize.width) * w
          imageSize.width = w
        } else {
          imageSize.width = (imageSize.width / imageSize.height) * h
          imageSize.height = h
        }
      } else {
        imageSize.height = (imageSize.height / imageSize.width) * w
        imageSize.width = w
      }
    } else if (imageSize.height < h) {
      if (imageSize.width < w) {
        var scale1 = imageSize.height / imageSize.width
        var scale2 = h / imageSize.height
        if (scale1 > scale2) {
          imageSize.height = (imageSize.height / imageSize.width) * w
          imageSize.width = w
        } else {
          imageSize.width = (imageSize.width / imageSize.height) * h
          imageSize.height = h
        }
      } else {
        imageSize.width = (imageSize.width / imageSize.height) * h
        imageSize.height = h
      }
    } else {
      var scale1 = imageSize.height / imageSize.width
      var scale2 = h / imageSize.height
      if (scale1 > scale2) {
        imageSize.height = (imageSize.height / imageSize.width) * w
        imageSize.width = w
      } else {
        imageSize.width = (imageSize.width / imageSize.height) * h
        imageSize.height = h
      }
    }
    return imageSize
  },

  //畫矩形渠旁,也是整塊畫布的大小,寬度是屏幕寬度斯碌,高度根據(jù)內(nèi)容多少來動態(tài)設(shè)置。
  drawSquare: function(ctx, height, color) {
    let that = this
    // 繪制大長方矩形
    ctx.setFillStyle(color)
    ctx.fillRect(
      (that.data.windowWidth - that.data.boxWidth) / 2,
      that.data.boxPageY,
      that.data.boxWidth,
      height
    )
    // // 繪制中間塊矩形
    // ctx.setFillStyle('red')
    // ctx.fillRect(
    //   (that.data.windowWidth-that.data.shadowWidth)/2,
    //   that.data.imgPageY,
    //   that.data.shadowWidth,
    //   that.data.shadowWidth
    // )
  },

  // ctx:canvas中的createCanvasContext,
  // x:矩形左上角的x坐標(biāo)
  // y:矩形左上角的y坐標(biāo)
  // w:矩形寬度
  // h:矩形高度
  // r:圓弧半徑
  roundRect: function(ctx, x, y, w, h, r) {
    // 開始繪制
    ctx.beginPath()
    // 因?yàn)檫吘壝柽叴嬖阡忼X傻唾,最好指定使用 transparent 填充
    // 這里是使用 fill 還是 stroke都可以投慈,二選一即可
    ctx.setFillStyle('transparent')
    // ctx.setStrokeStyle('transparent')
    // 左上角
    ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)

    // border-top
    ctx.moveTo(x + r, y)
    ctx.lineTo(x + w - r, y)
    ctx.lineTo(x + w, y + r)
    // 右上角
    ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)

    // border-right
    ctx.lineTo(x + w, y + h - r)
    ctx.lineTo(x + w - r, y + h)
    // 右下角
    ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)

    // border-bottom
    ctx.lineTo(x + r, y + h)
    ctx.lineTo(x, y + h - r)
    // 左下角
    ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)

    // border-left
    ctx.lineTo(x, y + r)
    ctx.lineTo(x + r, y)

    // 這里是使用 fill 還是 stroke都可以,二選一即可冠骄,但是需要與上面對應(yīng)
    ctx.fill()
    // ctx.stroke()
    ctx.closePath()
    // 剪切
    ctx.clip()
    ctx.restore()
  },

  // 根據(jù)文字多少動態(tài)計(jì)算高度伪煤,然后依次畫出矩形凛辣,文字抱既,橫線和小程序碼。
  createNewImg: function() {
    let that = this
    let ctx = wx.createCanvasContext('myCanvas')
    // let contentHeight = that.data.boxheight  //修改圖片高度
    let contentHeight = that.data.shadowWidth + that.data.imgPageY + 100
    // 繪制圓角矩形
    that.roundRect(
      ctx,
      (that.data.windowWidth - that.data.boxWidth) / 2,
      that.data.boxPageY,
      that.data.boxWidth,
      contentHeight - 32,
      14
    )
    that.drawSquare(ctx, contentHeight, '#333')
    that.setData({
      contentHeight: contentHeight
    })
    //商品圖片
    // 繪制圖片圓角
    let bg_r = 14
    ctx.save()
    ctx.beginPath()
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 + bg_r,
      that.data.imgPageY + bg_r,
      bg_r,
      Math.PI,
      Math.PI * 1.5
    )
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 +
        that.data.imgWidth -
        bg_r,
      that.data.imgPageY + bg_r,
      bg_r,
      Math.PI * 1.5,
      Math.PI * 2
    )
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 +
        that.data.imgWidth -
        bg_r,
      that.data.imgPageY + that.data.imgHeight - bg_r,
      bg_r,
      0,
      Math.PI * 0.5
    )
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 + bg_r,
      that.data.imgPageY + that.data.imgHeight - bg_r,
      bg_r,
      Math.PI * 0.5,
      Math.PI
    )
    ctx.clip()
    ctx.drawImage(
      that.data.goodsInfoImg,
      (that.data.windowWidth - that.data.imgWidth) / 2,
      that.data.imgPageY,
      that.data.imgWidth,
      that.data.imgHeight
    )
    ctx.restore()
    // 繪制商品蒙層矩形
    ctx.save()
    ctx.beginPath()
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 + bg_r,
      that.data.imgPageY + that.data.imgHeight - 60 + bg_r,
      30,
      Math.PI,
      Math.PI * 1.5
    )
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 +
        that.data.imgWidth -
        bg_r,
      that.data.imgPageY + that.data.imgHeight - 60 + bg_r,
      30,
      Math.PI * 1.5,
      Math.PI * 2
    )
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 +
        that.data.imgWidth -
        bg_r,
      that.data.imgPageY + that.data.imgHeight - 60 + 60 - bg_r,
      bg_r,
      0,
      Math.PI * 0.5
    )
    ctx.arc(
      (that.data.windowWidth - that.data.imgWidth) / 2 + bg_r,
      that.data.imgPageY + that.data.imgHeight - 60 + 60 - bg_r,
      bg_r,
      Math.PI * 0.5,
      Math.PI
    )
    ctx.clip()
    ctx.setFillStyle('rgba(0,0,0,0.5)')
    ctx.fillRect(
      (that.data.windowWidth - that.data.imgWidth) / 2,
      that.data.imgPageY + that.data.imgHeight - 60,
      that.data.imgWidth,
      60
    )
    ctx.restore()
    ctx.setFillStyle('#fff')
    ctx.font = 'normal 13px Microsoft YaHei'
    ctx.fillText(
      '標(biāo)題logo',
      (that.data.windowWidth - that.data.shadowWidth) / 2,
      that.data.imgPageY - 10
    )
    ctx.setFillStyle('#fff')
    // ctx.setTextAlign="center"
    ctx.fillText(
      '填商品名字',
      (that.data.windowWidth - ctx.measureText('填商品名字').width) * 0.5,
      that.data.imgPageY + that.data.imgHeight - 40
    )
    ctx.font = 'normal 22px Microsoft YaHei'
    ctx.setFillStyle('#ECC781')
    ctx.fillText(
      '填價(jià)格',
      (that.data.windowWidth - ctx.measureText('填價(jià)格').width) * 0.5,
      that.data.imgPageY + that.data.imgHeight - 10
    )
    // 繪制您的好友
    ctx.font = 'normal 16px Microsoft YaHei'
    ctx.setFillStyle('#fff')
    ctx.fillText(
      '您的好友已為您',
      (that.data.windowWidth - that.data.shadowWidth) / 2,
      that.data.shadowWidth + that.data.imgPageY + 30
    )
    ctx.font = 'normal 16px Microsoft YaHei'
    ctx.setFillStyle('#fff')
    ctx.fillText(
      '這里填所需文字',
      (that.data.windowWidth - that.data.shadowWidth) / 2,
      that.data.shadowWidth + that.data.imgPageY + 52
    )
    // 繪制長按識別小程序
    ctx.font = 'normal 12px Microsoft YaHei'
    ctx.setFillStyle('#AAAAAA')
    ctx.fillText(
      '長按識別小程序即可參與',
      (that.data.windowWidth - that.data.shadowWidth) / 2,
      that.data.shadowWidth + that.data.imgPageY + 80
    )
    // 填充小程序碼
    ctx.drawImage(
      that.data.qrCode,
      (that.data.windowWidth - that.data.shadowWidth) / 2 +
        that.data.shadowWidth -
        that.data.codeWidth,
      that.data.shadowWidth + that.data.imgPageY + 80 - that.data.codeHeight,
      that.data.codeWidth,
      that.data.codeHeight
    )
    ctx.draw() //繪制到canvas
    that.generateCanvasImg()
  },

  //下載小程序碼
  downloadSkuQrCode: function(url) {
    let that = this
    wx.downloadFile({
      url: url,
      success: function(res) {
        that.setData({
          qrCode: res.tempFilePath
        })
        //生成數(shù)據(jù)
        wx.getImageInfo({
          src:
            'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1254162229,4079702590&fm=26&gp=0.jpg',
          success(res) {
            that.setData({
              codeWidth: res.width * 0.1,
              codeHeight: res.height * 0.1
            })
            that.getData()
          }
        })
      },
      fail: function(err) {
        wx.showToast({
          title: '下載商品碼失敗,稍后重試防泵!',
          icon: 'none',
          duration: 5000
        })
      }
    })
  },
// 生成圖片中,這個方法是生成臨時(shí)圖片代替canvas展示,因?yàn)樾〕绦蚶锩鎐anvas的層級太高蝗敢,會擋住彈窗的內(nèi)容捷泞,所有需要把canvas放到視圖之外,用img展示即可
  generateCanvasImg() {
    var that = this
    setTimeout(function() {
      wx.canvasToTempFilePath({
        x: (that.data.windowWidth - that.data.boxWidth) / 2,
        y: that.data.boxPageY,
        width: that.data.boxWidth,
        height: that.data.shadowWidth + that.data.imgPageY + 68,
        destWidth: that.data.boxWidth * wx.getSystemInfoSync().pixelRatio,
        destHeight:
          (that.data.shadowWidth + that.data.imgPageY + 68) *
          wx.getSystemInfoSync().pixelRatio,
        canvasId: 'myCanvas',
        success: function(res) {
          wx.hideLoading()
          that.setData({
            canvasTempFile: res.tempFilePath
          })
        },
        fail: function(res) {}
      })
    }, 1000)
  },

//點(diǎn)擊保存到相冊前驗(yàn)證是否授權(quán)  最這兩個方法就是保存相冊了  把它放置到按鈕的點(diǎn)擊事件即可
  saveShareImg: function() {
    wx.getSetting({
      success: res => {
        if (!res.authSetting['scope.writePhotosAlbum']) {
          //未授權(quán)的話發(fā)起授權(quán)
          wx.authorize({
            scope: 'scope.writePhotosAlbum',
            success: () => {
              //用戶允許授權(quán)寿谴,保存到相冊
              this.saveImg()
            },
            fail: () => {
              //用戶拒絕授權(quán),然后就引導(dǎo)授權(quán)(這里的話如果用戶拒絕讶泰,不會立馬彈出引導(dǎo)授權(quán)界面咏瑟,坑就是上邊所說的官網(wǎng)原因)
              wx.showModal({
                content: '保存到相冊需要獲得你的授權(quán)',
                showCancel: false,
                confirmText: '確認(rèn)',
                success: function(res) {
                  wx.openSetting({
                    success: () => {
                      wx.authorize({
                        scope: 'scope.writePhotosAlbum',
                        succes: () => {
                          //授權(quán)成功,保存圖片
                          this.saveImg()
                        }
                      })
                    }
                  })
                },
                fail: function(res) {}
              })
            }
          })
        } else {
          //已經(jīng)授權(quán)
          this.saveImg()
        }
      }
    })
  },

  saveImg() {
    var that = this
    wx.showLoading({
      title: '正在保存',
      mask: true
    })
    wx.saveImageToPhotosAlbum({
      filePath: that.data.canvasTempFile,
      success(res) {
        wx.hideLoading()
        wx.showModal({
          content: '圖片已保存到相冊痪署,趕緊曬一下吧~',
          showCancel: false,
          confirmText: '好的',
          success: function(res) {
            if (res.confirm) {
            }
          },
          fail: function(res) {}
        })
        that.setData({
          sharePopup: false
        })
      },
      fail: function(res) {
        wx.showToast({
          title: '保存失敗',
          icon: 'none',
          duration: 2000
        })
      }
    })
  },
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末码泞,一起剝皮案震驚了整個濱河市狼犯,隨后出現(xiàn)的幾起案子余寥,更是在濱河造成了極大的恐慌,老刑警劉巖辜王,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異罐孝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)莲兢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門汹来,熙熙樓的掌柜王于貴愁眉苦臉地迎上來续膳,“玉大人,你說我怎么就攤上這事收班》夭恚” “怎么了摔桦?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵社付,是天一觀的道長。 經(jīng)常有香客問我邻耕,道長鸥咖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任啼辣,我火速辦了婚禮,結(jié)果婚禮上御滩,老公的妹妹穿的比我還像新娘鸥拧。我一直安慰自己,他們只是感情好削解,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布富弦。 她就那樣靜靜地躺著钠绍,像睡著了一般舆声。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柳爽,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天媳握,我揣著相機(jī)與錄音,去河邊找鬼磷脯。 笑死,一個胖子當(dāng)著我的面吹牛赵誓,可吹牛的內(nèi)容都是我干的打毛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼俩功,長吁一口氣:“原來是場噩夢啊……” “哼幻枉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起诡蜓,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔓罚,沒想到半個月后椿肩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瞻颂,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年郑象,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厂榛。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡盖矫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出噪沙,到底是詐尸還是另有隱情炼彪,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布辐马,位于F島的核電站,受9級特大地震影響局义,放射性物質(zhì)發(fā)生泄漏喜爷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一萄唇、第九天 我趴在偏房一處隱蔽的房頂上張望檩帐。 院中可真熱鬧,春花似錦湃密、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至忿危,卻和暖如春达箍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背铺厨。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留解滓,地道東北人赃磨。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像洼裤,于是被迫代替她去往敵國和親邻辉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345