乐趣区

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);
}
退出移动版