Vue + html2canvas 生成海报

本文介绍了一种使用Vue.js结合html2canvas生成海报的方法,并详细解释了如何将图片转换为Base64编码格式,以便于在生成海报时直接使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Html:

<div class="record">
  <!-- 如果没有生成过海报,则先拼接成海报样式展示 --> 
  <div v-show="!imageUrl || (imageUrl && !isImageLoaded)" class="poster-preview" id="poster-preview">
    <!-- 内容自定义, 需要在海报各元素加载完成并使用base64格式进行生成海报 --> 
    <img crossOrigin='anonymous' @load="loadBackground" class="display-image" :src="recordBackgroundPng" />
    <img crossOrigin='anonymous' class="record-detail-logo" @load="loadLogoPng" :src="logoPng" />
    <div class="val other-val">{{targets[2].target}}</div>
  </div>
  <!-- 如果生成海报完毕,则显示图片,长按可保存 --> 
  <img v-show="isImageLoaded" @load="loadImage" class="record-image" :src="recordSrc" />
</div>

JS: 

async created() {
  this.convertImageToBase64();
  this.$nextTick(() => {
    setTimeout(() => {
      this.generatImage();
    }, 1000);
  });
},
watch: {
  imageUrl: {
    handler() {
      this.setImageSrc(this.imageUrl);
    },
  },
},
convertImageToBase64() {
  UploadUtil.getBase64(RecordBackgroundPng)
    .then((pngData) => {
      this.recordBackgroundPng = pngData;
    });
  UploadUtil.getBase64(this.images.LogoPng)
    .then((pngData) => { this.logoPng = pngData; });
 },
generatImage() {
  this.timer = setInterval(() => {
    // 设置定时器,等图片加载完成才可以进行canvas绘制,否则有可能海报不完整
    if (this.isLogoPngLoaded && this.isRecordTopPngLoaded) {
      clearInterval(this.timer);
      const div = document.getElementById('poster-preview');
      html2canvas(div, {
        useCORS: true,
        allowTaint: true,
      }).then(async (canvas) => {
        const key = `image/poster${getFileNameUUID()}.png`;
        const file = this.canvasToFile(canvas, key);
        const img = [{ key, file, src: window.URL.createObjectURL(file) }];
        try {
          const imagesInfo = await uploadService.uploadFiles(img);
          this.imageUrl = imagesInfo[0].fileUrl;
          this.saveImageUrl();
        } catch (error) {
          console.log(error);
        }
      });
    }
  }, 1000);
},
async saveImageUrl() {
  await api.saveImage({ imageUrl: this.imageUrl });
  this.setImageSrc(this.imageUrl);
},
setImageSrc(url) {
  if (!url) return;
  UploadUtil.getBase64(url).then((res) => {
    this.recordSrc = res;
    this.$forceUpdate();
  });
},
canvasToFile(canvas, fileName) {
  const uricode = canvas.toDataURL('images/png', 1.0);
  const blobs = UploadUtil.urlToBlob(uricode);
  const file = UploadUtil.blobToFile(blobs, fileName);
  return file;
},

Util:
 

import Compressor from 'compressorjs';

// 当使用uploader元素 比如<van-uploader /> 可以先压缩
function beforeRead(file) {
  return new Promise((resolve) => {
    // eslint-disable-next-line no-new
    new Compressor(file, {
      quality: 0.6,
      convertSize: 2000000, // png超过2MB则转为jpeg
      success: resolve,
      error(err) {},
    });
  });
}

function urlToBlob(dataURL, specificContentType = null) {
  const BASE64_MARKER = ';base64,';
  if (dataURL.indexOf(BASE64_MARKER) === -1) {
    const parts = dataURL.split(',');
    const contentType = specificContentType || parts[0].split(':')[1];
    const raw = decodeURIComponent(parts[1]);
    return new Blob([raw], { type: contentType });
  }
  const parts = dataURL.split(BASE64_MARKER);
  const contentType = specificContentType || parts[0].split(':')[1];
  const raw = window.atob(parts[1]);
  const rawLength = raw.length;
  const uInt8Array = new Uint8Array(rawLength);
  for (let i = 0; i < rawLength; i += 1) {
    uInt8Array[i] = raw.charCodeAt(i);
  }
  return new Blob([uInt8Array], { type: contentType });
}

function blobToFile(theBlob, fileName) {
  theBlob.lastModifiedDate = new Date();
  theBlob.name = fileName;
  return theBlob;
}

function getBase64(url) {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.setAttribute('crossOrigin', 'anonymous');
    image.onload = () => {
      const canvas = document.createElement('canvas');
      canvas.width = image.width;
      canvas.height = image.height;
      const context = canvas.getContext('2d');
      context.drawImage(image, 0, 0, image.width, image.height);
      const quality = 0.8;
      const dataURL = canvas.toDataURL('image/png', quality);
      resolve(dataURL);
    };
    image.src = `${url}?time=${new Date().valueOf()}`;
    image.onerror = (error) => {
      reject(new Error('Image stream is abnormal'));
    };
  });
}

export function getFileNameUUID() {
  const s = [];
  const hexDigits = '0123456789abcdef';
  for (let i = 0; i < 36; i += 1) {
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  }
  const uuid = s.join('');
  return uuid;
}

export default {
  beforeRead,
  urlToBlob,
  blobToFile,
  getBase64,
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值