小程序canvas生成海报以及保存相册授权

责编:menVScode 2020-09-30 13:58 阅读(100)

小程序使用canvas生成海报以及保存相册授权,上代码。

页面代码

<view bindtap='showModal'>生成海报</view>

<!-- 弹出底部分享操作  -->
<view class="modals-cancel" bindtap="hideModal" hidden="{{hideModal}}"></view>
<view class="modals modals-bottom-dialog" >
  <view class="bottom-pos Bottomframe" animation="{{animationData}}">
    <button class='CreatePosterBtn' hover-class='none' bindtap='createPoster'>
      <image class='bottom-pos-icon' src='/images/icon_pic.png'></image>
      <view>生成海报</view>
    </button>
    <button class='ShareFriendsBtn' open-type="share" hover-class='none' bindtap='showStoryShare'>
      <image class='bottom-pos-icon' src='/images/icon_sharewx.png'></image>
      <view>分享给朋友</view>
    </button>
  </view>
</view>

<!-- 生成海报 -->
  <view class='imagePathBox' hidden="{{maskHidden == false}}">
    <view class='CreateImg' style='margin-left:-{{canvasWidth/2}}px;margin-top:-{{canvasHeight/2}}px;'>
     <image style="width: {{canvasWidth}}px; height: {{canvasHeight}}px;" src="{{imagePath}}" mode='aspectFill' catchtap='preview_img'></image>
     <image class='closeCanvas' src='/images/icon_close.png' catchtap='closeCanvas'></image>
    </view>
    <view class="saveImage" catchtap="saveImage">
      <image class='btn_login_bg' src='/images/btn_bg.png'>
        <text>保存图片</text>
      </image>
    </view>
  </view>
  
  <view class="canvas-box">
    <canvas style="width: {{canvasWidth}}px; height: {{canvasHeight}}px; position:fixed;top:9999px" canvas-id="mycanvas" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd" />
  </view>  

<!-- 授权弹窗 -->
<view class='open-seting-bg' wx:if='{{openSet}}' catchtap='cancleSet'>
  <view class='open-set-inner'>
    <view class='set-title'>请在设置中打开相册权限~</view>
    <view class='btn-openset'>
        <button open-type='openSetting' class='button-style' catchtap='cancleSet'>知道了</button>
    </view>
  </view>
</view>

wxss代码

/* 整体遮罩层 */
.modals-cancel{
  position:fixed; 
  z-index:101; 
  top:0; 
  left: 0; 
  right:0; 
  bottom: 0; 
  background-color: rgba(0,0,0,.6);
}
.Bottomframe{
  position:fixed; 
  z-index:102; 
  bottom:0; 
  left:0; 
  right:0; 
  padding: 27rpx 0;
  background-color: #fff;
  display: flex;
  justify-content: space-around;
}
.bottom-pos-icon{
  width: 100rpx;
  height: 100rpx;
  margin-bottom: 28rpx;
}
/*动画前初始位置*/
.bottom-pos{
  -webkit-transform:translateY(100%);transform:translateY(100%);
}
.ShareFriendsBtn, .CreatePosterBtn{
  background-color: #ffffff;
  color: #333333;
  line-height: 0.5;
  height: 146rpx;
  font-size: 26rpx;
}
.ShareFriendsBtn::after{ 
  border: none;
}
.CreatePosterBtn::after{ 
  border: none;
}

/* 生成海报 */
.imgBox{
  text-align: center;
  width: 100%;
  margin-top:60rpx;
  padding-bottom: 120rpx;
} 
.imagePathBox{
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.7);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 103;
}
.CreateImg{
  position:fixed; 
  left: 50%;
  top: 45%;
}
.saveImage{
  position:fixed;
  width:490rpx;
  height:97rpx;
  bottom:50rpx;
  left:50%;
  margin-left:-245rpx;
}
.saveImage text{
  position:absolute;
  top:0;
  left:0;
  right:0;
  color:#fff;
  font-size:34rpx;
  line-height:97rpx;
  text-align:center;
}
.btn_login_bg{
  height:100%;
  width:100%;
}
.closeCanvas{
  position:absolute;
  right:20px;
  top:20px;
  width:20px;
  height:20px;
}
/* 授权弹窗 */
.open-seting-bg {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background: rgba(0, 0, 0, 0.6);
  z-index:10000;
}
.btn-openset {
  border-top:1px solid #f4f4ef;
}
.set-title {
  margin: 40rpx 0;
}
.open-set-inner {
  width: 520rpx;
  height: 220rpx;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: auto;
  background: #ffffff;
  border-radius:6rpx;
  text-align: center;
  font-size:32rpx;
}
.button-style {
  width: 100%;
  height: 100%;
  background: #fff;
  color:#48a2f8;
}
button::after {
  border: 0;
}

js代码

const app = getApp()
Page({

  data: {
    hideModal: true,
    animationData: {},
    maskHidden: false,
    canvasHeight: "",
    canvasWidth: "",
    openSet: false,//授权弹窗
    firstNo: true,
    pixelRatio: '',//像素		
   	photourl:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=659048405,486552330&fm=115&gp=0.jpg",               
    snapshotUrl:"http://res.iiiview.net/ugc/file/2017/08/11/i52a077rui955x7v0123hwhtoq353m80.jpg"
  },

  onLoad: function (options) {
    wx.getSystemInfo({  // 获取页面可视区域的高度
      success: (res) => {
        this.setData({
          height: res.screenHeight,
          // canvasHeight: res.screenWidth * 0.8 * 8 / 5,   8 / 5为设计图的比例  //画布高
          // canvasWidth: res.screenWidth * 0.8,//画布宽
          canvasHeight: 480,
          canvasWidth: 300,//画布宽
          pixelRatio: res.pixelRatio,//像素
        })
      },
    })
  },


  // 调起底部分享操作
  // 显示遮罩层
  showModal: function (res) {
    var that = this;
    var animation = wx.createAnimation({
      duration: 400,//动画的持续时间 默认400ms   数值越大,动画越慢   数值越小,动画越快
      timingFunction: 'ease'
    })
    this.animation = animation
    setTimeout(function () {
      that.fadeIn();//调用
    }, 200)
  },

  // 隐藏遮罩层
  hideModal: function () {
    var that = this;
    var animation = wx.createAnimation({
      duration: 400,
      timingFunction: 'ease',
    })
    this.animation = animation
    that.fadeDown();//调用隐藏动画   
    setTimeout(function () {
      that.setData({
        hideModal: true
      })
    }, 200)//先执行下滑动画,再隐藏模块

  },

  //动画集 显示动画
  fadeIn: function () {
    this.animation.translateY(0).step()
    this.setData({
      animationData: this.animation.export()//动画实例的export方法导出动画数据传递给组件的animation属性
    })
  },
  //动画集 隐藏动画
  fadeDown: function () {
    this.animation.translateY(300).step()
    this.setData({
      animationData: this.animation.export(),
    })
  },


  // 生成海报
  //点击生成
  createPoster: function (e) {
    var that = this;
    this.setData({
      maskHidden: false
    });

    // 调用生成海报方法
    that.createNewImg();
  },

  //生成海报
  createNewImg: function () {
    wx.showLoading({
      title: '海报生成中...',
      mask: true,
    });
    /* 注意画布画的字体 x 轴 需要加上字的高度 */
    let that = this,
      canvasWidth = that.data.canvasWidth,
      canvasHeight = that.data.canvasHeight;

    that.hideModal()//隐藏遮罩层

   
    let qrcode = "/images/qrcode.jpg";//二维码
    // 下载头像图片
    wx.downloadFile({
      url: that.data.photourl,
      success(res) {
        let photourl = res.tempFilePath;//二维码
        // 下载封面
        wx.getImageInfo({
          src: that.data.snapshotUrl,
          success(res) {
            let snapshotUrl = res.path;//封面
            //创建画布
            let ctx = wx.createCanvasContext('mycanvas');
            ctx.clearRect(0, 0, 300, 480)//清除画布
            ctx.drawImage("/images/canvasBg.png", 0, 0, canvasWidth, canvasHeight);
            let textSize = canvasHeight * 28 / 960;/*文字大小 */
            let tipsSize = canvasHeight * 24 / 960;/*文字大小 */
            console.log(photourl)
            // // 绘制头像
            ctx.save(); // 保存当前ctx的状态
            ctx.beginPath();
            let headL = canvasWidth / 2,
              headR = canvasHeight * 62 / 960, /* 头像半径,*/
              headT = headR + canvasHeight * 48 / 960; /* 120rpx头像高,*/
            ctx.arc(headL, headT, headR, 0, 2 * Math.PI, false); //画出圆
            ctx.setFillStyle('lightgreen')
            ctx.fill()
            ctx.clip(); //裁剪上面的圆形
            ctx.drawImage(photourl, headL - headR, canvasHeight * 48 / 960, 2 * headR, 2 * headR);
            ctx.restore(); // 还原状态

            // 绘制名字
            ctx.setFontSize(textSize);
            ctx.setFillStyle("#333333");
            ctx.setTextAlign('center');
            ctx.fillText("canvas", headL, canvasHeight * 218 / 960)

            //绘制封面
            let clip_left = canvasWidth * 36 / 600,  /* 左偏移值 */
              clip_top = canvasHeight * 242 / 960,  /* 上偏移值 */
              clip_width = canvasWidth * 528 / 600,  /* 截取宽度 */
              clip_height = canvasHeight * 297 / 960, /* 截取高度 */
              imgH = res.height,//图片高
              imgW = res.width;//图片宽

            // 绘制封面圆角
            let x = clip_left, y = clip_top, r = 6, w = clip_width, h = clip_height
            ctx.save()//先保存
            ctx.beginPath() // 开始绘制
            ctx.setFillStyle('white')// 因为边缘描边存在锯齿,最好指定使用 transparent 填充,但是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)
            ctx.fill()
            ctx.closePath()
            ctx.clip()// 剪切

            // 按短边计算
            if (imgW * 9 / 16 > imgH) {
              let sx = (imgW - imgH * 16 / 9) / 2
              ctx.drawImage(snapshotUrl, sx, 0, imgH * 16 / 9, imgH, clip_left, clip_top, clip_height * 16 / 9, clip_height);
            } else {
              let sy = (imgH - imgW * 9 / 16) / 2
              ctx.drawImage(snapshotUrl, 0, sy, imgW, imgW * 9 / 16, clip_left, clip_top, clip_width, clip_width * 9 / 16);
            }
            ctx.restore(); // 还原状态

            // 绘制作品名称
            ctx.setFontSize(canvasHeight * 30 / 960);
            ctx.setFillStyle("#333333");
            ctx.setTextAlign('left');
            ctx.fillText("绘制canvas作品名称", clip_left, canvasHeight * 599 / 960)

            // 绘制二维码
            let qrcodeW = canvasHeight * 200 / 960;/*二维码宽高 */
            ctx.drawImage(qrcode, headL - qrcodeW / 2, canvasHeight * 629 / 960, qrcodeW, qrcodeW);

            // 绘制文字描述
            ctx.setFontSize(tipsSize);
            ctx.setFillStyle("#373737");
            ctx.setTextAlign('center');
            ctx.fillText("长按识别小程序,进入页面观看作品", headL, canvasHeight * 885 / 960)
            ctx.setFontSize(tipsSize);
            ctx.setFillStyle("#373737");
            ctx.setTextAlign('center');
            ctx.fillText("还能给作者点赞鼓励哦!", headL, canvasHeight * 916 / 960)
            ctx.draw()
          }
        })

        //将生成好的图片保存到本地,需要延迟一会,绘制期间耗时
        let pixelRatio = that.data.pixelRatio;
        setTimeout(function () {
          wx.canvasToTempFilePath({
            x: 0,
            y: 0,
            width: canvasWidth,
            height: canvasHeight,
            destWidth: canvasWidth * pixelRatio,
            destHeight: canvasHeight * pixelRatio,
            canvasId: 'mycanvas',
            success: function (res) {
              var tempFilePath = res.tempFilePath;
              that.setData({
                imagePath: tempFilePath,
                maskHidden: true
              });
              wx.hideLoading()

            },
            fail: function (res) {
              console.log(res);
            }
          });
        }, 2000);
      }
    })
      
    
    
  },

  //预览图片
  preview_img: function () {
    var that = this;
    console.info("preview_img", that.data.imagePath);
    wx.previewImage({
      current: that.data.imagePath,
      urls: [that.data.imagePath]
    })
  },

  touchStart: function () {
    var that = this;
    console.info("touchStart", that.data.imagePath);
    wx.previewImage({
      current: that.data.imagePath,
      urls: [that.data.imagePath]
    })
  },

  // 授权弹窗
  cancleSet() {
    this.setData({
      openSet: false
    })
  },

  // 关闭海报
  closeCanvas: function () {
    this.setData({
      maskHidden: false
    })
  },

  //点击保存到相册
  saveImage: function () {
    var that = this;
    wx.getSetting({
      success(res) {
        console.log("没有则获取授权")
        // 如果没有则获取授权
        if (!res.authSetting['scope.writePhotosAlbum']) {
          console.log("没有则获取授权")
          wx.authorize({
            scope: 'scope.writePhotosAlbum',
            success() {
              console.log(res)
              wx.saveImageToPhotosAlbum({
                filePath: that.data.imagePath,
                success(res) {
                  wx.showModal({
                    content: '图片已保存到相册,去晒一下吧~',
                    showCancel: false,
                    confirmText: '好的',
                    confirmColor: '#333',
                    success: function (res) {
                      if (res.confirm) {
                        that.setData({
                          maskHidden: false
                        })
                      }
                    },
                    fail: function (res) {
                      console.log(res)
                    }
                  })
                }
              })
            },
            fail(error) {
              console.log(error)
              // 处理用户第一次拒绝后禁止调用授权弹窗
              if (that.data.firstNo == true) {
                that.setData({
                  maskHidden: false,
                  firstNo: false
                })
              } else {
                that.setData({
                  maskHidden: false,
                  openSet: true
                })
              }
            }
          })
        } else {
          // 授权成功保存
          wx.saveImageToPhotosAlbum({
            filePath: that.data.imagePath,
            success(res) {
              wx.showModal({
                content: '图片已保存到相册,去晒一下吧~',
                showCancel: false,
                confirmText: '好的',
                confirmColor: '#333',
                success: function (res) {
                  if (res.confirm) {
                    that.setData({
                      maskHidden: false
                    })
                  }
                },
                fail: function (res) {
                  console.log(res)
                }
              })
            }
          })
        }
      },
      fail(error){
        console.log(error)
      }
    })
  },
});

这里面的960和600是我设计图的比例,宽600,高960,具体根据设计图来,9/16也是我封面图片的比例 528 和 297 是封面的宽和高,最大的难点我个人感觉就是计算图片的的所在位置了,值得注意的是画布的宽和高最好按照设备的一边来取,不要既取设备的宽又取设备的高,我在这上面爬坑爬了好久
// canvasHeight: res.screenWidth * 0.8 * 8 / 5, 8 / 5为设计图的比例 //画布高
// canvasWidth: res.screenWidth * 0.8,//画布宽
可以按这种取法,或者写死
以上代码拿下来就就可以用,有不对的地方欢迎指出来。


1. 生成图片


2. 获取授权


3. 用户拒绝授权之后,再次生成图片提示用户去授权


4. 用户打开授权


5. 授权成功保存到相册


来源:https://blog.csdn.net/Rocky_cx/article/details/87983575

标签: canvas 海报 小程序
前端交流群: MVC前端网(menvscode.com)-qq交流群:551903636

邮箱快速注册

忘记密码