html2pdf.js
html2pdf.js copied to clipboard
blank pdf generated for large documents
When a document is big spanning 150-200 pages , blank pdf is generated. v0.9.0 is this a limitation of canvas element ? Can this be fixed ?
I encounter the same issue in Chrome, and not only for big documents, also for tinny docs
@eKoopmans is there an error callback that will say that the limit has exceeded the canvas size. We can show an error message to user in that case then
Same here. I have a pdf consisting of 93 blank pages. In another pdf with 81 pages some elements that should be in the pdf are only present on the first pages then disappear.
config:
margin: [8, 8, 8, 8],
filename: fileName,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 1 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'landscape' },
pagebreak: { after: '.page-break' }
using version 0.9.2
What code and config are you guys using?
Same issue here - not consistently though, sometimes same input will print to PDF just fine, sometimes it is a semi-blank or completely blank output. Using v0.9.1 and config is:
html2pdf()
.set({
margin: [10, 10, 20, 10],
filename: fileName,
image: {type: 'jpeg', quality: 1},
html2canvas: {dpi: 192, letterRendering: true},
jsPDF: {unit: 'mm', format: 'letter', orientation: 'landscape'},
pageBreak: {mode: ['avoid-all', 'css'], avoid: ['.pi-row']},
})
.from(container[0].innerHTML)
.toPdf()
.save();```
So this is a known but hard to fix issue. See #19
@eKoopmans Yes , i understand it is hard to fix , but can there be a way to atleast generate an error . I ask this because , in Firefox , if the document is huge , the screen gets frozen, and there is nothing that the user can do . He has to close the browser and restart it Chrome is working because it is atleast able to generate a pdf , eventhough it is blank. Screen is not frozen. Wheras Firefox is unable to handle a canas size that exceeds its limit. The screen gets frozen and i can see errors in the console of Firefox . i have reprted this issue here with the errors received --> https://github.com/eKoopmans/html2pdf.js/issues/351
@eKoopmans Any update on this ?
@kirtipriya the only way to fix is as suggested here you'll have to divide up your html content into different "pages" so that a new canvas is created for each "page", preventing the content height from exceeding canvas upper limit.
i did it this way in my code and it works totally fine albeit a bit slower:
// ---------- HTML output for pdf export ----------
<div aria-label="pdf-page-1">...content</div>
<div aria-label="pdf-page-2">...content</div>
...
// ---------- Javascript ----------
// pages => individual html blocks to print
// select all elements marked with 'pdf-page-*' to be printed into PDF
const pages = Array.from(document.querySelectorAll('div[aria-label^="pdf-page-"]'))
const pdfOptions = { ... pdf options here }
await downloadPDF(pages, pdfOptions)
const downloadPDF = (elements, pdfOptions) => {
let worker = html2pdf()
.set(options)
.from(elements[0])
if (elements.length > 1) {
worker = worker.toPdf() // worker is now a jsPDF instance
// add each element/page individually to the PDF render process
elements.slice(1).forEach((element, index) => {
worker = worker
.get('pdf')
.then(pdf => {
pdf.addPage()
})
.from(element)
.toContainer()
.toCanvas()
.toPdf()
})
}
worker = worker.save()
}
@kirtipriya the only way to fix is as suggested here you'll have to divide up your html content into different "pages" so that a new canvas is created for each "page", preventing the content height from exceeding canvas upper limit.
i did it this way in my code and it works totally fine albeit a bit slower:
// ---------- HTML output for pdf export ---------- <div aria-label="pdf-page-1">...content</div> <div aria-label="pdf-page-2">...content</div> ... // ---------- Javascript ---------- // pages => individual html blocks to print // select all elements marked with 'pdf-page-*' to be printed into PDF const pages = Array.from(document.querySelectorAll('div[aria-label^="pdf-page-"]')) const pdfOptions = { ... pdf options here } await downloadPDF(pages, pdfOptions) const downloadPDF = (elements, pdfOptions) => { let worker = html2pdf() .set(options) .from(elements[0]) if (elements.length > 1) { worker = worker.toPdf() // worker is now a jsPDF instance // add each element/page individually to the PDF render process elements.slice(1).forEach((element, index) => { worker = worker .get('pdf') .then(pdf => { pdf.addPage() }) .from(element) .toContainer() .toCanvas() .toPdf() }) } worker = worker.save() }
@shan-du : Thank you for the suggestion. The content is dynamic in my case. It might be difficult to for me to identify which div tags i have to treat as pages - div[aria-label^="pdf-page-"], or do you have a solution for that too ?
@kirtipriya the only way to fix is as suggested here you'll have to divide up your html content into different "pages" so that a new canvas is created for each "page", preventing the content height from exceeding canvas upper limit. i did it this way in my code and it works totally fine albeit a bit slower:
// ---------- HTML output for pdf export ---------- <div aria-label="pdf-page-1">...content</div> <div aria-label="pdf-page-2">...content</div> ... // ---------- Javascript ---------- // pages => individual html blocks to print // select all elements marked with 'pdf-page-*' to be printed into PDF const pages = Array.from(document.querySelectorAll('div[aria-label^="pdf-page-"]')) const pdfOptions = { ... pdf options here } await downloadPDF(pages, pdfOptions) const downloadPDF = (elements, pdfOptions) => { let worker = html2pdf() .set(options) .from(elements[0]) if (elements.length > 1) { worker = worker.toPdf() // worker is now a jsPDF instance // add each element/page individually to the PDF render process elements.slice(1).forEach((element, index) => { worker = worker .get('pdf') .then(pdf => { pdf.addPage() }) .from(element) .toContainer() .toCanvas() .toPdf() }) } worker = worker.save() }
@shan-du : Thank you for the suggestion. The content is dynamic in my case. It might be difficult to for me to identify which div tags i have to treat as pages - div[aria-label^="pdf-page-"], or do you have a solution for that too ?
not sure what your requirements are, but in that case, i would probably still try to divide the print content, not by page, but every X pages.
for example: for every 10 <div>
content blocks, or every 3000px
, start a new page
@kirtipriya the only way to fix is as suggested here you'll have to divide up your html content into different "pages" so that a new canvas is created for each "page", preventing the content height from exceeding canvas upper limit. i did it this way in my code and it works totally fine albeit a bit slower:
// ---------- HTML output for pdf export ---------- <div aria-label="pdf-page-1">...content</div> <div aria-label="pdf-page-2">...content</div> ... // ---------- Javascript ---------- // pages => individual html blocks to print // select all elements marked with 'pdf-page-*' to be printed into PDF const pages = Array.from(document.querySelectorAll('div[aria-label^="pdf-page-"]')) const pdfOptions = { ... pdf options here } await downloadPDF(pages, pdfOptions) const downloadPDF = (elements, pdfOptions) => { let worker = html2pdf() .set(options) .from(elements[0]) if (elements.length > 1) { worker = worker.toPdf() // worker is now a jsPDF instance // add each element/page individually to the PDF render process elements.slice(1).forEach((element, index) => { worker = worker .get('pdf') .then(pdf => { pdf.addPage() }) .from(element) .toContainer() .toCanvas() .toPdf() }) } worker = worker.save() }
@shan-du : Thank you for the suggestion. The content is dynamic in my case. It might be difficult to for me to identify which div tags i have to treat as pages - div[aria-label^="pdf-page-"], or do you have a solution for that too ?
not sure what your requirements are, but in that case, i would probably still try to divide the print content, not by page, but every X pages. for example: for every 10
<div>
content blocks, or every3000px
, start a new page
can it work with css?
I'm also getting a blank document, but am trying to generate a very large PDF of 48"x69". Is this just not going to be possible?
How can canvas be exhausted if space between "legacy" with <br class="html2pdf__page-break">
is max 500px height (300pages)
@kirtipriya the only way to fix is as suggested here you'll have to divide up your html content into different "pages" so that a new canvas is created for each "page", preventing the content height from exceeding canvas upper limit.
i did it this way in my code and it works totally fine albeit a bit slower:
// ---------- HTML output for pdf export ---------- <div aria-label="pdf-page-1">...content</div> <div aria-label="pdf-page-2">...content</div> ... // ---------- Javascript ---------- // pages => individual html blocks to print // select all elements marked with 'pdf-page-*' to be printed into PDF const pages = Array.from(document.querySelectorAll('div[aria-label^="pdf-page-"]')) const pdfOptions = { ... pdf options here } await downloadPDF(pages, pdfOptions) const downloadPDF = (elements, pdfOptions) => { let worker = html2pdf() .set(options) .from(elements[0]) if (elements.length > 1) { worker = worker.toPdf() // worker is now a jsPDF instance // add each element/page individually to the PDF render process elements.slice(1).forEach((element, index) => { worker = worker .get('pdf') .then(pdf => { pdf.addPage() }) .from(element) .toContainer() .toCanvas() .toPdf() }) } worker = worker.save() }
code is working but hyperlink is not able to click in exported pdf
@shan-du Your code is useful to me, but if you need to wait for all pages to be generated before doing something, you can change the code to the following:
const downloadPDF = (elements, pdfOptions) => {
return new Promise((resolve, reject) => {
try {
let worker = html2pdf().set(pdfOptions).from(elements[0])
let pageCount = 1
if (elements.length > 1) {
worker = worker.toPdf() // worker is now a jsPDF instance
// add each element/page individually to the PDF render process
elements.slice(1).forEach((element, index) => {
worker = worker
.get('pdf')
.then(pdf => {
pageCount++
pdf.addPage()
if (pageCount === elements.length) {
resolve()
}
})
.from(element)
.toContainer()
.toCanvas()
.toPdf()
})
}
worker = worker.save()
if (elements.length === 1) {
resolve()
}
} catch (e) {
reject()
}
})
}
// ...
loading = true
await downloadPDF(pages, pdfOptions)
loading = false