How to create and download pdf file

hi all,

I want to create a pdf and download this pdf when a button is pressed. I started from this tutorial and modify
a code but the downloaded file cannot be opened.
Upload and Download Files with Plotly Dash

Below is my code:

import base64
import os

from flask import Flask, send_from_directory

# imports for the dashboard creation
import dash
import dash_html_components as html
from dash.dependencies import Input, Output
from dash_extensions.snippets import send_file
from dash_extensions import Download

import numpy as np

from io import BytesIO


# imports for the pdf creation
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import ParagraphStyle



UPLOAD_DIRECTORY = "/files/pdf"

# create folder if not yet created
if not os.path.exists(UPLOAD_DIRECTORY):
    os.makedirs(UPLOAD_DIRECTORY)



# Normally, Dash creates its own Flask server internally. By creating our own,
# we can create a route for downloading files directly:
server = Flask(__name__)
app = dash.Dash(server=server)


# Dash Layout
app.layout = html.Div(
    [
        html.Div([html.Button("Download File", id="button_download_file", n_clicks=0), Download(id="download")]),
    ],
)


@server.route("/download/<path:path>")
def download(path):
    """Serve a file from the upload directory."""
    
    
    # Create PDF
    #-----------
    pdf_buffer = BytesIO()
    elements = []
    # create style
    doc = SimpleDocTemplate(pdf_buffer)
    style_title_header = ParagraphStyle(name = 'Title')       
    # Create Paragraph.
    elements.append(Paragraph('hello world !!!', style_title_header))
    # create pdf
    doc.multiBuild(elements)
        
    # store pdf file
    with open(path, "wb") as fp:
#        fp.write(base64.decodebytes(pdf_buffer.getvalue()))
        fp.write(base64.decodebytes(pdf_buffer.read()))

    
    
@app.callback(Output("download", "data"),
                [Input("button_download_file", "n_clicks")])
def download_file(n_clicks):
    if n_clicks>0:
        
        # pdf file name
        pdf_name = 'test.pdf'  
        
        # init path of the pdf file 
        path = os.path.join(UPLOAD_DIRECTORY, pdf_name)
        
        
        # create pdf and store it
        download(path)
        
        
        return send_file(path, mime_type='application/pdf')

    else:
        return None


if __name__ == "__main__":
    app.run_server(debug=True)
    
    

@cedric51
Hi generated the pdf using html2pdf hope u find out helpfull
python code

import pandas as pd 
import datetime as dt

import plotly.offline as pyo 
import plotly.graph_objs as go 
import plotly.express as px

import dash
import dash_core_components as dcc 
import dash_html_components as html 
import dash_bootstrap_components as dbc

from dash.dependencies import Input, Output, State

labels = ['Oxygen','Hydrogen','Carbon_Dioxide','Nitrogen']
values = [4500, 2500, 1053, 500]

app = dash.Dash(__name__,external_stylesheets=[dbc.themes.BOOTSTRAP])

card1 = dbc.Card([
    dbc.CardBody([
        html.P(['2 His Majesties Letter to the Lord Thresurer & other of the Lords to deliver the Charge of the Tower & Prisones thereunto S.r Wm Wade Knight which was done by the Earle of Dorsett and the Earle of Devonshire on Thursday in the Afternoon, at the Clock being the 15 of Aug. 1605'],
                className = "narrative"
            )
    ])
],className='cardDesign')

card2 = dbc.Card([
    dbc.CardBody([
               dcc.Graph(figure=dict(
                   data=[go.Pie(labels=labels,values=values)],
                   layout=dict(autosize=True)
               ),
               responsive=True,
               )
    ])        
],className='cardDesign')


card2_1 = dbc.Card([
    dbc.CardBody([
               dcc.Graph(figure=dict(
                   data=[go.Pie(labels=labels,values=values)]
               ))
    ])
 ],className='cardDesign')

card2_2 = dbc.Card([
    dbc.CardBody([
               dcc.Graph(figure=dict(
                   data=[go.Pie(labels=labels,values=values)]
               ))
    ])
 ],className='cardDesign')

card3 = dbc.Card([
    dbc.CardBody([
               dcc.Graph(figure=dict(
                   data=[go.Bar(x=labels,y=values)]
               ))
    ])        
],className='cardDesign')

app.layout = html.Div([
    html.Div([
        dbc.Row([
            dbc.Col([
                html.H3(['Report PDF Generator'])
            ]),
        ]),

        dbc.Row([
            dbc.Col([
                card1
            ],id="col1"),
        ]),

        dbc.Row([
            dbc.Col([
                card2
            ],id="col2"),
        ]),

        dbc.Row([
        dbc.Col([
            dbc.Row([
                dbc.Col([card2_1],xs=12, sm=12, md=12, lg=6, xl=6,id="col3"),
                dbc.Col([card2_2],xs=12, sm=12, md=12, lg=6, xl=6,id="col4"),
            ])
        ]),
    ]),

        dbc.Row([
            dbc.Col([
                card3
            ],id="col5"),
        ]),
    ],id='print'),
    dbc.Button(children=['Download'],className="mr-1",id='js',n_clicks=0),
],id='main',)

app.clientside_callback(
    """
    function(n_clicks){
        if(n_clicks > 0){
            var opt = {
                margin: 1,
                filename: 'myfile.pdf',
                image: { type: 'jpeg', quality: 0.98 },
                html2canvas: { scale: 3},
                jsPDF: { unit: 'cm', format: 'a2', orientation: 'p' },
                pagebreak: { mode: ['avoid-all'] }
            };
            html2pdf().from(document.getElementById("print")).set(opt).save();
        }
    }
    """,
    Output('js','n_clicks'),
    Input('js','n_clicks')
)

if __name__ == '__main__':
    app.run_server(port='8050',debug=True)

js code

function addScript(url) {
    var script = document.createElement('script');
    script.type = 'application/javascript';
    script.src = url;
    document.head.appendChild(script);
}
addScript('https://raw.githack.com/eKoopmans/html2pdf/master/dist/html2pdf.bundle.js');

css code

@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;600;700&display=swap');

#main{
    font-family: 'Montserrat', sans-serif;
  }

.cardDesign{
    box-shadow:0 4px 8px 0 rgba(0, 0, 0, 0.2);
    margin-top: 5px;
    margin-bottom: 5px;
}

Instead of:

doc.multiBuild(elements)
    
# store pdf file
with open(path, "wb") as fp:
    fp.write(base64.decodebytes(pdf_buffer.read()))

write:

doc.build(elements)

pdf_value = pdf_buffer.getvalue()
pdf_buffer.close()

    
# store pdf file
with open(path, "wb") as fp:
    fp.write(pdf_value)