Я могу оторвать часть бумажки с QR-кодом, помять её, снять камерой под углом и всё равно получить правильную ссылку. На первый взгляд выглядит почти как магия. На деле перед нами очень продуманная конструкция из данных, служебных меток, геометрических ориентиров и математической коррекции ошибок.
Главная идея проста. QR-код не хранит ссылку в каком-то одном участке картинки. Информация превращается в последовательность битов, дополняется проверочными данными, перемешивается по матрице и маскируется. Камера сначала восстанавливает геометрию квадрата, затем считывает сетку чёрных и белых модулей, снимает маску и исправляет часть ошибок. Поэтому царапина или пятно часто не мешают, а отсутствие интернета вообще не влияет на само распознавание.
Разбираю QR-код по слоям
QR-код появился в Denso Wave в 1994 году. Разработчики хотели получить двумерный код, который содержал бы больше данных обычного штрихкода и быстро находился сканером. Название QR происходит от Quick Response, то есть быстрого отклика. Сегодня обычный QR Code Model 2 описан международным стандартом ISO/IEC 18004.
Первое, что я бы перестал называть «пикселями», это маленькие чёрные и белые квадраты. В терминологии стандарта их называют модулями. Самый маленький QR версии 1 имеет сетку 21 × 21 модуль. Каждая следующая версия добавляет по четыре модуля на сторону, а версия 40 достигает 177 × 177.
Три огромных квадрата в углах не содержат вашу ссылку. Перед нами маркеры положения. Сканер ищет характерное чередование тёмных и светлых полос с отношением ширины 1 к 1 к 3 к 1 к 1. По трём найденным маркерам программа понимает, где находится QR-код, насколько он повернут и какие три угла видит камера.
Между маркерами проходят чередующиеся чёрно-белые линии. Это синхронизирующие шаблоны. По ним декодер уточняет размер одного модуля и сетку строк и столбцов. Начиная со второй версии появляются дополнительные небольшие маркеры выравнивания. Они помогают справляться с перспективой и геометрическими искажениями, когда бумага изогнута или камера смотрит сбоку.
Есть ещё служебная информация. Поле формата сообщает выбранный уровень коррекции ошибок и номер маски. Для крупных QR начиная с версии 7 отдельно записывается номер версии. Популярное объяснение, будто где-то в углу QR лежит отдельная область с надписью «здесь ссылка», неверно. Режим кодирования находится внутри потока данных.
Я возьму совсем короткий настоящий пример и закодирую слово HELLO в QR версии 1. Для буквенно-цифрового режима сначала записывается четырёхбитный идентификатор 0010. Затем идёт длина строки. Для версий с 1 по 9 длина в таком режиме занимает девять бит, поэтому число 5 выглядит как 000000101.
0010 режим букв и цифр
000000101 длина 5 символов
HE
17 × 45 + 14 = 779
779 = 01100001011
LL
21 × 45 + 21 = 966
966 = 01111000110
O
24 = 011000
Получается поток битов, к которому кодировщик добавляет признак конца, выравнивание по байтам и заполняющие байты. Для версии 1 с уровнем L доступно 152 бита данных. После подготовки данных вычисляются дополнительные кодовые слова коррекции ошибок Рида-Соломона.
Дальше происходит вещь, которую редко объясняют в популярных статьях. Полученный поток нельзя просто последовательно нарисовать чёрными и белыми клетками. Кодовые слова раскладываются по свободным модулям матрицы по заданному маршруту, после чего применяется одна из восьми масок.
Маска здесь не имеет отношения к шифрованию. По математическому правилу кодировщик меняет часть светлых модулей на тёмные и наоборот, чтобы на изображении не появлялись огромные одноцветные области, длинные полосы или узоры, похожие на служебные маркеры. Кодировщик пробует восемь вариантов и выбирает подходящий по правилам оценки. Номер выбранной маски сохраняется в поле формата, поэтому декодер потом выполняет обратную операцию.
Отсюда интересный вывод. Формула «чёрный квадрат равен единице, белый равен нулю» годится только как первое приближение. Служебные модули вообще не являются пользовательскими данными, а модули данных на готовой картинке уже прошли через маску.
Как камера превращает кривую фотографию в ссылку
Сканирование начинается не с чтения текста, а с компьютерного зрения. Камера получает обычное изображение с тенями, бликами, перспективой и шумом. Алгоритм переводит кадр в подходящее представление яркости и ищет характерные квадратные маркеры. Исследования алгоритмов распознавания показывают, что соотношение 1 к 1 к 3 к 1 к 1 позволяет довольно надёжно обнаруживать маркеры даже в повёрнутом кадре.
После нахождения трёх углов декодер оценивает положение четвёртого и выполняет преобразование перспективы. Кривой четырёхугольник на фотографии математически превращается обратно в квадрат. Маркеры выравнивания и синхронизирующие линии помогают уточнить сетку.
Затем программа решает, какой модуль считать тёмным, а какой светлым, получает поле формата, узнаёт уровень коррекции и маску, снимает маску, восстанавливает последовательность кодовых слов и запускает коррекцию ошибок. Только после всех этих операций декодер разбирает режимы и получает исходный текст, адрес сайта, платёжные данные или другую информацию.
Именно поэтому QR можно считывать вверх ногами и под заметным углом. Телефону не требуется заранее знать, где у картинки верх. Три крупных маркера задают ориентацию сами. Современные алгоритмы ещё и компенсируют перспективу, хотя бесконечных возможностей у них нет.
Белая рамка вокруг QR тоже не украшение. Стандартный QR требует свободную тихую зону шириной не менее четырёх модулей со всех сторон. Рамка отделяет код от текста, рисунков и других контрастных объектов. Denso Wave прямо рекомендует оставлять четыре модуля свободного поля. Обрезанная рамка часто объясняет ситуацию, когда красивый дизайнерский QR отлично работает на одном телефоне и упорно не читается на другом.
Слишком маленький QR ломается по другой причине. Камера должна различать каждый отдельный модуль. Если несколько соседних клеток попадают в один размытый участок изображения, декодеру уже нечего восстанавливать. Поэтому физический размер QR нельзя оценивать отдельно от версии кода, расстояния, разрешения камеры, качества печати и освещения.
Само декодирование интернету не нужно. Например, официальный интерфейс Google для распознавания штрихкодов выполняет анализ на устройстве и работает без сетевого соединения. Если внутри записан обычный текст, телефон способен показать его полностью в автономном режиме. Если внутри находится веб-адрес, интернет понадобится уже браузеру для загрузки сайта.
С оплатой похожая история. QR СБП можно распознать локально, но для самой банковской операции потребуется связь с банком и платёжной инфраструктурой. НСПК использует как статические, так и динамические QR-коды. Картинка здесь только передаёт параметры, а деньги через чёрно-белые квадраты, конечно, не путешествуют.
Почему оторванный кусок не всегда убивает QR
За живучесть QR отвечает коррекция ошибок Рида-Соломона. Кодировщик вычисляет из исходных данных дополнительные проверочные кодовые слова. Если при чтении часть кодовых слов оказалась испорчена, математический алгоритм способен определить ошибки и восстановить исходные значения.
Стандарт предлагает четыре уровня коррекции. Чем выше уровень, тем больше избыточности и тем меньше полезных данных помещается в QR.
| Уровень | Примерная доля восстанавливаемых кодовых слов |
|---|---|
| L | около 7% |
| M | около 15% |
| Q | около 25% |
| H | около 30% |
Но здесь появляется самый популярный миф про QR. Уровень H не означает, что можно вырезать любые 30% площади квадрата и гарантированно получить данные. Denso Wave говорит примерно о 30% восстанавливаемых кодовых слов. Геометрическое повреждение картинки и потеря кодовых слов связаны не один к одному.
Если грязь закрыла распределённые по матрице данные, коррекция может прекрасно справиться. Если ножницы уничтожили критический маркер положения, большую часть тихой зоны или другие функциональные элементы, сканер может вообще не определить, где находится QR. Математика Рида-Соломона вступает в игру после того, как программа сумела обнаружить символ и получить из него кодовые слова.
По той же причине логотип посередине QR иногда работает удивительно хорошо. Генератор выбирает высокий уровень коррекции, оставляет служебные области нетронутыми и сознательно жертвует частью данных. Но правило «логотип может занимать 30% картинки» я бы не использовал. Реальный предел зависит от версии, положения изображения, раскладки кодовых слов, декодера и качества печати.
Максимальная ёмкость тоже требует оговорки. Для обычного QR Model 2 версии 40 при минимальной коррекции L спецификация допускает до 7089 цифр, 4296 символов ограниченного буквенно-цифрового набора, 2953 байт двоичных данных или 1817 символов в специальном режиме кандзи. При уровне H доступная ёмкость заметно падает. Например, двоичный режим версии 40-H вмещает максимум 1273 байта.
Поэтому фраза «QR хранит до 3000 символов» неточна. Байты и символы не одно и то же. Кириллица в UTF-8 обычно требует по два байта на букву, часть места забирают служебные поля, а конкретный генератор может использовать дополнительные режимы кодирования.
Ещё один миф касается динамических QR. Сами чёрные квадраты после печати измениться не способны. Сервисы «динамических QR» обычно помещают внутрь постоянный короткий адрес-посредник, а уже сервер решает, куда перенаправить пользователя сегодня. По похожей схеме работают системы статистики переходов и отслеживания сканирований.
Короткая оговорка по безопасности. QR-код не подтверждает безопасность ссылки и не доказывает личность получателя платежа. Материал предназначен для легального и ответственного применения технологии. Не стоит подменять чужие коды, использовать их для фишинга, слежки, несанкционированного доступа или нарушения правил сервисов и законодательства своей страны. Перед оплатой я всегда проверяю получателя и сумму, а перед открытием сайта смотрю на домен. Отдельно мы уже разбирали, как работает квишинг и как считать QR со скриншота на самом смартфоне.
В результате QR оказывается гораздо интереснее обычной «картинки со ссылкой». Три угловых квадрата помогают найти символ, служебные шаблоны восстанавливают геометрию, маска делает рисунок удобнее для камеры, а Рид-Соломон спасает часть испорченных данных. Поэтому хороший QR переживает поворот, перспективу, грязь и небольшие повреждения, но не нарушает законы физики. Срежьте критические ориентиры, сделайте модули меньше разрешения камеры или уничтожьте слишком много кодовых слов, и никакая коррекция уже не поможет.
Короткие ответы про QR-коды
Нужен ли интернет, чтобы прочитать QR-код
Нет. Декодер может распознать QR полностью на смартфоне. Интернет понадобится только для дальнейшего действия, например загрузки сайта или проведения платежа.
Что означают три больших квадрата в QR-коде
Это маркеры положения. По ним сканер находит QR-код, определяет его ориентацию и восстанавливает геометрию изображения.
Почему повреждённый QR-код продолжает работать
В QR заранее добавляют избыточные кодовые слова Рида-Соломона. Декодер использует их для исправления части ошибок. Возможности зависят от выбранного уровня коррекции и места повреждения.
Можно ли закрыть логотипом 30% QR-кода
Гарантии нет. Число 30% относится примерно к восстанавливаемой доле кодовых слов при уровне H, а не к любой произвольной площади изображения. Логотип может уничтожить критические элементы и сделать код нечитаемым.
Сколько информации помещается в QR-код
Максимальный стандартный QR версии 40 при уровне L способен хранить до 7089 цифр, 4296 символов ограниченного буквенно-цифрового набора или 2953 байт данных. Более высокая коррекция ошибок уменьшает доступную ёмкость.
Зачем вокруг QR-кода оставляют белую рамку
Свободная зона отделяет QR от окружающих рисунков и текста. Для обычного QR стандартная тихая зона имеет ширину четыре модуля с каждой стороны.