Creating Images with PyQRCode

Mass generation of QR codes with Python.

This is a script for taking a list of URLs from a spreadsheet and generating a captioned QR code for each entry.

Specifically, the script reads the ‘LongURLs‘ input file, shortens the URLs, creates QR Codes, adds captions, and saves each QR code as a .PNG image file.

We shorten the URLs to reduce the complexity of the QR code, which makes it less likely to become unreadable from printing imperfections and dirt smudges.

We’ll use:

1. Numpy
2. Pandas
3. PyQRCode
4. pyshorteners
5. PIL
6. PyPNG

We load our URLs and IDs (captions) using the LongURLs template.

LongURLs Template

Next, we run the script and our QR codes will be output as PNG files in the same directory as our script.

Email links (such as “”) can be used as input URLs, but you’ll need to disable the ValueError:’Please enter a valid url’ that pyshorteners will raise.

import numpy as np
import pyqrcode
import pandas as pd
from pyshorteners import Shortener
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

DF = pd.DataFrame(pd.read_excel(r'C:\Users\Craig\Documents\Python Scripts\LongURLs.xlsx',

ShortURL=np.array(LongURL, dtype='str')

for i in range(0,len(LongURL)):
    code.png(ID[i] + '.png', scale=6, module_color=[0,0,0,128],quiet_zone=7) 

    #Adds caption[i] + '.png')
    font = ImageFont.truetype("ariblk.ttf", 20)
    draw.text((xcor,245),str(ID[i]),font=font)[i]) + '.png')


With pyshorteners, we have the option of using a bunch of different URL shorteners – in this case we used TinyURL.  See the pyshorteners github for a full list.

The font of your caption can be adjusted by taking the desired font’s .tff file (found in Control Panel > Appearance and Personalization > Fonts), copying it into the same folder as your script, and updating line 25.

You might need to adjust the “xcor” value (based on the length of your IDs) to get your caption centered under the QR image.  If your ID lengths are all different, consider adding a few lines of code to detect the ID length and update “xcor” dynamically.