三方库关于项目中 pdf、word、html转换的不同方案(分享)

1. pdf 相关

1.1 html2Canvas、JsPDF分页打印
  • 安装包
html2canvas jspdf

该应用场景是,是使用luckysheet生成PDF,一共分了四种情况,传值的时候只需要判断,生成html的宽度(需要乘0.75,因为是pt单位做对比)只要大于a4的宽度就需要纵向打印,jspdf在线demo戳这里api文档戳这里

  1. 单张纵向a4
  2. 单张横向a4
  3. 分页纵向a4
  4. 分页横向a4
  5. 这四种都可以识别
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
/**
 * 导出页面为PDF格式,1pt === 4/3px,1px === 0.75pt
 * @param { String } title 文件名
 * @param { Number } type 0:生成PDF、1:生成base64
 * @param { Boolean } longitudinalShow true:横向打印,false:纵向打印
 * @returns { Promise }
 */
export function getPdf(title, type, longitudinalShow = false) {
  return new Promise((res, rej) => {
    html2Canvas(document.querySelector('#printHtml'), {
      allowTaint: true, // 是否允许不同源的图片污染画布
      taintTest: false, // 是否在渲染前测试图片
      useCORS: true, // 是否尝试使用 CORS 从服务器加载图片
      dpi: window.devicePixelRatio * 1, // 将分辨率提高到特定的DPI
      scale: 1, // 用于渲染的比例,默认为浏览器设备像素比率
    }).then((canvas) => {
      // a4纸 pt尺寸
      let a4Size = {
        w: 595.28,
        h: 841.89,
      };
      // 算的是 px单位需要转 pt,a4纸与当前canvas的间距,用于居中
      let l = (((longitudinalShow ? a4Size.h : a4Size.w) * 1.33 - canvas.width) / 2) * 0.75;

      let pageData = canvas.toDataURL('image/jpeg', 1.0);

      let PDF = new JsPDF({
        // landscape:横向打印,默认纵向打印
        orientation: longitudinalShow ? 'landscape' : '',
        unit: 'pt',
        format: 'a4',
      });
      // 表高度,pt单位比较
      let sheetHeight = canvas.height * 0.75;
      let t = 0;
      // 是否需要转换宽高(a4纸打印做转向了,但是分页处理没有转向)
      let isRotate = longitudinalShow ? a4Size.w : a4Size.h;
      // 当表小于a4的高时,无需分页
      if (isRotate > sheetHeight) {
      	/*
		  addImage(img, JPEG, left, top, width, height) pt单位
		    1. 宽高传0,默认为原始图片的px单位
		    2. 如果传入图片原始宽高会识别为pt,打印出来后会进行1.333倍的放大
		    3. 打个比方a4纸的宽pt单位为595.28,px单位为793.71,一个图片宽高为180px
		       如果使用默认为0的,打印出来还是为180px,如果手动设置180,打印出来就会转换为240px
		       意思就是如果图片原始为px单位,设置的pt单位打印就不需要传,如果图片原始为pt单位,设置的pt单位打印就需要传
		*/
        PDF.addImage(pageData, 'JPEG', l, 24, 0, 0);
      } else {
        while (sheetHeight > 0) {
          PDF.addImage(pageData, 'JPEG', l, t, 0, 0);
          sheetHeight -= isRotate;
          t -= isRotate;
          // 避免添加空白页
          if (sheetHeight > 0) {
            PDF.addPage();
          }
        }
      }
      if (!type) {
        PDF.save(title + '.pdf');
      } else {
        var basePDf = PDF.output('datauristring');
        res(basePDf);
      }
    });
  });
}
1.2 pdfmake
  • 安装包
pdfmake html-to-pdfmake

这种场景我是确认了就是 a4 的宽度,所以没有做过多的配置,官网戳这里

:这里要特别说一下,关于打印 pdf 中文乱码的问题,pdfmake 本身就没有去适配中文的字体,用的都是 Roboto 字体,所以要去官网拉原本的项目,重新添加中文字体然后打包,替换 pdfmake/build/vfs_fonts.js 文件,项目地址戳这里

  1. 在该项目 examples/fonts 目录下移入一个中文字体包(.ttf 文件)
  2. 使用 npm run build:vfs 命令在 build 下生成 vfs_fonts.js 文件
  3. 如果 npm run build:vfs 报错,需要先执行 npm run build:fonts 在执行 npm run build:vfs
  4. 拿到 vfs_fonts.js 文件,替换自己项目中的文件(自己项目中的文件在哪里,ctrl+鼠标左键 导的包,可以直接跳到包的位置)
  5. 不要直接替换文件,打包后的文件和之前的不一样,只需要替换 vfs 对象中的内容就可以了
  6. 修改 node_modules 中的文件后,需要重新运行项目
// pdfmake 数据格式导出pdf
const pdfMake = require('pdfmake/build/pdfmake');
// pdfmake 导出的 fonts 字体
const pdfFonts = require('pdfmake/build/vfs_fonts');
pdfMake.vfs = pdfFonts.pdfMake.vfs;

// 将 HTML 转 Pdfmake 数据格式
const htmlToPdfmake = require('html-to-pdfmake');

// 配置字体
pdfMake.fonts = {
  Roboto: {
    bold: "Roboto-Medium.ttf",
    bolditalics: "Roboto-MediumItalic.ttf",
    italics: "Roboto-Italic.ttf",
    normal: "Roboto-Regular.ttf",
  },
  // 中文字体
  msyh: {
    normal: "msyh.ttf",
    bold: "msyh.ttf",
    italics: "msyh.ttf",
    bolditalics: "msyh.ttf",
  },
};

pdfMake
  .createPdf({
   // 默认使用中文字体
    defaultStyle: {
      font: "msyh",
    },
    content: htmlToPdfmake(`我是html数据结构`), // 需要转换成 pdfmake 识别的数据结构
  })
  // pdfMake.createPdf() 原型上有获取base64的方法
  .download();
1.3 vue-html2pdf 对 vue2 的项目进行导出
  • 安装包
vue-html2pdf

这个库的功能也是非常强大的,但是只适用于 vue2,配置文档和 demo 可以直接在 npm 搜对应的包

<vue-html2pdf
  :show-layout="false"
  :float-layout="true"
  :enable-download="true"
  :preview-modal="true"
  :paginate-elements-by-height="1400"
  filename="hee hee"
  :pdf-quality="2"
  :manual-pagination="false"
  pdf-format="a4"
  pdf-orientation="landscape"
  pdf-content-width="800px"
  @progress="onProgress($event)"
  @hasStartedGeneration="hasStartedGeneration()"
  @hasGenerated="hasGenerated($event)"
  ref="html2Pdf"
>
  <section slot="pdf-content">
    <!-- PDF 对应要导出的 html 内容 -->
  </section>
</vue-html2pdf>

// 调用该方法生成 pdf
this.$refs.html2Pdf.generatePdf()

这里简单汇总一下上面几种方案

  1. jspdf 是属于打印,可以控制清晰度、百分比等,如果只是做预览的话建议使用这个,对框架也没有什么要求
  2. pdfmake 是属于解析 html 元素,在处理成 pdf,对预览效果不是很好,很可能达不到想要的效果,但是可以保存超链接,如果是功能类的建议使用这个,对框架没什么要求
  3. vue-html2pdf 这种挺强大的,上面两个的优点都保留(这个没用过,还不知道有什么坑),但是只能 vue2 项目可以用,这点比较坑,使用 vue2 项目开发的可以试试这个,上手比较简单

2. word 相关

2.1 html 导出 word
  • 安装包
jquery file-saver
// 导入下面的 js 文件就可以了
$("html元素").wordExport('测试world');
// 导入 js 文件
import saveAs from "file-saver";
if (typeof $ !== "undefined" && typeof saveAs !== "undefined") {
  (function ($) {
    $.fn.wordExport = function (fileName) {
      fileName = typeof fileName !== "undefined" ? fileName : "jQuery-Word-Export";
      var statics = {
        mhtml: {
          top:
            "Mime-Version: 1.0\nContent-Base: " +
            location.href +
            '\nContent-Type: Multipart/related; boundary="NEXT.ITEM-BOUNDARY";type="text/html"\n\n--NEXT.ITEM-BOUNDARY\nContent-Type: text/html; charset="utf-8"\nContent-Location: ' +
            location.href +
            "\n\n<!DOCTYPE html>\n<html>\n_html_</html>",
          head: '<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n<style>\n_styles_\n</style>\n</head>\n',
          body: "<body>_body_</body>",
        },
      };
      var options = {
        maxWidth: 624,
      };
      // Clone selected element before manipulating it
      var markup = $(this).clone();
      // Remove hidden elements from the output
      markup.each(function () {
        var self = $(this);
        if (self.is(":hidden")) self.remove();
      });
      // Embed all images using Data URLs
      var images = Array();
      var img = markup.find("img");
      for (var i = 0; i < img.length; i++) {
        // Calculate dimensions of output image
        var w = Math.min(img[i].width, options.maxWidth);
        var h = img[i].height * (w / img[i].width);
        // Create canvas for converting image to data URL
        var canvas = document.createElement("CANVAS");
        canvas.width = w;
        canvas.height = h;
        // Draw image to canvas
        var context = canvas.getContext("2d");
        context.drawImage(img[i], 0, 0, w, h);
        // Get data URL encoding of image
        var uri = canvas.toDataURL("image/png/jpg");
        $(img[i]).attr("src", img[i].src);
        img[i].width = w;
        img[i].height = h;
        // Save encoded image to array
        images[i] = {
          type: uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")),
          encoding: uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")),
          location: $(img[i]).attr("src"),
          data: uri.substring(uri.indexOf(",") + 1),
        };
      }

      // Prepare bottom of mhtml file with image data
      var mhtmlBottom = "\n";
      for (var j = 0; j < images.length; j++) {
        mhtmlBottom += "--NEXT.ITEM-BOUNDARY\n";
        mhtmlBottom += "Content-Location: " + images[j].location + "\n";
        mhtmlBottom += "Content-Type: " + images[j].type + "\n";
        mhtmlBottom += "Content-Transfer-Encoding: " + images[j].encoding + "\n\n";
        mhtmlBottom += images[j].data + "\n\n";
      }
      mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";

      //TODO: load css from included stylesheet
      var str = '<head><meta charset="utf-8"></meta>',
        styles = document.querySelectorAll("style");
      for (var n = 0; n < styles.length; n++) {
        str += styles[n].outerHTML;
      }
      str +=
        "<style>table tr td{padding-left:5px;padding-right:5px}.tdTitle{background:#c2c1c1}.spaceRow{margin-top:10px;}table{width:100%;}</style>";
      str += "<style>table{border-collapse: collapse;table-layout: fixed}</style>";
      str +=
        "<style>table td,th{ height:30px;font-size:14px;border-width:1px;border-style: solid;border-color: #000;word-break: keep-all;}</style>";
      str += "</head>";

      // Aggregate parts of the file together
      var fileContent =
        statics.mhtml.top.replace(
          "_html_",
          statics.mhtml.head.replace("_styles_", str) +
            statics.mhtml.body.replace("_body_", markup.html())
        ) + mhtmlBottom;
      // Create a Blob with the file contents
      var blob = new Blob([fileContent], {
        type: "application/msword;charset=utf-8",
      });

      saveAs(blob, fileName + ".doc");
    };
  })($);
} else {
  if (typeof $ === "undefined") {
    console.error("jQuery Word Export: missing dependency (jQuery)");
  }
  if (typeof saveAs === "undefined") {
    console.error("jQuery Word Export: missing dependency (FileSaver.js)");
  }
}

3. html 相关

3.1 word 转 html
  • 安装包
import mammoth from "mammoth"

用法比较简单,但是有一个问题就是表格边框会丢失,npm 上也提到过了

const file = filexxx; // 获取选择的文件
const reader = new FileReader();
reader.readAsArrayBuffer(file); // 将文件读取为字节数组
reader.onload = () => {
  const arrayBuffer = reader.result;
  mammoth
    .convertToHtml({ arrayBuffer })
    .then((result) => {
      const html = result.value; // 返回 html
      })
    .done();
};
在Node.js,可以使用`ffmpeg`这个强大的多媒体处理转换视频格式,包括将WebM转换为MP4。`ffmpeg`是一个命令行工具,它支持几乎所有的视频和音频格式之间的转换。在Node.js,可以通过`fluent-ffmpeg`这个npm包来更方便地使用`ffmpeg`的功能。 首先,你需要确保在你的系统上安装了`ffmpeg`。安装`ffmpeg`的方法取决于你的操作系统,你可以从`ffmpeg`官方网站下载对应版本的安装程序。 接下来,通过npm安装`fluent-ffmpeg`: ```bash npm install fluent-ffmpeg ``` 安装完成后,你就可以在Node.js代码使用`fluent-ffmpeg`来调用`ffmpeg`进行格式转换了。下面是一个简单的示例代码: ```javascript const FFmpeg = require('fluent-ffmpeg'); // 设置ffmpeg的路径,如果是在系统路径已经安装,则不需要这一步 FFmpeg.setFfmpegPath('/path/to/ffmpeg'); // 使用fluent-ffmpeg进行转换 new FFmpeg({ source: 'input.webm' }) .withOptions(['-c:v libx264', '-preset fast', '-crf 22', '-c:a aac', '-b:a 192k']) .on('error', function(err) { console.log('An error occurred: ' + err.message); }) .on('end', function(outputPath) { console.log('Finished processing: ' + outputPath); }) .save('output.mp4'); ``` 在这段代码,`withOptions`方法用于指定转换过程的编码选项,如视频编码器(libx264)、预设(preset fast)、视频质量控制(CRF 22)、音频编码器(aac)和音频比特率(192k)。`save`方法用于指定输出文件的路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值