javascript

Пошагово создаём QR-код

  • суббота, 22 марта 2025 г. в 00:00:04
https://habr.com/ru/companies/beeline_tech/articles/892884/
В этой статье (оригинал представляет собой интерактивное приложение на JavaScript) подробно описывается, как текстовая строка кодируется в символ QR-кода. Она, по сути, объясняет, как устроена внутри моя библиотека генератора QR-кодов.

Пользовательский ввод




Результат генерации QR-кода




Пошаговый процесс


0. Анализируем символы Unicode


Количество кодовых точек во входной текстовой строке: 17.

Подробности о каждом из символов:

Index: индекс во входной строке
Char: сам символ
CP hex: значение кодовой точки Unicode в шестнадцатеричном виде
NM: можно ли закодировать в цифровом режиме
AM: можно ли закодировать в алфавитно-цифровом режиме
BM: можно ли закодировать в байтовом режиме
KM: можно ли закодировать в режиме кандзи


Можно ли закодировать каждый символ в соответствующем режиме:


Для кодирования всех символов выбран сегментный режим Byte

1. Создаём сегмент данных


Преобразуем каждый символ в биты. В цифровом и алфавитно-цифровом режиме идущие по порядку символы группируются, а затем кодируются в биты. В байтовом режиме символ преобразуется в 8, 16, 24 или 32 бита.


Созданный единый сегмент:

  • Режим: Byte
  • Количество: 17 байтов
  • Данные: длина 136 байтов

(Для упрощения моё демо всегда создаёт единый сегмент. Но можно сегментировать текст оптимально, чтобы минимизировать общую длину в битах.)

2. Подстраиваемся под номер версии


Общая длина в битах должна представлять список сегментов в зависимости от версии:


(Примечание: кодовое слово определяется как 8 битов, также известные как байт.)

Ёмкость кодовых слов данных QR-кода для каждой версии, уровень коррекции ошибок и помещаются ли данные (зелёный/красный фон):

ECC L: low
ECC M: medium
ECC Q: quartile
ECC H: high


Выбранный номер версии: 1

3. Выполняем конкатенацию сегментов, добавляем заполнители, создаём кодовые слова


Объединяем различные битовые строки:


Примечание:

  • Описание режима сегмента — это всегда 4-битное поле.
  • Ширина поля количества символов в сегменте зависит от режима и версии.
  • Разграничителем обычно являются четыре бита «0», но их бывает и меньше, если мы достигли предела ёмкости кодового слова данных.
  • Битовый заполнитель имеет ширину от нуля до семи битов «0», чтобы заполнить все неиспользованные биты в последнем байте.
  • Байтовый заполнитель состоит из перемежающихся (шестнадцатеричных) EC и 11, пока не будет заполнена вся ёмкость.

Полная последовательность битов данных:

01000001000101001000011001010110110001101100011011110010110000100000011101110110111101110010011011000110010000100001001000000011000100110010001100110000

Вся последовательность байтов кодовых слов данных (полученная разбиением битовой строки на группы по 8 бит) в шестнадцатеричном виде:

41 14 86 56 C6 C6 F2 C2 07 76 F7 26 C6 42 12 03 13 23 30

4. Разбиваем блоки, добавляем ECC, реализуем чередование


Статистика обо всех блоках:


Разделяем последовательность кодовых слов данных (зелёный фон) на короткие и длинные блоки; затем для каждого блока вычисляем кодовые слова ECC (синий) и добавляем их в конец блока:


(Примечание: математические расчёты вычислений кодов коррекции ошибок Рида-Соломона пропущены, потому что это долго и скучно.)

Окончательная последовательность кодовых слов, образованная чередованием кодовых слов данных/ECC из разных блоков:


Окончательная последовательность битов для отрисовки сканирования зигзагом:

0100000100010100100001100101011011000110110001101111001011000010000001110111011011110111001001101100011001000010000100100000001100010011001000110011000010000101101010010101111000000111000010100011011011001001

5. Рисуем фиксированные паттерны


Рисуем горизонтальные и вертикальные паттерны таймингов (в строке 6 и столбце 6, считая с 0 начиная с левого верхнего угла):


Рисуем опорные паттерны (finder pattern) в трёх углах, каждый из которых имеет размер 8×8, включая разделитель, перерисовывая некоторые модули таймингов:


Рисуем временные макетные биты формата (format bit) (рядом с finder pattern):


6. Отрисовываем кодовые слова и остаток


Вычисляем сканирование зигзагом (которое начинается с правого нижнего угла) так, чтобы посетить все незаполненные модули (то есть пропуская функциональные модули):


Рисуем модули данных/ECC согласно порядку сканирования зигзагом и битовые значения из окончательной последовательности кодовых слов:


(Например, байт годового слова C5 (шестнадцатеричный) — это двоичные 11000101, создающие последовательность модулей [тёмный, тёмный, светлый, светлый, светлый, тёмный, светлый, тёмный].)

7. Пробуем применять каждую из масок


Паттерн маски (влияющий только на нефункциональные модули):


Ниже показаны примеры для паттерна маски 3.

Выполняем XOR маски с модулями данных, ECC и остатком:


Отрисовываем сами биты формат (рядом с finder pattern):


8. Находим штрафные паттерны


Горизонтальные последовательности модулей одного цвета (каждый длиной не более 5 битов):


Вертикальные последовательности модулей одного цвета (каждый длиной не более 5 битов):


Прямоугольники 2×2 модулей одного цвета:


Горизонтальные паттерны, похожие на finder pattern:


Вертикальные паттерны, похожие на finder pattern:


Баланс тёмных/светлых модулей:


9. Вычисляем штрафные очки, выбираем наилучшую маску


Mask: номер паттерна маски
RunP: штрафные очки линейной последовательности одного цвета
BoxP: штрафные очки прямоугольника 2×2 одного цвета
FindP: штрафные очки паттернов, похожих на finder pattern
BalP: штрафные очки за баланс тёмного/светлого
TotalP: сумма штрафных очков


Наименьшая сумма штрафных очков: паттерн маски 3

Как вычисляются штрафы:

  • RunP: 3 очка за каждую линейную последовательность из 5 модулей одного цвета, 4 очка за каждую последовательность из 6 модулей, 5 очков за каждые 7 модулей, 6 очков за каждые 8 модулей и так далее. Последовательности не могут пересекаться.
  • BoxP: 3 очка за каждый прямоугольник 2×2 одного цвета. Прямоугольники могут пересекаться.
  • FindP: 40 очков за каждый паттерн, похожий на finder pattern. Finder pattern могут пересекаться.
  • BalP: 0 очков, если соотношение тёмных модулей находится в интервале [45%, 55%]; 10 очков, если в интервале [40%, 60%]; 20 очков, если в интервале [35%, 65%]; 30 очков, если в интервале [30%, 70%] и так далее.

Вы можете изучить исходный код этого веб-приложения на TypeScript (файл 0, файл 1) и скомпилированный код на JavaScript.

Дополнительная информация