Каждый, кто генерировал QR-коды, сталкивался с этой загадкой: содержимое не длинное, а код выходит настолько плотным, что его трудно разобрать, — тогда как чужой код, ведущий на довольно длинный URL, выглядит куда реже.
Причина в том, что внутри QR-кода есть четыре разных режима кодирования. Разные виды символов идут по разным каналам, и занимаемое ими место может различаться в несколько раз. Поняв это, можно сознательно управлять плотностью кода.
Четыре режима кодирования: одна информация, очень разные размеры
QR-коды предоставляют отдельные кодировки для разных типов символов, каждая со своей «эффективностью упаковки»:
| Режим | Символы | Бит на символ | Относительная эффективность |
|---|---|---|---|
| Цифровой | 0-9 | около 3,33 бита | Наивысшая (экономия 40 %) |
| Буквенно-цифровой | 0-9 A-Z пробел $%*+-./: | около 5,5 бита | Высокая |
| Байтовый | Всё остальное (вкл. китайский) | 8 бит | Базовый |
| Кандзи | Кандзи Shift-JIS | 13 бит | Немного лучше для частых CJK |
Главное: один китайский иероглиф в UTF-8 занимает 3 байта, то есть 24 бита, тогда как одна латинская буква — 1 байт (8 бит). Значит, для одних и тех же «20 символов» китайскому нужно 480 бит, а английскому всего 160 — разница в 3 раза.
Это и есть самая прямая причина, почему китайские QR-коды выходят плотнее.
Режим кандзи помогает немного, но с условиями
Стандарт QR включает отдельный «режим кандзи», где каждый символ занимает всего 13 бит — почти вдвое меньше 24 бит байтового режима. Звучит отлично, но есть жёсткое ограничение: он поддерживает только символы, существующие в кодировке Shift-JIS.
Shift-JIS — японская кодировка, и набор охватываемых ею символов не полностью совпадает с GB2312 или Unicode. Поэтому:
- Многие частые китайские иероглифы попадают в неё и экономят место;
- Часть упрощённых иероглифов, редкие иероглифы и все некитайские символы (китайская пунктуация, эмодзи) возвращаются к байтовому режиму;
- Генератор должен разумно переключаться между режимами, иначе экономится очень мало.
На практике многие генераторы используют байтовый режим сплошь, чтобы гарантировать совместимость и корректность. В результате китайское содержимое целиком считается по 24 бита на символ, и код выходит плотным.
Попутный практический совет: китайская пунктуация тоже занимает 3 байта. Полноширинная точка 。, запятая ,и перечислительная запятая 、все полноширинные и занимают по 3 байта. Если ваш текст насыщен пунктуацией, попробуйте перейти на полуширинные знаки, чтобы вернуть немного места.
Уровень коррекции ошибок: избыточность покупает устойчивость
Другое место, где QR-код расходует пространство, — код коррекции ошибок. Он использует кодирование Рида — Соломона, чтобы добавить данным избыточность, так что даже при загрязнении части узора исходное содержимое всё ещё можно восстановить. Четыре уровня:
- Уровень L: около 7 % избыточности, восстанавливает примерно 7 % повреждений
- Уровень M: около 15 % (самое частое значение по умолчанию)
- Уровень Q: около 25 %
- Уровень H: около 30 %, наибольшая устойчивость
Эта избыточность занимает реальное место. На версии 10 (57×57 модулей) уровень L вмещает 271 байт, а уровень H — только 119, то есть почти на 56 % меньше.
Так что если ваш код нужно сканировать лишь с экрана, L или M вполне достаточно, и узор будет заметно реже и легче для сканирования. Прибегайте к Q или H только когда код печатается на чём-то, что может изнашиваться, или когда в центр идёт логотип.
Именно так работает логотип в центре: закрытая область трактуется как повреждение и восстанавливается из 30 % избыточности уровня H. Поставьте логотип на код уровня L — и он по сути не будет сканироваться.
Версия: «размерный класс» QR-кода
Всего есть 40 версий, и версия n имеет длину стороны 4n + 17 модулей:
- Версия 1: 21 × 21
- Версия 2: 25 × 25
- Версия 10: 57 × 57
- Версия 20: 97 × 97
- Версия 40: 177 × 177
Ёмкость растёт от нескольких десятков байт на версии 1 до 2 953 байт на версии 40 (уровень L, байтовый режим). Генератор выбирает наименьшую версию, в которую помещается ваш текст.
Здесь стоит отметить два момента:
- Число модулей растёт как квадрат стороны. Переход с версии 20 на 40 менее чем удваивает сторону, но умножает число модулей на 3,3. Поэтому код высокой версии получает очень мелкие отдельные модули.
- Слишком мелкие модули не сканируются. Теоретически каждому модулю нужно минимум 2–3 пикселя для стабильного распознавания. Если ваш текст загоняет версию выше 20, а размер печати скромный, на практике он вполне может оказаться нечитаемым.
Практические выводы: сделайте QR-код удобнее для сканирования
Чтобы получить код, который и чёткий, и легко сканируется, оптимизируйте в таком порядке:
- Сократите содержимое. Это самый действенный рычаг. Более короткие URL, меньше параметров и перенаправление через короткую ссылку посередине — обычный подход. Уменьшите содержимое вдвое, и версия может упасть на несколько ступеней.
- Понизьте уровень коррекции ошибок. Используйте L или M для показа на экране, а не выбирайте рефлекторно H. Высшие уровни оправданы лишь тогда, когда нужно встроить логотип или код печатается на изнашиваемом материале.
- Сохраняйте тихую зону. QR-коду нужен чистый отступ минимум в четыре модуля шириной со всех сторон — тихая зона, — который алгоритм распознавания использует, чтобы найти край кода. Срезать её — причина номер один неудач сканирования, ещё более частая, чем размытость.
- Дайте достаточно пикселей. Минимум 4 пикселя на модуль — безопасная цель, поэтому версии 10 (57 модулей) нужно минимум 228 пикселей ширины.
- Не используйте маленькое растровое изображение. Если нужно встроить код в картинку, экспортируйте с достаточным разрешением или используйте векторный формат (SVG), чтобы масштабирование его не размыло.
Как понять, насколько плотен ваш код
Два подхода:
Во-первых, следите за номером версии, который сообщает инструмент при генерации: чем ниже версия, тем легче сканирование. Если воспользуетесь генератором QR-кодов, он покажет версию и число байт, занимаемых вашим содержимым, так что можно править текст и наблюдать за версией, получая ощущение, что «убрать эти несколько символов — минус одна версия».
Во-вторых, отнесите существующий код в декодер QR-кодов и проверьте его версию, уровень коррекции ошибок и тип содержимого. Если найдёте якобы длинный текст в низкой версии, скорее всего, в содержимом есть короткая ссылка.
Оба инструмента работают локально в вашем браузере; изображения, которые вы генерируете и загружаете, никогда не проходят через сервер.
Одним предложением
Плотность QR-кода = байты содержимого ÷ эффективность кодирования + избыточность коррекции ошибок. Китайский считается по 3 байта, китайская пунктуация тоже, поэтому китайские коды от природы плотнее. Чтобы сделать код реже, самые действенные шаги — меньше содержимого и ниже уровень коррекции, а не другой генератор.