小程序canvasdrawer 自定义画布保存海报到相册

29 阅读9分钟

VVfAQQBrG10Mbd2ea1525937f105a5d026b78693848b.png

canvasdrawer 组件
/* global Component wx */
// 可参考文档地址  https://github.com/kuckboy1994/mp_canvas_drawer#api

Component({
  properties: {
    painting: {
      type: Object,
      value: {view: []},
      observer (newVal, oldVal) {
        if (!this.data.isPainting) {
          if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
            if (newVal && newVal.width && newVal.height) {
              this.setData({
                showCanvas: true,
                isPainting: true
              })
              this.readyPigment()
            }
          } else {
            if (newVal && newVal.mode !== 'same') {
              this.triggerEvent('getImage', {errMsg: 'canvasdrawer:samme params'})
            }
          }
        }
      }
    }
  },
  data: {
    showCanvas: false,

    width: 100,
    height: 100,

    tempFileList: [],

    isPainting: false
  },
  ctx: null,
  cache: {},
  ready () {
    wx.removeStorageSync('canvasdrawer_pic_cache')
    this.cache = wx.getStorageSync('canvasdrawer_pic_cache') || {}
    this.ctx = wx.createCanvasContext('canvasdrawer', this)
  },
  methods: {
    readyPigment () {
      const { width, height, views } = this.data.painting
      this.setData({
        width,
        height
      })

      const inter = setInterval(() => {
        if (this.ctx) {
          clearInterval(inter)
          this.ctx.clearActions()
          this.ctx.save()
          this.getImagesInfo(views)
        }
      }, 100)
    },
    getImagesInfo (views) {
      const imageList = []
      for (let i = 0; i < views.length; i++) {
        if (views[i].type === 'image') {
          imageList.push(this.getImageInfo(views[i].url))
        }
      }

      const loadTask = []
      for (let i = 0; i < Math.ceil(imageList.length / 8); i++) {
        loadTask.push(new Promise((resolve, reject) => {
          Promise.all(imageList.splice(i * 8, 8)).then(res => {
            resolve(res)
          }).catch(res => {
            reject(res)
          })
        }))
      }
      Promise.all(loadTask).then(res => {
        let tempFileList = []
        for (let i = 0; i < res.length; i++) {
          tempFileList = tempFileList.concat(res[i])
        }
        this.setData({
          tempFileList
        })
        this.startPainting()
      })
    },
    startPainting () {
      const { tempFileList, painting: { views } } = this.data
      console.log(tempFileList)
      for (let i = 0, imageIndex = 0; i < views.length; i++) {
        if (views[i].type === 'image') {
          this.drawImage({
            ...views[i],
            url: tempFileList[imageIndex]
          })
          imageIndex++
        } else if (views[i].type === 'text') {
          if (!this.ctx.measureText) {
            wx.showModal({
              title: '提示',
              content: '当前微信版本过低,无法使用 measureText 功能,请升级到最新微信版本后重试。'
            })
            this.triggerEvent('getImage', {errMsg: 'canvasdrawer:version too low'})
            return
          } else {
            this.drawText(views[i])
          }
        } else if (views[i].type === 'rect') {
          this.drawRect(views[i])
        }
      }
      this.ctx.draw(false, () => {
        wx.setStorageSync('canvasdrawer_pic_cache', this.cache)
        const system = wx.getSystemInfoSync().system
        if (/ios/i.test(system)) {
          this.saveImageToLocal()
        } else {
          // 延迟保存图片,解决安卓生成图片错位bug。
          setTimeout(() => {
            this.saveImageToLocal()
          }, 800)
        }
      })
    },
    drawImage (params) {
      this.ctx.save()
      const { url, top = 0, left = 0, width = 0, height = 0, borderRadius = 0, deg = 0 } = params
      // if (borderRadius) {
      //   this.ctx.beginPath()
      //   this.ctx.arc(left + borderRadius, top + borderRadius, borderRadius, 0, 2 * Math.PI)
      //   this.ctx.clip()
      //   this.ctx.drawImage(url, left, top, width, height)
      // } else {
      if (deg !== 0) {
        this.ctx.translate(left + width/2, top + height/2)
        this.ctx.rotate(deg * Math.PI / 180)
        this.ctx.drawImage(url, -width/2, -height/2, width, height)
      } else {
        this.ctx.drawImage(url, left, top, width, height)
      }
      // }
      this.ctx.restore()
    },
    drawText (params) {
      this.ctx.save()
      const {
        MaxLineNumber = 2,
        breakWord = false,
        color = 'black',
        content = '',
        fontSize = 16,
        top = 0,
        left = 0,
        lineHeight = 20,
        textAlign = 'left',
        width,
        bolder = false,
        textDecoration = 'none'
      } = params
      
      this.ctx.beginPath()
      this.ctx.setTextBaseline('top')
      this.ctx.setTextAlign(textAlign)
      this.ctx.setFillStyle(color)
      this.ctx.setFontSize(fontSize)

      if (!breakWord) {
        this.ctx.fillText(content, left, top)
        this.drawTextLine(left, top, textDecoration, color, fontSize, content)
      } else {
        let fillText = ''
        let fillTop = top
        let lineNum = 1
        for (let i = 0; i < content.length; i++) {
          fillText += [content[i]]
          if (this.ctx.measureText(fillText).width > width) {
            if (lineNum === MaxLineNumber) {
              if (i !== content.length) {
                fillText = fillText.substring(0, fillText.length - 1) + '...'
                this.ctx.fillText(fillText, left, fillTop)
                this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText)
                fillText = ''
                break
              }
            }
            this.ctx.fillText(fillText, left, fillTop)
            this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText)
            fillText = ''
            fillTop += lineHeight
            lineNum ++
          }
        }
        this.ctx.fillText(fillText, left, fillTop)
        this.drawTextLine(left, fillTop, textDecoration, color, fontSize, fillText)
      }
      
      this.ctx.restore()

      if (bolder) {
        this.drawText({
          ...params,
          left: left + 0.3,
          top: top + 0.3,
          bolder: false,
          textDecoration: 'none' 
        })
      }
    },
    drawTextLine (left, top, textDecoration, color, fontSize, content) {
      if (textDecoration === 'underline') {
        this.drawRect({
          background: color,
          top: top + fontSize * 1.2,
          left: left - 1,
          width: this.ctx.measureText(content).width + 3,
          height: 1
        })
      } else if (textDecoration === 'line-through') {
        this.drawRect({
          background: color,
          top: top + fontSize * 0.6,
          left: left - 1,
          width: this.ctx.measureText(content).width + 3,
          height: 1
        })
      }
    },
    drawRect (params) {
      this.ctx.save()
      const { background, top = 0, left = 0, width = 0, height = 0 } = params
      this.ctx.setFillStyle(background)
      this.ctx.fillRect(left, top, width, height)
      this.ctx.restore()
    },
    getImageInfo (url) {
      console.log(url,'========url')
      return new Promise((resolve, reject) => {
        if (this.cache[url]) {
          resolve(this.cache[url])
        } else {
          const objExp = new RegExp(/^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/)
          console.log(url,'========url')
          if (objExp.test(url)) {
            wx.getImageInfo({
              src: url,
              complete: res => {
                if (res.errMsg === 'getImageInfo:ok') {
                  this.cache[url] = res.path
                  resolve(res.path)
                } else {
                  this.triggerEvent('getImage', {errMsg: 'canvasdrawer:download fail'})
                  reject(new Error('getImageInfo fail'))
                }
              }
            })
          } else {
            this.cache[url] = url
            resolve(url)
          }
        }
      })
    },
    saveImageToLocal () {
      const { width, height } = this.data
      wx.canvasToTempFilePath({
        x: 0,
        y: 0,
        width,
        height,
        canvasId: 'canvasdrawer',
        complete: res => {
          if (res.errMsg === 'canvasToTempFilePath:ok') {
            this.setData({
              showCanvas: false,
              isPainting: false,
              tempFileList: []
            })
            this.triggerEvent('getImage', {tempFilePath: res.tempFilePath, errMsg: 'canvasdrawer:ok'})
          } else {
            this.triggerEvent('getImage', {errMsg: 'canvasdrawer:fail'})
          }
        }
      }, this)
    }
  }
})



wxml 文件
<canvas canvas-id="canvasdrawer" style="width:{{width}}px;height:{{height}}px;" class="board" wx:if="{{showCanvas}}"></canvas>

wxss 文件
.board {
  position: fixed;
  top: 10000rpx;
}

如何使用页面需要引入改组件
"usingComponents": {
        "canvasdrawer": "/components/canvasdrawer/canvasdrawer"
    }
<!--packageHome/pages/ShareBill/ShareBill.wxml
测试数据
appPosterConfig/detail返回报文:>>{"code":"200","message":"","data":{"appNo":"A003","posterUrls":["https://v3-cs.obs.cn-south-1.myhuaweicloud.com:443/boss/app_config/2024/04/337_1675069394379_1713149938541.jpg?AccessKeyId=4QVR19MB9WULK1AUMG9R&Expires=2068767627&Signature=8ZKjZKJJ%2BqG6NC7z8dPk0sobEtw%3D"],"descMessage":"<p>测试测试</p><p><span style=\"color: rgb(247, 89, 171); background-color: rgb(255, 255, 255); font-size: 19px;\">拓展代理商推广海报配置</span></p><p><span style=\"color: rgb(83, 29, 171); background-color: rgb(255, 255, 255); font-size: 24px;\">拓展代理说明文案配置</span></p><p><span style=\"color: rgb(83, 29, 171); background-color: rgb(255, 255, 255); font-size: 24px;\"> </span><a href=\"http://www.baidu.com\" target=\"_blank\">百度</a> </p>","agentNo":"8121749390","agentName":"联盟代理商A003-2","qrCodeUrl":"https://zxy001-agent-h5-expand.51ydmw.com/agentExpand?appNo=A003&userId=100122120&businessType=POS","defaultStatus":"1"}}
-->
<pageViewThemeColor>
<view class="mani_content">
	<!-- 
    swiper 标签存在默认的宽度和高度
     宽度:100%
     高度是 150 px
    image 标签也存在默认的宽度和高度
    320*240
    如何设计轮播图和图片的等比例宽高
    1 745   x   1326   pixels
    2 先让图片高度自适应;宽度100%
    1 首先先找出原图的高度与宽度 比如  1326   x   745 然后等比例给swiper 计算高度
    swiper(w)/swiper(h)=1326/745
    swiper(h) =  swiper(w)*1326/745
    height = 100vw*1326/745
   -->
	<view class="bannerswiper">
		<swiper bindchange="handleBindchange" indicator-dots="{{true}}" autoplay="{{false}}" interval="{{2000}}" duration="{{500}}" indicator-color="#bbb" indicator-active-color="#333333">
			<swiper-item wx:for="{{appPosterConfig.posterUrls}}" wx:key="*this">
				<image class="swiper-image" src="{{item}}" mode="scaleToFill" />
			</swiper-item>
		</swiper>

		<view class="kzexpend" bind:tap="handleExpend" wx:if="{{appPosterConfig.descMessage}}">
			<view class="label">拓展说明<text class="iconfont icon-jiantou-you" style="color: white;"></text></view>
		</view>
	</view>

	<view class="sharebillwrap" style="background-image: url({{baseImgUrl+'sharebill_bg@2x.png'}});">
		<view class="leftpersion">
			<image class="icon_persion" src="{{baseImgUrl+'icon_persion@2x.png'}}" mode="widthFix" />
			<view class="persioon_name">{{appPosterConfig.agentName}}</view>
		</view>
		<!-- 二维码 -->
		<image class="qrcode" mode="widthFix" src="{{paymentCodeImgPath}}"></image>
	</view>

	<view class="bottom_wrap2" style="padding-bottom: {{isIPhoneX?74:40}}rpx;">
		<button class="comfit" bind:tap="goMyPolicyClick" wx:if="{{tag !== 'wifi' }}">默认政策</button>
		<button class="comfit" bindtap="bindClick" style="{{tag=='wifi'? 'width: 630rpx;':''}}">分享</button>
	</view>

</view>

<van-toast id="van-toast" />
<!-- <canvas class='canvas-paymentcode-parent' type="2d" id='canvas-paymentcode' hidden='{{canvasHiddenBigImg}}'></canvas> -->
<!-- 二维码 -->
<canvas class="canvas-qrcode" type="2d" id='qrcode'></canvas>

<canvasdrawer painting="{{painting}}" class="canvasdrawer" bind:getImage="eventGetImage"/>

<!-- 选择器 -->
<van-popup show="{{ isShow }}" round position="bottom" custom-style="van-popup" bind:close="onClose">
	<!-- 自定义部分 -->
	<view class="share_main_content">
		<view class="share_title">分享或保存</view>
		<view class="share_item" bindtap="handleSaveImage">
			<image class="icon" src="{{baseImgUrl+'icon_save_img@2x.png'}}" mode="widthFix"></image>
			<view class="item_label">保存到相册</view>
		</view>
		<view class="cancel_wrap" bind:tap="bindCancel">取消</view>
	</view>
	
	

</van-popup>
</pageViewThemeColor>
// packageHome/pages/ShareBill/ShareBill.js
const app = getApp()
import Toast from '@vant/weapp/toast/toast';
import {
    appPosterConfig,
    showM,
    showT
} from "../../../utils/api.js";
import {
    encode,
    decode,
    isNull,
    loadImgSync,
    canvasToUrlSync,
    formatTime,
    getMessageTitleAndDateHtml
} from "../../../utils/util"
//联拓宝用的新的二维码生成库
import drawQrcode from '../../../utils/weapp.qrcode.esm.js'
Page({

    /**
     * 页面的初始数据
     */
    data: {
        tag: '',//跳转页面表示
        baseUrl: app.globalData.baseUrl,
        baseImgUrl: app.globalData.baseImgUrl,
        isIPhoneX: app.globalData.isIPhoneX,
        index: 0, //滑动索引
        isShow: false,
        canvasHiddenQrcode: true,
        canvasHiddenBigImg: true,
        appPosterConfig: '', //扩展代理返回的实体
        paymentCodeImgPath: '', //二维码的图片路径
        wxBgUrlPath: '', //图片背景
        bigPosterImgWidth: '',
        bigPosterImgHeigth: '',
        wxLogoUrlPath: '', //头像logo
        wxLogoUrlPathWidth: '',
        wxLogoUrlPathHeigth: '',
        wxBottomImgbgPath: '', //底部背景图
        wxBottomImgbgPathWidth: '',
        wxBottomImgbgPathHeight: '',
        painting: {},
        shareImage: '',
        screenWidth: 750,
        screenHeight: 0,
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad(options) {
        let tag = options.tag || ''
        this.setData({
            tag
        })
        this.appPosterConfig()
    },
    eventDraw() {
        let that = this
        const {
            index,
            appPosterConfig
        } = this.data
        var bgUrl = appPosterConfig.posterUrls[index];
        // 大的海报图
        var rate = that.data.bigPosterImgHeigth / that.data.bigPosterImgWidth //海报的高宽比
        var imgHigth = that.data.screenWidth * rate //换算后图片海报高度

        // 底部圆点图
        var bottomBgRate = that.data.wxBottomImgbgPathHeight / that.data.wxBottomImgbgPathWidth //底部图片的高宽比
        var bottomImgHigth = that.data.screenWidth * bottomBgRate //换算后底部图片高度

        // 头像
        var wxLogoUrlPathW = 108
        var wxLogoUrlPathH = 108
        var wxLogoUrlPathX = (that.data.screenWidth - wxLogoUrlPathW - 604)
        var wxLogoUrlPathY = (imgHigth + bottomImgHigth / 2 - wxLogoUrlPathH / 2)

        // 代理商名称
        var agentFontSize = 32
        var agentNameY = imgHigth + bottomImgHigth / 2 - agentFontSize / 2
        var agentNameX = wxLogoUrlPathX + wxLogoUrlPathW + 16

        // 二维码
        var wxQrCodePathW = 160;
        var wxQrCodePathH = 160;
        var qrCodeY = imgHigth + bottomImgHigth / 2 - wxQrCodePathH / 2
        var qrCodeX = that.data.screenWidth - 44 - wxQrCodePathW

        // 整张图片高度
        that.data.screenHeight = imgHigth + bottomImgHigth;

        this.setData({
            painting: {
                width: that.data.screenWidth,
                height: that.data.screenHeight,
                clear: true,
                views: [{
                    type: 'image',
                    url: bgUrl,
                    top: 0,
                    left: 0,
                    width: that.data.screenWidth,
                    height: imgHigth
                },
                {
                    type: 'image',
                    url: this.data.wxBottomImgbgPath,
                    top: imgHigth,
                    left: 0,
                    width: this.data.screenWidth,
                    height: bottomImgHigth
                },
                {
                    type: 'image',
                    url: this.data.wxLogoUrlPath,
                    top: wxLogoUrlPathY,
                    left: wxLogoUrlPathX,
                    width: wxLogoUrlPathW,
                    height: wxLogoUrlPathH
                },
                {
                    type: 'text',
                    content: that.data.appPosterConfig.agentName,
                    fontSize: agentFontSize,
                    color: '#333333',
                    textAlign: 'left',
                    top: agentNameY,
                    breakWord: true,
                    width: 360,
                    lineHeight: 40,
                    MaxLineNumber: 3,
                    left: agentNameX,
                    bolder: false
                },
                {
                    type: 'image',
                    url: that.data.paymentCodeImgPath,
                    top: qrCodeY,
                    left: qrCodeX,
                    width: wxQrCodePathW,
                    height: wxQrCodePathH
                },
                ]
            }
        })
    },
    eventSave() {
        wx.saveImageToPhotosAlbum({
            filePath: this.data.shareImage,
            //保存成功失败之后,都要隐藏画板,否则影响界面显示。
            success: (res) => {
                wx.hideLoading()
                this.setData({
                    isShow: false
                })
                showT("保存相册成功")
                console.log("已保存到相册")
            },
            fail: (err) => {
                wx.hideLoading()
                showT("保存相册失败")
                console.log("保存失败" + JSON.stringify(err))
            }
        })
    },
    eventGetImage(event) {
        // wx.hideLoading()
        const {
            tempFilePath,
            errMsg
        } = event.detail
        if (errMsg === 'canvasdrawer:ok') {
            this.setData({
                shareImage: tempFilePath
            })

            this.checkPhotoAlbumPerm()
        }
    },
    /**
     * 我的政策
     */
    goMyPolicyClick() {
        wx.navigateTo({
            url: '/packagePolicy/pages/mypolicy/index',
        })
    },
    appPosterConfig() {
        wx.showLoading({
            title: '加载中..',
            mask: true
        })
        let params = {
            businessType: this.data.tag == 'wifi' ? 'WIFI' : 'POS',//业务类型: 区分 POS WIFI
        }
        appPosterConfig(params).then((res) => {
            wx.hideLoading()
            if (res.code == '200') {
                var appPosterConfig = res.data
                //注意二维码库,如果为空值,会出现默认的“爱一个人就要勇敢说出来”几个字,所以要记得判空;
                if (!isNull(appPosterConfig.qrCodeUrl)) {
                    this.saveImageQrcode()
                }
                this.setData({
                    appPosterConfig,
                })
            } else {
                Toast(res.message)
            }
        }).catch(res => {
            console.log(res);
            wx.hideLoading()
        });
    },
    /**
     * 生成小的二维码图路径
     */
    saveImageQrcode() {
        const that = this;
        that.setData({
            canvasHiddenQrcode: false
        })
        const systemInfo = wx.getSystemInfoSync()
        const width = 160 * systemInfo.windowWidth / 375
        // const width = 160 
        const height = width;
        //
        const query = wx.createSelectorQuery()
        query.select('#qrcode')
            .fields({
                node: true,
                size: true
            })
            .exec((res) => {
                var canvas = res[0].node
                // 调用方法drawQrcode生成二维码
                drawQrcode({
                    canvas: canvas,
                    canvasId: 'qrcode',
                    width: height,
                    height: height,
                    padding: 1,
                    background: '#ffffff',
                    foreground: '#000000',
                    correctLevel: 1,
                    text: that.data.appPosterConfig.qrCodeUrl,
                })
                wx.canvasToTempFilePath({
                    fileType: 'jpg',
                    canvas: canvas,
                    canvasId: 'qrcode',
                    success: function (res) {
                        console.log("canvasToTempFilePath 保存二维码成功")
                        console.log("saveImageQrcode res.tempFilePath=" + res.tempFilePath)
                        wx.hideLoading()
                        wx.setStorage({
                            key: "codeLinkImg",
                            data: res.tempFilePath,
                        });
                        that.setData({
                            canvasHiddenQrcode: true,
                            paymentCodeImgPath: res.tempFilePath //二维码图片路径,后面绘制图片的时候需要
                        })
                    },
                    fail: function (res) {
                        console.log("saveImageQrcode res.tempFilePath 保存二维码失败" + JSON.stringify(res))
                        wx.hideLoading()
                        that.setData({
                            canvasHiddenQrcode: true
                        })
                        wx.setStorage({
                            key: "codeLinkImg",
                            data: "",
                        });
                    },
                    complete: function (res) {
                        console.log("complete=" + JSON.stringify(res))
                    }
                }, that)
            })

    },
    /**
     * 拓展说明
     * @param {*} e 
     */
    handleExpend(e) {
        var title = "拓展说明"
        var tempUrl = encodeURIComponent(this.data.appPosterConfig.descMessage)
        wx.navigateTo({
            url: `/pages/webview/richWebview?url=${tempUrl}&title=${title}`,
        })
    },
    //滑动监听
    handleBindchange(e) {
        const index = e.detail.current //滑动的索引
        console.log("滑动索引:" + index);
        this.setData({
            index,
        })
    },
    //保存图片到相册
    handleSaveImage(e) {
        wx.showLoading({
            title: '保存中...',
            mask: true
        })
        this.saveDownLoadImg()
    },

    async saveDownLoadImg() {
        this.data.wxBgUrlPath = await this.downLoadBigBg()
        if (isNull(this.data.wxBgUrlPath)) {
            wx.hideLoading()
            showT("保存失败")
            return
        }
        this.data.wxLogoUrlPath = await this.downLoadHeadImg()
        if (isNull(this.data.wxLogoUrlPath)) {
            wx.hideLoading()
            showT("保存失败")
            return
        }
        this.data.wxBottomImgbgPath = await this.downLoadBottomImgbg()
        if (isNull(this.data.wxBottomImgbgPath)) {
            wx.hideLoading()
            showT("保存失败")
            return
        }
        this.eventDraw()
        // this.checkPhotoAlbumPerm()
    },
    /**
     * 校验保存相册权限
     */
    checkPhotoAlbumPerm() {
        //先校验权限
        var that = this
        wx.getSetting({
            success(res) {
                console.log('res', res)
                if (!res.authSetting['scope.writePhotosAlbum']) { //如果没有授权,则去请求授权
                    wx.authorize({
                        scope: 'scope.writePhotosAlbum',
                        success() {
                            //授权成功
                            // wx.showLoading({
                            // 	title: '保存中...',
                            // 	mask: true
                            // })
                            setTimeout(() => {
                                that.createCanvas()
                            }, 0)
                        },
                        fail() {
                            showM("温馨提示", "您还未授权保存到相册,是否现在去授权?", "确定", "取消").then(() => {
                                wx.openSetting({}) //跳转微信的设置权限的界面
                            }).catch(() => {

                            })
                        }
                    })
                } else {
                    // wx.showLoading({
                    // 	title: '保存中...',
                    // 	mask: true
                    // })
                    setTimeout(() => {
                        that.createCanvas()
                    }, 0)
                }
            }
        })
    },
    //创建canvas,使用2d方式;
    createCanvas() {
        this.eventSave()
        // return
        // var that = this
        // const query = wx.createSelectorQuery()
        // query.select('#canvas-paymentcode')
        // 	.fields({
        // 		node: true,
        // 		size: true
        // 	})
        // 	.exec((res) => {
        // 		var canvas = res[0].node
        // 		const ctx = canvas.getContext('2d')
        // 		that.saveImageToPhotosAlbum(canvas, ctx)

        // 	})
    },
    /**
     * 定义的保存图片方法
     * 点击保存的时候再执行保存到相册功能
     */
    // async saveImageToPhotosAlbum(canvas, ctx) {
    // 	var that = this;
    // 	var wxBgUrlPath = that.data.wxBgUrlPath //背景路径
    // 	var wxLogoUrlPath = that.data.wxLogoUrlPath //头部logo路径
    // 	var wxBottomImgbgPath = that.data.wxBottomImgbgPath //底部背景图路径
    // 	var qrcodeImg = that.data.paymentCodeImgPath //二维码图路径
    // 	wx.showLoading({
    // 		title: '保存中...',
    // 	})
    // 	//设置画板显示,才能开始绘图
    // 	that.setData({
    // 		canvasHiddenBigImg: false
    // 	})

    // 	//绘制图像到画布 x y width height
    // 	that.data.screenWidth = 750; //根据蓝湖尺寸定义的,图片高度等比
    // 	var rate = that.data.bigPosterImgHeigth / that.data.bigPosterImgWidth //海报的高宽比
    // 	var imgHigth = that.data.screenWidth * rate //换算后图片海报高度

    // 	var bottomBgRate = that.data.wxBottomImgbgPathHeight / that.data.wxBottomImgbgPathWidth //底部图片的高宽比
    // 	var bottomImgHigth = that.data.screenWidth * bottomBgRate //换算后底部图片高度

    // 	var bottomSpace = bottomImgHigth //底部区域高度 理想的高度是261
    // 	that.data.screenHeight = imgHigth + bottomSpace;
    // 	const systemInfo = wx.getSystemInfoSync();
    // 	const dpr = systemInfo.pixelRatio;
    // 	this.setData({
    // 		dpr
    // 	})
    // 	console.log("dpr:--->" + dpr);
    // 	// canvas.width = canvasDomWidth * dpr; // 设计稿宽度 * DPR
    // 	// canvas.height = canvasDomHeight * dpr; // 设计稿高度 * DPR
    // 	console.log("canvas=" + JSON.stringify(canvas))
    // 	canvas.width = that.data.screenWidth;
    // 	canvas.height = that.data.screenHeight;
    // 	ctx.scale(dpr, dpr); // 缩放绘图上下文
    // 	let img = await loadImgSync(canvas, wxBgUrlPath)
    // 	console.log('img:' + img);
    // 	if (isNull(img.src)) {
    // 		wx.hideLoading()
    // 		showT("保存相册失败")
    // 		return
    // 	}
    // 	console.log("that.data.screenWidth=" + that.data.screenWidth)
    // 	console.log("imgHigth=" + imgHigth)
    // 	console.log("img=========" + img.height)
    // 	ctx.drawImage(img, 0, 0, that.data.screenWidth, imgHigth); //绘制海报图
    // 	ctx.restore();

    // 	let bottomImg = await loadImgSync(canvas, wxBottomImgbgPath)
    // 	ctx.drawImage(bottomImg, 0, imgHigth, that.data.screenWidth, bottomImgHigth); //绘制底图
    // 	ctx.restore();
    // 	//开始绘制头部logo
    // 	let imgwxLogoUrlPath = await loadImgSync(canvas, wxLogoUrlPath)
    // 	var wxLogoUrlPathW = 108
    // 	var wxLogoUrlPathH = 108
    // 	var wxLogoUrlPathX = (that.data.screenWidth - wxLogoUrlPathW - 590)
    // 	// var wxLogoUrlPathY = 1064
    // 	var wxLogoUrlPathY = (imgHigth + bottomSpace - 208)
    // 	ctx.drawImage(imgwxLogoUrlPath, wxLogoUrlPathX, wxLogoUrlPathY, wxLogoUrlPathW, wxLogoUrlPathH);
    // 	ctx.restore();
    // 	// //绘制 二维码的圆角白色底图
    // 	// var qrcodeRectW = 630;
    // 	// var qrcodeRectH = 630;
    // 	// var startRectX = (that.data.screenWidth - qrcodeRectW) / 2;
    // 	// var startRectY = 240;
    // 	// that.roundRect(ctx, startRectX, startRectY, qrcodeRectW, qrcodeRectH, 20, '#fff', '#fff');

    // 	//绘制代理商名称
    // 	ctx.font = "normal 500 34px Arial, sans-serif"
    // 	ctx.fillStyle = "#333333"
    // 	var merchantNameW = ctx.measureText(that.data.appPosterConfig.agentName).width
    // 	var merchantX = (that.data.screenWidth - merchantNameW - 80) / 2
    // 	var merchantY = imgHigth + bottomSpace - 138 //距离顶部 x是以文本的中间位置定位的
    // 	ctx.fillText(that.data.appPosterConfig.agentName, merchantX, merchantY)
    // 	ctx.restore();

    // 	//开始绘制二维码
    // 	let imgqrcodeImg = await loadImgSync(canvas, qrcodeImg)
    // 	var wxLogoUrlPathW = 160
    // 	var wxLogoUrlPathH = 160
    // 	var wxLogoUrlPathX = (that.data.screenWidth - wxLogoUrlPathW - 70)
    // 	var wxLogoUrlPathY = (imgHigth + bottomSpace - 206)
    // 	ctx.drawImage(imgqrcodeImg, wxLogoUrlPathX, wxLogoUrlPathY, wxLogoUrlPathW, wxLogoUrlPathH);
    // 	ctx.restore();
    // 	//绘制底部图标
    // 	// let imgwxPayIconPath = await loadImgSync(canvas, wxBottomImgbgPath)
    // 	// var wxPayIconPathW = 690 //蓝湖图宽度
    // 	// var wxPayIconPathH = 216 //蓝湖图高度
    // 	// var wxPayIconPathX = (that.data.screenWidth - 720)
    // 	// var wxPayIconPathY = imgHigth - 216 //蓝湖图片,距离顶部距离
    // 	// ctx.drawImage(imgwxPayIconPath, wxPayIconPathX, wxPayIconPathY, wxPayIconPathW, wxPayIconPathH);
    // 	// ctx.restore();
    // 	// 把画板内容绘制成图片,并回调 画板图片路径
    // 	that.getCanvasUrl(canvas).then((canvaspath) => {
    // 		if (!isNull(canvaspath)) {
    // 			//画板路径保存成功后,调用方法吧图片保存到用户相册
    // 			wx.saveImageToPhotosAlbum({
    // 				filePath: canvaspath,
    // 				//保存成功失败之后,都要隐藏画板,否则影响界面显示。
    // 				success: (res) => {
    // 					wx.hideLoading()
    // 					that.setData({
    // 						canvasHiddenBigImg: true,
    // 						isShow: false
    // 					})
    // 					showT("保存相册成功")
    // 					console.log("已保存到相册")
    // 				},
    // 				fail: (err) => {
    // 					wx.hideLoading()
    // 					that.setData({
    // 						canvasHiddenBigImg: true,
    // 					})
    // 					showT("保存相册失败")
    // 					console.log("保存失败" + JSON.stringify(err))
    // 				}
    // 			})
    // 		}

    // 	})
    // },
    /**
     * 下载大的背景图
     */
    downLoadBigBg() {
        var that = this
        const {
            index,
            appPosterConfig
        } = this.data
        var bgUrl = appPosterConfig.posterUrls[index];
        return new Promise((resolve, reject) => {
            wx.getImageInfo({
                src: bgUrl, //请求的网络图片路径
                type: 'png',
                success: function (res) {
                    that.data.bigPosterImgWidth = res.width;
                    that.data.bigPosterImgHeigth = res.height
                    console.log("downLoadBigBg 保存背景图成功 图片高=" + that.data.bigPosterImgHeigth + "图片宽=" + that.data.bigPosterImgWidth)
                    resolve(res.path)
                },
                fail: function (res) {
                    console.log("downLoadBigBg 保存背景图失敗")
                    wx.hideLoading()
                    showT("保存失败")
                    reject("")
                }
            })
        })
    },
    /**
     * 下载头部logo
     */
    downLoadHeadImg() {
        var that = this
        var logoUrl = this.data.baseImgUrl + 'icon_persion@2x.png';
        return new Promise((resolve, reject) => {
            wx.getImageInfo({
                src: logoUrl, //请求的网络图片路径
                success: function (res) {
                    that.data.wxLogoUrlPathWidth = res.width;
                    that.data.wxLogoUrlPathHeigth = res.height
                    console.log("downLoadHeadImg 保存头部成功")
                    resolve(res.path)
                },
                fail: function (res) {
                    console.log("downLoadHeadImg 保存头部失敗")
                    wx.hideLoading()
                    showT("保存失败")
                    reject("")
                }
            })
        })

    },

    /**
     * 下载底部背景图
     */
    downLoadBottomImgbg() {
        var that = this
        var bottomImgbg = this.data.baseImgUrl + 'sharebill_bg@2x.png';
        return new Promise((resolve, reject) => {
            wx.getImageInfo({
                src: bottomImgbg, //请求的网络图片路径
                success: function (res) {
                    that.data.wxBottomImgbgPathWidth = res.width;
                    that.data.wxBottomImgbgPathHeight = res.height
                    console.log("downLoadBottomImgbg 保存底部背景图成功wxBottomImgbgPathWidth=" + that.data.wxBottomImgbgPathWidth + "wxBottomImgbgPathHeigth=" + that.data.wxBottomImgbgPathHeight)
                    resolve(res.path)
                },
                fail: function (res) {
                    console.log("downLoadBottomImgbg 保存底部背景图失敗")
                    wx.hideLoading()
                    showT("保存失败")
                    reject("")
                }
            })
        })

    },
    bindClick(e) {
        this.setData({
            isShow: true
        })
    },
    bindCancel(e) {
        this.setData({
            isShow: false
        })
    },
    async getCanvasUrl(canvas) {
        return await canvasToUrlSync(canvas)
    },
    //绘制圆角矩形
    roundRect(ctx, x, y, w, h, r, colorBackground, strokeColor) {
        // 开始绘制
        ctx.beginPath();
        ctx.fillStyle = colorBackground;
        ctx.strokeStyle = strokeColor
        // 左上角
        ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
        // 右上角
        ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);
        // 右下角
        ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);
        // 左下角
        ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);
        // border-left
        ctx.lineTo(x, y + r);

        ctx.fill();
        ctx.stroke();
        ctx.closePath();
        // 剪切
        // ctx.clip();
        ctx.restore();
    },
    /**
     * 生命周期函数--监听页面初次渲染完成
     */
    onReady() {

    },

    /**
     * 生命周期函数--监听页面显示
     */
    onShow() {

    },

    /**
     * 生命周期函数--监听页面隐藏
     */
    onHide() {

    },

    /**
     * 生命周期函数--监听页面卸载
     */
    onUnload() {

    },

    /**
     * 页面相关事件处理函数--监听用户下拉动作
     */
    onPullDownRefresh() {

    },

    /**
     * 页面上拉触底事件的处理函数
     */
    onReachBottom() {

    },


})