
Взгляните на эти два 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 можно просмотреть сырые байты каждого кода.
ВЕРХНИЙ РЕГИСТР
20 93 1a a6 54 63 dd 28 35 1b 50 e9 3b dc 00 ec11 ec 11
нижний регистр
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 |
Разбиение |
---|---|---|---|
ВЕРХНИЙ |
20 93 |
00100000 10010011 |
0010 000010010011 |
нижний |
41 26 |
01000001 00100110 |
0100 000100100110 |
Для ВЕРХНЕГО регистра используется код 0010; это обозначает, что он алфавитно-цифровой, и стандарт гласит, что следующие 9 битов показывают длину данных.
Для нижнего регистра используется код 0100, который означает байтовый режим; стандарт гласит, что длину данных показывают следующие 8 битов.
Тип |
HEX |
BIN |
Разбиение |
---|---|---|---|
ВЕРХНИЙ |
20 93 |
00100000 10010011 |
0010 0000 10010 |
нижний |
41 26 |
01000001 00100110 |
0100 000 10010 |
Посмотрите на это! Оба они имеют длину 10010; если преобразовать значение из двоичной системы, получится 18, то есть длина текста.
Алфавитно-цифровой режим использует по 11 битов на каждые два символа, а байтовый режим использует (как можно догадаться) по 8 битов на один символ.
Почему же QR-код в нижнем регистре генерируется в байтовом режиме? Разве в нём не используются буквы и цифры?
Вообще да, но для эффективного хранения данных у алфавитно-цифрового режима есть только ограниченное подмножество символов. Это буквы в верхнем регистре и несколько пунктуационных символов: пробел $ % * + - . / :
К счастью, этого хватает для хранения протокола, домена и пути. Но, увы, не параметров GET.
Так что имейте в виду: если вам нужен минимальный физический размер QR-кода, содержащий URl, то весь текст должен быть написан заглавными буквами.
Автор: PatientZero