Почему QR-коды в верхнем регистре меньше, чем в нижнем?
- пятница, 28 февраля 2025 г. в 00:00:15
Взгляните на эти два QR-кода. Отсканируйте их, если хотите: обещаю, в них нет ничего опасного.
Слева HTTPS://EDENT.TEL/ в верхнем регистре, а справа — https://edent.tel/ в нижнем.
Можно чётко заметить, что слева QR-код «меньше», то есть в нём меньше битов данных. Оба ведут на один и тот же URl, единственное различие заключается в регистре.
Что здесь происходит?
Первым делом вы могли бы подумать, что причина в разных уровнях коррекции ошибок. QR-коды могут иметь повышающиеся уровни избыточности на случай, чтобы их можно было отсканировать даже в повреждённом виде. Но в данном случае они оба имеют низкую (Low) коррекцию ошибок.
Левый имеет «Type 1» и размер 21px * 21px. Правый — «Type 2» и размер 25px * 25px.
В официальной спецификации версии описаны подробнее. В меньший код должно умещаться 25 алфавитно-цифровых символов. Но https://edent.tel/ имеет длину всего 18 символов. Почему же эта строка превратилась в больший код?
При помощи декодера наподобие ZXING можно просмотреть сырые байты каждого кода.
UPPER
20 93 1a a6 54 63 dd 28 35 1b 50 e9 3b dc 00 ec11 ec 11
lower
41 26 87 47 47 07 33 a2 f2 f6 56 46 56 e7 42 e746 56 c2 f0 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11 ec 11
Можно заметить, что оба они заканчиваются одинаковой последовательностью ec 11. Это «байты-заполнители», необходимые, потому что данные должны полностью заполнять QR-код. Но постойте, почему QR-код верхнего регистра не только вполне может уместить в себе текст, но и имеет лишний заполнитель?
Ответ таится в первой паре байтов.
После считывания сырых байтов сканер QR-кодов должен точно знать, с каким типом кода он имеет дело. Первые четыре бита сообщают ему режим. Давайте преобразуем шестнадцатеричные данные в двоичные и выделим первые четыре бита:
Тип | HEX | BIN | Разбиение |
---|---|---|---|
UPPER | 20 93 | 00100000 10010011 | 0010 000010010011 |
lower | 41 26 | 01000001 00100110 | 0100 000100100110 |
Для UPPER используется код 0010; это обозначает, что он алфавитно-цифровой, и стандарт гласит, что следующие 9 битов показывают длину данных.
Для lower используется код 0100, который означает байтовый режим; стандарт гласит, что длину данных показывают следующие 8 битов.
Тип | HEX | BIN | Разбиение |
---|---|---|---|
UPPER | 20 93 | 00100000 10010011 | 0010 0000 10010 |
lower | 41 26 | 01000001 00100110 | 0100 000 10010 |
Посмотрите на это! Оба они имеют длину 10010; если преобразовать значение из двоичной системы, получится 18, то есть длина текста.
Алфавитно-цифровой режим использует по 11 битов на каждые два символа, а байтовый режим использует (как можно догадаться) по 8 битов на один символ.
Почему же QR-код в нижнем регистре генерируется в байтовом режиме? Разве в нём не используются буквы и цифры?
Вообще да, но для эффективного хранения данных у алфавитно-цифрового режима есть только ограниченное подмножество символов. Это буквы в верхнем регистре и несколько пунктуационных символов: пробел $ % * + - . / :
К счастью, этого хватает для хранения протокола, домена и пути. Но, увы, не параметров GET.
Так что имейте в виду: если вам нужен минимальный физический размер QR-кода, содержащий URl, то весь текст должен быть написан заглавными буквами.