Serial QR Code Generator Project

December 2022

QR Codes

Example output PDF from generating 50 QR codes.


For my research in detecting cafeteria foods, my lab planned to take pictures and collect weights of food trays from the dining hall at my university. We aimed to collect this data both before and after the consumer ate the food, so we could see how much food was eaten versus how much was thrown away. The problem we faced was: how do we keep track of which image before consumption corresponds to which image after consumption?


Solution Overview

The solution I devised was to stick a unique QR code on the edge of each tray. Our computer vision software can then autonomously match the before and after pictures. However, two questions arose while discussing our plan:

  1. How can we generate unique QR codes?
  2. How will we print the QR codes onto stickers?

As for the first problem, I quickly wrote a python script to generate unique QR codes and formatted them onto pages of a PDF document for easy printing. To ensure the QR Codes were unique, we used a serial numbering system to label the QR codes 1000001, 1000002, ... up to a limit the user specifies. We could have used UUIDs, but our serial numbering allows us to have different "batches" of numbers for different experiments.

To solve the second problem, I found 8.5x11" sticker sheets online that we could print the QR codes onto using a standard inkjet printer.

QR Codes

Example output PDF from generating 50 QR codes.


Walking through the code

The design of the algorithm is fairly straightforward:

  1. First, create a list of serially labeled QR codes as PIL image objects.
  2. Second, take the list of QR code images and format as many of them onto a PDF page as possible. When the page is full, we write it to a PDF file. Repeat this step with the remaining QR codes onto a new blank page, until all remaining QR codes are written onto a page.
  3. Now that we have a bunch of one-page files, the program merges them into a multi-page PDF.

There is one problem I identified with this approach: this script uses a substantial amount of memory. If the user wanted to generate millions of QR codes, the program would have to create an image object for each and store them in a list. While most computers would be able to handle a few Gigabytes of memory consumption from the program, we can use the generator feature instead and only consume a few Megabytes.

You can see the first step of my algorithm below, where I yield the newly-created QR code image:

def create_qr_code_image_objects():
    """Returns a generator of qr code PIL ImageDraw objects."""

    for i in range(total_qr_codes):
        curr_num = starting_num + i

        # Generate qr code.
        data = str(curr_num)
        qr_code_img = qrcode.make(data)
        qr_code_img = qr_code_img.resize(QR_SIZE, resample=Resampling.BOX)

        # Add text to the qr code (attempt to center at top)
        draw_canvas = ImageDraw.Draw(qr_code_img)
        draw_canvas.text(((QR_SIZE[0] // 2) - 20, 0), data, font=FONT)

        yield qr_code_img

Then, in the second step of the algorithm, I simply call next() on the generator to retrieve the next QR code image object.

while row + QR_SIZE[0] + VERT_SPACING_BETWEEN_QR_CODES <= pdf_height:
  while col + QR_SIZE[0] + HORZ_SPACING_BETWEEN_QR_CODES <= pdf_width:
      try:
          qr_code_img = next(qr_code_image_generator)
      except StopIteration:
          break

      resized_qr_code_img_obj = ImageOps.fit(qr_code_img, QR_SIZE, Resampling.LANCZOS)  
      pdf_canvas.paste(resized_qr_code_img_obj, (col, row))

      # code for the rest of the function omitted

Conclusion

Overall, even with a project of small scope, I learned how to use the generator feature and wrote a script that will save time for my lab and the open-source community.

You can find the entire python script as well as instructions for running the program in my github repo linked here.


back to home