dom-to-image 与 html2canvas

3,475 阅读4分钟

移动端需求

业务背景:自动获取用户姓名,每个人输入自己想说的话,上传头像,然后自动生成统一背景的图片,并且长按下载下来。上传头像不进行存储到数据库,所以不涉及图片问题跨域。 (注:如果用户不输入文字,只有图片,直接用html2canvas就行)

技术选型:dom-to-imagehtml2canvas

一.dom-to-image

1.dom-to-image ios只支持生成svg图片,并且不支持background 引入的背景图片,

生成图片高清,但是在企业微信上面长按保存 模糊

2.dom-to-image android 可以生成svg图片,但是svg在android上不支持长按保存,

只能采取toPng,toJepg,但是生成图片模糊,长按保存也模糊

二.html2canvas

html2canvas 生成的图片高清且支持安卓 与 ios,生成图片时需要一个延时显示生成的图片。

注意点:若内容高于body时,在生成截图前,先把滚动条置顶

使用方法:

1.安装 npm install --save html2canvas

2.import html2canvas from 'html2canvas'

3.生成图片代码内容:如下

//先把滚动条置顶

window.pageYoffset=0;

document.documentElement.scrollTop=0;

document.body.scrollTop=0;

let node=document.getElementById('my-node');

let w=parseInt(node.offsetWidth);

let h=parseInt(node.offsetHeight);

html2canvas(node).then((canvas)=>{

canvas.style.width= w + 'px';

canvas.style.height=h + 'px';

let url =canvas.toDataURL();

const img=new Image();

img.src=url;

//设置生成图片展示的大小

img.style.width=w * 0.9 + 'px';

img.style.height=h * 0.7 + 'px';

//放在渲染的div里面

document.getElementById('generate-photo').appendChild(img)

},200)

//渲染的div需要延时,不然生成图片不完整

setTimout(()=>{

this.vshowPhoto=true;

},3500)

我以为用html2canvas就好了,结果部分手机测试发现生成图片字体会叠加在一起,用了好多方法都没有效果,最后用dom-to-image插件生成svg图片,然后再用html2canvas生成图片,字段才不重叠,图片也高清 代码片段如下:

//node需要渲染的div
var node = document.getElementById("my-node");
function filter(node) {
      return node.tagName !== "i";
    }
    domtoimage.toSvg(node, {
        filter: filter,
      })
      .then((dataUrl) => {
        /* do something */
        let img = new Image();
        img.src = dataUrl;
        //photo 一个空div,用来存放dom-to-image生成的svg图片
        let photo = document.getElementById("help-div-img");
        img.onload = () => {
        //渲染第一个svg生成的dom
          this.vshowMainOne = 1;
          document.getElementById("help-div-img").appendChild(img);
          var w = parseInt(node.offsetWidth);
          var h = parseInt(node.offsetHeight);
          //隐藏原页面的节点
          this.vshowMain = false;
          this.showLoading("生成图片中");
          window.pageYoffset = 0;
          document.documentElement.scrollTop = 0;
          document.body.scrollTop = 0;
          let photoStyle;
          //因为苹果系统此版本生成照片时,背景图片失踪,做特殊处理,直接用html2canvas生成
          if (this.$platform == "ios_12.5.4") {
            photoStyle = node;
          } else {
            photoStyle = photo;
          }
          //html2canvas 重绘svg
          html2canvas(photoStyle).then((canvas) => {
            if (canvas) {
              canvas.style.width = w + "px";
              canvas.style.height = h + "px";
              var url = canvas.toDataURL();
              const img2 = new Image();
              img2.src = url;
              img2.style.transform = " scale(1.1)";
              img2.style.width = w * 0.8 + "px";
              img2.style.height = h * 0.7 + "px";
              //渲染第二次生成的图片,隐藏第一次生成的图片
              this.vshowMainOne = 2;
              img2.onload = () => {
                document.getElementById("help-ios-img").appendChild(img2);
                photo.style.height = 0;
                this.closeLoading();
              };
            }
          });
        };
      });

pc端需求

需求:将系统统计的数据生成分析报告,然后可以导出成PDF下载到电脑上。

一. 安装依赖

npm install --save html2canvas  // 页面转图片
npm install jspdf --save  // 图片转pdf

二. 写一个pdf.js文件

import html2canvas from "html2canvas";
import jsPDF from "jspdf";

export const downloadPDF = page => {
  html2canvas(page).then(function(canvas) {
    canvas2PDF(canvas);
  });
};

const canvas2PDF = canvas => {
  let contentWidth = canvas.width;
  let contentHeight = canvas.height;

  //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  let imgWidth = 595.28;
  let imgHeight = 592.28/contentWidth * contentHeight;

  // 第一个参数: l:横向  p:纵向
  // 第二个参数:测量单位("pt","mm", "cm", "m", "in" or "px")
  let pdf = new jsPDF("p", "pt");

  pdf.addImage(
    canvas.toDataURL("image/jpeg", 1.0),
    "JPEG",
    0,
    0,
    imgWidth,
    imgHeight
  );

  pdf.save("导出.pdf");
};


三.页面转图片

在index.vue 页面:

<template>
  <div ref="pdf">
    这是待转换的页面,点击 
    <button @click="handleExport">导出</button> 按钮,完成导出操作。
  </div>
</template>

<script>
import {downloadPDF} from "@/util/pdf.js"  //工具方法,导出操作
export default {
  name: "pdf",
  data() {
    return {};
  },
  methods: {
    handleExport(){
      downloadPDF(this.$refs.pdf)
    }
  }
};
</script>


pc端转成pdf文档下载,参考文档:blog.csdn.net/ksjdbdh/art…

pc端扩展(带大图缩放展示)

需求:将系统统计的数据与图片生成分析报告,然后可以导出成PDF下载到电脑上,并且图片支持大图查看细节。
pdf导出图片效果图如下:

image.png

一. 安装依赖

npm install --save html2canvas  // 页面转图片
npm install jspdf --save  // 图片转pdf

二. 写一个pdf.js文件

import html2canvas from "html2canvas";
import jsPDF from "jspdf";

export const downloadPDF = (page, img, width, height, userName) => {
  //数据详情页面画成canvas
  html2canvas(page).then(function (canvas) {
    canvas2PDF(canvas, img, width, height, userName, account);
  });
};

const canvas2PDF = (canvas, img, width, height, userName) => {
  let contentWidth = canvas.width;
  let contentHeight = canvas.height;

  //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  let imgWidth = 595.28;
  let imgHeight = (592.28 / contentWidth) * contentHeight;
  //控制第二个页面图片的大小,按照一定的比例去缩放图片
  if (width > height) {
    if (width > 2000) {
      width = width * 0.1;
      height = height * 0.1;
    } else if (1000 < width < 2000) {
      width = width * 0.2;
      height = height * 0.2;
    } else if (800 < width < 1000) {
      width = width * 0.4;
      height = height * 0.4;
    } else if (400 < width < 800) {
      width = width * 0.7;
      height = height * 0.7;
    }
  } else {
    if (height > 2000) {
      width = width * 0.1;
      height = height * 0.1;
    } else if (1000 < height < 2000) {
      width = width * 0.2;
      height = height * 0.2;
    } else if (800 < height < 1000) {
      width = width * 0.4;
      height = height * 0.4;
    } else if (400 < height < 800) {
      width = width * 0.7;
      height = height * 0.7;
    }
  }
  console.log(width, height, "widht,height----------", img);

  // 第一个参数: l:横向  p:纵向
  // 第二个参数:测量单位("pt","mm", "cm", "m", "in" or "px")
  let pdf = new jsPDF("p", "pt");
  //第一个数据详情页面
  pdf.addImage(
    canvas.toDataURL("image/jpeg", 1.0),
    "JPEG",
    0,
    50,
    imgWidth,
    imgHeight
  );
  //只有一张图片时,展示图片的代码如下所示
  ·····只取其一·········
  if (img) {
    // 添加第二页,设置页面的大小
    pdf.addPage([imgWidth, 700]);
    //添加第二个页面的图片
    pdf.addImage(img, "png", 20, 30, width, height);
  }
  ······只取其一···················
  //如果有两张图片时,展示图片的代码如下所示(上面传递的参数也要跟着变化eg:imgOne...)
   if (imgOne) {  //第一张图片
    pdf.addPage([imgWidth, 700]);
    pdf.addImage(imgOne, "png", 20, 30, widht1, height1);
    if (imgTwo) {  //有第二张图片时
      if (height1 + height2 < 750) {
        //两张图片小于pdf页面总高度,就添加到一个页面
        pdf.addImage(imgTwo, "png", 20, height1 + 40, widht2, height2);
      } else {
        //大于则再添加一个新页面
        pdf.addPage([imgWidth, 700]);
        pdf.addImage(imgTwo, "png", 20, 30, widht2, height2);
      }
    }
  }
  ....................
  
  pdf.save(`xxx_${userName}.pdf`);
};

三.页面转图片

在index.vue 页面:

<template>
  <div ref="pdf">
      <img ref="imgPdf"
            :src="'data:image/png;base64,' + file"
            class="img-view"
            alt=""
          />
    这是待转换的页面,点击 
    <button @click="handleExport">导出</button> 按钮,完成导出操作。
  </div>
</template>

<script>
import {downloadPDF} from "@/util/pdf.js"  //工具方法,导出操作
export default {
  name: "pdf",
  data() {
    return {
    file:'',
    name:'',
    };
  },
  methods: {
    handleExport(){
        let image = document.querySelector(".img-view");
        downloadPDF(
          this.$refs.pdf,  //pdf第一页
          this.$refs.imgPdf, //pdf第二页
          image.naturalWidth, //图片宽度
          image.naturalHeight, //图片高度
          name, //pdf文件名字
        );
    }
  }
};
</script>