Add watermark to uni-app pictures; Add watermark to applet pictures; Use canvas to upload pictures and add watermark

Original blogger : Click to view

Requirements: Wechat applet, upload pictures, after success, the picture will have a watermark, both the network address of the picture and the watermark.
Use the uni.chooseImage() method of uni-app to upload images, and use canvas for watermarks.

The following code can be used directly: (Note: If the canvas is invalid or the image does not display: it may be caused by you using the canvas in the custom component, but not passing the second parameter this, see known problems and solutions for details )

<template>
  <view class="content">
    <view v-for="(photo,index) in photoData" :key="index" class="photo">
      <image :src="photo" @click="previewPhoto(photo,photoData)"></image>
      <view class="closeA" @tap="deletePhoto(index)">&times;</view>
    </view>
    <view class="btnAddPhoto" @click="btnAddPhoto">+</view>
    <!-- 获取有水印的图片过程 必须使canvas显示 获取完成后在隐藏掉canvas 配合canvas样式定位 使其错位 -->
    <!-- canvas的隐藏 在小程序中 使用 v-if或display:none 都不生效   使用hidden属性 true隐藏 false显示 -->
    <canvas :style="{width:canvasWidth,height:canvasHeight}" canvas-id="myCanvas" :hidden='flagC'></canvas>
  </view>
</template>

<script>
export default {
    
    
  data() {
    
    
    return {
    
    
      flagC: false,
      photoData: [],
      photoArray: [],
      canvasWidth: '',
      canvasHeight: '',
      photoIndex: 0
    }
  },
  onLoad() {
    
    
  },
  methods: {
    
    
    // 添加图片事件
    btnAddPhoto() {
    
    
      this.photoIndex = 0;
      let ctx = uni.createCanvasContext('myCanvas');
      uni.chooseImage({
    
    
        count: 6,
        sourceType: ['album', 'camera'],
        success: res => {
    
    
          this.photoArray = res.tempFilePaths;
          uni.showLoading({
    
    
            title: "图片加载中..."
          })
          this.callAddWaterMart();
        }
      })
    },

    // 调用添加水印的函数
    callAddWaterMart() {
    
    
      this.addWaterMark(() => {
    
    
        if (this.photoIndex < this.photoArray.length - 1) {
    
    
          this.photoIndex++;
          this.callAddWaterMart()
        } else {
    
    
          uni.hideLoading()
        }
      })
    },

    // 添加水印
    addWaterMark(callback) {
    
    
      this.flagC = false
      uni.getImageInfo({
    
    
        // 注意此时的地址是正常的图片地址 以下是给图片添加水印返回新的url地址
        src: this.photoArray[this.photoIndex],
        success: res => {
    
    
          this.canvasWidth = `${
      
      res.width}px`;
          this.canvasHeight = `${
      
      res.height}px`;
          var ctx = uni.createCanvasContext('myCanvas');
          // 在自定义组件内 需要传递第二参数 this canvas才生效
          // var ctx = uni.createCanvasContext('myCanvas', this);
          ctx.clearRect(0, 0, res.width, res.height);
          ctx.beginPath();
          ctx.drawImage(this.photoArray[this.photoIndex], 0, 0, res.width, res.height); // 第一个参数是图片 第二、三是图片在画布位置 第四、五是将图片绘制成多大宽高(不写四五就是原图宽高)

          // 为图片添加水印
          ctx.translate(res.width / 2, res.height / 2);
          ctx.rotate(45 * Math.PI / 180);

		  //这部分是水印的大小位置和数量
          let horizontal = res.width / 4;
          let vertical = res.height / 3;
          let fonstsize = res.width / 30;
          for (let i = 0; i <= 2; i++) {
    
    
            for (let j = 0; j <= 2; j++) {
    
    
              ctx.beginPath();
              ctx.setFontSize(fonstsize);
              ctx.setFillStyle("rgba(255,255,255,0.3)");
              // ctx.fillText("-仅供保险投保使用-", i * horizontal - res.width / 2, j * vertical - res.height / 2);
              ctx.fillText("--仅供保险投保使用--", (i * horizontal - res.width / 2) * 2, j * vertical - res.height / 2, fonstsize*15*2);
            }
          }

          // 开始绘制添加水印的图片并显示在页面中
          ctx.draw(false, () => {
    
    
            setTimeout(() => {
    
    
              console.log("asdf");
              uni.canvasToTempFilePath({
    
    
                canvasId: "myCanvas",
                success: res => {
    
    
                  // 注意此时的地址是加了水印的图片地址(直接url输入浏览器也可以查看包含水印)
                  console.log(123,res.tempFilePath)
                  this.flagC = true
                  this.photoData.push(res.tempFilePath);
                  callback();
                }
              })
            // 在自定义组件内 需要传递第二参数 this canvas才生效
           // }, this)
            }, 500)
          });
        }
      })
    },

    // 预览图片
    previewPhoto(url, list) {
    
    
      uni.previewImage({
    
    
        current: url,
        urls: list.map(item => item)
      })
    },

    // 删除图片
    deletePhoto(index) {
    
    
      this.photoArray.splice(index, 1);
      this.photoData.splice(index, 1);
      console.log(this.photoArray)
    }
  }
}
</script>

<style>
.content {
    
    
  padding: 20upx;
}
.photo,
.photo image {
    
    
  display: inline-block;
  width: 220upx;
  height: 220upx;
}
.btnAddPhoto {
    
    
  width: 220upx;
  height: 220upx;
  border: dashed 1px #aaa;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 50upx;
}
canvas {
    
    
  border: solid 1px gray;
  position: absolute;
  left: 5000upx;
}
</style>

Unknown problem: On the applet simulator, uploading the first picture is fine, uploading the second picture again, you will find that the second picture shows the superimposed picture of the two pictures; but when using the real machine, it does not It will not affect if it appears (so there is no processing, guess the solution: you can use different canvas elements every time you upload an image to process the watermark, and don't use the same one for watermarking);

Known issues:
1. If the canvas image cannot be rendered, that is, the uni.createCanvasContext() method is invalid;
2. or ctx.draw() is invalid;
3. or the uni.canvasToTempFilePath() interface always fails;
4. Or cannot get to the tempFilePath of the picture; the above problems are caused by one reason

(Check the uni-app document or the WeChat applet canvas document , and you can see the reasons: 1. It is necessary to have a canvas element in the template template; 2. It is in a custom component or a public component, and the second parameter this must be passed) .

The solution is: the methods of createCanvasContext and canvasToTempFilePath need to pass the second parameter
this

var ctx = uni.createCanvasContext('myCanvas', this);

uni.canvasToTempFilePath({
    
    获取图片的内容代码 详见下面}, this)

The screenshot is from uni-app's documentation:insert image description here
insert image description here

WeChat applet tool operation to upload a picture:
insert image description here

Demonstration of unknown problem: Upload the second picture: (The problem of overlaying pictures will only appear in the applet simulator, and will not affect the actual use of the real machine)

insert image description here

Guess you like

Origin blog.csdn.net/i_am_a_div/article/details/118302757#comments_27880309