vue 在图片上传时进行图片二维码、文字等水印生成并上传文字

import { addWatermark } from '@/utils/common/WatermarkHelper';
/**
     * 上传前校验
     */
    function beforeUpload(file, files) {
      let fileType = file.type;
      if (fileType.indexOf('image') < 0) {
        createMessage.info('请上传图片');
        return false;
      }
      let num = uploadFileList.value.length + files.length;
      if (num > props['fileMax']) {
        createMessage.info('图片超出可上传个数');
        return false;
      }
      if (props.isWatermark) {
        return addWatermark(file, {}, props.url)  // 关键代码
          .then((watermarkedFile) => {
            // 将处理后的图片加入到文件列表中
            files.push({
              ...file,
              status: 'done', // 设置状态为已完成
              url: URL.createObjectURL(watermarkedFile) // 使用 ObjectURL 作为临时展示
            });
            return watermarkedFile;
          })
          .catch((error) => {
            console.error('Error adding watermark:', error);
          });
      }
    }
addWatermark  组件

import bgCanvas from '@/assets/images/bgCanvas.png';
import bgCanvasCode from '@/assets/images/bgCanvasCode.png';
import QRCode from 'qrcode';
import dayjs from 'dayjs';

interface TextWatermark {
  content: string;
  fontSize?: number;
  color?: string;
  x?: number;
  y?: number;
  type?: string;
}

interface ImageWatermark {
  url: string;
  x?: number;
  y?: number;
  width?: number;
  height?: number;
  type?: string;
}

interface WatermarkOptions {
  texts?: TextWatermark[];
  images?: ImageWatermark[];
}

function generateQRCode(url: string): Promise<string> {
  return QRCode.toDataURL(url, { width: 128, margin: 1 }).then((dataURL) => {
    const img = new Image();
    img.src = dataURL;
    return new Promise((resolve) => {
      img.onload = () => resolve(dataURL);
    });
  });
}

export const addWatermark = (file: File, options: WatermarkOptions, url: string): Promise<File> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = (e) => {
      const img = new Image();
      img.src = e.target?.result as string;

      img.onload = () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        if (!ctx) {
          reject(new Error('Failed to get canvas context'));
          return;
        }

        // 设置画布尺寸与底图相同
        // canvas.width = 1080 || 1920
        // canvas.height = 1920 || 1080
        canvas.width = img.width;
        canvas.height = img.height;
        const scaleX = img.width > 1080 ? img.width / 1080 : 1;
        const scaleY = img.height > 1920 ? img.height / 1080 : 1;
        const scale = scaleX > scaleY ? scaleX : scaleY;

        // 禁用图像平滑处理,防止模糊
        ctx.imageSmoothingEnabled = false;
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

        // 如果没有提供图片水印,则使用默认图片
        generateQRCode(url).then((qrcodeImage) => {
          let images: ImageWatermark[] = [
            { url: bgCanvas, x: 0, y: 0, width: 230 * scale, height: 68.5 * scale },
            { url: bgCanvasCode, x: canvas.width - 138 * scale, y: canvas.height - 160 * scale, width: 128 * scale, height: 150 * scale },
            { url: qrcodeImage, x: canvas.width - 124 * scale, y: canvas.height - 120 * scale, width: 100 * scale, height: 100 * scale }
          ];
          if (options?.images) images.push(...options.images);
          let loadedImages = 0;
          const totalImages = images.length;
          const imageElements: HTMLImageElement[] = [];

          images.forEach((imageOptions, index) => {
            const watermarkImg = new Image();
            watermarkImg.src = imageOptions.url;

            watermarkImg.onload = () => {
              imageElements[index] = watermarkImg;
              loadedImages++;
              if (loadedImages === totalImages) {
                imageElements.forEach((watermarkImg, i) => {
                  const { x = canvas.width - watermarkImg.width, y = canvas.height - watermarkImg.height, width = watermarkImg.width, height = watermarkImg.height, type } = images[i];
                  ctx.drawImage(watermarkImg, x, y, width, height);
                });
                canvas.toBlob((blob) => {
                  if (blob) {
                    const watermarkedFile = new File([blob], file.name, { type: 'image/png' }); // 使用 PNG 格式以保留质量
                    resolve(watermarkedFile);
                  } else {
                    reject(new Error('Failed to convert canvas to blob'));
                  }
                }, 'image/png'); // 确保使用 PNG 格式,以避免图像质量损失
              }
            };

            watermarkImg.onerror = () => {
              reject(new Error('Failed to load watermark image'));
            };
          });
        });
    // 文字添加
        const texts = options.texts?.length ? options.texts : [{ content: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'), fontSize: 12 * scale, color: 'rgba(255, 255, 255, 1)', x: 110 * scale, y: 30 * scale }];
        texts.forEach((text) => {
          const { content, fontSize = Math.max(canvas.width, canvas.height) * 0.05, color = 'rgba(255, 255, 255, 1)', x = canvas.width * 0.02, y = canvas.height * 0.02 } = text;
          ctx.font = `${fontSize}px Arial`;
          ctx.fillStyle = color;
          ctx.textAlign = 'left';
          ctx.textBaseline = 'top';
          ctx.fillText(content, x, y);
        });
      };

      img.onerror = () => {
        reject(new Error('Failed to load image'));
      };
    };

    reader.onerror = () => {
      reject(new Error('Failed to read file'));
    };
    reader.readAsDataURL(file);
  });
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

℡╮荆棘鸟゛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值