vue上传图片加水印

565 阅读1分钟

功能需求

产品要求前端在上传图片时自动给图片打上当前时间的水印

实现效果

image.png image.png

直接上代码

这里还包含了上传视频和音频的内容,可无视

<!-- Annex.vue -->
<template>
  <div class="annex">
    <div class="annexTitle">
      <span class="xing">*</span>
      <span>附件(至少需上传一张照片):</span>
    </div>
    <div class="displayArea">
      <div
        class="displayAreaItem common"
        v-for="item in annexArr[dataType]"
        :key="item.id"
      >
        <!-- 视频 -->
        <div class="mp4" v-if="item.type === 'mp4'">
          <!--          <img class="displayImg" :src="item.videoImgUrl" alt="" />-->
          <div class="displayImg"></div>
          <img class="play" src="@/assets/play.png" alt="" />
        </div>
        <!-- 图片 -->
        <div v-if="verifyImg.includes(item.type)" class="displayImgArea">
          <img class="displayImg" :src="item.url" alt="" />
          <div
            v-if="showSelectType"
            @click="selectType(item)"
            class="displayBox"
          >
            {{ item.classifyName || "选择类型" }}
          </div>
        </div>
        <!-- 音频 -->
        <div class="mp3" v-if="item.type === 'wav'">
          <img src="@/assets/audio.png" alt="" />
        </div>
        <img
          @click="displayClose(item)"
          class="displayClose"
          src="@/assets/close.png"
          alt=""
        />
      </div>
    </div>
    <!-- 三个按钮 -->
    <div class="annexContent">
      <div class="operationArea">
        <div class="operationItem" v-for="item in operateImg" :key="item.text">
          <img @click="photographClick(item)" :src="item.imgUrl" alt="" />
          <!-- 手动加载模式 -->
          <input
            :ref="item.ref"
            style="display: none"
            type="file"
            @change="onChange"
            :accept="item.type"
            multiple
          />
          <div class="operationItemText">{{ item.text }}</div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import dayjs from "dayjs";
import { handleAddWaterMarker } from "./watermark.js";
// 无用部分省略了
methods: {
    onChange(e) {
      if (this.beforeUpload(e.target.files[0])) {
        const fileType = e.target.files[0].type.split("/")[0];
        const file = e.target.files[0];
        this.getFormData(file).then(async (data) => {
          const res = await upload(data); // 调用上传文件的接口upload
          this.clickImg.push({
            id: res.data.fileId,
            fileType: fileType,
            type: res.data.fileExtName,
            url: res.data.fileUrl,
            name: res.data.fileName,
          });
        });
        
        // 这一步是将得到的数据塞进页面展示的数组里,可根据自己项目来写
        this.SET_ANNEX_ARR({ type: this.dataType, data: this.clickImg });
      }
    },
    getFormData(file) {
      const content = dayjs().format("YYYY-MM-DD HH:mm:ss"); // 当前时间
      const fileType = file.type.split("/")[0];
      const name = file.name.split(".")[0];
      let formdata = new FormData();
      return new Promise((resolve) => {
        if (fileType === "image") { // !!!!图片类型的文件,进行打水印
          const reader = new FileReader();
          reader.readAsDataURL(file);
          reader.onload = function () {
            const img = document.createElement("img"); // 手动创建一个img标签
            img.src = reader.result;
            img.onload = function () {
              const res = handleAddWaterMarker(img, content, name);
              formdata.append("file", res);
              resolve(formdata);
            };
          };
        } else {
          formdata.append("file", file);
          resolve(formdata);
        }
      });
    },
    beforeUpload(file) {
      const isLt1M = file.size / 1024 / 1024 < 50;
      if (isLt1M) {
        return true;
      }
      console.log("上传文件不超过50M", "warning");
      return false;
    },
}
</script>

打水印的最主要方法在以下:

// watermark.js
export function handleAddWaterMarker(imageCon, content, fileName) {
  let canvas = document.createElement("canvas"); //创建canvas容器
  canvas.width = imageCon.width; //设置canvas容器宽度
  canvas.height = imageCon.height; //设置canvas容器高度

  let ctx = canvas.getContext("2d"); //获取2d画笔

  //在canvas画布上绘制图片 ctx.drawImage(图片, x位置, y位置,  图像宽度, 图像高度);
  ctx.drawImage(imageCon, 0, 0, imageCon.width, imageCon.height);

  //设置文本画笔的样式
  ctx.textAlign = "right"; //设置文本对齐方式
  ctx.textBaseline = "top"; //设置文本基线
  ctx.font = "12px PingFang SC, PingFang SC-Regular"; //设置文本字体属性
  ctx.fillStyle = "#FFFFFF"; //设置文本字体颜色
  ctx.shadowBlur = 4;
  ctx.shadowColor = "rgba(0,0,0,0.50)";
  //在canvas画布上绘制文字 ctx.fillText(文字内容, x位置, y位置, 文本最大宽度)
  ctx.fillText(
    content,
    // imageCon.width - (content.split("").length * 12 + 8),
    imageCon.width - 8,
    11,
    imageCon.width
  ); //14为文字大小
  const data = btof(canvas.toDataURL("image/png"), fileName); // canvas转base64输出
  return data; // 但是我们需要的是file类型,所以需要再转一下
}
// base64转file
export function btof(data, fileName = "") {
  const dataArr = data.split(",");
  const byteString = atob(dataArr[1]);

  const options = {
    type: "image/png",
    endings: "native",
  };
  const u8Arr = new Uint8Array(byteString.length);
  for (let i = 0; i < byteString.length; i++) {
    u8Arr[i] = byteString.charCodeAt(i);
  }
  return new File([u8Arr], fileName + ".png", options);
}