URL.createObjectURL加水印的函数封装

Gary Chen
URL.createObjectURL加水印的函数封装

封装URL.createObjectURL加水印的函数

以下是一个封装好的函数,可以为通过URL.createObjectURL创建的URL对象添加水印:

/**
 * 创建带水印的对象URL
 * @param {Blob|MediaSource} blob - 原始Blob对象
 * @param {Object} options - 配置选项
 * @param {string} [options.text='Watermark'] - 水印文字
 * @param {string} [options.color='rgba(180, 180, 180, 0.5)'] - 水印颜色
 * @param {string} [options.font='16px Arial'] - 水印字体
 * @param {number} [options.rotate=-20] - 水印旋转角度
 * @param {number} [options.interval=100] - 水印间隔
 * @returns {Promise<string>} 带水印的对象URL
 */
async function createObjectURLWithWatermark(blob, options = {}) {
  // 默认配置
  const {
    text = 'Watermark',
    color = 'rgba(180, 180, 180, 0.5)',
    font = '16px Arial',
    rotate = -20,
    interval = 100
  } = options;

  // 如果是图片类型
  if (blob.type.startsWith('image/')) {
    return createImageWatermark(blob, { text, color, font, rotate, interval });
  }
  
  // 如果是视频类型
  if (blob.type.startsWith('video/')) {
    return createVideoWatermark(blob, { text, color, font });
  }
  
  // 其他类型直接返回原始URL
  return URL.createObjectURL(blob);
}

/**
 * 为图片添加水印
 */
async function createImageWatermark(blob, options) {
  const { text, color, font, rotate, interval } = options;
  
  // 创建图片元素
  const img = await blobToImage(blob);
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  // 设置画布大小与图片一致
  canvas.width = img.width;
  canvas.height = img.height;
  
  // 绘制原始图片
  ctx.drawImage(img, 0, 0, img.width, img.height);
  
  // 设置水印样式
  ctx.fillStyle = color;
  ctx.font = font;
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.translate(canvas.width / 2, canvas.height / 2);
  ctx.rotate(rotate * Math.PI / 180);
  
  // 绘制水印
  for (let x = -canvas.width; x < canvas.width * 2; x += interval) {
    for (let y = -canvas.height; y < canvas.height * 2; y += interval) {
      ctx.fillText(text, x, y);
    }
  }
  
  // 转换回Blob并创建URL
  return new Promise((resolve) => {
    canvas.toBlob((watermarkedBlob) => {
      resolve(URL.createObjectURL(watermarkedBlob));
    }, blob.type);
  });
}

/**
 * 为视频添加水印(简单实现,实际需要更复杂的处理)
 */
async function createVideoWatermark(blob, options) {
  // 注意:实际视频水印需要更复杂的处理,这里只是简单示例
  const videoUrl = URL.createObjectURL(blob);
  return videoUrl;
}

/**
 * 将Blob转换为Image对象
 */
function blobToImage(blob) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = URL.createObjectURL(blob);
  });
}

// 导出函数
export default createObjectURLWithWatermark;

使用示例

// 对于图片文件
const fileInput = document.getElementById('file-input');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];
  if (file) {
    const watermarkedUrl = await createObjectURLWithWatermark(file, {
      text: '机密文件',
      color: 'rgba(255, 0, 0, 0.5)',
      font: '20px Arial',
      rotate: -30,
      interval: 150
    });
    
    // 使用带水印的URL
    const img = document.createElement('img');
    img.src = watermarkedUrl;
    document.body.appendChild(img);
  }
});

注意事项

  1. 视频水印的实现比较复杂,上面的示例只是一个简单框架,实际应用中可能需要使用WebGL或专门的视频处理库。
  2. 水印功能会增加处理时间,特别是对大文件。
  3. 使用完毕后,记得调用URL.revokeObjectURL()释放内存。
  4. 这种方法的水印在前端可以被移除,如需更安全的水印,应考虑在后端处理。
  5. 对于PDF等非图像文件,需要先转换为图像才能添加水印。