Create or Sign a PDF in Python | Three Ways - Dropbox Sign (2024)

If you've ever done any sort of development work for a company of any size, you know that almost all companies send and receive information in more or less the same way: via PDF files.

Whether you're sending out newsletters or invoices, they're all delivered in PDF format, and just about every personal computing device on the planet has a PDF reader installed on it to be able to access these files.

For businesses, the ability to dynamically generate invoices based on sales data extracted from a database eliminates the rush to dispatch all invoices at the end of the month. Alternatively, a template-type PDF can be filled in with accurate information for specific users who've indicated that they're only interested in receiving newsletters for certain categories, like monthly specials.

In this article, you'll learn all about generating PDFs in a Python, a versatile scripting language. You'll be introduced to two popular PDF generation libraries for Python and learn how to leverage these libraries to generate your own PDF files. Additionally, you'll explore Dropbox Sign, an API that can be used to digitally sign PDF files using legally binding eSignatures.

Methods to generate a PDF in Python

Before you review specific tools/libraries for generating a PDF in Python, you need to prepare a Python project.

Set up a virtual environment

It's good practice to set up your Python project using virtual environments. While it's possible to run your Python script under the global Python interpreter, your global environment can end up cluttered if you keep installing packages that your project needs under the global system packages.

Additionally, if you package your virtual environment with your project, you can ensure that the installation process is smooth when you want to use the same project on another system.

When you upload your project to a code-sharing platform site like GitHub, it also simplifies virtual environment setup for other users who want to clone your project on their local systems.

There are all kinds of ways to set up a virtual environment. This tutorial uses an advanced package tool (APT)–based package manager, which means it may differ from your system. So adjust your commands accordingly.

The commands used in this tutorial are all run inside a terminal window on a Linux-based computer. Run the following commands:

# Make sure that Python3 and pip are installed.# Note that package names might also differ depending on the Linux distributionsudo apt install python3 pip

# Create your project directory, possibly in your user's home directory, like belowmkdir ~/python_pdfcd ~/python_pdf

# Create a virtual environment inside your project directory# The command below will create a directory called ".venv" inside your project directorypython3 -m venv .venv

Finally, activate your virtual environment using the newly supplied shell script:

# Activate the virtual environmentsource .venv/bin/activate

You should see that your prompt gets modified to show you that you're working inside a virtual environment for your Python project:

(.venv) user@localhost:~/projects/python_pdf$

You can deactivate the virtual environment by entering deactivate:

deactivateuser@localhost:~/projects/python_pdf$

If you want to install any project-specific modules, you should do so while your project's virtual environment is activated. This ensures that the module is only available to your project and not the global Python interpreter.

From here, you can also set up a Git repository for your project if that's how you normally do things, but this step is beyond the scope of this tutorial.

Now, it's time to create your first PDF using ReportLab.

Use ReportLab to create a PDF

ReportLab is a PDF library that lets you create PDF files using the Python language.

To include the ReportLab module in your project, remember to activate your virtual environment and run the following:

pip install reportlab

And that's it! That's all you need to do to include the module as part of your Python project.

Create a PDF with ReportLab

To create a PDF, start with a skeleton for your main script:

"""This is the main Python script for generating a PDF file using ReportLab"""# Importsimport sys# Global variables# Class declarations# Function declarationsdef main(): print("nothing to do! (yet)")# Main bodyif __name__ == '__main__': main()

This program will run as is, but it doesn't do anything except output "nothing to do! (yet)" to the console.

It's time to start modifying the code so that you can create a PDF file. ReportLab supports multiple methods for creating a PDF file, but you can start by using the Canvas class:

"""This is the main Python script for generating a PDF file using ReportLab"""# Importsimport sys# import the reportlab canvas objectfrom reportlab.pdfgen import canvas# import pagesizes you might needfrom reportlab.lib.pagesizes import A4# Global variables# Class declarations# Function declarationsdef main(): # create a Canvas object with a filename c = canvas.Canvas("hello_world.pdf", pagesize=A4) # Write text on the canvas c.drawString(50, 780, "Hello World") # Save the current page of the canvas c.showPage() # Save the file to disk c.save()# Main bodyif __name__ == '__main__': main()

Once you've run this code, you should have a hello_world.pdf file waiting for you in your project directory. Open it up, and you should see something like this:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (1)

As you can see, it worked! Now, it's time to expand the code and see what other options are available.

Draw shapes with ReportLab

Once you've created your PDF, you can modify your code to draw shapes using the ReportLab library. The following code is the entire main.py with all the necessary changes you need to draw some shapes on your canvas object:

"""This is the main Python script for generating a PDF file using ReportLab"""# Importsimport sys# import the reportlab canvas objectfrom reportlab.pdfgen import canvas# import pagesizes you might needfrom reportlab.lib.pagesizes import A4# Global variables# Class declarations# Function declarationsdef main(): # create a Canvas object with a filename c = canvas.Canvas("hello_world.pdf", pagesize=A4) # Write text on the canvas c.drawString(50, 780, "Hello World") # What else can we do? # draw all kinds of shapes # a line c.line(60,750,500,750) # an arc c.arc(160, 700, 360, 550) # a circle c.circle(300, 500, 50, stroke=1, fill=0) # Save the current page of the canvas c.showPage() # Save the file to disk c.save()# Main bodyif __name__ == '__main__': main()

This code draws a few shapes onto the canvas before saving it as a PDF:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (2)

Change fonts with ReportLab

Next, try changing the font of your string. For this, you're going to need a fonts directory in the root of your project path, and you'll need to drop a TrueType Font file (TTF) in that directory. There are plenty of free and open source TrueType fonts on the internet, and you can try any that you like. Here, Inter is used.

Once you've downloaded a font and extracted the TTF file to the fonts directory, take a look at the following code:

"""This is the main Python script for generating a PDF file using ReportLab"""# Importsimport sysfrom pathlib import Path# import the reportlab canvas objectfrom reportlab.pdfgen import canvas# import pagesizes you might needfrom reportlab.lib.pagesizes import A4# we need these for importing TrueType Fonts (TTF)from reportlab.pdfbase import pdfmetricsfrom reportlab.pdfbase.ttfonts import TTFont# Global variables# Class declarations# Function declarationsdef main(): # create a Canvas object with a filename c = canvas.Canvas("hello_world.pdf", pagesize=A4) # location of our TTF file ttf = Path('fonts/Inter-ExtraBold.ttf') # Register a font before we use drawString pdfmetrics.registerFont(TTFont('Inter-ExtraBold', ttf)) # Set the canvas font c.setFont('Inter-ExtraBold', 18) # Write text on the canvas c.drawString(50, 780, "Hello World") # What else can we do? # draw all kinds of shapes # a line c.line(60,750,500,750) # an arc c.arc(160, 700, 360, 550) # a circle c.circle(300, 500, 50, stroke=1, fill=0) # Save the current page of the canvas c.showPage() # Save the file to disk c.save()# Main bodyif __name__ == '__main__': main()

Look carefully at these lines:

ttf = Path('fonts/Inter-ExtraBold.ttf') pdfmetrics.registerFont(TTFont('Inter-ExtraBold', 'fonts/Inter-ExtraBold.ttf')) c.setFont('Inter-ExtraBold', 18)

Make sure to set these values according to the font file you downloaded and extracted to the fonts directory.

Run the script to confirm that the font has changed:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (3)

Other things to try with ReportLab

ReportLab has a lot more features available. If you're interested in learning more, check out their documentation to find out more about features such as the following:

ReportLab also has a ReportLab PLUS library, which is a paid library that supports creating PDF files using a templating language called Report Markup Language (RML). This allows you to create PDF files using a structure similar to HTML.

The code for this example project is available on GitHub.

PDFKit

PDFKit is another popular Python package that can generate PDF files. However, it has a different methodology when it comes to creating PDFs. Instead of manipulating a blank canvas, it allows you to take standard HTML pages and convert them to PDF.

This approach works wonderfully for developers who might already be well versed in HTML, while others might find the clean slate approach that ReportLab offers more appealing.

Follow the same instructions for preparing a Python project as before but in a separate directory and virtual environment. Additionally, create the same skeleton script as was used previously.

Then install PDFKit into your activated virtual environment using the following command:

pip install pdfkit

PDFKit also requires the wkhtmltopdf binary to be installed on the system.

On an APT-based system, install it like this:

sudo apt install wkhtmltopdf

If you're struggling to install it on your system, please consult the wkhtmltopdf documentation to try to resolve your issue.

Use PDFKit to create a PDF

There are multiple ways you can generate a PDF using PDFKit. You can even generate a PDF from an existing URL. However, for this tutorial, you're going to create your own HTML file.

A common business use-case might be something like a Non-disclosure agreement or an NDA. The basic HTML file looks like this:

 NON-DISCLOSURE AGREEMENT 

Agreement Details

TERMS OF AGREEMENT

The receiver of this document, upon signing, agrees to keep safe, private, and secure any information that is to be disclosed to them during their dealings with:

The Company

Situated at 1 Main Street, Fictional Country

The receiver will be held responsible for any breach or disclosure of any information supplied by “The Company” and may be legally held accountable in case of such breach or disclosure.

SIGNED by :

DATE SIGNED:

Name this file contract.html and place it in the root of your project.

Then modify the skeleton script to look like this:

"""This is the main Python script for generating a PDF file using pdfkit"""# Importsimport sys# import pdfkitimport pdfkit# Global variables# Class declarations# Function declarationsdef main(): pdfkit.from_file('contract.html', 'contract.pdf')# Main bodyif __name__ == '__main__': main()

Once you run this code, you should have a PDF file in the root of your project directory that looks like this:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (4)

Add options with PDFKit

You can pass an options object to the main method to set parameters like margin and page size to make sure the HTML fits nicely on the page. To do so, modify the main() method like this:

def main(): options = { 'page-size': 'A4', 'margin-top': '0.75in', 'margin-right': '0.75in', 'margin-bottom': '0.75in', 'margin-left': '0.75in', } pdfkit.from_file('contract.html', 'contract.pdf', options=options)

For a list of the options that you can set, consult the documentation.

Add color with PDFKit

Currently, the contract looks a bit bland, but just like with normal HTML, it's something you can remedy using CSS.

Create a basic CSS file that changes the color of the <H1> heading and changes the icon of the bulleted list:

h1 { color: blue;}.bigheader { color: #0061FE; font-family: serif; font-size: 50px; font-weight: normal; line-height: 54px; margin: 0 0 54px; }.thecompany { font-size: 20px; font-style: italic; line-height: 1.1em; font-weight: 600;}

Save this file as style.css in the root of your project directory.

Now modify the following line in main.py to use your newly created CSS file:

pdfkit.from_file('contract.html', 'contract.pdf', options=options, css='style.css')

Run the command again to see what your new contract looks like:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (5)

As you can see, PDFKit is fairly flexible if you're familiar with HTML and CSS. Anything you can dream up in HTML can be converted to a PDF file.

All the code examples for this project are available in this GitHub repository.

Dropbox Sign

Dropbox Sign is a service from Dropbox that allows you to digitally sign your PDF files. It helps you streamline any business workflow that might require a signature on the customer's end.

This removes the hassle that most customers experience when they need to physically sign a form, like having to print, sign, and finally, scan the document in order to send it back. Additionally, the signatures are considered to be legally binding signatures.

In this section, you’ll explore a common use case for using a service like Dropbox Sign.

You've been tasked by your employer, “The Company”, to streamline the sending of NDAs to prospective third-party developers who might be on-boarded from time to time as needed.

Sign up for the Dropbox Sign API

If you're a Dropbox customer already, you can skip this step. If not, you'll need to sign up for a Dropbox account.

Once you've selected which account you want to sign up with, you need to accept the terms and conditions:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (6)

Depending on your needs, you'll be asked which plan you want to sign up for. If you're only testing the service for possible future use, you can select the Start free trial button on any of the plans:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (7)

Even if you're only using the free trial, you still need to provide your credit card details. Don't worry, as long as you cancel before the trial period is up, you won't be charged:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (8)

Note that there are differences in what you can do with the API depending on which plan you sign up for:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (9)

Once you've signed up, you'll be logged into the main application page:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (10)

Prepare your first document template with Dropbox

To prepare your first document template, click the Create a template button on the home page to get started.

While you can use any PDF, this tutorial will use the contract.pdf file that was created in the previous example. Upload that file to the template and click Next:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (11)

Next, you'll need to create a signer role. In this example, call the role Developer and click Next:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (12)

You should be greeted by the template designer, where you can add all sorts of fields to your PDF file:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (13)

Some fields can be automatically filled when a signature request gets generated. The “Date Signed” field is a good spot to do this. Drag a “Date signed” field from the “Auto-fill fields” section on the left to the location on the PDF where you would like the date to appear:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (14)

Next, drag a “Signature” field from the left sidebar to the position where you would like it to appear on the template:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (15)

With the field selected, check the right sidebar for field options and make sure the field is set to Required and the right signer role has been selected. Also, note the field name, as you will need to reference that name in your Python code later:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (16)

Once completed, click Next.

Review, give your template a name, and save it:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (17)

Now, you're ready to integrate this into your Python workflow to send a signature request to your friend.

Create an API key

For your Python project to authenticate to the Dropbox Sign API, you need to create an API key.

Navigate to the Settings page and then click API:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (18)

Click Generate Key and give your API key a name:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (19)

Lastly, copy the key by clicking the copy icon on the newly generated key:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (20)

Prepare your project

Prepare your Python project in the usual manner:

  1. Create a project directory.
  2. Create a virtual environment in that directory using python3 -m venv .venv.
  3. Create a main.py file with the normal bare-bones skeleton.
  4. Create an empty config.py file that will store your API credentials.

Finally, don't forget to install the Dropbox API module in your virtual environment:

pip install dropbox-sign

Set up API access

To set up API access, you need to fill out the script with the basics:

"""This is the main Python script for signing a PDF file using the Dropbox Sign API"""# Importsimport sys# pretty print makes JSON responses look good on the console outputfrom pprint import pprint# Import config.py config.py is in .gitignore so that it doesn't get pushed to Git repoimport config# import different Dropbox Sign modulesfrom dropbox_sign import \ ApiClient, ApiException, Configuration, apis, models # Global variablesconfiguration = Configuration( # Configure HTTP basic authorization: api_key username=config.API_KEY, # or, configure Bearer (JWT) authorization: oauth2 # access_token="YOUR_ACCESS_TOKEN",)# Class declarations# Function declarationsdef main(): with ApiClient(configuration) as api_client: account_api = apis.AccountApi(api_client) try: response = account_api.account_get(email_address=config.EMAIL_ADDRESS) pprint(response) except ApiException as e: print("Exception when calling Dropbox Sign API: %s\n" % e)# Main bodyif __name__ == '__main__': main()

And config.py should look like this:

API_KEY = ''EMAIL_ADDRESS = ''

Once you run that, you should get an output that gives you a few statistics regarding your account:

{'account': {'account_id': '', 'callback_url': None, 'email_address': '', 'is_locked': False, 'is_paid_hf': False, 'is_paid_hs': True, 'locale': 'en-US', 'quotas': {'api_signature_requests_left': 0, 'documents_left': None, 'templates_left': 4, 'templates_total': 5}, 'role_code': None}}

This means you've successfully connected your Python script to the API.

Next, you'll want to send the template you created previously to your friend for signing. To do so, modify the main script like this:

"""This is the main Python script for signing a PDF file using the Dropbox Sign API"""# Importsimport sys# pretty print makes JSON responses look good on the console outputfrom pprint import pprint# Import config.py config.py is in .gitignore so that it doesn't get pushed to Git repoimport config# import different Dropbox Sign modulesfrom dropbox_sign import \ ApiClient, ApiException, Configuration, apis, models # Global variablesconfiguration = Configuration( # Configure HTTP basic authorization: api_key username=config.API_KEY, # or, configure Bearer (JWT) authorization: oauth2 # access_token="YOUR_ACCESS_TOKEN",)# Class declarations# Function declarationsdef main(): with ApiClient(configuration) as api_client: signature_request_api = apis.SignatureRequestApi(api_client) signer_1 = models.SubSignatureRequestTemplateSigner( role="Developer", email_address=config.SIGNER_EMAIL_ADDRESS, name="Prospective Developer", ) signing_options = models.SubSigningOptions( draw=True, type=True, upload=True, phone=True, default_type="draw", ) data = models.SignatureRequestSendWithTemplateRequest( template_ids=config.TEMPLATE_IDS, subject="Standard Developer NDA", message="Please sign the NDA first", signers=[signer_1], signing_options=signing_options, test_mode=True, ) try: response = signature_request_api.signature_request_send_with_template(data) pprint(response) except ApiException as e: print("Exception when calling Dropbox Sign API: %s\n" % e)# Main bodyif __name__ == '__main__': main()

You'll notice that your data object requires a value for the template_ids variable. You'll need to fetch the template ID for the document template you created.

Navigate to the Templates page and view the information for the template you created:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (21)

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (22)

Modify config.py to include the Template ID:

API_KEY = ''EMAIL_ADDRESS = ''SIGNER_EMAIL_ADDRESS = ''TEMPLATE_IDS = ['']

Replace all the placeholder values in config.py with the correct ones. Notice that TEMPLATE_IDS is a Python list because the signature_request_send_with_template method supports sending multiple document templates with a single request.

Also, note that your data object has test_mode set to True. While test_mode is True, the documents are not considered legally binding. This is a good setting to have while you are in a testing phase. For the production code, you would need to set that to False.

Now, run your code.

If all goes well, you should receive a response like this:

{'signature_request': {'cc_email_addresses': [], 'created_at': 1689578419, 'custom_fields': [], 'details_url': '', 'expires_at': None, 'files_url': '', 'final_copy_uri': '', 'has_error': False, 'is_complete': False, 'is_declined': False, 'message': "Please sign the NDA first", 'metadata': {}, 'original_title': 'Standard Developer NDA', 'requester_email_address': '', 'response_data': [], 'signature_request_id': '', 'signatures': [{'error': None, 'has_pin': False, 'has_sms_auth': False, 'has_sms_delivery': False, 'last_reminded_at': None, 'last_viewed_at': None, 'order': None, 'signature_id': '', 'signed_at': None, 'signer_email_address': '', 'signer_name': 'Prospective Developer', 'signer_role': 'Developer', 'sms_phone_number': None, 'status_code': 'awaiting_signature'}], 'signing_redirect_url': None, 'signing_url': '', 'subject': 'Standard Developer NDA', 'template_ids': [''], 'test_mode': True, 'title': 'Standard Developer NDA'}}

Success! The rockstar developer you found on LinkedIn should have the contract waiting in their inbox, ready to be signed.

Sign the document

The email that the prospective developer receives will look like this:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (23)

Once your friend clicks the Review & sign button, they'll be taken to a page where they can sign the document.

The signature field looks like this:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (24)

Clicking on that field gives you the signature widget, where you can digitally sign the document:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (25)

Once you click Insert, the signature will be embedded in the document.

The prospective developer can now click Continue in the top right-hand corner, review the Dropbox Terms of Service, and then click I agree.

Once the signature has been submitted, the signer will be greeted by the last page:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (26)

Confirm the signed document

On your Dropbox Sign home page, navigate to the Documents tab on the left sidebar. You should find a signed copy of the contract here:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (27)

Download the PDF to see your (soon-to-onboarded) developer’s signature on the document:

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (28)

And you're done!

All the code used for this example is available in this GitHub repository.

Conclusion

In this tutorial, you learned how to do the following:

And that's only scratching the surface of what's possible with these tools. You could streamline all kinds of business processes including accepting quotes and estimates, signing contracts, and signing school permission slips.

If you're planning on using PDFs in your business processes, Dropbox Sign could be the perfect automation tool to save you time and effort.

Create or Sign a PDF in Python | Three Ways - Dropbox Sign (2024)

References

Top Articles
Latest Posts
Article information

Author: Msgr. Benton Quitzon

Last Updated:

Views: 5951

Rating: 4.2 / 5 (43 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Msgr. Benton Quitzon

Birthday: 2001-08-13

Address: 96487 Kris Cliff, Teresiafurt, WI 95201

Phone: +9418513585781

Job: Senior Designer

Hobby: Calligraphy, Rowing, Vacation, Geocaching, Web surfing, Electronics, Electronics

Introduction: My name is Msgr. Benton Quitzon, I am a comfortable, charming, thankful, happy, adventurous, handsome, precious person who loves writing and wants to share my knowledge and understanding with you.