Рабочий QR-код на Python можно сохранить в PNG за несколько строк, но его ещё нужно проверить камерой. Вы установите qrcode, закодируете ссылку, сохраните изображение и разберётесь, почему поля и контраст важнее декоративного градиента.
QR-код не является короткой ссылкой. Он хранит переданную строку прямо в рисунке. Чем длиннее данные, тем плотнее сетка и сложнее чтение. Поэтому для первого проекта возьмём короткий HTTPS-адрес и стандартные чёрно-белые цвета.
Берём пакет qrcode с поддержкой Pillow.
Добавляем строку, строим матрицу и сохраняем PNG.
Сканируем с экрана и бумаги на двух телефонах.
Что именно хранится внутри QR-кода
Для быстрого варианта достаточно qrcode.make. Явный объект QRCode полезнее: вы контролируете box_size, border и уровень коррекции. border=4 оставляет стандартную тихую зону вокруг сетки, куда нельзя ставить текст или логотип.
| Параметр | Стартовое значение | Что меняет |
|---|---|---|
| version | None | Размер выбирается автоматически |
| error_correction | M | Запас восстановления |
| box_size | 12 | Пиксели одного модуля |
| border | 4 | Пустые модули вокруг кода |
После этого шага у каждой части есть одна роль. Интерфейс собирает действие, логика меняет состояние, а вывод показывает признак успеха. Это проще отлаживать, чем один большой обработчик.

Генерация заканчивается реальным сканом. Переход должен открыть точный адрес
Пишем генератор PNG на Python
Установите пакет в виртуальное окружение. В строку data положите конечный HTTPS-адрес. После make(fit=True) библиотека сама подберёт версию матрицы, а Pillow сохранит PNG.
# python -m pip install "qrcode[pil]"
import qrcode
from qrcode.constants import ERROR_CORRECT_M
data = "https://itcodik.com"
qr = qrcode.QRCode(
version=None,
error_correction=ERROR_CORRECT_M,
box_size=12,
border=4,
)
qr.add_data(data)
qr.make(fit=True)
image = qr.make_image(fill_color="#111827", back_color="white")
image.save("codik-qr.png")
print("Готово: codik-qr.png", image.size)Ссылка начинается с https и не содержит случайных пробелов. Размер матрицы выбирается автоматически. Вокруг кода остаётся border=4. Файл сохраняется как PNG и открывается обычной камерой.

Контраст важнее украшений. Сравнение показывает, какой вариант легче поддерживать и проверять.
Как размер, поля и коррекция влияют на чтение
Коррекция ошибок добавляет избыточность. Уровень M подходит для обычной чистой картинки. Высокий уровень иногда используют рядом с небольшим логотипом, но он увеличивает плотность. Логотип всё равно может перекрыть важные служебные области, поэтому каждую версию нужно сканировать.
| Решение | Плюс | Риск |
|---|---|---|
| Чёрный на белом | Максимальный контраст | Минимум декора |
| Фирменный тёмный цвет | Поддерживает стиль | Должен остаться контрастным |
| Логотип в центре | Узнаваемость | Закрывает модули |
| Длинная ссылка | Без редиректа | Более плотная матрица |
Сохраняйте в одном месте то, что может измениться. Если одно и то же значение скопировано в три функции, после первой правки они начнут расходиться. Один объект состояния и одна функция отрисовки снимают эту проблему.
Практика: проверяем настоящий скан
Откройте PNG в масштабе 100%, затем уменьшите до предполагаемого размера. Сканируйте при ярком и тусклом свете, с экрана и распечатки. Проверьте адрес до перехода. QR-код без проверки может красиво выглядеть и вести на опечатку. Сделайте вторую версию с длинным URL и сравните плотность модулей. Так станет видно, почему короткий стабильный адрес легче читать на маленькой наклейке. Если код пойдёт в печать, попросите другого человека отсканировать пробный экземпляр с обычного расстояния. Автор часто знает, куда наводить камеру, и не замечает неудобный размер или блик.
- Создайте виртуальное окружение и установите qrcode[pil].
- Сгенерируйте код для короткой HTTPS-ссылки.
- Откройте PNG и проверьте белое поле вокруг.
- Сканируйте двумя разными камерами.
- Поменяйте box_size и сравните файл.
- Замените цвет на фирменный тёмный и снова проверьте.
PNG существует и имеет достаточный размер. Тихая зона не обрезана. Камера быстро читает код с экрана. После скана открывается точный безопасный адрес.

Четыре обязательные проверки. Пройдите все четыре сценария перед публикацией проекта.
Доводим QR-код до готового результата
Если ссылка может измениться, обычный QR-код придётся пересоздать. Для печатных материалов используйте короткий стабильный адрес на своём домене, который можно перенаправить позже. Не кодируйте секреты: содержимое QR считывается любым сканером.
Камера хуже отделяет сетку от окружения.
Контраста недостаточно.
Матрица становится плотной и мелкой.
QR не шифрует данные.
Что получится в итоге

В результате получается чистый PNG с QR-кодом, подписью назначения и безопасным свободным полем вокруг матрицы.
Что хранит QR-код?
Переданную строку, например URL, а не автоматически созданную короткую ссылку.
Зачем border=4?
Тихая зона помогает сканеру отделить код от окружения.
Можно ли хранить секрет?
Нет, любой сканер прочитает содержимое.
Как понять, что проект готов?
Он повторяет целевой сценарий несколько раз подряд, понятно реагирует на ошибочный ввод и не теряет состояние при обычных действиях.
Можно ли копировать код целиком?
Можно как стартовую точку, но сначала замените значения из примера, затем запустите проект по шагам. Если вы не можете объяснить одну строку, её лучше разобрать до следующего шага.
Пакеты, файлы и виртуальные окружения разбираются в курсе Python. Если модуль не импортируется, откройте разбор ModuleNotFoundError.
Путь к сохранённому PNG можно проверить по гайду о FileNotFoundError. В Кодике сохраните генератор и несколько тестовых ссылок как отдельные версии.