Статья Создание и чтение QR-кода с Python

Еще недавно QR-коды были актуальны как никогда. Но, тьфу-тьфу, надеюсь, что все осталось позади. Тем не менее, эти коды быстрого доступа довольно удобны и используются повсеместно. Поэтому нелишним будет создать приложение, которое их создает. Ну и добавить туда чуть-чуть функционала. Никакого открытия Америки, все довольно просто и банально.

000.jpg


Что понадобиться?

Понадобиться, несмотря на простоту кода довольно много библиотек. Библиотека qrcode, для создания кода, библиотека path для работы с путями. opencv-python для распознавания картинки с кодом. pyzbar для считывания кодов. И еще нужен будет небольшой модуль, который я нашел и который делает создание кода довольно забавным делом. Об этом будет подробнее ниже. А сейчас, устанавливаем библиотеки:

pip install opencv-python qrcode[pil] pyzbar path

После чего импортируем в модуль:

Python:
import os

import qrcode
import cv2
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer
from pyzbar.pyzbar import decode
from path import Path

Теперь приступим к созданию функций. Я разделил их по функционалу, чтобы не запрашивать слишком много данных у пользователя. Хотя, если по правильному, то следовало бы. Но, для демонстрационного кода, да и в большинстве случаев, размер и качество создаваемы QR достаточно для того, чтобы они считывались телефоном. Создадим функцию qr_standard(). Данная функция создает код с классическими квадратиками. Ничего необычного и нестандартного. Для начала запрашиваем текст, который нужно закодировать. Это может быть ссылка на ресурс или просто какое-либо приветствие.

qr_text = input('\n[+] Введите текст или ссылку: ')

Создаем объект QRCode с параметрами. Параметр version отвечает за размер кода. Данный параметр варьируется от 1 до 40. Чем больше значение, тем больше размер создаваемого кода. Параметр error_correction отвечает за коррекцию ошибок. Ее желательно включить, так как при создании кода с картинкой часть кода будет нарушена, что затруднит считывание. Параметр box_size отвечает за количество создаваемых пиксельных квадратов. Чем больше данный параметр, тем больше квадратиков создается в коде. И наконец, параметр border указывает, какой толщины рамку делать у кода. 0 – без рамки, а дальше уже идет толщина. В данном коде выставлено в 1, чтобы рамка все же была, но была минимальной, так как без рамки смотрится все это дело не очень.

Добавляем текст в код:

qr.add_data(qr_text)

Создаем его в черно-белом цвете. После чего сохраняем с заранее предопределенным именем файла. Важно, сохранять в png. После чего выводим сообщение о том, что код сохранен и запускаем функцию main(), чтобы у пользователя отобразилось начальное меню. После чего выходим из функции.

Python:
img = qr.make_image(fill_color="black", back_color="white")
img.save('qr_standard.png')
print('[+] QR-код создан и сохранен: "qr_standard1.png"')
main()
return

Python:
def qr_standard():
    qr_text = input('\n[+] Введите текст или ссылку: ')

    qr = qrcode.QRCode(
        version=3,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=15,
        border=1,
    )
    qr.add_data(qr_text)

    img = qr.make_image(fill_color="black", back_color="white")
    img.save('qr_standard.png')
    print('[+] QR-код создан и сохранен: "qr_standard1.png"')
    main()
    return

На следующем этапе создадим функцию qr_round(), которая будет создавать код с закругленными квадратами. В этой функции все, как и в предыдущей, за исключением того, что при создании QR-кода указываем параметры image_factory, который отвечает за указание при создании кода использовать модуль StyledPilImage, и module_drawer, который и отвечает за отрисовку скругленных квадратов.

img = qr.make_image(image_factory=StyledPilImage, module_drawer=RoundedModuleDrawer())

Python:
def qr_round():
    qr_text = input('\n[+] Введите текст или ссылку: ')
    qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H, version=3, border=1, box_size=15)
    qr.add_data(qr_text)
    img = qr.make_image(image_factory=StyledPilImage, module_drawer=RoundedModuleDrawer())
    img.save('qr_round.png')
    print('[+] QR-код создан и сохранен: "qr_round.png"')
    main()
    return

Далее создаем функцию для создания кода с картинкой в центре. Здесь, помимо текста кода запрашиваем у пользователя путь к картинке. Выполняем проверку корректности пути, после чего создаем нужный код. В остальном код идентичен предыдущему, за исключением параметра embeded_image_path, в котором указывается путь к картинке, которая и помещается в центре.

Python:
def qr_image():
    qr_text = input('\n[+] Введите текст или ссылку: ')
    qr_path = input('[+] Введите путь к картинке >>> ')
    while not os.path.isfile(qr_path):
        qr_path = input('\n[-] Неверный путь.\n[+] Введите путь к картинке >>> ')
    qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H, version=3, border=1, box_size=15)
    qr.add_data(qr_text)
    img = qr.make_image(image_factory=StyledPilImage, embeded_image_path=qr_path)
    img.save('qr_image.png')
    print('[+] QR-код создан и сохранен: "qr_image.png"')
    main()
    return

Так же я создал отдельную функцию, которая и запрашивает у пользователя, какой код из стандартных от желает создать. И в зависимости от выбора запускает ту или иную функцию. На входе функция standard_code_param() ничего не принимает. Ее задача только лишь определить чего хочет пользователь.

Python:
def standard_code_param():
    qr_vid = input('[+] Выберите вид QR-кода:\n\t[1] Простой QR-код;\n\t[2] QR с закругленными элементами;'
                   '\n\t[3] QR с картинкой по центру\n\t[4] Выход\n\t>>> ')
    if qr_vid == "1":
        qr_standard()
    elif qr_vid == "2":
        qr_round()
    elif qr_vid == '3':
        qr_image()
    elif qr_vid == "4":
        exit(0)
    else:
        standard_code_param()

А вот дальше начинается интересное. Нашел я данный код на просторах Хабра у пользователя с ником Pornosenok. Поэтому, никаких авторских прав на данный код не имею. Вот ссылка на статью с данным кодом. Так же в статье есть ссылка на GitHub, откуда и был взят модуль для создания кода с фоном из картинки. То есть здесь я только лишь вызываю необходимую функцию. Вся «магия» твориться в подключенном модуле. Данный модуль, как и код скрипта будет во вложении к статье, а также его можно скачать напрямую с GitHub, по ссылке в статье на Хабре. Спасибо доброму человеку!

Python:
def back_image_qr():
    text_code = input('\n[+] Введите тест или ссылку для создания qr-кода: ')
    image_path = input('[+] Введите путь к картинке фона >>> ')
    while not os.path.isfile(image_path):
        image_path = input('\n[-] Неверный путь.\n[+] Введите путь к картинке фона >>> ')
    path_to_download = Path().joinpath(image_path)
    path_to_save = Path().joinpath('qr_back_image.png')
    gen_qr_code(text_code, path_to_download, path_to_save)
    print(f'[+] QR-код создан и сохранен: {path_to_save}')
    main()
    return

Теперь нужно сделать функцию, которая будет считывать содержимое QR-кода, то есть тот текст, который там содержится и выводить на экран. Назову ее qr_read(). Здесь указывается путь к картинке с кодом, далее, данная картинка считывается с помощью cv2, после чего декодируется с помощью pyzbar и функции decode, чтобы вывести на экран информацию в utf-8. Так как считанные данные находятся в байтовом виде. Ну и печатаем полученный текст на экране. В случае, если код не будет прочитан и словарь вернется пустым, выводим на экран сообщение.

Python:
def qr_read():
    img_path = input('\n[+] Введите путь к QR-коду >>> ')
    while not os.path.isfile(img_path):
        img_path = input('\nНеверный путь.\n[+] Введите путь к QR-коду >>> ')
    img = cv2.imread(img_path)
    if not decode(img):
        print('[-] Не могу прочитать данные')
    else:
        bartext = decode(img)[0][0].decode('utf-8')
        print(f'Текст QR-кода: {bartext}')
        main()
        return

И еще одна функция определения пользовательского выбора. Подробно на ней останавливаться не стоит. Обычное сравнение с помощью if-elif-else.

Python:
def user_check(qr_style):
    if qr_style == "1":
        standard_code_param()
    elif qr_style == '2':
        back_image_qr()
    elif qr_style == "3":
        qr_read()
    elif qr_style == "4":
        exit(0)
    else:
        print('\n[-] Сделайте правильный выбор!')
        main()
        return

И функция main(), в которой также запрашивается пользовательский ввод.

Python:
def main():
    qr_style = input('\n[+] Выберите действие:\n\t[1] Создать стандартный QR-код;\n'
                     '\t[2] Создать QR-код с фоном-картинкой;\n\t[3] Чтение содержимого QR-кода\n\t[4] Выход\n\t>>> ')
    user_check(qr_style)

Вот и все. Скрипт для создания и чтения QR-кода можно считать завершенным. Осталось только протестировать его функции, как все создается и отображается.

Python:
# pip install opencv-python qrcode[pil] pyzbar path
import os

import qrcode
import cv2
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer
from pyzbar.pyzbar import decode
from path import Path

# код пользователя с хабр!
from main_qr import gen_qr_code


# создаем простой код
def qr_standard():
    qr_text = input('\n[+] Введите текст или ссылку: ')

    qr = qrcode.QRCode(
        version=3,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=15,
        border=1,
    )
    qr.add_data(qr_text)

    img = qr.make_image(fill_color="black", back_color="white")
    img.save('qr_standard.png')
    print('[+] QR-код создан и сохранен: "qr_standard1.png"')
    main()
    return


# создаем код с закругленными элементами
def qr_round():
    qr_text = input('\n[+] Введите текст или ссылку: ')
    qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H, version=3, border=1, box_size=15)
    qr.add_data(qr_text)
    img = qr.make_image(image_factory=StyledPilImage, module_drawer=RoundedModuleDrawer())
    img.save('qr_round.png')
    print('[+] QR-код создан и сохранен: "qr_round.png"')
    main()
    return


# создаем код с картинкой посередине
def qr_image():
    qr_text = input('\n[+] Введите текст или ссылку: ')
    qr_path = input('[+] Введите путь к картинке >>> ')
    while not os.path.isfile(qr_path):
        qr_path = input('\n[-] Неверный путь.\n[+] Введите путь к картинке >>> ')
    qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H, version=3, border=1, box_size=15)
    qr.add_data(qr_text)
    img = qr.make_image(image_factory=StyledPilImage, embeded_image_path=qr_path)
    img.save('qr_image.png')
    print('[+] QR-код создан и сохранен: "qr_image.png"')
    main()
    return


# выбор параметров стандартного кода
def standard_code_param():
    qr_vid = input('[+] Выберите вид QR-кода:\n\t[1] Простой QR-код;\n\t[2] QR с закругленными элементами;'
                   '\n\t[3] QR с картинкой по центру\n\t[4] Выход\n\t>>> ')
    if qr_vid == "1":
        qr_standard()
    elif qr_vid == "2":
        qr_round()
    elif qr_vid == '3':
        qr_image()
    elif qr_vid == "4":
        exit(0)
    else:
        standard_code_param()


# создание кода с картинкой на фоне
def back_image_qr():
    text_code = input('\n[+] Введите тест или ссылку для создания qr-кода: ')
    image_path = input('[+] Введите путь к картинке фона >>> ')
    while not os.path.isfile(image_path):
        image_path = input('\n[-] Неверный путь.\n[+] Введите путь к картинке фона >>> ')
    path_to_download = Path().joinpath(image_path)
    path_to_save = Path().joinpath('qr_back_image.png')
    gen_qr_code(text_code, path_to_download, path_to_save)
    print(f'[+] QR-код создан и сохранен: {path_to_save}')
    main()
    return


# чтение содержимого кода
def qr_read():
    img_path = input('\n[+] Введите путь к QR-коду >>> ')
    while not os.path.isfile(img_path):
        img_path = input('\nНеверный путь.\n[+] Введите путь к QR-коду >>> ')
    img = cv2.imread(img_path)
    if not decode(img):
        print('[-] Не могу прочитать данные')
    else:
        bartext = decode(img)[0][0].decode('utf-8')
        print(f'Текст QR-кода: {bartext}')
        main()
        return


# обработка пользовательского выбора
def user_check(qr_style):
    if qr_style == "1":
        standard_code_param()
    elif qr_style == '2':
        back_image_qr()
    elif qr_style == "3":
        qr_read()
    elif qr_style == "4":
        exit(0)
    else:
        print('\n[-] Сделайте правильный выбор!')
        main()
        return


# выбор типа кода, создание или чтение
def main():
    qr_style = input('\n[+] Выберите действие:\n\t[1] Создать стандартный QR-код;\n'
                     '\t[2] Создать QR-код с фоном-картинкой;\n\t[3] Чтение содержимого QR-кода\n\t[4] Выход\n\t>>> ')
    user_check(qr_style)


if __name__ == "__main__":
    main()

Давайте создадим по коду из каждой функции. И посмотрим, что получилось:

001.png

Да простит, меня Codeby за взятое лого )), но вроде бы неплохо. Можно было бы и лучше, но я проверил каждый код. Все читается замечательно.

И напоследок попробовал прочитать созданное изображение с помощью скрипта. Получилось вот что:

screenshot1.png


Все так, как и было закодировано.

Спасибо за внимание. Надеюсь, что данная информация будет кому-нибудь полезной
 

Вложения

  • qr_code.zip
    2,7 КБ · Просмотры: 236
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!