uni-app 上传图片加水印问题(canvas)

670 阅读2分钟

适用于拍照或从相册选择图片,每次上传一张,上传多张需要稍作修改

Demo

<template>
    <view class="wrap">
        <canvas class="canvas" :style="{ width: w + 'px', height: h + 'px' }" canvas-id="firstCanvas"></canvas>
        <button class="button" @click="getImg">获取图片</button>
        <image mode="aspectFill" :src="src" @click="preview"></image>
    </view>
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue';
import dayjs from 'dayjs';

/**
 * 画布宽度
 */
const w = ref<number>(200);

/**
 * 画布高度
 */
const h = ref<number>(200);

/**
 * 生成图片的路径
 */
const src = ref<string>('');

/**
 * 选择图片
 */
function getImg() {
    // 从本地相册选择图片或使用相机拍照
    uni.chooseImage({
        count: 1,
        sizeType: 'compressed',
        success: (res: any) => {
            setImg(res.tempFilePaths[0]);
        },
    });
}

/**
 * 生成图片
 */
function setImg(url: string) {
    // 创建 canvas 绘制上下文,参数(canvas-id, 组件实例)
    // vue2 第二个参数即 this
    const ctx = uni.createCanvasContext('firstCanvas');

    // 获取图片信息
    uni.getImageInfo({
        src: url,
        success: (res) => {
            uni.showLoading({
                title: '水印添加中...',
                mask: true,
            });

            const currentTime: string = dayjs().format('YYYY-MM-DD HH:mm:ss');
            const x: number = res.width / 2 - 270;
            const y: number = res.height / 2 - 50;

            nextTick(() => {
                w.value = res.width / 2;
                h.value = res.height / 2;

                // 填充一个矩形
                ctx.fillRect(0, 0, w.value, h.value);

                // 绘制图像到画布,参数(图片资源路径, 图片左上角在目标 canvas 上 x 轴的位置, 图片左上角在目标 canvas 上 y 轴的位置, 绘制图像的宽度, 绘制图像的高度)
                ctx.drawImage(res.path, 0, 0, res.width / 2, res.height / 2);

                // 设置字体大小
                ctx.setFontSize(24);

                // 设置填充颜色
                ctx.setFillStyle('#ffffff');

                // 在画布上绘制被填充的文本,参数(文本, 文本左上角 x 坐标位置, 文本左上角 y 坐标位置)
                ctx.fillText(currentTime, x, y);

                // 不加异步首次渲染图片有问题
                setTimeout(() => {
                    // 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中,参数(是否接着上一次绘制, 绘制完成后回调)
                    ctx.draw(false, () => {
                        // 把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径
                        uni.canvasToTempFilePath({
                            canvasId: 'firstCanvas',
                            success: (res) => {
                                src.value = res.tempFilePath;
                            },
                            complete: () => {
                                uni.hideLoading();
                            },
                        });
                    });
                }, 500);
            });
        },
    });
}

/**
 * 预览图片
 */
function preview() {
    uni.previewImage({
        urls: [src.value],
        current: 0,
    });
}
</script>
<style>
.wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    position: relative;
}

.canvas {
    border: 2rpx solid pink;
    background: pink;
    width: 100%;
    height: 100%;
    overflow: auto;

    /* 使用定位脱离页面显示区域 */
    position: absolute;
    top: -1000px;
    left: -1000px;
}

.button {
    margin: 10px;
}
</style>