Method of JS Exporting PDF Plug in of Supports Chinese and Picture Use Path

  • 2021-07-02 23:23:00
  • OfStack

I want to do a function of exporting PDF on WEB, and find that jsPDF is recommended by many people, but unfortunately it does not support Chinese. Finally, I found pdfmake, which solved this problem well. Its effect can be checked at http://pdfmake.org/playground.html first. In the process of using, it is also found that the insertion of pictures is a relatively tedious thing.

To solve these problems, the main content of this paper can be divided into three parts:

The basic usage of ES 14EN;
How to solve Chinese problems;
How to insert a picture by specifying a picture address.

Basic usage of pdfmake

1. Include the following two files


 <script src="build/pdfmake.min.js"></script>
  <script src="build/vfs_fonts.js"></script>

2. Declare an Document-definition object in the JS code, which is pdfmake's own term. Simply put, it is to create an object with at least content attributes. Then you can call the method of pdfMake to export PDF, as shown in the following code:


<script type="text/javascript">
 // Create Document-definition Object  
 var dd = {
      content: [
       'One paragraph',
       'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
       ]
    };
 // Export PDF
 pdfMake.createPdf(dd).download();
 </script>

Follow the above example, and you can see the prompt file downloaded. For a complete tutorial on pdfmake, please visit the pdfmake project.

pdfmake supports Chinese

Three steps:

1. Go to the pdfmake project website, download all the projects, then enter the project directory and put the font files (such as Microsoft Yahei. ttf) into the examples/fonts directory, and then use grunt dump_dir to generate a new vfs_fonts. js file;

It can be seen from the above description that the project is managed through grunt. If there is no relevant knowledge, please go online for tutoring first.

The grunt dump_dir command packages all files in the fonts directory, so don't put useless files in.

Microsoft Yahei. ttf online 1 search 1 a lot, WINDOWS computer system disk storage font directory can also be found.

2. Go back to your example code. In the JS code, modify the fonts object of pdfMake and declare the font to be used at present:


 pdfMake.fonts = {
      Roboto: {
        normal: 'Roboto-Regular.ttf',
        bold: 'Roboto-Medium.ttf',
        italics: 'Roboto-Italic.ttf',
        bolditalics: 'Roboto-Italic.ttf'
      },
       Microsoft Yahei : {
        normal: ' Microsoft Yahei .ttf',
        bold: ' Microsoft Yahei .ttf',
        italics: ' Microsoft Yahei .ttf',
        bolditalics: ' Microsoft Yahei .ttf',
      }
    };

3. Declare the font to be used by default in the Document-definition object. Specifically, it is to declare an object, which has an defaultStyle attribute in addition to the content attribute, and there is another font attribute under the defaultStyle:


var dd = {
      content: [
       ' Chinese and English tests ',
       'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
       ],
       defaultStyle: {
         font: ' Microsoft Yahei '
       }
    };

The following is a complete example source code according to the above steps:


<!DOCTYPE html>
<html lang="zh-CN">
  <head>
  <meta charset="utf-8">
  <title>my first export PDF</title>
  <script src="build/pdfmake.min.js"></script>
  <script src="build/vfs_fonts.js"></script>
  <script>
  function down() {
    var dd = {
      content: [
       ' Chinese and English tests ',
       'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
       ],
       defaultStyle: {
         font: ' Microsoft Yahei '
       }
    };
    pdfMake.fonts = {
      Roboto: {
        normal: 'Roboto-Regular.ttf',
        bold: 'Roboto-Medium.ttf',
        italics: 'Roboto-Italic.ttf',
        bolditalics: 'Roboto-Italic.ttf'
      },
       Microsoft Yahei : {
        normal: ' Microsoft Yahei .ttf',
        bold: ' Microsoft Yahei .ttf',
        italics: ' Microsoft Yahei .ttf',
        bolditalics: ' Microsoft Yahei .ttf',
      }
    };
    pdfMake.createPdf(dd).download();
  }
  </script>
  </head>
  <body>
  <button onclick="down()"> Download </button>
  </body>
</html>

Insert a picture

In terms of inserting pictures, jsPDF requires that the pictures should be converted into Data URL first, while pdfmake allows direct assignment of paths, which seems very convenient, but this is conditional. node. js must be used as a server, or the pictures must be put into vfs_fonts. js, so in general, it is of little use, or it is necessary to convert the pictures into Data URL.

To solve this problem, I wrote a function object of ImageDataURL, which can pass in multiple picture addresses at the same time. After all the pictures are loaded, ImageDataURL. oncomplete will be triggered. In the callback, Data and URL of each picture will be taken out through this. imgdata. According to the requirements of pdfmake, pdf can be generated correctly.

The principle of ImageDataURL is to draw the picture on canvas through canvas tag of H5, and then get Data URL of the image through toDataURL of canvas. Please pay attention to browser compatibility problems when using.

The following is an example of writing sampleImage. jpg, sampleage. jpg and sampleImage. jpg into PDF in turn. sampleage. jpg does not exist during the test, and PDF is ignored directly.


<!DOCTYPE html>
<html lang="zh-CN">
  <head>
  <meta charset="utf-8">
  <title>my second export PDF</title>
  <script src="build/pdfmake.min.js"></script>
  <script src="build/vfs_fonts.js"></script>
  <script>
  
  function down() {
    var x = new ImageDataURL(["sampleImage.jpg", "samplage.jpg", "sampleImage.jpg"]);
    x.oncomplete = function() {
      var imgs = new Array();
      console.log("complete");
      for (key in this.imgdata) {
        if (this.imgdata[key] == this.emptyobj)// Images that do not exist are ignored directly 
          continue;
        imgs.push({image:this.imgdata[key]});//pdfmake Image format of {image:image dataurl}
      }
      var dd = {
        content: [
         'Title',
         imgs,
         ],
      };
      pdfMake.createPdf(dd).download();
    }
  }
  </script>
  </head>
  <body>
  <button onclick="down()"> Download </button>
  <script>
  function ImageDataURL(urls) {//urls Must be a string or string array 
    this.completenum = 0;
    this.totalnum = 0;
    this.imgdata = new Array();
    this.emptyobj = new Object();
    this.oncomplete = function(){};
    this.getDataURL = function(url, index) {
      var c = document.createElement("canvas");
      var cxt = c.getContext("2d");
      var img = new Image();
      var dataurl;
      var p;
      p = this;
      img.src = url;
      img.onload = function() {
        var i;
        var maxwidth = 500;
        var scale = 1.0;
        if (img.width > maxwidth) {
          scale = maxwidth / img.width;
          c.width = maxwidth;
          c.height = Math.floor(img.height * scale);
        } else {
          c.width= img.width;
          c.height= img.height;
        }
        cxt.drawImage(img, 0, 0, c.width, c.height);

        p.imgdata[index] = c.toDataURL('image/jpeg');
        for (i = 0; i < p.totalnum; ++i) {
          if (p.imgdata[i] == null)
            break;
        }
        if (i == p.totalnum) {
          p.oncomplete();
        }
      };
      img.onerror = function() {
        p.imgdata[index] = p.emptyobj;
        for (i = 0; i < p.totalnum; ++i) {
          if (p.imgdata[i] == null)
            break;
        }
        if (i == p.totalnum) {
          p.oncomplete();
        }
      };
    }
    if (urls instanceof Array) {
      this.totalnum = urls.length; 
      this.imgdata = new Array(this.totalnum);
      for (key in urls) {
        this.getDataURL(urls[key], key);
      }
    } else {
      this.imgdata = new Array(1);
      this.totalnum = 1;
      this.getDataURL(urls, 0);
    }
  }

  </script>
  </body>
</html>

Related articles: