uni-app为图片添加自定义水印(解决生成图片不全问题)

需求背景

APP 中上传图片可以拍照单个上传,也可以从相册中选择多个上传,要为它们都添加上水印,这里底层使用的就是 uni.chooseImage

代码逻辑

废话不多说,直接上核心代码:

html 复制代码
<template>
  <canvas v-if="waterMarkParams.display" canvas-id="waterMarkCanvas" :style="canvasStyle"/>
</template>

<script>
  export default {
    data() {
      return {
        waterMarkParams: {
          display: false, // 控制 canvas 创建与销毁
          canvasWidth: 300, // 默认宽度
          canvasHeight: 225, // 默认高度
          contentHeight: 150, // 将要被绘制到图像中的矩形的高度(px)
        },
      }
    },
    computed: {
      canvasStyle() {
        return {
          position: 'fixed', // 移除到屏幕外
          left: '9999px',
          width: this.waterMarkParams.canvasWidth + 'px',
          height: this.waterMarkParams.canvasHeight + 'px',
        }
      }
    },
    methods: {
      chooseImage() {
        uni.chooseImage({
          sourceType: ['all'],
          success: async ({ tempFilePaths, tempFiles }) => {
            // 这里就得到了带水印的图片路径列表
             const imgFileArr = await this.callAddWaterMark(tempFilePaths)
          }
        })
      },
      // 因为有可能在相册中选择多个图片,所以这里要依次生成水印
      async callAddWaterMark(imgPathArr, sourceType) {
        let results = []
        if(imgPathArr.length > 0) {
          let addIndex = 0
          while(addIndex < imgPathArr.length) {
            const tempFilePath = await this.addWaterMark(imgPathArr[addIndex], sourceType)
            results.push(tempFilePath)
            addIndex = addIndex + 1
          }
        }
        return results
      },
      // 添加水印
      addWaterMark(src, sourceType) {
        return new Promise((resolve, reject) => {
          // 获取图片信息,配置 canvas 尺寸
          uni.getImageInfo({
            src,
            success: res => {
              // 修复部分手机(如红米9)手机屏幕比较窄拍摄出来的图片水印压缩着覆盖的问题
              this.waterMarkParams.canvasWidth = Math.max(res.width, 886);
              this.waterMarkParams.canvasHeight = res.height;
              this.waterMarkParams.display = true
              console.log('当前图片信息waterMarkParams:', this.waterMarkParams);
              // 等待 canvas 元素创建
              this.$nextTick(() => {
                let context = uni.createCanvasContext("waterMarkCanvas", this);
                /* 绘制 */
                const { canvasWidth, canvasHeight, contentHeight } = this.waterMarkParams
                // 绘制前清空画布
                context.clearRect(0, 0, canvasWidth, canvasHeight);
                // 将图片src放到cancas内,宽高必须为图片大小
                context.drawImage(src, 0, 0, canvasWidth, canvasHeight, canvasWidth, canvasHeight);
                // 设置边框的透明度
                context.setGlobalAlpha(0.3);
                context.beginPath();
                // 绘制底部的白色背景
                context.rect(0, canvasHeight - contentHeight, canvasWidth, contentHeight);
                context.setFillStyle("white");
                context.fill();
                // 设置文字的透明度
                context.setGlobalAlpha(1);
                // 3.绘制底部的文字
                context.setFontSize(32);
                context.setTextAlign("left");
                context.setFillStyle("black");
                context.fillText(`拍摄人:${this.$store.state.userModule.name}`, 50 , canvasHeight - 90 );
                context.fillText(`拍摄时间:${this.$u.timeFormat(new Date(), "yyyy-mm-dd hh:MM:ss")}`, 50, canvasHeight - 40);
                // 一定要加上一个定时器否则进入到页面第一次可能会无法正常拍照,后几次才正常
                setTimeout(() => {
                  // 本次绘画完重开开始绘画,并且在绘画完毕之后再保存图片,不然页面可能会出现白屏等情况
                  context.draw(false, () => {
                    console.log('!!!!!开始绘画', canvasWidth, canvasHeight);
                    uni.canvasToTempFilePath({
                      canvasId: "waterMarkCanvas",
                      fileType: "jpg",
                      width: canvasWidth,
                      height: canvasHeight,
                      destWidth: canvasWidth,
                      destHeight: canvasHeight,
                      success: ({ tempFilePath }) => {
                        console.log('绘制成功', tempFilePath);
                        this.waterMarkParams.display = false
                        resolve(tempFilePath)
                      },
                      fail: err => {
                        reject(err)
                        console.log(err);
                      }
                    }, this)
                  })
                }, 1000);
              })
            }
          })
        })
      },
    }
  }
</script>

上面最重要的一点就是每次生成水印前要通过切换 this.waterMarkParams.display 的值让 canvas 元素每次都重新创建,否则调用 uni.canvasToTempFilePath 生成的图片经常会只有原图左上角的一部分。

效果

参考

感谢我的好室友的文章给了我参考,他的原文链接放在这了:uniapp制作水印相机给图片添加水印并且保存图片至本地

相关推荐
未来之窗软件服务7 分钟前
资源管理器必要性———仙盟创梦IDE
前端·javascript·ide·仙盟创梦ide
liuyang___1 小时前
第一次经历项目上线
前端·typescript
西哥写代码1 小时前
基于cornerstone3D的dicom影像浏览器 第十八章 自定义序列自动播放条
前端·javascript·vue
清风细雨_林木木2 小时前
Vue 中生成源码映射文件,配置 map
前端·javascript·vue.js
FungLeo2 小时前
node 后端和浏览器前端,有关 RSA 非对称加密的完整实践, 前后端匹配的代码演示
前端·非对称加密·rsa 加密·node 后端
雪芽蓝域zzs2 小时前
JavaScript splice() 方法
开发语言·javascript·ecmascript
不灭锦鲤2 小时前
xss-labs靶场第11-14关基础详解
前端·xss
不是吧这都有重名3 小时前
利用systemd启动部署在服务器上的web应用
运维·服务器·前端
霸王蟹3 小时前
React中巧妙使用异步组件Suspense优化页面性能。
前端·笔记·学习·react.js·前端框架
Maỿbe3 小时前
利用html制作简历网页和求职信息网页
前端·html