Skip to content

Instantly share code, notes, and snippets.

@eoin-obrien
Created January 12, 2022 04:42
Show Gist options
  • Save eoin-obrien/6ce76ae1400672032600990017a11cbe to your computer and use it in GitHub Desktop.
Save eoin-obrien/6ce76ae1400672032600990017a11cbe to your computer and use it in GitHub Desktop.
Extract EU Digital COVID Certificate QR code data from images and PDFs
import argparse
import json
import pathlib
import sys
import zlib
import cbor2
from base45 import b45decode
from cose.messages import CoseMessage
from PIL import Image
from pygments import formatters, highlight, lexers
from pyzbar import pyzbar
from pyzbar.wrapper import ZBarSymbol
__doc__ = """Extracts EU Digital COVID Certificate QR code data from images and PDFs"""
def detect_dcc_qr_codes(image):
"""Extracts EU Digital COVID Certificate QR codes from an image"""
qr_codes = pyzbar.decode(image, symbols=[ZBarSymbol.QRCODE])
decoded = [qr.data.decode("utf-8") for qr in qr_codes]
return [qr for qr in decoded if qr.startswith("HC1:")]
def parse_digital_green_cert(qr_code_data):
"""Extracts the payload from an EU Digital COVID Certificate QR code"""
base45_data = qr_code_data[len("HC1:") :]
compressed_data = b45decode(base45_data)
cose_signed_document = zlib.decompress(compressed_data)
cose_message = CoseMessage.decode(cose_signed_document)
payload = cbor2.loads(cose_message.payload)
return payload
def highlight_json(obj):
"""Prints an object as syntax-highlighted JSON"""
formatted_json = json.dumps(obj, indent=2)
return highlight(formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter())
def main(arguments):
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("infile", help="QR code image or PDF", type=pathlib.Path)
args = parser.parse_args(arguments)
# PIL can't read PDFs, so render these first
if args.infile.suffix == ".pdf":
import pdf2image
images = pdf2image.convert_from_path(args.infile)
else:
images = [Image.open(args.infile)]
# Detect all DCC QR codes
qr_codes = []
for image in images:
qr_codes.extend(detect_dcc_qr_codes(image))
# Print formatted results to the terminal
for qr_code in qr_codes:
payload = parse_digital_green_cert(qr_code)
print(highlight_json(payload))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment