preface

A recent company project presented a new requirement to generate and output a PDF contract on the front end. As the language of the contract is Chinese, the best way to find the contract is to convert it to canvas through html2Canvas. But still stepped on a lot of pits, so to summarize the pits and the process.


The first step is to introduce html2Canvas.js, a plug-in that draws pages or DOM elements onto a Canvas canvas

<script src="http://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>

We also need to introduce jspdf.js, which is used to convert the drawn canvas into PDF and output it.

<script src="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script>

1. Contract style

First, reproduce the contract in HTML (with a reference snippet)

<p class="title_1">< SPAN class="item">1</ SPAN > Licensing cooperation </p> <p class="title_2">< SPAN class="item">1.1</span> Licensing works: The audio and video recording products and related materials, including but not limited to singer information, portraits, pictures and text introduction, which are mainly musical content, enjoyed by the licensor. In addition to the works listed in the List of Licensed Songs, the Licensor shall take the initiative to submit an updated list of musical works during the term of the Agreement, which shall also belong to the Agreement and have the same effect as this Agreement. < / p > < p class = "title_2" > < span class = "item" > 1.2 < / span > authorized rights: The copyright of lyrics and music, producer of audio and video recordings, performer's right, information network communication right, neighboring right, portrait right, etc., and the right to use, spread, copy, adapt, perform, transfer, and promote xinghui's works. </ P >< p class="title_2">< SPAN class="item">1.3</ SPAN > Authorized fields: including but not limited to computers, mobile phones, tablets and other smart end Internet, telecom carrier networks, smart hardware manufacturers, etc. </p>Copy the code

2. Generate canvas

Use the html2Canvas () function to generate canvas from the specified DOM and convert it to base64 format. Note here! , the definition of canvas generated by default is very poor, so it needs magnification processing, so that the final generated PDF can have high definition. (Attach the function code)

// The name argument is the id of a DOM passed in that needs to be copied.  function addPdfPage(name) { var page = new Promise(function(resolve, reject) { var copyDom = $("#" + name + ""); var width = copyDom.offsetWidth; var height = copyDom.offsetHeight; var scale = 2; / / magnification $(" body "). Append (' < canvas class = "canvas_pdf '+ name +" > < / canvas >'); var canvas = $('.' + name)[0]; canvas.width = width * scale; canvas.height = height * scale; var content = canvas.getContext("2d"); content.scale(scale, scale); var rect = copyDom.get(0).getBoundingClientRect(); Content.translate (-rect.left, -rect.top); Html2canvas (copyDom[0], {dpi: window.devicepixelRatio * 2, scale: scale, canvas: canvas, width: width, heigth: height, }).then(function(canvas) { var contentWidth = canvas.width; var contentHeight = canvas.height; Var imgWidth = 595.28; Var imgHeight = 592.28 / contentWidth * contentHeight; Img: canvas. ToDataURL ('image/ JPEG ', 1.0), width: imgWidth, height: imgHeight }) resolve(); }); }); return page; }Copy the code

3. Export and save the PDF to the local PC

Iterate through the pageData array and call the pdf.addimage () method to add page images to the PDF object one by one. Finally, the pdF.save () method is called to output the resulting PDF.

var pdf = new jsPDF('', 'pt', 'a4'), pageData = []; addPdfPage('page1').then(function() { for (i in pageData) { pdf.addImage(pageData[i].img, 'JPEG', 0, 0, pageData[i].width, pageData[i].height); } pdf.save(' contract.pdf '); // Output the final generated PDF});Copy the code

The final result

The final effect can refer to the following renderings, need code or where do not understand can be private message me. The part involving project privacy has been coded, sorry ~

A few words of caution for those of you who are about to tread:

  • If there is a table on the page, the border property of the table should be reset to 0, for example<table border="0" cellspacing="0" cellpadding="0"></table>, and then write the table style on CSS. This makes the output table perfect.
  • As HTML is converted to canvas and then to picture, it will be directly truncated when pagination is encountered. I have studied two methods for this problem, which will not attach the code for general reference.
  1. Breaking content up into DOM pieces is a good way to write down content that doesn’t need padding.
  2. Each DOM in the content is traversed, stored in a temporary DOM, and then stored in a new temporary DOM when the height exceeds the page. Finally, the temporary DOM is traversed for output. This method is troublesome but can fulfill my requirements.
  • The final output is an image PDF, not a text PDF, and the need for high resolution results in a large final file, around 1M per page,

So if it is generated after the same apes to the background to give up, not only slow and very troublesome. Not as fast and convenient as direct background generation of text PDF. (The key is not to calculate the case of pagination lol)