给网页图片添加水印

给网页图片添加水印

出于保密或者版权声明等因素,网页图片会通过设置水印的方式来保密。保密可以通过服务端返回保密后的图片地址,也可以通过前端canvas实现。下面通过canvas实现给图片添加水印。

· 代码

/**
 * 画布添加水印
 * @param {Object} ctx  canvas上下文
 * @param {Number} imgWidth 图片宽度
 * @param {Number} imgHeight  图片高度
 * @param {Object} config config.font:字体;config.textArray: ['张三','2024/11/08 16:44'], 水印文本内容,
允许数组最大长度3 即:3行水印;
config.density 密度 建议取值范围1-5 值越大,水印越多,可能会导致水印重叠等问题,慎重!!!
 */
 function drawWatermark(ctx, imgWidth, imgHeight, config = {}) {
  try {
    if (typeof ctx !== 'object' || typeof imgWidth !== 'number' || typeof imgHeight !== 'number' || typeof config !== 'object') {
      throw new Error('Invalid arguments provided.');
    }

    const defaultConfig = {
      font: 'microsoft yahei',
      textArray: ['图片版权归原作者所有',new Date().toLocaleDateString()],
      density: 3
    };
    const watermarkConfig = Object.assign(defaultConfig, config);

    if (!watermarkConfig.font || typeof watermarkConfig.density !== 'number' || watermarkConfig.density <= 0 || watermarkConfig.density > 5) {
      throw new Error('Invalid configuration values.');
    }

    if (!Array.isArray(watermarkConfig.textArray) || !watermarkConfig.textArray.every(text => typeof text === 'string')) {
      throw new Error('textArray must be an array of strings.');
    }

    const fontSize = imgWidth >= imgHeight ? Math.floor(imgWidth / 40) : Math.floor(imgHeight / 40);

    ctx.font = `${fontSize}px ${watermarkConfig.font}`;
    ctx.lineWidth = 1;
    ctx.fillStyle = 'rgba(200, 200, 200, 0.85)';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'middle';

    const maxDimension = Math.max(imgWidth, imgHeight);
    const stepSize = Math.floor(maxDimension / watermarkConfig.density);
    const xPositions = [0];
    while (xPositions[xPositions.length - 1] < maxDimension / 2) {
      xPositions.push(xPositions[xPositions.length - 1] + stepSize);
    }
    xPositions.push(...xPositions.slice(1, xPositions.length).map((pos) => -pos));

    for (let i = 0; i < xPositions.length; i++) {
      for (let j = 0; j < xPositions.length; j++) {
        ctx.save();
        ctx.translate(imgWidth / 2, imgHeight / 2);
        ctx.rotate(-Math.PI / 5);
        if (watermarkConfig.textArray.length > 3) {
          watermarkConfig.textArray = watermarkConfig.textArray.slice(0, 3);
        }
        watermarkConfig.textArray.forEach((text, index) => {
          const verticalOffset = fontSize * index + 2;
          ctx.fillText(text, xPositions[i], xPositions[j] + verticalOffset);
        });
        ctx.restore();
      }
    }
  } catch (error) {
    console.error('Draw watermark failed:', error);
    throw error;
  }
}

/**
 * 添加水印并返回新的图片地址
 * @param {String} imageUrl 图片地址
 * @param {Object} config config.font:字体;config.textArray: ['张三','2024/11/08 16:44'], 水印文本内容,允许数组最大长度3 即:3行水印;config.density 密度 建议取值范围1-5 值越大,水印越多,可能会导致水印重叠等问题,慎重!!!
 */
 function getWatermarkImageUrl(imageUrl, config) {
  return new Promise((resolve, reject) => {
    fetch(imageUrl)
      .then(response => {
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.blob();
      })
      .then(blob => {
        const img = new Image();
        img.src = URL.createObjectURL(blob);

        img.onload = () => {
          const canvas = document.createElement('canvas');
          canvas.width = img.width;
          canvas.height = img.height;
          const ctx = canvas.getContext('2d');

          if (!ctx) {
            throw new Error('Canvas context is null');
          }

          ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
          drawWatermark(ctx, img.width, img.height, config);

          canvas.toBlob(newBlob => {
            const resultUrl = URL.createObjectURL(newBlob);
            resolve(resultUrl);
            URL.revokeObjectURL(img.src);
          });
        };

        img.onerror = () => {
          console.error('加载图片失败');
          resolve(imageUrl);
        };
      })
      .catch(error => {
        console.error('添加水印失败:', error);
        reject(error);
      });
  });
}

· 使用示例

//使用示例
window.onload = async function() {
  const img = await getWatermarkImageUrl('images/redtory2.jpg')
  console.log('获取的水印图片🐞🐞')
  console.log(img)
}

· 效果


原创文章,如需转载,请注明出处。

发表回复

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