JS给图片添加水印

一、单一水印(较复杂,推荐)

1、样式

在这里插入图片描述

2、功能介绍
  1. 根据图片路径获取图片数据,转成blob类型
  2. 用FileReader读取图片blob数据为dataURL
  3. 创建img标签,src属性为dataURL
  4. 监听img.onload, 创建canvas,将img对象draw在canvas里
  5. 添加水印
  6. 使用canvas.toBlob转成最终图像
3、代码
<template>
  <div class="pic-item"></div>
</template>

<script setup>
import { onMounted } from "vue"


onMounted(() => {
  const url = 'https://cdn.jsdelivr.net/gh/zhangpanfei/static@demo/img/test.jpg'
  watermark(url, ['2024-08-17'], (460-24), (580-30-24-10)/2)
})

/**
 * 
 * @param {图片路径} imgUrl 
 * @param {图片宽度} width 
 * @param {图片高度} height 
 * @param {水印文字} watermarkText 
 */
async function watermark(imgUrl, textArray, width = 300, height = 300) {
  // 水印参数
  const  wmConfig = {
      font: "microsoft yahei", //字体
      textArray: textArray,//水印文本内容,允许数组最大长度3 即:3行水印
      density: 3  //密度 建议取值范围1-5   值越大,水印越多,可能会导致水印重叠等问题,慎重!!!
  }

  // 1. 根据图片路径获取图片数据,转成blob类型
  const fileBlob = await fetch(imgUrl)
    .then((r) => r.blob())
    .then((file) => file);

  // 2. 用`FileReader`读取图片blob数据为dataURL
  const reader = new FileReader();
  reader.readAsDataURL(fileBlob);

  // 3. 创建img标签,src属性为dataURL
  const tempImg = await new Promise((resolve) => {
    reader.onload = () => {
      const img = document.createElement(`img`);
      img.src = reader.result;
      resolve(img);
    };
  });

  // 4. 监听`img.onload`, 创建canvas,将img对象`draw`在canvas里
  const canvas = await new Promise((resolve) => {
    const canvas = document.createElement(`canvas`);
    canvas.width = tempImg.width;
    canvas.height = tempImg.height;
    let resultBase64 = null;

    tempImg.onload = () => {
      const ctx = canvas.getContext("2d");
      ctx.drawImage(tempImg, 0, 0);
      
      // 5. 类文档水印
      drawWaterMark(ctx, tempImg.width, tempImg.height, wmConfig);
      resultBase64 = canvas.toDataURL("image/png");

      if (!resultBase64) {
          reject();
      } else {
          resolve(canvas);
      }
    };
  });

  // 6. 使用`canvas.toBlob`转成最终图像
  const newImg = await new Promise((resolve) => {
    canvas.toBlob((canvasBlob) => {
      const newImg = document.createElement(`img`),
        url = URL.createObjectURL(canvasBlob);

      newImg.onload = function () {
        // 图片加载完成后销毁objectUrl
        URL.revokeObjectURL(url);
      };
      newImg.width = width;
      newImg.height = height;
      newImg.src = url;
      resolve(newImg);
    });
  });

  document.getElementsByClassName('pic-item')[0].appendChild(newImg);
  // return newImg;
}

// 画布添加水印
const drawWaterMark = (ctx, imgWidth, imgHeight, wmConfig) => {
  let fontSize;
  if (imgWidth >= 3456) {
      fontSize = imgWidth * 38 / 1920;
  } else if (imgWidth >= 2700) {
      fontSize = imgWidth * 48 / 1920;
  } else if (imgWidth >= 2000) {
      fontSize = imgWidth * 58 / 1920;
  } else if (imgWidth >= 1436) {
      fontSize = imgWidth * 68 / 1920;
  } else if (imgWidth >= 800) {
      fontSize = imgWidth * 78 / 1920;
  } else if (imgWidth >= 500) {
      fontSize = imgWidth * 88 / 1920;
  } else {
      fontSize = imgWidth * 98 / 1920;
  }
  console.log(imgWidth, imgHeight, fontSize);

  ctx.font = `${fontSize}px ${wmConfig.font}`;
  ctx.fillStyle = "#000000";
  ctx.textAlign = "left";
  ctx.textBaseline = "middle";
  ctx.fillText(wmConfig.textArray[0], imgWidth * 50 / 1920, imgHeight * 100 / 980);
};
</script>

二、单一水印(简单)

1、样式

在这里插入图片描述

2、功能介绍
  1. 图片路径转成canvas
  2. canvas添加水印
  3. canvas转成img
3、代码
<template>
  <div class="pic-item"></div>
</template>

<script setup>
import { onMounted } from "vue"

onMounted(() => {
  const url = 'https://cdn.jsdelivr.net/gh/zhangpanfei/static@demo/img/test.jpg'
  run(url, ['2024-08-17'], (460-24), (580-30-24-10)/2)
})

/**
 * 图片路径转成canvas
 * @param {图片url} url
 */
async function imgToCanvas(url) {
  // 创建img元素
  const img = document.createElement("img");
  img.src = url;
  img.setAttribute("crossOrigin", "anonymous"); // 防止跨域引起的 Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
  await new Promise((resolve) => (img.onload = resolve));
  // 创建canvas DOM元素,并设置其宽高和图片一样
  const canvas = document.createElement("canvas");
  canvas.width = img.width;
  canvas.height = img.height;
  // 坐标(0,0) 表示从此处开始绘制,相当于偏移。
  canvas.getContext("2d").drawImage(img, 0, 0);
  return canvas;
}

/**
 * canvas添加水印
 * @param {canvas对象} canvas
 * @param {水印文字} text
 */
function addWatermark(canvas, text) {
  const ctx = canvas.getContext("2d");
  ctx.font = "28px microsoft yahei";
  ctx.fillStyle = "#ffffff";
  ctx.textBaseline = "middle";
  ctx.fillText(text, 20, 35);
  return canvas;
}

/**
 * canvas转成img
 * @param {canvas对象} canvas
 */
function convasToImg(canvas, width, height) {
  // 新建Image对象,可以理解为DOM
  var image = new Image();
  // canvas.toDataURL 返回的是一串Base64编码的URL
  // 指定格式 PNG
  image.width = width;
  image.height = height;
  image.src = canvas.toDataURL("image/png");
  return image;
}

/**
 * 运行示例
 * @param {图片路径} imgUrl 
 * @param {图片宽度} width 
 * @param {图片高度} height 
 * @param {水印文字} watermarkText 
 */
async function run(url, textArray, width = 300, height = 300,) {
  const imgUrl = url;
  // 1.图片路径转成canvas
  const tempCanvas = await imgToCanvas(imgUrl);
  // 2.canvas添加水印
  const canvas = addWatermark(tempCanvas, textArray[0]);
  // 3.canvas转成img
  const newImg = convasToImg(canvas, width, height);
  // 查看效果
  document.getElementsByClassName('pic-item')[0].appendChild(newImg);
}
</script>

三、文档水印

1、样式

在这里插入图片描述

2、功能介绍(同一)

仅仅是画布添加的水印方法不一样!

3、代码

这里只写添加水印的方法

// 画布添加水印
const drawWaterMark = (ctx, imgWidth, imgHeight, wmConfig) => {
  let fontSize;
  if (imgWidth >= 3456) {
      fontSize = imgWidth * 38 / 1920;
  } else if (imgWidth >= 2700) {
      fontSize = imgWidth * 48 / 1920;
  } else if (imgWidth >= 2000) {
      fontSize = imgWidth * 58 / 1920;
  } else if (imgWidth >= 1436) {
      fontSize = imgWidth * 68 / 1920;
  } else if (imgWidth >= 800) {
      fontSize = imgWidth * 78 / 1920;
  } else if (imgWidth >= 500) {
      fontSize = imgWidth * 88 / 1920;
  } else {
      fontSize = imgWidth * 98 / 1920;
  }
  console.log(imgWidth, imgHeight, fontSize);
  ctx.fillStyle = "white";

  ctx.font = `${fontSize}px ${wmConfig.font}`;
  ctx.lineWidth = 1;
  ctx.fillStyle = "#ffffff";
  ctx.textAlign = "left";
  ctx.textBaseline = "middle";

  //文字坐标
  const maxPx = Math.max(imgWidth, imgHeight);
  const stepPx = Math.floor(maxPx / wmConfig.density);

  let arrayX = [0];//初始水印位置 canvas坐标 0 0 点
  while (arrayX[arrayX.length - 1] < maxPx/2) {
    arrayX.push(arrayX[arrayX.length - 1] + stepPx);

  }
  arrayX.push(...arrayX.slice(1, arrayX.length).map((el) => {
    return -el;
  }));

  for (let i = 0; i < arrayX.length; i++) {
    for (let j = 0; j < arrayX.length; j++) {
        ctx.save();
        ctx.translate(imgWidth / 2, imgHeight / 2); ///画布旋转原点 移到 图片中心
        ctx.rotate(-Math.PI / 5);
        if (wmConfig.textArray.length > 3) {
            wmConfig.textArray = wmConfig.textArray.slice(0, 3);
        }
        wmConfig.textArray.forEach((el, index) => {
            let offsetY = fontSize * index + 2;
            ctx.fillText(el, arrayX[i], arrayX[j] + offsetY);
        });
        ctx.restore();
    }

  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值