小程序 canvas(canvas2d) 新写法画布之生成海报保存

先来张效果图

 

  <view>
        <canvas type="2d" class="canvas" id="firstCanvas"></canvas>
    </view>
    <button wx:if="{{imageTempPath !=''}}" class='btn' catchtap='saveImageToPhotosAlbum'>保存图片到手机分享朋友圈</button>
    canvas() {
        const self = this;
        // 使用 wx.createContext 获取绘图上下文 context
        const query = wx.createSelectorQuery()
        // 新接口 canvas2d
        query.select('#firstCanvas')
            .fields({
                node: true,
                size: true
            })
            .exec((res) => {
                console.log(res[0].node)
                const canvas = res[0].node
                const ctx = canvas.getContext('2d')
                const dpr = wx.getSystemInfoSync().pixelRatio
                canvas.width = res[0].width * dpr
                canvas.height = res[0].height * dpr
                ctx.scale(dpr, dpr)
                self.saveCanvers(canvas, ctx)
            });

    },
    async saveCanvers(canvas, ctx) {
        const self = this;
        const {
            helpBuyBegin,
            shopImagePath,
            avatarPath,
            imgList,
            ewmImg
        } = self.data
        const width = wx.getSystemInfoSync().screenWidth // 获取设备宽度
        //let ctx = wx.createCanvasContext('firstCanvas', this); /** 创建画布 */
        // 背景色
        ctx.fillStyle = '#ffffff'
        ctx.fillRect(0, 0, 375, 589)
        //绘制背景图
        // ctx.drawImage(imgList[0].value.path, 0, 0, wx.getSystemInfoSync().windowWidth, 589);
        await self.downLoadDrow(canvas, ctx, imgList[0].src, 0, 0, wx.getSystemInfoSync().windowWidth, 589)

        //头像二维码 开始
        var a_avatarurl_width = 52; //绘制的头像宽度
        var a_avatarurl_heigth = 52; //绘制的头像高度
        var a_avatarurl_x = (width / 2) - (a_avatarurl_width / 2); //绘制的头像在画布上的位置
        var a_avatarurl_y = 29; //绘制的头像在画布上的位置
        ctx.save();
        ctx.beginPath(); //开始绘制
        //先画个圆   前两个参数确定了圆心 (x,y) 坐标  第三个参数是圆的半径  四参数是绘图方向  默认是false,即顺时针
        ctx.arc(a_avatarurl_width / 2 + a_avatarurl_x, a_avatarurl_width / 2 + a_avatarurl_y, a_avatarurl_width / 1.99, 0, Math.PI * 2, false);
        //画好了圆 剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 这也是我们要save上下文的原因  
        ctx.fill()
        ctx.clip();
        // let base64Png = wx.getFileSystemManager().readFileSync(qrcodeData.path, 'base64');
        // let qrcodeData_base64 = 'data:image/jpg;base64,' + base64Png
        //ctx.drawImage(avatarPath, a_avatarurl_x, a_avatarurl_y, a_avatarurl_width, a_avatarurl_heigth);
        await self.downLoadDrow(canvas, ctx, avatarPath, a_avatarurl_x, a_avatarurl_y, a_avatarurl_width, a_avatarurl_heigth)
        // //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 还可以继续绘制  
        ctx.restore();
        //头像二维码 结束

        //内容背景
        // const contentImage = (width / 2) - (imgList[1].src.width / 4)
        const contentImage = (width / 2) - (imgList[1].value.width / 4)
        await self.downLoadDrow(canvas, ctx, imgList[1].src, contentImage, 125, 345, 212.5)
        // ctx.drawImage(imgList[1].value.path, contentImage, 125, 345, 212.5);       
        // ctx.stroke();
        //商品图片
        // ctx.drawImage(shopImagePath, 32, 220, 100, 100);
        await self.downLoadDrow(canvas, ctx, shopImagePath, 32, 220, 100, 100)

        let nickName = helpBuyBegin.userName
        if (nickName.length > 12) {
            nickName = nickName.substring(0, 10) + '...'
        }
        ctx.font = 'normal bold 12px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#ffffff'
        ctx.fillText(nickName, (width - ctx.measureText(nickName).width) * 0.5, 106);

        let explain = '   我参与了xxxxx活动,您xxxxx助力可帮我xxxxxx,快来助我一臂之力吧!'
        ctx.font = 'normal bold 13px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#000000'
        await self.fillTextWrap(ctx, explain, 35, 180, 300, 20);

        let str = helpBuyBegin.commodityName.substring(0, 30);
        if (str.length * 2 <= 40) {
            str = helpBuyBegin.commodityName.substring(0, 30)
        } else {
            str = helpBuyBegin.commodityName.substring(0, 28) + '...';
        }
        ctx.font = 'normal 12px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#000000'
        await self.fillTextWrap(ctx, str, 150, 235, 160, 20);

        ctx.font = 'normal 10px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#999999'
        ctx.fillText('xxxx市场价: ¥ ' + helpBuyBegin.linePrice, 150, 298);

        ctx.font = 'normal bold 10px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#df1111'
        ctx.fillText('xxxx最低价:', 150, 315);

        ctx.font = 'normal 10px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#df1111'
        ctx.fillText('¥', 215, 315);

        ctx.font = 'normal bold 18px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#df1111'
        ctx.fillText(helpBuyBegin.price, 223, 315);

        //商品二维码 开始
        var e_avatarurl_width = 100; //绘制的头像宽度
        var e_avatarurl_heigth = 100; //绘制的头像高度
        var e_avatarurl_x = (width - width * 0.2) / 2.15; //绘制的头像在画布上的位置
        var e_avatarurl_y = 370; //绘制的头像在画布上的位置
        ctx.save();
        ctx.beginPath(); //开始绘制
        //先画个圆   前两个参数确定了圆心 (x,y) 坐标  第三个参数是圆的半径  四参数是绘图方向  默认是false,即顺时针
        ctx.arc(e_avatarurl_width / 2 + e_avatarurl_x, e_avatarurl_width / 2 + e_avatarurl_y, e_avatarurl_width / 1.9, 0, Math.PI * 2, false);
        //画好了圆 剪切  原始画布中剪切任意形状和尺寸。一旦剪切了某个区域,则所有之后的绘图都会被限制在被剪切的区域内 这也是我们要save上下文的原因  
        // ctx.setFillStyle('#ffffff');
        ctx.fillStyle = '#ffffff'
        ctx.fill();
        ctx.clip();
        //ctx.drawImage(qrcodeData.path, e_avatarurl_x, e_avatarurl_y, e_avatarurl_width, e_avatarurl_heigth);
        await self.downLoadDrow(canvas, ctx, ewmImg, e_avatarurl_x, e_avatarurl_y, e_avatarurl_width, e_avatarurl_heigth)
        //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 还可以继续绘制  
        ctx.restore();
        //商品二维码 结束        

        const tips = '长按两秒帮TA助力';
        ctx.font = 'normal 10px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#ffffff'
        //3表示宽度,4表示高度
        ctx.fillText(tips, (width - ctx.measureText(tips).width) * 0.5, 495); // 绘制文字(文字居中)

        const tips2 = '助力好友,免费领更多物品';
        ctx.font = 'normal 10px sans-serif'
        ctx.textAlign = 'left';
        ctx.fillStyle = '#ffffff'
        //3表示宽度,4表示高度
        ctx.fillText(tips2, (width - ctx.measureText(tips2).width) * 0.5, 511); // 绘制文字(文字居中)

        wx.canvasToTempFilePath({
            // x: 0, //指定的画布区域的左上角横坐标    
            // y: 0, //指定的画布区域的左上角纵坐标    
            // width: 375, //指定的画布区域的宽度
            // height: 589, //指定的画布区域的高度
            // destWidth: 375*dpr, //输出的图片的宽度 
            // destHeight: 589*dpr, //输出的图片的高度 
            canvas: canvas,
            // canvasId: 'firstCanvas',
            fileType: 'jpg', //图片的质量,目前仅对 jpg 有效。取值范围为 (0, 1],不在范围内时当作 1.0 处理。
            success(res) {
                // 获得图片临时路径
                console.log(res, '8520');
                wx.hideLoading({
                    fial: (err) => { }
                })
                self.setData({
                    imageTempPath: res.tempFilePath
                });
                // self.saveImg(res.tempFilePath)
               
            }
        })
    },
    downLoadDrow(canvas, ctx, url, x, y, w, h) {
        return new Promise((resolve, reject) => {
            wx.getImageInfo({
                src: url,
                success: (res) => {
                    const img = canvas.createImage();
                    img.src = res.path; //微信请求返回头像
                    img.onload = () => {
                        console.log(img)
                        ctx.drawImage(img, x, y, w, h);
                        img.src = ""
                        resolve()
                    }
                },
                fail: (err) => {
                    // wx.hideLoading()
                    wx.showToast({
                        title: '下载图片失败,请稍后重试',
                        icon: 'none'
                    })
                    reject()
                    return false
                }
            })
        })
    },
    saveImg(path) {
        // wx.hideLoading()
        wx.saveImageToPhotosAlbum({
            filePath: path,
            success: (res) => {
                wx.showToast({
                    title: '已保存到相册',
                    icon: 'success',
                    duration: 2000
                })
            },
            fail: (err) => {
                wx.showToast({
                    title: '保存失败',
                    icon: 'none'
                });
            }
        })
    },

不懂可以私聊或者微信联系哈 992307513

 

posted @ 2022-06-21 14:42  晨曦_yuan小海  阅读(1422)  评论(6)    收藏  举报