eKoopmans / html2pdf.js

Client-side HTML-to-PDF rendering using pure JS.
MIT License
4.06k stars 1.37k forks source link

0.9.1: I can't make the page-break options work at all #184

Open AbelVM opened 5 years ago

AbelVM commented 5 years ago

I have tested all the combinations of options with the same result: the pages break wherever they needs to, regardless the avoid settings or mode, the CSS properties and so on. The DOM flows across the page break.

If using legacy code to force break the page, the next element is moved to the next page break and then split too!! Leaving a blank page behind...

I've seen the PRs and others issues about the same subject, but no movement since 0.9.1 was released, more than a month ago, and in my project at least, this feature is plainly broken :disappointed: . Everything worked OK for me till I needed a multipage export, now I'm totally lost.

foria commented 5 years ago

+1

eKoopmans commented 5 years ago

Hi @AbelVM @foria, things move a bit slowly here, you'll have to bear with me. As I see it there's three possible issues here:

  1. Page breaks aren't working for you at all. Is this the case? Try out this test Fiddle, which showcases all the different kinds of page-breaks you can use.

  2. Pages break in the middle of text when you have elements longer than one page. This is a more complicated issue that there's no fix for currently, but the vast majority of page-break needs should have been resolved with v0.9.1.

  3. Something else? If it's not one of the two above, give me an example so I can reproduce it and see what's going on.

Thanks!

AbelVM commented 5 years ago

Hi @eKoopmans , I've played with that example before, it works flawless but looks like it's not applicable on my end.

I'm working with dynamically generated tables (with head and body), and any available combination of page break related options leads to undesirable results. My first case has 4 DIVs (1st with some charts, the rest with tables):

I can't recall now all the tests I've performed, but I can assure you I spent a lot of time testing all the different combinations I could imagine with no result but hundreds of failed PDFs in my download folder :stuck_out_tongue_closed_eyes:

eKoopmans commented 5 years ago

Have you tried anything like:

html2pdf().set({
    pagebreak: {avoid: 'tr'}
});

That's specifically telling it to avoid breaking across a table row - the "modes" are only one small part of what the pagebreak functionality can do. That said, tables are tricky and don't behave like most other elements, they may still need some work.

AbelVM commented 5 years ago

Yep, for each and every CSS selector that I could imagine to "protect" my tables from splitting :(

eKoopmans commented 5 years ago

:) Okay well if you can give me an example I'll put it in the queue of things to fix, a jsFiddle or something would help (you can fork the template). My guess is it boils down to tables not behaving like everything else, and I may need to program in a special case for that. No promises on timeline though, there's a long list of things that need work!

AbelVM commented 5 years ago

Sure. It may take some time, as the current project it's being used in is an internal one with non-public data, so I need to build a specific report with fake data and some other tweaks.

One of my suspects for this issue is flexboxes being used all around... Maybe html2PDF is being fooled by flexboxes? I've tried to apply a variation of the SVG trick with the onrender function to explicitly set the height and width (#185). No success.

Alcoine commented 5 years ago

@eKoopmans Hi, is your lib supports flex boxes? Cuz, I've got the same issue with page-brakes if I'm using flex boxes, but it's okay if not ;(

UPD: I can confirm that the entire problem with the pagebreaks is a flexbox model. Right now I switched from a flex box model to a box model (display: block-inline, etc.);

eKoopmans commented 5 years ago

Hi @Jujeu, thanks for finding that out! I think what you've found is a separate issue from @AbelVM, who I believe is having issues with regular tables, no flex involved.

Under the hood we use html2canvas to convert the HTML to an image, so my guess is that flex-boxes aren't supported there. I'd recommend testing html2canvas on its own with some flex-boxes, and see if they're behaving as intended - if not, you could open an issue over there about flex.

If it's only an issue in html2pdf (and works fine in html2canvas), please open a new issue here about it so we can investigate further!

AbelVM commented 5 years ago

Hi @eKoopmans, my tables are:

eKoopmans commented 5 years ago

Ah okay, so flexboxes are relevant for you too! Good to know. For what it's worth, I think there could be table issues even without flexboxes involved, but that will add to the challenge. Thanks for the info!

Edit: Sorry, I missed that you had already mentioned flexboxes in your earlier post.

AbelVM commented 5 years ago

Moved from flex to block, same behavior :disappointed:

Alcoine commented 5 years ago

Moved from flex to block, same behavior 😞

@AbelVM Hey, can you provide a fiddle with a chunk of your code? Are you using the data-html2canvas-ignore feature?

eKoopmans commented 5 years ago

Hi, I've attempted a fix just for tables (nothing about flex yet). Give it a try: https://github.com/eKoopmans/html2pdf/tree/bugfix/pagebreak-tables/dist/

I haven't been able to reproduce the table issues yet on my end, so I can't say whether the fix will work, but give it a shot and let me know how it goes!

candice-chang commented 5 years ago

@eKoopmans new bug fix works for me, Thanks.

zorent-zebra commented 4 years ago

@eKoopmans thank you so much for providing this awesome library.

I think that the running count for the height of pages for a PDF exporting tables is off by a couple of pixels. pagebreak: {avoid: 'tr'} runs really great until around page 13 - 15 for us. At that point the top line gets cut off, and with each subsequent page it's cut off a tiny bit more.

To fix this we employed manual page breaks. Here are our settings: pagebreak: {mode: 'css', after: '.avoidThisRow'}

Then we got the height of the exported letter-sized PDF from here: https://github.com/MrRio/jsPDF/blob/master/docs/modules_html.js.html#L728 Since we're always exporting in landscape, the height was 612. We then multiplied that by 1.33333, since that's the point-to-pixel conversion.

We then looped through our table and kept a running count of the height. When the running height total exceeded 612 1.3, we added the avoidThisRow class to the previous TR. To offset the library's page height calculations, we'd add a padding of ((numberOfPages - 1) 2) + 8 to the top of the current row. We'd then reset our running height count to 0 - (numberOfRows / 40). Right now I'm not sure why we didn't employ the same math for the padding and starting height.

Yeah, this is quite a gizmodic solution. So far it seems to work. I'm posting this so that it may help with somebody else with this issue, or possibly eventually help towards a fix to the library.

Thank you again for this crazy wicked awesome library. It was crucial for a feature we just built.

gillespieza commented 4 years ago

Just to comment here, because my experience might help. I also had issues with the page breaks. My document was about 15 pages long. I discovered the pixel limitation on the canvas size was the main issue. It worked much better when I chained sending individual sections/divs to the canvas, creating a new page in the PDF, and saving the whole PDF at the end.

darbandi commented 3 years ago

Have you tried anything like:

html2pdf().set({
    pagebreak: {avoid: 'tr'}
});

That's specifically telling it to avoid breaking across a table row - the "modes" are only one small part of what the pagebreak functionality can do. That said, tables are tricky and don't behave like most other elements, they may still need some work.

that's great ... it's working. thank you so much ❤❤❤❤❤❤❤

mjmicro commented 3 years ago

@eKoopmans, Can it work in flex div as well, Currently i am facing issue with line split into two pages.

Screenshot 2021-07-08 at 6 42 37 PM

Is there a way we can fix this, i'm using v0.9.1?

albertomanzano11 commented 2 years ago

@mjmicro For that case i have approach a partial-solution where divs overlap on pages :

.set({...options, mode: ['legacy'], margin: [0.2, 0.1, 0.6, 0.2], pagebreak: { after: 'section'}})

I have set my options to have a margin-bottom of 0.6 and you can set pagebreak to automatically break afer each section :

<section class="pdf-item">
    <div class="myStyle">
       ....your content
     </div>
</section>

<section class="pdf-item">
    <div class="myStyle">
       ....your content
     </div>
</section>

etc...

Then set myStyle to:

.myStyle {
   overflow-wrap: break-word;
    word-wrap: break-word;
    -ms-word-break: keep-all;
    word-break: keep-all;
    -ms-hyphens: auto;
    -moz-hyphens: auto;
    -webkit-hyphens: auto;
    hyphens: auto;
     }

Theres still some cases where it could be better. Does someone found a better solution ?

Best regards.

albertomanzano11 commented 2 years ago

UPDATED Solution from my last response:

I solved on my projects using this options:

<vue3-html2pdf
        :show-layout="false"
        :float-layout="true"
        :enable-download="false"
        :preview-modal="false"
        filename="memoria-del-projecte.pdf"
        :pdf-quality="1"
        :manual-pagination="true"
        pdf-format="a4"
        pdf-orientation="portrait"
        pdf-content-width="800px"
        ref="html2Pdf"
        @beforeDownload="beforeDownload($event)"
      >

---

.set({
          ...options,
              margin: [0,15, 15, 15],
             filename: 'pdfFileName.pdf',
             image:        { type: 'jpeg', quality: 0.98 },
             html2canvas:  { scale: 1, letterRendering: true },
             jsPDF:        { unit: 'pt', format: 'letter', orientation: 'portrait' },
            pagebreak: { after: 'section', mode: ['avoid-all', 'css', 'legacy'] }
        })

I had a 60 pages PDF, so i divide my PDF into sections and break after each section.

<section class="pdf-item">
    <div class="myStyle keeptogether">
       ....your content
     </div>
</section>

<section class="pdf-item">
    <div class="myStyle keeptogether">
       ....your content
     </div>
</section>

The other problem i had was those super long text's I used this class for those super text's, in order to break if text was too long.

.keeptogether {page-break-inside:avoid; break-inside: avoid;}
.myStyle {

// for me had to do some teeeks on wordbreaking
   overflow-wrap: break-word;
    word-wrap: break-word;
    -ms-word-break: keep-all;
    word-break: keep-all;
    -ms-hyphens: auto;
    -moz-hyphens: auto;
    -webkit-hyphens: auto;
    hyphens: auto;
     }
PATELNAMRATA commented 8 months ago

i use this code for sap.m table but it's not work i want all content in single page in sapui5 i'm not able to work my page break functionality

var options = {
            filename: filename,
            image: { type: 'jpeg', quality: 1.0 },
            html2canvas: {
                scale: 1, // Adjust this value to fit more content into a single page
                dpi: 95, // Increase the DPI for better quality
                useCORS: true,
                letterRendering: true
                // pagebreak: { mode: 'avoid-all' } // Avoid page breaks
            },
            jsPDF: { unit: 'pt', format: 'a4', orientation: 'p' },
        };

        var source = this.byId("idMyExpense").getDomRef();

        html2pdf().from(source).set(options).outputPdf().save();
        that.closeBusyDialog();
TizonX commented 6 months ago

you can try with different unit:

"mm": Millimeters "cm": Centimeters "in": Inches "pt": Points (1/72 of an inch) "px": Pixels

In my case unit: "pt" works fine.

also use margin to adjust your page size.