第一种(较简单)

  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);}