Banner of how to create pdf with python from html

How to Generate PDFs from Jinja2 Templates in Python


Category: Python

Date: 28 hours ago
Views: 125


How to Generate PDFs from Jinja2 Templates Using Python

In this tutorial, we will show you how to use a Python script to generate beautiful PDFs from Jinja2 templates. Whether you're creating invoices, reports, or any custom documents, this method allows you to automate the generation of PDFs directly from templates. We will also discuss the importance of using a local Python environment and good practices to keep your projects organized and manageable.

Prerequisites

Before we start, ensure that you have the following tools and libraries installed:

Python: The programming language for this script.

Jinja2: A templating engine used to generate HTML from data.

pdfkit: A Python wrapper for wkhtmltopdf, which converts HTML to PDF.

wkhtmltopdf: A command-line tool for rendering HTML into PDFs.

Install the necessary libraries using the following commands:

    
pip install jinja2 pdfkit
    

Additionally, ensure that wkhtmltopdf is installed on your system:

    
sudo apt-get install wkhtmltopdf
    

Setting Up the Virtual Environment

It's a good practice to use a local Python environment for your projects. This helps keep your dependencies isolated and ensures that your project is not affected by global Python packages. Follow these steps to set up the environment:

    
# Create a new directory for your project if you haven't already
mkdir ~/my_project
cd ~/my_project

# Create a virtual environment in ~/bin/env
python3 -m venv ~/bin/env

# Activate the environment
source ~/bin/env/bin/activate

# Install the necessary Python dependencies
pip install jinja2 pdfkit
    

Once the environment is set up, you can simply activate it by running:

    
source ~/bin/env/bin/activate
    

Creating the Template

Next, create a Jinja2 template to define the structure and design of your PDF. In this example, we’ll create a simple template with a title, content, a list of items, and an image.

    
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title }}</title>
    <!-- Bootstrap CSS -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
    <style>
        /* Custom styles for PDF generation */
        @page {
            size: A4;
            margin: 1cm;
        }

        body {
            font-family: 'Arial', sans-serif;
            line-height: 1.5;
            margin: 0;
        }

        .header, .footer {
            background-color: #f8f9fa;
            padding: 10px;
            text-align: center;
            color: #333;
        }

        .header h1 {
            margin: 0;
            font-size: 1.8rem;
            color: #007bff;
        }

        .footer p {
            margin: 0;
            font-size: 0.9rem;
        }

        .content {
            padding: 20px;
        }

        .content h2 {
            color: #28a745;
            margin-top: 20px;
        }

        .content p {
            text-align: justify;
        }

        .content blockquote {
            background-color: #f1f3f4;
            border-left: 4px solid #007bff;
            padding: 10px 15px;
            font-style: italic;
            color: #555;
            margin: 20px 0;
        }

        .content .table {
            margin-top: 20px;
        }

        .content .btn {
            display: inline-block;
            margin-top: 15px;
        }

        .highlight {
            color: #dc3545;
            font-weight: bold;
        }

        .list-group-item {
            background-color: #f9f9f9;
            color: #333;
        }

        .list-group-item:hover {
            background-color: #007bff;
            color: #fff;
        }

        .img-container {
            text-align: center;
            margin-top: 20px;
        }

        .img-container img {
            max-width: 50%;
            height: auto;
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>{{ title }}</h1>
        <p>PDF generated using Jinja2 and PDFKit</p>
    </div>

    <div class="content container">
        <h2>Introduction</h2>
        <p>{{ content }}</p>

        <h2>Highlighted Text</h2>
        <p>You can use <span class="highlight">colors and bold text</span> to draw attention to key points in your PDF.</p>

        <h2>Table Example</h2>
        <table class="table table-bordered">
            <thead class="thead-dark">
                <tr>
                    <th>Item</th>
                    <th>Description</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Example 1</td>
                    <td>This is the first example item.</td>
                    <td>$10</td>
                </tr>
                <tr>
                    <td>Example 2</td>
                    <td>This is the second example item.</td>
                    <td>$20</td>
                </tr>
            </tbody>
        </table>

        <h2>List Example</h2>
        <ul class="list-group">
            {% for item in items %}
            <li class="list-group-item">{{ item }}</li>
            {% endfor %}
        </ul>

        <h2>Blockquote Example</h2>
        <blockquote>
            "This is a beautifully styled blockquote to emphasize key ideas."
        </blockquote>

        <h2>Image Example</h2>
        <div class="img-container">
            <img src="{{ image_path }}" alt="Example Image">
        </div>

        <h2>Button Example</h2>
        <a href="https://mosaid.xyz" class="btn btn-primary">Click Me</a>
    </div>

    <div class="footer">
        <p>{{ footer }}</p>
    </div>

    <!-- Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.4.4/dist/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>


    

Save this file as template.html in your project directory.

Generating the PDF

Now let’s use a Python script to generate the PDF from the Jinja2 template. Below is the script that takes the template, renders it with data, and generates the PDF:

    
import pdfkit
from jinja2 import Environment, FileSystemLoader
import os
import sys
from datetime import datetime

def generate_pdf(template_file, output_dir="./output"):
    # Create output directory if it doesn't exist
    os.makedirs(output_dir, exist_ok=True)

    # Extract the directory and filename from the template file
    template_dir = os.path.dirname(template_file)
    template_name = os.path.basename(template_file)

    # Set up Jinja2 environment
    env = Environment(loader=FileSystemLoader(template_dir))
    template = env.get_template(template_name)

    # Define data to be rendered in the template
    data = {
        "title": "Jinja2 to PDF Example",
        "content": "This is a PDF generated using Jinja2 and pdfkit.",
        "items": ["Introduction", "Body Content", "Conclusion"],
        "footer": "Generated by Radouan MOSAID",
        "image_path": "/path/to/image.jpg",  # Absolute path
    }

    # Render the template with the data
    rendered_html = template.render(data)

    # Get the current date string in YYYY-MM-DD format
    date_str = datetime.now().strftime("%Y-%m-%d")

    # Output PDF file path with the date appended to make it unique
    output_pdf_path = os.path.join(output_dir, f"output_{date_str}.pdf")

    # Define pdfkit options to enable local file access
    options = {
        'enable-local-file-access': '',  # Allow access to local files
    }

    # Convert the rendered HTML to a PDF with options
    pdfkit.from_string(rendered_html, output_pdf_path, options=options)

    print(f"PDF has been created successfully: {output_pdf_path}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <template_file>")
        sys.exit(1)

    # Get the template file from the command-line arguments
    template_file = sys.argv[1]

    # Check if the file exists
    if not os.path.isfile(template_file):
        print(f"Error: Template file '{template_file}' not found.")
        sys.exit(1)

    # Generate PDF
    generate_pdf(template_file)


    

This script loads the template, renders it with the provided data, and outputs a PDF to the specified directory. The path to the image is provided as an absolute path to avoid errors.

Running the Script

To run the script, simply execute it from your terminal while in the project directory:

    
python script.py template.html
    

This will generate a PDF file with the rendered content. The output PDF will be saved in the output directory with a unique name based on the current date.

generated PDF file
generated PDF file

Handling Errors

Sometimes, you might encounter issues like missing image files or incorrect file paths. Make sure to:

• Check the file path of the image used in the template.

• Ensure that --enable-local-file-access is set in the pdfkit options to allow local file access.

• Use absolute paths for local files to avoid any issues related to relative paths.

Customizing Your PDF

You can customize the PDF output by modifying the template, adding more dynamic data to the Jinja2 context, and adjusting the CSS styling. For example, you could change the page layout, font styles, or add additional sections like tables or charts.

Conclusion

In this tutorial, we’ve shown how to create PDFs using Jinja2 templates and Python. By organizing your code into a local Python environment and following best practices for managing dependencies, you can easily generate custom documents automatically. This process can be extended and customized for various use cases, making it an efficient way to automate document generation.



125 views


Previous Article

0 Comments, latest

No comments yet. Be the first to Comment.