js给图片加水印的两种方法

第一种(较复杂)

  1. 根据图片路径获取图片数据,转成blob类型
  2. FileReader读取图片blob数据为dataURL
  3. 创建img标签,src属性为dataURL
  4. 监听img.onload, 创建canvas,将img对象draw在canvas里
  5. 添加水印
  6. 使用canvas.toBlob转成最终图像

代码

  • async/await版
/**
 * 
 * @param {图片路径} imgUrl 
 * @param {图片宽度} width 
 * @param {图片高度} height 
 * @param {水印文字} watermarkText 
 */
async function watermark(
  imgUrl,
  width = 300,
  height = 300,
  watermarkText = "zpfei.ink"
) {
  // 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 = width;
    canvas.height = height;

    tempImg.onload = () => {
      const ctx = canvas.getContext("2d");
      ctx.drawImage(tempImg, 0, 0);

      // 5. 添加水印
      ctx.fillStyle = "red";
      ctx.textBaseline = "middle";
      ctx.fillText(watermarkText, 20, 20);

      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.src = url;
      resolve(newImg);
    });
  });

  //   document.body.appendChild(newImg);
  return newImg;
}
  • 常规回调版
const imgUrl =
  "https://cdn.jsdelivr.net/gh/zhangpanfei/static@demo/img/test.jpg";

fetch(imgUrl)
  .then((r) => r.blob())
  .then((file) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => {
      const canvas = document.createElement("canvas");
      canvas.width = 400;
      canvas.height = 400;
      const img = document.createElement("img");
      img.src = reader.result;
      img.onload = () => {
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, 0);
        ctx.fillStyle = "red";
        ctx.textBaseline = "middle";
        ctx.fillText("zpfei.ink", 20, 20);
        canvas.toBlob((canvasBlob) => {
          const newImg = document.createElement("img"),
            url = URL.createObjectURL(canvasBlob);

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

第二种(简单)

  1. 图片路径转成canvas
  2. canvas添加水印
  3. canvas转成img

代码

/**
 * 图片路径转成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.fillStyle = "red";
  ctx.textBaseline = "middle";
  ctx.fillText(text, 20, 20);
  return canvas;
}

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

// 运行示例
async function run() {
  const imgUrl =
    "https://cdn.jsdelivr.net/gh/zhangpanfei/static@demo/img/test.jpg";
  // 1.图片路径转成canvas
  const tempCanvas = await imgToCanvas(imgUrl);
  // 2.canvas添加水印
  const canvas = addWatermark(tempCanvas, "zpfei.ink");
  // 3.canvas转成img
  const img = convasToImg(canvas);
  // 查看效果
  document.body.appendChild(img);
}
点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注