VinnieS
VinnieS

Reputation: 85

html2pdf fit image to pdf

I finally got my html2pdf to work showing my web page just how I want it in the pdf(Any other size was not showing right so I kept adjusting the format size until it all fit properly), and the end result is exactly what I want it to look like... EXCEPT even though my aspect ratio is correct for a landscape, it is still using a very large image and the pdf is not standard letter size (Or a4 for that matter), it is the size I set. This makes for a larger pdf than necessary and does not print well unless we adjust it for the printer. I basically want this exact image just converted to a a4 or letter size to make a smaller pdf. If I don't use the size I set though things are cut off.

Anyway to take this pdf that is generated and resize to be an a4 size(Still fitting the image on it). Everything I try is not working, and I feel like I am missing something simple.

 const el = document.getElementById("test);
    var opt = {
      margin: [10, 10, 10, 10],
      filename: label,
      image: { type: "jpeg", quality: 0.98 },
      //pagebreak: { mode: ["avoid-all", "css"], after: ".newPage" },
      pagebreak: {
        mode: ["css"],
        avoid: ["tr"],
        //    mode: ["legacy"],
        after: ".newPage",
        before: ".newPrior"
      },
      /*pagebreak: {
      before: ".newPage",
      avoid: ["h2", "tr", "h3", "h4", ".field"]
    },*/
      html2canvas: {
        scale: 2,
        logging: true,
        dpi: 192,
        letterRendering: true
      },
      jsPDF: {
        unit: "mm",
        format: [463, 600],
        orientation: "landscape"
      }
    };

   
      var doc = html2pdf()
     
        .from(el)
        .set(opt)
        .toContainer()
        .toCanvas()
        .toImg()
        .toPdf()
         .save()

Upvotes: 0

Views: 10769

Answers (2)

K J
K J

Reputation: 11857

The core problem here, is the common one of layout specification not matching expectation.

The core units of PDF production (/UserUnits) are met by page sizes are fixed before any other process.

So the relevant part from question will be,

jsPDF: {
        unit: "mm",
        format: [463, 600],
        orientation: "landscape"
      }

The desired size is for example, one not big enough. enter image description here

A4 Landscape

var doc = new jsPDF({
 orientation: 'l',
 unit: 'mm',
 format: 'a4',
 floatPrecision: 6,
});

Then it is as easy as any "Computer Aided Design" (CAD) task, change units to smaller. enter image description here You know your initial starting sheet size and can write all the prior code to achieve that basic media layout.
A4 Landscape

var doc = new jsPDF({
 orientation: 'l',
 unit: 'pt',
 format: 'a4',
 floatPrecision: 6,
});

Upvotes: 0

tobyvd
tobyvd

Reputation: 148

I have been struggling with this a lot as well. In the end I was able to resolve the issue for me. What did the trick for me was setting the width-property in html2canvas. My application has a fixed width, and setting the width of html2canvas to the width of my application, scaled the PDF to fit on an A4 paper.

html2canvas: { width: element_width},

Try adding the above option to see if it works. Try to find out the width of your print area in pixels and replace element_width with that width.

For completeness: I am using Plotly Dash to create web user interfaces. On my interface I include a button that when clicked generates a PDF report of my dashboard. Below I added the code that I used for this, in case anybody is looking for a Dash solution. To get this working in Dash, download html2pdf.bundlemin.js and copy it to the assets/ folder. The PDF file will be downloaded to the browsers default downloads folder (it might give a download prompt, however that wasn't how it worked for me).

from dash import html, clientside_callback
import dash_bootstrap_components as dbc

# Define your Dash app in the regular way

# In the layout define a component that will trigger the download of the 
# PDF report. In this example a button will be responsible.
app.layout = html.Div(
    id='main_container',
    children = [
        dbc.Button(
            id='button_download_report',
            children='Download PDF report',
            className='me-1')
     ])

# Clientside callbacks allow you to directly insert Javascript code in your
# dashboards. There are also other ways, like including your own js files
# in the assets/ directory.  
clientside_callback(
    '''
    function (button_clicked) {
        if (button_clicked > 0) {
            // Get the element that you want to print. In this example the 
            // whole dashboard is printed
            var element = document.getElementById("main_container")

            // create a date-time string to use for the filename
            const d = new Date();
            var month = (d.getMonth() + 1).toString()
            if (month.length == 1) {
                month = "0" + month
            }
            let text = d.getFullYear().toString() + month + d.getDay() + '-' + d.getHours() + d.getMinutes();

            // Set the options to be used when printing the PDF
            var main_container_width = element.style.width;
            var opt = {
                margin: 10,
                filename: text + '_my-dashboard.pdf',
                image: { type: 'jpeg', quality: 0.98 },
                html2canvas: { scale: 3, width: main_container_width, dpi: 300 },
                jsPDF: { unit: 'mm', format: 'A4', orientation: 'p' },
                // Set pagebreaks if you like. It didn't work out well for me.
                // pagebreak: { mode: ['avoid-all'] }
            };
            // Execute the save command. 
            html2pdf().from(element).set(opt).save();
        }
    }
    ''',
    Output(component_id='button_download_report', component_property='n_clicks'),
    Input(component_id='button_download_report', component_property='n_clicks')
)

Upvotes: 0

Related Questions