文章目录

    • 1,添加水印
    • 2,图片截图
    • 3,上传多个图片同时并添加上水印

1,添加水印

选择上传一张图片,使用cavans对其添加水印;
我这里使用的是vantUI的uploader组件上传图片,当然也可以使用原生的input type='file'来上传图片,然后拿到资源句柄;

效果图如下: 水印是在左下角

vue - vue中实现对图片添加水印和截图的功能

代码如下:

大家主要看afterRead(file) 方法即可,其中需要注意的是:

1,形参file是拿到的图片的base64格式和其他的一些信息;
2,添加水印主要使用this.base64AddWaterMaker()这个方法进行操作,返回的是一个promise可以使用await进行接收也可以直接在then里面拿到返回的base64图片文件;
3,canvas.getContext(‘2d’)创建了一个2d的画布,而ctx.drawImage()像是一个画笔,开始绘制图像;
4,img.onload()方法是一个异步加载的方法;
5,toDataURL()方法把图形转变成base64编码格式的png;

<template>
  <div>
    <p>用户选择一张图片进行添加水印并截图</p>
    <!--  <van-uploader :after-read="afterRead" />-->
    <van-uploader :after-read="afterRead"> <van-button icon="plus" type="primary" size="small">上传文件</van-button></van-uploader>
    <van-button type="primary" size="small" class="del" @click="delImg">删除图片</van-button>
    <van-button type="primary" size="small" class="del" @click="screenShot">图片截图</van-button>
    <van-button type="primary" size="small" class="del" @click="jumpTo">跳转静态路由</van-button>
    <div class="preview" v-if="true">
      <div class="perview-box">
        <img :src="imgBase64" alt="" id="img" />
      </div>
    </div>
  </div>
</template>
<script>
// 引入截图所需要的依赖  下载地址为:https://blog-static.cnblogs.com/files/lyt520/html2canvas.min.js
import html2canvas from '../../plugins/html2canvas.js';
export default {
  components: {},
  data() {
    return {
      // 图片的base编码
      imgBase64: '',
      // 水印配置项
      waterMakeConfig: {
        font: 'microsoft yahei', //字体
        //水印文本内容
        textArray: ['风-温迪', '2022/9/1 10:13'], 
      },
    };
  },
  // 计算属性
  computed: {},
  // 监听属性
  watch: {},
  created() {},
  mounted() {},
  methods: {
    // 图片上传完成的操作
    afterRead(file) {
      // 下面是给图片添加水印
      try {
        this.base64AddWaterMaker(file.content, this.waterMakeConfig).then((res) => {
          这里可以把添加水印后的文件传给后端,我这里只是举例并没有做
          console.log("res",res);
        });
      } catch (error) {
        console.log('error:', error);
      }
    },
     // 给图片添加水印
    base64AddWaterMaker(base64Img, waterMakeConfig) {
      // 保留this指向 后面会用到的
      let _this = this;
      return new Promise((resolve, reject) => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        const img = new Image();
        img.crossOrigin = 'Anonymous'; // 图片加载的过程中允许出现跨域
        // 先有src属性才会触发 onload函数
        img.src = base64Img;
        // 异步加载
        img.onload = function () {
          // 注意img.onload方法是异步的
          canvas.width = img.width;
          canvas.height = img.height;
          ctx.font = `40px Georgia`;
          // 给文字添加颜色
          // ctx.fillStyle = 'red';
          // 添加渐变颜色的水印
          var gradient = ctx.createLinearGradient(0, 0, 200, 0);
          gradient.addColorStop(0, 'blue');
          gradient.addColorStop(1, 'red');
          ctx.fillStyle = gradient;
          // 以左上角为坐标原点 开始绘制图像
          ctx.drawImage(img, 0, 0, img.width, img.height);
          ctx.fillText(waterMakeConfig.textArray[0], img.width * 0.05, img.height * 0.8); //在图片上添加字体
          ctx.fillText(waterMakeConfig.textArray[1], img.width * 0.05, img.height * 0.85);
          let resultBase64 = canvas.toDataURL('image/png'); // 返回的图片文件也是base64格式的
          if (!resultBase64) {
            reject();
          } else {
            _this.imgBase64 = resultBase64;
            resolve(resultBase64);
          }
        };
      });
    },
    // 删除图片
    delImg() {
      this.imgBase64 = null;
    },
    // 测试动态路由 点击跳转动态路由页面 并传参
    jumpTo() {
      this.$router.push({ path: '/routers/123' });
    },
     // 图片截图 使用了html2canvas插件
    screenShot() {
      if(!this.imgBase64){
        return alert("请先上传一张图片!")
      }
      // 获取截取的元素 这里直接获取img
      const imgEl = document.getElementById('img');
      html2canvas(imgEl, {
        scale: window.devicePixelRat, //设备像素比
        backgroundColor: null, //设置截图的背景色
        allowTaint: false, //允许跨域(图片跨域相关)
        useCORS: true, // 如果截图的内容里有图片,可能会有跨域的情况,加上这个参数,解决文件跨域问题
        taintTest: true, //是否在渲染前测试图片
      }).then((canvas) => {
        // 导出图像
        let url = canvas.toDataURL('image/png', 1.0);
        var saveLink = document.createElement('a'); // 创建a链接
        saveLink.href = url;
        saveLink.download = 'downLoad.png'; // 下载的图片名称
        saveLink.click();
      });
    },
  },
};
</script>
<style lang="scss" src="./cavans.scss" scoped></style>

2,图片截图

1, 图片截图功能需要引入一个插件,插件下载地址为:

https://blog-static.cnblogs.com/files/lyt520/html2canvas.min.js

2,下载完成后放到一个指定的位置 然后引入:

vue - vue中实现对图片添加水印和截图的功能

3, 然后在 methods里面 新增一个screenShot()方法即可完成截图功能

代码如下:

 // 图片截图 使用了html2canvas插件
    screenShot() {
      if(!this.imgBase64){
        return alert("请先上传一张图片!")
      }
      // 获取截取的元素 这里直接获取img
      const imgEl = document.getElementById('img');
      html2canvas(imgEl, {
        scale: window.devicePixelRat, //设备像素比
        backgroundColor: null, //设置截图的背景色
        allowTaint: false, //允许跨域(图片跨域相关)
        useCORS: true, // 如果截图的内容里有图片,可能会有跨域的情况,加上这个参数,解决文件跨域问题
        taintTest: true, //是否在渲染前测试图片
      }).then((canvas) => {
        // 导出图像
        let url = canvas.toDataURL('image/png', 1.0);
        var saveLink = document.createElement('a'); // 创建a链接
        saveLink.href = url;
        saveLink.download = 'downLoad.png'; // 下载的图片名称
        saveLink.click();
      });
    },

3,上传多个图片同时并添加上水印

如果你的业务需求是上传多个图片,同时要求添加水印;可以预览;我们也可以使用vant的uploader组件的 v-model="fileList"属性进行操作;

实现效果如下:
vue - vue中实现对图片添加水印和截图的功能
实现代码如下:

注意
一个afterReadImg()方法就可以实现了,原理主要是监听(this.$watch)fileList的长度变化,如果新增了一张或多张,那就同步的把每一张都添加水印,并添加一个新的属性 watermark: true, //水印标识;这是判断是否添加水印的标识,新增的图片肯定没有此属性,就可以添加水印了;

在循环的最后面要调用unWatch()方法解除监听,否则会引起无限监听循环;因为我们this.fileList = templateList改变了响应式属性fileList;

<template>
  <div>
    <p>请选择图片</p>
    <van-uploader v-model="fileList" :after-read="afterReadImg" multiple />
  </div>
</template>
<script>
export default {
  components: {},
  data() {
    return {
      // 水印配置项
      waterMakeConfig: {
        font: "microsoft yahei", //字体
        //水印文本内容
        textArray: ["风-温迪", "2022/9/1 10:13"],
      },
      // 图片列表
      fileList: [],
    };
  },
  methods: {
    // 上传多个文件
    async afterReadImg(files) {
      // 开始启动监听
      let unWatch = this.$watch(
        () => this.fileList,
        async (newValue, oldValue) => {
          if (newValue.length == 0) {
            return;
          }
          let templateList = []; //存储临时文件列表
          for (let index = 0; index < newValue.length; index++) {
            // 说明没有添加水印
            if (!newValue[index].watermark) {
              // 开始加水印
              let base64 = await this.base64AddWaterMaker(
                newValue[index].content,
                this.waterMakeConfig
              );
              // 把base64转为文件类型 用于后续上传到后端
              let file = this.convertBase64UrlToBlob(base64); 
              templateList.push({
                file,
                url: base64, // 图片的base64
                watermark: true, //水印标识
              });
            } else {
              // 已经添加水印的会自动排在最前面
              templateList.push(newValue[index]);
              console.log("已经添加过水印");
            }
          }
          unWatch(); // 此处一点要解除监听  否则会引起无线循环监听
          this.fileList = templateList; // 重新赋值
        },
        { immediate: true }
      );
    },
    // 给图片添加水印
    base64AddWaterMaker(base64Img, waterMakeConfig) {
      // 保留this指向 后面会用到的
      let _this = this;
      return new Promise((resolve, reject) => {
        const canvas = document.createElement("canvas");
        const ctx = canvas.getContext("2d");
        const img = new Image();
        img.crossOrigin = "Anonymous"; // 图片加载的过程中允许出现跨域
        // 先有src属性才会触发 onload函数
        img.src = base64Img;
        // 异步加载
        img.onload = function () {
          // 注意img.onload方法是异步的
          canvas.width = img.width;
          canvas.height = img.height;
          ctx.font = `40px Georgia`;
          // 给文字添加颜色
          // ctx.fillStyle = 'red';
          // 添加渐变颜色的水印
          var gradient = ctx.createLinearGradient(0, 0, 200, 0);
          gradient.addColorStop(0, "blue");
          gradient.addColorStop(1, "red");
          ctx.fillStyle = gradient;
          // 以左上角为坐标原点 开始绘制图像
          ctx.drawImage(img, 0, 0, img.width, img.height);
          ctx.fillText(
            waterMakeConfig.textArray[0],
            img.width * 0.05,
            img.height * 0.8
          ); //在图片上添加字体
          ctx.fillText(
            waterMakeConfig.textArray[1],
            img.width * 0.05,
            img.height * 0.85
          );
          let resultBase64 = canvas.toDataURL("image/png"); // 返回的图片文件也是base64格式的
          if (!resultBase64) {
            reject();
          } else {
            // _this.imgBase64 = resultBase64;
            resolve(resultBase64);
          }
        };
      });
    },
    /**
     * 将以base64的图片url数据转换为Blob  并进行上传
     * @param urlData 用url方式表示的base64图片数据
     */
    convertBase64UrlToBlob(urlData, filename) {
      console.log(222);
      if (urlData == "" || !urlData) {
        return console.warn("base64的图片不存在");
      }
      // 以base64的图片url数据转换为Blob
      var arr = urlData.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      let bold = new Blob([u8arr], { type: mime });
      return bold;
    },
  },
};
</script>
<style lang="scss" src="./cavans.scss" scoped></style>

css代码如下:


.container{
    width: 402px;
    height: 300px;
    background:#ccc;
    border: 1px solid red;  
    margin: 0 auto;     
}
// 预览的盒子
.perview-box{
    width: 402px;
    height: 400px;
    border: 1px solid;
    margin-top: 10px;
    #img{
        display: inline-block;
        width: 400px;
    }
}
.del{
    margin-left: 20px;
}

发表回复