html-to-pdfmake
Version:
Convert HTML code to PDFMake
411 lines (338 loc) • 11.4 kB
Markdown
# html-to-pdfmake
[pdfmake](https://pdfmake.github.io/docs/) permits to easily create a PDF with JavaScript, but the support of HTML was missing. After [reviewing issue #205](https://github.com/bpampuch/pdfmake/issues/205) I decided to create a module to handle this feature.
## Online Demo
You can find the online demo at <a href="https://aymkdn.github.io/html-to-pdfmake/index.html">https://aymkdn.github.io/html-to-pdfmake/index.html</a>
## Install
```bash
npm install html-to-pdfmake
```
## How to use
This module will convert some basic and valid HTML code to its equivalent in *pdfmake*.
```javascript
var pdfMake = require("pdfmake/build/pdfmake");
var pdfFonts = require("pdfmake/build/vfs_fonts");
pdfMake.vfs = pdfFonts.pdfMake.vfs;
var htmlToPdfmake = require("html-to-pdfmake");
// or:
// import htmlToPdfmake from "html-to-pdfmake"
// or, if used directly in a web browser:
// <script src="https://cdn.jsdelivr.net/npm/html-to-pdfmake/docs/browser.js"></scrpipt>
var html = htmlToPdfmake(`
<div>
<h1>My title</h1>
<p>
This is a sentence with a <strong>bold word</strong>, <em>one in italic</em>,
and <u>one with underline</u>. And finally <a href="https://www.somewhere.com">a link</a>.
</p>
</div>
`);
/*
it will return:
{
stack:[
{
text: 'My title',
fontSize: 24,
bold: true,
marginBottom: 5,
style: ['html-h1']
},
{
text: [
{
text: 'This is a sentence with a '
},
{
text: 'bold word',
bold: true,
style: ['html-strong']
},
{
text: ', '
},
{
text: 'one in italic',
italics: true,
style: ['html-em']
},
{
text: ', and '
},
{
text: 'one with underline',
decoration: 'underline',
style: ['html-u']
},
{
text: '. And finally '
},
{
text: 'a link',
color: 'blue',
decoration: 'underline',
link: 'https://www.somewhere.com',
style: ['html-a']
},
{
text: '.'
}
],
margin: [0, 5, 0, 10],
style: ['html-p']
}
],
style: ['html-div']
}
*/
```
## Documentation
### Options
Some options can be passed to `htmlToPdfmake` function as a second argument.
#### `window`
If you use Node, then you'll have to pass the `window` object ([see below](https://github.com/Aymkdn/html-to-pdfmake#use-with-node)).
#### `defaultStyles`
You can overwrite the default stles using `defaultStyles` ([see below](https://github.com/Aymkdn/html-to-pdfmake#default-styles)).
#### `tableAutoSize`
By pass `tableAutoSize` with `true`, then the program will try to define `widths` and `heights` for the tables, based on CSS properties `width` and `height` that have been provided to `TH` or `TD`.
Example:
```javascript
var html = htmlToPdfmake(`<table>
<tr style="height:100px">
<td style="width:250px">height:100px / width:250px</td>
<td>height:100px / width:'auto'</td>
</tr>
<tr>
<td style="width:100px">Here it will use 250px for the width because we have to use the largest col's width</td>
<td style="height:200px">height:200px / width:'auto'</td>
</tr>
</table>`, {
tableAutoSize:true
});
```
### HTML tags supported
The below HTML tags are supported:
- DIV / P / SPAN
- BR
- B / STRONG
- I / EM
- S
- UL / OL / LI
- TABLE / THEAD / TBODY / TFOOTER / TR / TH / TD
- H1 to H6
- IMG
- SVG
### Default styles
I've defined some default styles for the supported element.
For example, using a <STRONG> will display the word in **bold**. Or, a link will appear in blue with an underline, and so on...
Here is the list of defaults styles:
```javascript
{
b: {bold:true},
strong: {bold:true},
u: {decoration:'underline'},
s: {decoration: 'lineThrough'},
em: {italics:true},
i: {italics:true},
h1: {fontSize:24, bold:true, marginBottom:5},
h2: {fontSize:22, bold:true, marginBottom:5},
h3: {fontSize:20, bold:true, marginBottom:5},
h4: {fontSize:18, bold:true, marginBottom:5},
h5: {fontSize:16, bold:true, marginBottom:5},
h6: {fontSize:14, bold:true, marginBottom:5},
a: {color:'blue', decoration:'underline'},
strike: {decoration: 'lineThrough'},
p: {margin:[0, 5, 0, 10]},
ul: {marginBottom:5},
li: {marginLeft:5},
table: {marginBottom:5},
th: {bold:true, fillColor:'#EEEEEE'}
}
```
**Please, note that the above default styles are stronger than the ones defined in the style classes.** Read below how to overwrite them.
### Customize style
Each converted element will have an associated style-class called `html-tagname`.
For example, if you want all <STRONG> tags to be highlighted with a yellow backgroud you can use `html-strong` in the `styles` definition:
```javascript
var html = htmlToPdfmake(`
<p>
This sentence has <strong>a highlighted word</strong>, but not only.
</p>
`);
var docDefinition = {
content: [
html
],
styles:{
'html-strong':{
background:'yellow' // it will add a yellow background to all <STRONG> elements
}
}
};
var pdfDocGenerator = pdfMake.createPdf(docDefinition);
```
### CSS class and style
The `class` and `styles` for the elements will also be added.
```javascript
var html = htmlToPdfmake(`
<p>
This sentence has <span style="font-weight:bold" class="red">a bold and red word</span>.
</p>
`);
/*
It returns:
{
text: [
{
text: 'This sentence has '
},
{
text: 'a bold and red word',
style: ['red', 'html-span'], // 'red' added because of `class="red"`
bold: true // added because of `style="font-weight:bold"`
},
{
text: '.'
}
],
margin: [0, 5, 0, 10],
style: ['html-p']
}
*/
var docDefinition = {
content: [
html
],
styles:{
red:{ // we define the class called "red"
color:'red'
}
}
};
var pdfDocGenerator = pdfMake.createPdf(docDefinition);
```
**Please, note that the default styles are stronger than the ones defined in the style classes.** For example, if you define a class `html-a` to change all links in *purple*, then it won't work because the default styles will overwrite it:
```javascript
var docDefinition = {
content: [
html
],
styles:{
'html-a':{
color:'purple' // it won't work: all links will remain 'blue'
}
}
};
```
To make it work, you have to either delete the default styles, or change it with a new value. Starting `v1.1.0`, an option parameter is available as a second parameter.
Example: you want `<li>` to not have a margin-left, and `<a>` to be 'purple' and without 'underline' style:
```javascript
var html = htmlToPdfmake('<ul><li>this is <a href="...">a link</a></li><li>another item</li><li class="with-margin">3rd item with a margin</li></ul>', {
defaultStyles:{ // change the default styles
a:{ // for <A>
color:'purple', // all links should be 'purple'
decoration:'' // remove underline
},
li:'' // remove all default styles for <LI>
}
});
var docDefinition = {
content: [
html
],
styles:{
'with-margin':{
marginLeft: 30 // apply a margin with the specific class is used
}
}
};
```
### `<img>`
The `<img>` tag is supported, however the `src` attribute must already be a **base64 encoded content** (as describe in the [PDFMake documentation](https://pdfmake.github.io/docs/document-definition-object/images/)).
This is too complex and out of the scope of this module to find and convert the image source to a base64 format. You can check [this Stackoverflow question](https://stackoverflow.com/questions/934012/get-image-data-in-javascript/42916772#42916772) to know the different ways to get a base64 encoded content from an image.
### page break
You can use [`pageBreakBefore`](https://pdfmake.github.io/docs/document-definition-object/page/) and a CSS class that you'll apply to your elements to identify when to add a page break:
```javascript
var html = htmlToPdfmake(`
<div>
<h1>My title on page 1</h1>
<p>
This is my paragraph on page 1.
</p>
<h1 class="pdf-pagebreak-before">My title on page 2</h1>
<p>This is my paragraph on page 2.</p>
</div>
`);
var docDefinition = {
content: [
html
],
pageBreakBefore: function(currentNode) {
return currentNode.style && currentNode.style.indexOf('pdf-pagebreak-before') > -1;
}
};
var pdfDocGenerator = pdfMake.createPdf(docDefinition);
```
See [example.js](example.js) to see another example.
### Special properties
PDFMake provides some special attributes, like `widths` or `heights` for `table`, or `fit` for `image`, and more.
To apply these special attributes, you have to use the attribute `data-pdfmake` on your HTML elements, and then pass the special attributes as a JSON string.
```html
<!-- Example with `widths:[100,"*","auto"]` and `heights:40` to apply to a `table`. -->
<table data-pdfmake="{"widths":[100,"*","auto"],"heights":40}">
<tr>
<td colspan="3">Table with <b>widths=[100,"*","auto"]</b> and <b>heights=40</b></th>
</tr>
<tr>
<td>Cell1</td>
<td>Cell2</td>
<td>Cell3</td>
</tr>
</table>
```
The expression provided by `data-pdfmake` must be a valid JSON string because it will be translated with `JSON.parse()`.
#### `<hr>`
An `<hr>` can also be customized using `data-pdfmake`. Some default styles are applied to this element:
```javascript
{
left:0, // the left position
width:514, // should be OK with a A4 page
color:'black', // the color of the line
thickness:0.5, // how thick the line must be
margin:[0,12,0,12] // same order as PDFMake, meaning: [left, top, right, bottom]
}
```
See the [example.js](example.js) file to see a `<hr>` example.
## Use with Node
To use it in a Node script you need to install `jsdom`:
```bash
npm install jsdom
```
Then in your JS file:
```javascript
var pdfMake = require("pdfmake/build/pdfmake");
var pdfFonts = require("pdfmake/build/vfs_fonts");
pdfMake.vfs = pdfFonts.pdfMake.vfs;
var fs = require('fs');
var jsdom = require("jsdom");
var { JSDOM } = jsdom;
var { window } = new JSDOM("");
var htmlToPdfMake = require("html-to-pdfmake");
var html = htmlToPdfMake(`<div>the html code</div>`, {window:window});
var docDefinition = {
content: [
html
]
};
var pdfDocGenerator = pdfMake.createPdf(docDefinition);
pdfDocGenerator.getBuffer(function(buffer) {
fs.writeFileSync('example.pdf', buffer);
});
```
## Examples
You can find more examples in [example.js](example.js) which will create [example.pdf](example.pdf):
```bash
npm install
node example.js
```
## Donate
You can support my work by [making a donation](https://www.paypal.me/aymkdn), or by visiting my [Github Sponsors page](https://github.com/sponsors/Aymkdn). Thank you!