Creating a vCard QR Code in Python

November 8, 2023

I read an article recently about generating a QR code in python. But once getting through the tutorial, it did not work for me. I thought this was a great concept and went down a rabbit hole to fix the code. Since I did all this work to create a vCard QR code in python, I thought I would share.

Introduction

In this blog post, we will explore a Python script that generates a QR (quick response) code from a vCard (virtual business card) and demonstrates how to add a customized image to it for added flair. QR codes are widely used for various purposes, including sharing contact information, web links, and more. Adding a logo to a QR code can make it visually appealing and brand-specific.

QR Codes

Throughout the pandemic, at least in the United State, QR codes have become more and more ubiquitous at restaurants and bars. Though, if you have not heard of a QR code before let me define it for you.

A QR code is a machine-readable code consisting of an array of black and white squares, typically used for storing URLs or other information for reading by the camera on a smartphone.

These neat images can share a lot of information quickly. They are used for link to a URL that will download a restaurant’s menu or drinks list. They can be used to download an image to your phone. And in this example they can store vCard information to share your contact data.

vCard

vCard is probably a little less known to many. But it is a data format that stores your contact data. iOS and Android can both use vCard to download your contact information into someone else’s phone.

vCard an electronic representation of a business card, usually a file attached to an email in place of a signature.

Converting this data into a QR code is pretty easy using a few Python packages and makes for a cool image to share with your contacts.

Let’s Code

The first thing we need to do is to become comfortable with the vCard code format. Below I show the smallest working vCard code that will work for our situation:

BEGIN:VCARD
VERSION:3.0
FN:Josh Finnie
END:VCARD

vCard defines many different properties that can be added; I do not use them all in the slightest, but find what works best for you. The vCard Wikipedia has a list of all of them. For me, this is what I went with:

vcard = f"""BEGIN:VCARD
VERSION:3.0
N:Finnie;Josh;;;
FN:Josh Finnie
BDAY:19831014
ADR;type=HOME:;;;Charlotte;North Carolina;28203;United States
TEL;type=CELL:8607165996
TZ:America/New_York
EMAIL;type=PERSONAL,INTERNET:josh@jfin.us
ORG:People Data Labs;
TITLE:Senior Software Engineer
EMAIL;type=WORK,INTERNET:josh.finnie@peopledatalabs.com
URL:https://www.joshfinnie.com
REV:{datetime.now()}
END:VCARD"""

You can see above, I put my birth day, home address, cell phone number, email, and work data. I find this is a great list of data I would wish new contacts to have. Again feel free to add as many or as few as you’d like. Also notice, I have gone from a pure textfile to python using f-strings. This is to help us with our next part, writing the python code!

Introducting Python

Now that we have the data we want to turn into a QR code, there is some Python we need to get it running. Below is the basic code implementation of turning that Python f-string into a QR code:

from datetime import datetime
import qrcode

VCARD = f"""BEGIN:VCARD
...
END:VCARD"""


def create_qr_code(output_path: str):
    """Create QR code image from content to output path."""
    qr_object = qrcode.QRCode(
        version=1,
        error_correction=qrcode.ERROR_CORRECT_H,
        box_size=10,
        border=4,
    )
    qr_object.add_data(VCARD)
    qr_object.make(fit=True)

    img = qr_object.make_image(fill_color="black", back_color="white").convert("RGBA")
    img.save(output_path)


if __name__ == "__main__":
    create_qr_code("/tmp/qr-part1.png")

Note you’ll need to pip install qrcode for this application to run, but running python part1.py will give you this QR code:

This is a wonderful QR code that you can scan and your phone will add it to your contacts. But we can do better.

Adding Some Flair

QR codes allow for some of the image to be covered up for redundancy. We can use that to our advantage and add an image in the center of the QR code to add some uniqueness to it.

Below is the Python code we need to do this. Also, we are going to use a new library Pillow to help us manipulate the images. So you will need to install this package as well using pip install pillow.

from datetime import datetime
from PIL import Image, ImageDraw, ImageOps
from typing import Optional
import qrcode

VCARD = f"""BEGIN:VCARD
...
END:VCARD"""


def generate_masked_inner_img(inner_img_path: str):
    """Create an inner image with a circular mask for center of QR code."""
    img = Image.open(inner_img_path).convert("RGBA")
    img_width, img_height = img.size

    # Create a circular mask for the inner image
    mask = Image.new("L", (img_width, img_height), 0)
    draw = ImageDraw.Draw(mask)
    circle_center = (img_width // 2, img_height // 2)
    circle_radius = min(img_width, img_height) // 2
    draw.ellipse(
        (
            circle_center[0] - circle_radius,
            circle_center[1] - circle_radius,
            circle_center[0] + circle_radius,
            circle_center[1] + circle_radius,
        ),
        fill=255,
    )

    # Apply the circular mask to the inner image
    img = Image.composite(
        img,
        Image.new("RGBA", img.size, (255, 255, 255, 255)),
        mask
    )

    padding = 20  # Adjust the padding as needed

    # Use ImageOps.expand to create a canvas with a white background and padding
    return ImageOps.expand(img, border=padding, fill="white")


def create_qr_code(output_path: str, inner_img_path: str):
    """Create QR code image from content to output path with a inner imgage"""
    qr_object = qrcode.QRCode(
        version=1,
        error_correction=qrcode.ERROR_CORRECT_H,
        box_size=10,
        border=4,
    )
    qr_object.add_data(VCARD)
    qr_object.make(fit=True)

    img = qr_object.make_image(fill_color="black", back_color="white").convert("RGBA")

    inner_img = generate_masked_inner_img(inner_img_path)

    # Paste the canvas onto the QR code image
    img.paste(
        inner_img,
        (
            img.width // 2 - inner_img.width // 2,
            img.height // 2 - inner_img.height // 2
        ),
        mask=inner_img.split()[3],
    )

    img.save(output_path)


if __name__ == "__main__":
    create_qr_code("/tmp/qr-part2.png", "assets/josh.png")

After running this code: python part2.py, we get the same vCard QR generation, but now my avatar is in the center of the QR code itself. I really enjoy this look:

Conclusion

These two Python scripts demonstrates how to create a QR code from vCard content and how to customize it by adding a circular inner image. QR codes are versatile tools that can be used for various purposes, and adding branding elements to them can make them more visually appealing and recognizable.

I hope you had fun reading about our small experiment into the inner workings of Python, the qrcode package and image manipulation with Pillow. I hope you enjoy and please share your QR codes with me on Threads.