uniapp中使用canvas绘图,并保存图片

3,081 阅读1分钟

需求:

  1. 保存分享二维码图片,并带上logo,等其他信息
  2. 保存的二维码图片在页面上是不可见的(需要悄悄的画图)
    • 解决方式:采用定位将canvas画布放在底部,在用一个同背景色的遮罩层挡住canvas画布

实现效果:

  • 页面显示:

image.png

  • 保存到相册后:

image.png

实现代码:

    <!-- 遮挡canvas画布 -->
    <view class="mask-box"></view>
    <canvas v-show="true" class="canvas" canvas-id="saveQr"></canvas>
<script>
export default {
    data() {
        return {
            qrImg: 'qr.png', // 二维码图片
            saveLogo:'logo.png',// logo图片
            qrcode:'很长的文字'
        }
    },
    methods: {
        // 点击保存二维码
        saveImg() {
            // 显示loading
            uni.showLoading({
                title:this.$t('loading.isSave')
            })
            // 画图
            this.drawQR()
        },
        // 画圆角矩形
        drawRound(ctx, x, y, w, h, r, fill, round) {
            ctx.fillStyle = fill
            ctx.fillRect(x, y, w, h)
            ctx.beginPath()
            ctx.fillStyle = round
            ctx.moveTo(x, y)
            ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
            ctx.moveTo(x + w, y)
            ctx.arc(x + w - r, y + r, r, 0, Math.PI * 1.5, true)
            ctx.moveTo(x + w, y + h)
            ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
            ctx.moveTo(x, y + h)
            ctx.arc(x + r, y + h - r, r, Math.PI, Math.PI * 0.5, true)
            ctx.fill()
            ctx.closePath
        },
        // 画图并保存
        drawQR() {
            // 画笔
            const ctx = uni.createCanvasContext('saveQr')
            // 填充背景
            ctx.fillStyle = '#0871EA'
            ctx.fillRect(0, 0, 371, 533)
            // 在画布中插入图片,需要等待图片加载完成,使用 uni.getImageInfo方法等待图片加载完成。
            uni.getImageInfo({
                src: this.saveLogo,
                // 在complete回调中处理,解决IOS兼容问题
                complete: res => {
                    // 画logo
                    ctx.drawImage(this.saveLogo, 92, 469, 192, 40)
                    // 画圆角矩形
                    this.drawRound(ctx, 16, 24, 343, 421, 8, '#ffffff', '#0871EA')
                    this.drawRound(ctx, 92, 85, 192, 24, 12, '#F5F7F9', '#ffffff')
                    // 画二维码边框
                    ctx.strokeStyle = '#F6F6F6'
                    ctx.strokeRect(88, 125, 200, 200)
                    // 二维码图片
                    uni.getImageInfo({
                        src: this.qrImg,
                        complete: res => {
                            // 画二维码
                            ctx.drawImage(this.qrImg, 88, 125, 200, 200)
                            // 文字样式
                            ctx.textAlign = 'center'
                            ctx.setTextBaseline('top')
                            ctx.fillStyle = "#162032"
                            // 插入文字
                            ctx.font = 'bold 14px sans-serif';
                            ctx.fillText('文字', 187.5, 50)
                            ctx.fillText('文字', 187.5, 350)
                            ctx.font = '12px sans-serif';
                            ctx.fillText('文字', 187.5, 92)
                            ctx.font = 'normal 14px sans-serif';
                            // 两行显示
                            ctx.fillStyle = "#717378"
                            ctx.fillText(this.qrcode.slice(0, 30), 187.5, 381)
                            ctx.fillText(this.qrcode.slice(30), 187.5, 400)
                            // 最后画出样式,画完后接收一个回调
                            ctx.draw(true, () => {
                                // 使用定时器,保存图片太快,导致图片空白
                                setTimeout(()=>{
                                    // 画图完成 保存图片
                                    uni.canvasToTempFilePath({
                                        canvasId: 'saveQr',
                                        success: res => {
                                            uni.saveImageToPhotosAlbum({
                                                filePath: res.tempFilePath,
                                                success: () => {
                                                    this.$u.toast('保存成功')
                                                },
                                                fail: () => {
                                                    this.$u.toast('保存失败')
                                                },
                                                complete() {
                                                    uni.hideLoading() // 取消loading
                                                }
                                            })
                                        }
                                    }, this) // 传入this,解决部分兼容问题
                                },100)
                            })
                        }
                    })
                }
            })
        },
    }
}
</script>

<style lang="scss" scoped>
    // 使用定位遮住canvas画布
    .mask-box {
        background-color: $uni-bg-color;
        position: absolute;
        top: 0;
        left: 0;
        width: 375px;
        height: 533px;
        z-index: -1;
    }
    .canvas {
        position: absolute;
        top: 0;
        left: 0;
        width: 375px;
        height: 533px;
        z-index: -10;
    }
</style>