Open CSENoni opened 7 years ago
@eKoopmans and anyone else please help.
I have hit a blocker when trying to convert a page to pdf. Apparently the issue is with the canvas size limitation that we have with respect to browser. The permissible limit for canvas height is 32,767px for chrome/edge/firefox
My code basically grabs the current page which is suppose to be a report and then adds a defined header footer to each page while adding the grabbed html instance.
The problem arrives when we have a longer report whose canvas size exceeds the defined canvas size of browser then it renders the whole pdf blank apart from header and footer.
Sharing the code for reference:
==========================
Note: renderFooter its is function to populate header and footer and is working fine for any number of pages. callback its just a value which updates the waiting status at the web page.
Kindly suggest and alternate solution which would be able to accomodate any number of pages in pdf. Currently its is able to create a maximum of pa pdf 16 pages, beyond that it makes the whole pdf empty. I need to go uptill 29-40 pages if possible.
@tmislos-cgi Becauase I am appending header and footer on each page explicitly
@GAVTIN here is how i resolved my issue with the canvas height limitation:
I added aria-label to my divs dynamically, where i can logically divide them.
<div aria-label={`pdf-page-` + ++i}>
then upon generating the pdf, I broke the html elements to an array and then combined them to a single pdf file.
const pages = Array.from(input.querySelectorAll('div[aria-label^="pdf-page-"]'))
let worker = html2pdf()
.set(pdfOptions)
.from(pages[0])
worker = worker.toPdf() // worker is now a jsPDF instance
if (pages.length > 1) {
// add each element/page individually to the PDF render process
pages.slice(1).forEach((page, index) => {
worker = worker
//worker = worker.toPdf() // worker is now a jsPDF instance
.get('pdf')
.then(pdf => {
pdf.addPage()
})
.from(page)
.toContainer()
.toCanvas()
.toPdf()
})
}
got these code from above or another issue i think.
@GAVTIN here is how i resolved my issue with the canvas height limitation:
I added aria-label to my divs dynamically, where i can logically divide them.
<div aria-label={`pdf-page-` + ++i}>
then upon generating the pdf, I broke the html elements to an array and then combined them to a single pdf file.
const pages = Array.from(input.querySelectorAll('div[aria-label^="pdf-page-"]')) let worker = html2pdf() .set(pdfOptions) .from(pages[0]) worker = worker.toPdf() // worker is now a jsPDF instance if (pages.length > 1) { // add each element/page individually to the PDF render process pages.slice(1).forEach((page, index) => { worker = worker //worker = worker.toPdf() // worker is now a jsPDF instance .get('pdf') .then(pdf => { pdf.addPage() }) .from(page) .toContainer() .toCanvas() .toPdf() }) }
got these code from above or another issue i think.
This fixes the problem yes!
Hola y una pregunta y como prodria hacer para que el contenido se agregue a continuación del anterior ejemlplo quiero hacer el metodo que tienen agregar las paginas pero deseo agregar justo donde terminar el primero ya que como mi contenido es dinamico no se cuando este termine.
@GAVTIN here is how i resolved my issue with the canvas height limitation: I added aria-label to my divs dynamically, where i can logically divide them.
<div aria-label={`pdf-page-` + ++i}>
then upon generating the pdf, I broke the html elements to an array and then combined them to a single pdf file.
const pages = Array.from(input.querySelectorAll('div[aria-label^="pdf-page-"]')) let worker = html2pdf() .set(pdfOptions) .from(pages[0]) worker = worker.toPdf() // worker is now a jsPDF instance if (pages.length > 1) { // add each element/page individually to the PDF render process pages.slice(1).forEach((page, index) => { worker = worker //worker = worker.toPdf() // worker is now a jsPDF instance .get('pdf') .then(pdf => { pdf.addPage() }) .from(page) .toContainer() .toCanvas() .toPdf() }) }
got these code from above or another issue i think.
This fixes the problem yes!
@GAVTIN Hyperlink content not able to click in exported pdf this issue we are faced.
Any update? still facing the issue when pages are more than 70
I ran this problem as well and @MaNuGitH's workaround didn't work for me. I wrote a function that might be helpful for someone. Lucky for me the new branch
new-api
exposes more functions and breaks the process of turning html into a pdf into several steps. I notice that I can output my html as an image created from being drawn onto a canvas which is pretty much the last step before turning it into a PDF. So, I decided to create my own instance ofjsPDF
and only pass in a page at a time tohtml2pdf
. Then I add the image created byhtml2pdf
to my instance ofjsPDF
. I hope this is helpful.import html2pdf from 'html2pdf.js'; import jsPDF from 'jspdf'; const exportHTMLToPDF = async (pages, outputType='blob') => { const opt = { margin: [0,0], filename: 'myfile.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { dpi: 192, letterRendering: true }, jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' } }; const doc = new jsPDF(opt.jsPDF); const pageSize = jsPDF.getPageSize(opt.jsPDF); for(let i = 0; i < pages.length; i++){ const page = pages[i]; const pageImage = await html2pdf().from(page).set(opt).outputImg(); if(i != 0) { doc.addPage(); } doc.addImage(pageImage.src, 'jpeg', opt.margin[0], opt.margin[1], pageSize.width, pageSize.height); } // This can be whatever output you want. I prefer blob. const pdf = doc.output(outputType); return pdf; }
You can also write it using recursion if you can't use async-await.
Hey , thanks for the solution as it is working and I am able to download pages with around 230 pages. But there is a new issue which I encountered the pdf css is not as in original page.
Anyone encountered the same problem? @eKoopmans
@GAVTIN here is how i resolved my issue with the canvas height limitation:
I added aria-label to my divs dynamically, where i can logically divide them.
<div aria-label={`pdf-page-` + ++i}>
then upon generating the pdf, I broke the html elements to an array and then combined them to a single pdf file.
const pages = Array.from(input.querySelectorAll('div[aria-label^="pdf-page-"]')) let worker = html2pdf() .set(pdfOptions) .from(pages[0]) worker = worker.toPdf() // worker is now a jsPDF instance if (pages.length > 1) { // add each element/page individually to the PDF render process pages.slice(1).forEach((page, index) => { worker = worker //worker = worker.toPdf() // worker is now a jsPDF instance .get('pdf') .then(pdf => { pdf.addPage() }) .from(page) .toContainer() .toCanvas() .toPdf() }) }
got these code from above or another issue i think.
I am using the same code in my project, but when there are multiple pages(more than 20) my application becomes static/hanging . I am not able to interact with my webpage, not able to click on the buttons etc..
To solve this I passed the whole html at-once to html2Pdf() instead of the loop. But in that case if there are multiple pages(more than 20), then pages are blank in the pdf
version: html2pdf.js@0.9.3 I hope this is helpful
my html code like this:
<div class="sep">xxxx</div>
<div class="sep">xxxx</div>
<div class="sep">xxxx</div>
<div class="sep">xxxx</div>
.sep
is a empty css class name, it is used to manual split large content into small chunk
js code
const pages = document.querySelectorAll('.sep');
const worker = html2pdf();
for (let i = 0; i < pages.length; i++){
const page = pages[I];
await worker.from(page).toPdf();
}
worker.save()
Hi @GGross5213 ,
I am still learning JS and I am running into the same problem and I was wondering how can I implement your workaround in my case.
Currently, I have a dynamic content and I am using @eKoopmans plugin to generate a PDF report for it.
So this is my current function:
$("#download").click(function(){ filename = this.value + '.pdf' var element = document.getElementById('report'); html2pdf(element, { margin: 0.25, filename: filename, image: { type: 'jpeg', quality: 0.98 }, html2canvas: { dpi: 96, letterRendering: true }, jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' } }); });
and I would like to know where should I put my "element" variable into your function in order to have it working?
I would much appreciate if you could give me hand with it.
I have this same implementation and issue, did you find any concrete solution for the same.
For those who are having issues exporting documents with many pages and find that they export blank, here is a solution I’ve found. When the document has more than 30 pages, I’ve noticed it exports empty. However, by separating the sections and processing them in batches of 30, I can avoid this problem. Then, I simply merge the results and download the final file. This method is faster than other solutions that process each section individually.
const exportFunction = async (idElement: string, nameFile: string, pageOrientation = 'portrait') => {
await new Promise(resolve => setTimeout(resolve, 0));
const element = document.getElementById(idElement);
if (!element) return;
const opt = {
margin: [0, 0, 0, 0],
filename: nameFile,
image: { type: 'jpeg', quality: 0.99 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'in', format: 'letter', orientation: pageOrientation },
pagebreak: { mode: ['avoid-all', 'css', 'legacy'] },
};
const sections = Array.from(element.children);
if (sections.length > 30) {
let worker = html2pdf().set(opt);
const processInBatches = async () => {
const batchSize = 30;
for (let i = 0; i < sections.length; i += batchSize) {
const batchElement = document.createElement('div');
const batchSections = sections.slice(i, i + batchSize);
batchSections.forEach(section => batchElement.appendChild(section.cloneNode(true)));
await worker.from(batchElement).toContainer().toCanvas().toPdf().get('pdf').then((pdf) => {
if (i + batchSize < sections.length) {
pdf.addPage();
}
});
}
await worker.save();
};
await processInBatches();
} else {
await html2pdf().set(opt).from(element).save();
}
};
Hi @eKoopmans,
Firstly, I want to thank you for writing this great file. It saves me a lot of time dealing with the quality of content and layout. Recently, I was playing around with this file and vue js and found an issue:
https://jsfiddle.net/rover1234/woa5ucyx/
In two tests in the link, I created a simple for loop which shows 5 texts on the screen, and it is fine to output to a pdf file with 5 pages which show these texts since I apply your page break. However, in the second test, it failed to show the content of more than 20 texts which are all blank pages even though the page break still works fine.
I am not sure about this case. Is it because the picture generated from canvas is too large? and how could I find a way to get away from it (like creates multiple elements to generate different pdf content and combine everything into one file)?
Thanks