uniapp canvas 生成海报并保存到本地

最终生成的样式

注释已经打好,详情看代码

<template>
    <view class="canvas-box">
        <!-- 导航栏 -->
        <view class="nav-box">
            <view class="title-top" :style="'padding-top:' + statusBarHeight + 'rpx'">
                <u-icon class="title-icon" name="arrow-left" color="#ffffff" size="36" @click="getBack"></u-icon>
                <text>海报分享</text>
            </view>
        </view>
        
        <!-- 开发完成之前,取消 fixed;opacity: 0;-->
        <canvas style=" 346px;height: 500px;position: fixed;opacity: 0;" class="canvas" canvas-id="canvasID"></canvas>
        <!-- 完成海报制作后,需要把canvas移到看不见的地方,或者隐藏,把image显示出来 -->
        <image :src="imgUrl" mode=""></image>

        <view class="footer">
            <view class="download" @click="saveImage">
                <!-- 小于符号图标 -->
                <u-icon name="download" color="#ffffff" size="34"></u-icon>
                <text>保存到相册</text>
            </view>
        </view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                imgUrl: '',
                statusBarHeight: 0,
                avatar: '../../../../static/images/default-chat-avatar.png', //头像地址
                hello: '../../../../static/images/share/weixin-hi.png', // hello图标
                mony: '../../../../static/images/share/mony.png' //圆的钱图标
            }
        },
        created() {
            this.$tool.getSystemInfo().then(res => {
                this.statusBarHeight = res
            })
        },
        mounted() {
            let ctx = uni.createCanvasContext('canvasID', this);
            // ctx.setFillStyle("transparent"); //设置canvas背景颜色
            // ctx.fillRect(0, 0, 346, 500) //设置canvas画布大小
            this.fillRoundRect(ctx, 0, 0, 346, 500, 15); //绘制一个圆角矩形
            this.fillRoundRect(ctx, 0, 0, 346, 182, 15, '#333231'); //绘制一个圆角矩形
            this.drawCircular(ctx, this.avatar, 36, 32, 50, 50) //绘制圆形头像

            ctx.setFontSize(18)
            ctx.setFillStyle("#ffffff")
            ctx.fillText('明天依然是晴天', 98, 65)
            ctx.drawImage(this.hello, 240, 10, 86, 86) //二维码
            ctx.font = '20px normal'
            ctx.setFillStyle("#09CFB1")
            ctx.fillText('我为“贤马”带盐', 30, 122)
            ctx.font = '16px normal'
            ctx.setFillStyle("#ffffff")
            ctx.fillText('“闲么?上贤马做兼职”', 20, 152)

            // 绘制职位标题,多余文字自动换行
            ctx.setFontSize(28)
            ctx.setFillStyle("#333333")

            let str = '店铺实习生ZAra重庆龙湖时代'
            // 字符串总长度
            let _strLength = str.length
            // 总结截取次数
            let _strNum = Math.ceil(_strLength / 9)

            // 每次开始截取字符串的索引
            let _strHeight = 0
            // 绘制的字体 x,y的初始位置
            let _strX = 27,
                _strY = 223
            let strIndex = 223
            // 开始截取
            for (let i = 0; i < _strNum; i++) {
                strIndex = _strY + i * 40
                ctx.fillText(str.substr(_strHeight + i * 9, 9), _strX, _strY + i * 40)
            }
            strIndex += 30
            ctx.setFontSize(14)
            ctx.setFillStyle("#1BB99A")
            let strtitle = '环境好/结算快/时间短'
            ctx.fillText(strtitle, _strX, strIndex)

            ctx.setFontSize(20)
            ctx.setFillStyle("#333231")
            ctx.fillText('16元/小时', _strX, 418)

            this.drawCircular(ctx, this.mony, _strX, 429, 14, 14) //绘制圆形头像
            ctx.setFontSize(12)
            ctx.setFillStyle("#F7BA65")
            ctx.fillText('已预付', _strX + 20, 440)

            // 绘制微信二维码
            ctx.drawImage(this.hello, 208, 370, 120, 120) //二维码

            ctx.draw(false, () => {
                // 返回canvas图片信息
                uni.canvasToTempFilePath({
                    canvasId: 'canvasID',
                    success: (res) => {
                        this.imgUrl = res.tempFilePath
                        // console.log(res.tempFilePath)
                    },
                    fail: function(err) {
                        console.log(err)
                    }
                })
            })
        },
        methods: {
            getBack() {
                uni.navigateBack({
                    delta: 1
                });
            },
            saveImage() { //点击保存
                var _this = this;
                uni.saveImageToPhotosAlbum({
                    filePath: _this.imgUrl,
                    success() {
                        uni.showModal({
                            title: "保存成功",
                            content: "图片已成功保存到相册,快去分享到您的圈子吧",
                            showCancel: false
                        })
                    }
                })
            },
            // 将网络图片转为临时图片地址
            async getImageInfo({imgSrc}) {
                return new Promise((resolve, errs) => {
                    uni.downloadFile({
                        src: imgSrc,
                        success: function(image) {
                            resolve(image);
                        },
                        fail(err) {
                            errs(err);
                        }
                    });
                });
            },
            // 绘制圆形头像
            drawCircular(ctx, url, x, y, width, height) {
                //画圆形头像
                var avatarurl_width = width;
                var avatarurl_heigth = height;
                var avatarurl_x = x;
                var avatarurl_y = y;
                ctx.save(); //先保存状态,已便于画完园再用
                ctx.beginPath(); //开始绘制
                ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math
                    .PI * 2, false);
                ctx.setFillStyle("#FFFFFF")
                ctx.fill() //保证图片无bug填充
                ctx.clip(); //剪切
                ctx.drawImage(url, avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth); //推进去图片
                ctx.restore();
            },
            // 绘制带圆角的矩形方法
            fillRoundRect(cxt, x, y, width, height, radius,  fillColor) {
                //圆的直径必然要小于矩形的宽高
                if (2 * radius > width || 2 * radius > height) {
                    return false;
                }

                cxt.save();
                cxt.translate(x, y);
                //绘制圆角矩形的各个边
                this.drawRoundRectPath(cxt, width, height, radius);
                cxt.fillStyle = fillColor || '#fff'; //若是给定了值就用给定的值否则给予默认值
                cxt.fill();
                cxt.restore();
            },
            drawRoundRectPath(cxt, width, height, radius) {
                cxt.beginPath(0);
                //从右下角顺时针绘制,弧度从0到1/2PI
                cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);

                //矩形下边线
                cxt.lineTo(radius, height);

                //左下角圆弧,弧度从1/2PI到PI
                cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);

                //矩形左边线
                cxt.lineTo(0, radius);

                //左上角圆弧,弧度从PI到3/2PI
                cxt.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);

                //上边线
                cxt.lineTo(width - radius, 0);

                //右上角圆弧
                cxt.arc(width - radius, radius, radius, (Math.PI * 3) / 2, Math.PI * 2);

                //右边线
                cxt.lineTo(width, height - radius);
                cxt.closePath();
            }
        }
    }
</script>

<style lang="scss" scoped>
    .canvas-box {
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: #1ABC9C;

        /deep/.nav-box {
             100%;
            padding: 0 20rpx;
            position: absolute;
            z-index: 9999;
            top: 0;
            left: 0;

            .title-top {
                font-size: 36rpx;
                font-weight: 550;
                color: #FFFFFF;
                display: flex;
                justify-content: center;
                align-items: center;
                position: relative;
                margin-bottom: 30rpx;

                .title-icon {
                    position: absolute;
                    left: 0;
                }
            }
        }

        image {
             335px;
            height: 500px;
        }

        .footer {
            display: flex;
            align-items: center;
            justify-content: space-between;
            position: absolute;
            justify-content: center;
            padding: 0 40rpx;
             100%;
            left: 0;
            bottom: 10%;

            .download {
                border: 1rpx solid #ffffff;
                color: #ffffff;
                display: flex;
                align-items: center;
            }

            view {
                padding: 0 20rpx;
                height: 78rpx;
                text-align: center;
                line-height: 78rpx;
                font-size: 30rpx;
                border-radius: 36rpx;
            }
        }
    }
</style>

  

原文地址:https://www.cnblogs.com/tlfe/p/15223727.html