h5通过html2canvas生成海报

276 阅读1分钟

使用html2canvas生成canvas图片并下载

过程中遇到的几个常见问题

  • 后端返回的图片跨域
  • 海报内容多行文本省略号截图失败
  • 图片模糊

海报效果图

a24b707d63f900e80c1f6b3ea565f38.jpg

话不多说上代码

<View className='postersBox'>
   <View className='posterBg'>
      <img className='posterBg-bgImg'
           src={info.h5ShareUrl}
           crossOrigin='anonymous'>
      </img>
      <View className='productTitle'>{info[groupName]}</View>
      <View className='productCanvas'>
        <canvas id='productCanvas' width={'540px'} height={'280px'} style={{ width:'270px',height: '140px' }}></canvas>
      </View>
  </View>
</View>
    // 开始绘制canvas
    let canvas: any = document.querySelector("#productCanvas");
    // 获取当前屏幕像素比
    const ratio = window.devicePixelRatio || 1;
    let ctx = canvas.getContext("2d");
    ctx.fillStyle = "#3D3D3D";
    const fontSize = 32; //放大两倍后的字号
    const lineHeight = fontSize * 1.42; //行高根据具体情况调整
    ctx.font = `${fontSize}px sans-serif`;
    ctx.textAlign = "center";
    ctx.textBaseline = "top";

    // 因html2canvs不能将多行文本省略号的div截下来,所以海报内容提前绘制成canvas并进行省略号及模糊问题处理
    const str = info?.description; //海报内容
    const lines: any = [];
    let line = "";
    let count = 0;
    for (let i = 0; i < str.length; i++) {
      if (ctx.measureText(line + str[i]).width > canvas.width) {
        count++;
        // 展示的行数,超出6行出现省略号
        if (count == 6) {
          lines.push(line.replace(/.$/, "..."));
          line = "";
        } else {
          lines.push(line);
          line = "";
        }
      }
      line += str[i];
    }
    lines.push(line);
    lines.forEach((item, index) => {
      console.log(canvas.width / 2,
        lineHeight * index + (lineHeight - fontSize) / 2)
      ctx.fillText(
        item,//文本
        canvas.width / 2, //x轴坐标
        lineHeight * index + (lineHeight - fontSize) / 2 //y轴坐标
      );
    });
    // 进行放大devicePixelRatio倍处理解决图片模糊问题
    ctx.scale(ratio, ratio)
    // 生成海报
    const posterBg: any = document.querySelector('.posterBg')
    return new Promise(() => {
      setTimeout(() => {
        // #posterBg 就是我们要获取截图对应的 DOM 元素选择器
        html2canvas(posterBg, {
          useCORS: true,    // 开启跨域配置
          allowTaint: true, // 允许跨域图片
          // backgroundColor: "transparent" //背景色
        }).then((res) => {
          // 生成海报后直接下载
          // const img = document.createElement('a')
          // img.href = res
          //   .toDataURL('image/jpeg')
          //   .replace('image/jpeg', 'image/octet-stream')
          // img.target = '_new'
          // img.download = 'xxxx.jpg'
          // img.click()
          // setPosters(false)

          // 新建一个生成后的img标签覆盖原有div以实现在微信浏览器中长按保存图片
          const posterBgWx = document.createElement('img') //创建一个图片标签
          const postersBox: any = document.querySelector('.postersBox')  //获取其父元素节点
          postersBox.appendChild(posterBgWx)
          posterBgWx.className = 'posterBgWx'
          posterBgWx.src = res
            .toDataURL('image/jpeg')
            .replace('image/jpeg', 'image/octet-stream')
        })
      }, 300)
    })

图片跨域在此场景尝试img转base64等格式处理无效最后在img标签加crossOrigin='anonymous'属性并配合后端配置CORS解决(根据实际情况配置)

dc52ff2774a40fb4e32f9d6963954f3.png