from typing import Optional from pyzbar import pyzbar import asyncio import cv2 from hermit.errors import InvalidSignatureRequest from .format import decode_qr_code_data from .utils import window_is_open def read_qr_code() -> Optional[str]: task = _capture_qr_code_async() return asyncio.get_event_loop().run_until_complete(task) async def _capture_qr_code_async() -> Optional[str]: capture = _start_camera() preview_dimensions = (640, 480) decoded_data = None encoded_data = None window_name = "Signature Request QR Code Scanner" cv2.namedWindow(window_name) while window_is_open(window_name): ret, frame = capture.read() frame = cv2.resize(frame, preview_dimensions) for qrcode in pyzbar.decode(frame): # Extract the position & dimensions of box bounding the QR # code (x, y, w, h) = qrcode.rect # Draw this bounding box on the image cv2.rectangle( frame, (x, y), (x + w, y + h), (0, 0, 255), 2) # Decode the QR code data encoded_data = qrcode.data try: decoded_data = decode_qr_code_data(encoded_data) except InvalidSignatureRequest as e: print("Invalid signature request: {}".format(str(e))) # Use the first QR code found if decoded_data is not None: break # Preview the (reversed) frame mirror = cv2.flip(frame, 1) cv2.imshow(window_name, mirror) # Break out of the loop if we found a valid QR code if decoded_data: break await asyncio.sleep(0.01) # Clean up windows before exiting. capture.release() cv2.destroyWindow(window_name) return decoded_data def _start_camera() -> cv2.VideoCapture: capture = cv2.VideoCapture(0) if not capture.isOpened(): raise IOError("Cannot open webcam") return capture