Skip to content

Commit 6e8cc99

Browse files
authored
Custom headers and footers (#129)
* Add new header/footer template options. * Add basic custom header/footer test. * Add custom header & footer docs. * Update version to 0.5.0.
1 parent 421610e commit 6e8cc99

File tree

4 files changed

+108
-2
lines changed

4 files changed

+108
-2
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,43 @@ const html = template(templateData);
125125
const pdf = await htmlPdf.create(html, options);
126126
```
127127

128+
### Custom Headers and Footers
129+
130+
_Note: Requires Chrome 65 or later._
131+
132+
You can optionally provide an HTML template for a custom header and/or footer.
133+
134+
A few classes can be used to inject printing values:
135+
136+
* `date` - formatted print date
137+
* `title` - document title
138+
* `url` - document location
139+
* `pageNumber` - current page number
140+
* `totalPages` - total pages in the document
141+
142+
You can tweak the margins with the `printOptions` of `marginTop`, `marginBottom`, `marginLeft`, and `marginRight`.
143+
144+
At this time, you must inline any images using [base64 encoding](http://www.bigfastblog.com/embed-base64-encoded-images-inline-in-html).
145+
146+
You can view how Chrome lays out the templates [here](https://cs.chromium.org/chromium/src/components/printing/resources/print_preview_page.html).
147+
148+
#### Example
149+
150+
```js
151+
const pdf = await htmlPdf.create(html, {
152+
port,
153+
printOptions: {
154+
displayHeaderFooter: true,
155+
headerTemplate: `
156+
<div class="text center">
157+
Page <span class="pageNumber"></span> of <span class="totalPages"></span>
158+
</div>
159+
`,
160+
footerTemplate: '<div class="text center">Custom footer!</div>',
161+
},
162+
});
163+
```
164+
128165
### Trigger Render Completion
129166

130167
There are a few `CompletionTrigger` types that wait for something to occur before triggering PDF printing.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "html-pdf-chrome",
3-
"version": "0.4.3",
3+
"version": "0.5.0",
44
"description": "HTML to PDF converter via Chrome/Chromium",
55
"main": "lib/src/index.js",
66
"scripts": {

src/typings/chrome/Page/PrintToPDFOptions.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
/**
44
* Chrome Page.printToPDF options.
5-
* Note: these require Chrome >= 60.
65
*
76
* @export
87
* @interface PrintToPDFOptions
@@ -105,4 +104,37 @@ export default interface PrintToPDFOptions {
105104
* @memberof PrintToPDFOptions
106105
*/
107106
ignoreInvalidPageRanges?: boolean;
107+
108+
/**
109+
* HTML template for the print header.
110+
* Should be valid HTML markup with following classes used to inject printing values into them:
111+
* - `date` formatted print date
112+
* - `title` document title
113+
* - `url` document location
114+
* - `pageNumber` current page number
115+
* - `totalPages` total pages in the document
116+
*
117+
* For example, `<span class="title"></span>` would generate a span containing the title.
118+
*
119+
* @type {string}
120+
* @memberof PrintToPDFOptions
121+
*/
122+
headerTemplate?: string;
123+
124+
/**
125+
* HTML template for the print footer. Should use the same format as the `headerTemplate`.
126+
*
127+
* @type {string}
128+
* @memberof PrintToPDFOptions
129+
*/
130+
footerTemplate?: string;
131+
132+
/**
133+
* Whether or not to prefer page size as defined by css.
134+
* Defaults to false, in which case the content will be scaled to fit the paper size.
135+
*
136+
* @type {boolean}
137+
* @memberof PrintToPDFOptions
138+
*/
139+
preferCSSPageSize?: boolean;
108140
}

test/index.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ describe('HtmlPdf', () => {
3535
'--disable-gpu',
3636
'--headless',
3737
],
38+
// uncomment if using Chrome Beta
39+
// chromePath: '/usr/bin/google-chrome-beta',
3840
connectionPollInterval: 250,
3941
logLevel: 'error',
4042
maxConnectionRetries: 50,
@@ -245,6 +247,41 @@ describe('HtmlPdf', () => {
245247
expect(pdf.getRawTextContent()).to.contain('Page (0) Break').and.to.contain('Page (1) Break');
246248
});
247249

250+
it('should generate a PDF with custom headers and footers', async () => {
251+
const html = `
252+
<html>
253+
<head>
254+
<title>TITLE</title>
255+
</head>
256+
<body>
257+
<div style="page-break-after:always">P1</div>
258+
<div>P2</div>
259+
</body>
260+
</html>
261+
`;
262+
const result = await HtmlPdf.create(html, {
263+
port,
264+
printOptions: {
265+
displayHeaderFooter: true,
266+
headerTemplate: `
267+
<div class="text center" style="color:red;">
268+
Custom <b>header</b>!
269+
Page <span class="pageNumber"></span> of <span class="totalPages"></span>.
270+
Title: <span class="title"></span>.
271+
</div>
272+
`,
273+
footerTemplate: '<div class="text center" style="color:green">Custom <i>footer</i>!</div>',
274+
},
275+
});
276+
expect(result).to.be.an.instanceOf(HtmlPdf.CreateResult);
277+
const pdf = await getParsedPdf(result.toBuffer());
278+
const pdfText = pdf.getRawTextContent();
279+
expect(pdfText).to.contain('Custom header!').and.to.contain('Custom footer!');
280+
expect(pdfText).to.contain('Page 1 of 2.').and.to.contain('Page 2 of 2.');
281+
expect(pdfText).to.contain('P1').and.to.contain('P2');
282+
expect(pdfText).to.contain('Title: TITLE.');
283+
});
284+
248285
it('should generate a PDF from a local file', async () => {
249286
const filePath = path.join('file://', __dirname, '../../test/test.html');
250287
const result = await HtmlPdf.create(filePath, {port});

0 commit comments

Comments
 (0)