QR-коды: основы
QR-код — это, по сути, способ закодировать несколько байт данных так, чтобы их можно было легко считать с фотографии смартфоном или похожим устройством. Они спроектированы очень устойчивыми к плохому фокусу, плохой печати, наклону под странным углом и отсутствующим участкам. Точный механизм их работы не так важен для этой темы, но в целом QR-код — это сетка квадратов, которая делится на две части: функциональные паттерны (жирные фигуры на примере выше) и модули данных (всё остальное). Функциональные модули в основном нужны сканеру, чтобы легко найти QR-код, поэтому они должны быть чёткими и однозначными. Модули данных — это место, где хранятся собственно данные вместе со служебной информацией заголовка, и, поскольку они считываются уже после того, как сканер с помощью функциональных модулей определил точное положение кода, их можно немного модифицировать. Этим часто пользуются бренды, чтобы сделать QR-коды визуально узнаваемыми: такая модификация немного снижает устойчивость к сканированию, но обычно запас прочности достаточно большой, прежде чем код перестанет читаться.
Как встроить картинку в QR-код
Идея отталкивается от QR-кода, замеченного в Mastodon. Один из способов модификации модулей данных — их уменьшение: сканер ищет пиксели там, где паттерны поиска указывают на их центр, и пока код не искажён при попытке считать, остальное пространство пикселя свободно для творчества. Дейв Ричесон делит каждый пиксель на сетку 3×3, используя средний квадрат для хранения данных, а остальные — для фотографии. Получается низкое разрешение, одно-битное изображение с эффектом "соль и перец" в виде шума.
Дизеринг
Когда изображение сжимается до низкой битовой глубины, обычно не применяют простое пороговое отсечение (тёмные пиксели — чёрные, светлые — белые). Вместо этого используют что-то вроде эффекта шахматной доски, чтобы создать полутона. Фильтр Байера позволяет применить эту идею ко всему изображению без потери мелких деталей.
Диффузия ошибки
Попыткой улучшить этот метод стал дизеринг Флойда-Стайнберга.
В этом методе обработка начинается с верхнего левого угла, и пиксель проходит обычное пороговое отсечение: если яркость больше 50%, пиксель становится белым, иначе — чёрным. Допустим, яркость пикселя была 70% — его сделают белым (100% яркости), значит, добавили лишние 30% яркости. Чтобы компенсировать это, ошибку "диффузируют" на соседние пиксели — все ближайшие пиксели, которые ещё не обработаны пороговым отсечением, становятся на несколько процентов темнее, в сумме на те же 30% пикселя. Когда очередь дойдёт до этих пикселей, ошибка уже будет учтена. Идея в том, что после обработки всего изображения каждая его часть в среднем окажется ближе к правильной яркости, чем при обычном дизеринге. Нерегулярный узор также меньше бросается в глаза.
QR-коды с диффузией ошибки
Ещё одно преимущество нерегулярного дизеринга в том, что шум "соль и перец" от модулей данных QR-кода становится гораздо труднее заметить. Но он всё же присутствует, и именно из-за него изображение выглядит шумным. Впрочем, оно и так выглядело бы довольно шумным, поскольку это одно-битное изображение размером 147×147 пикселей, но часть этого шума возникает именно из-за того, что каждый девятый пиксель фактически имеет случайный цвет.
Эту проблему можно решить с помощью ещё большей диффузии ошибки.
Диффузия ошибки для модулей данных
Здесь применяется два прохода диффузии ошибки. Второй — обычный, а первый специально предназначен для маскировки модулей данных. Заранее известно, каким цветом должен быть каждый из этих пикселей, поэтому их окрашивают в нужный цвет и диффузируют возникшую ошибку на восемь соседних пикселей. Ошибка может оказаться довольно большой — обычно есть свобода выбора цвета, поэтому ошибка никогда не превышает 50%, но здесь может понадобиться сделать пиксель в тёмной области чисто белым, что создаёт ошибку в 95%. Звучит плохо, но именно поэтому так важно диффузировать эту ошибку, а не просто мириться с ней.
Заметно, что это заметно очищает изображение.
Дополнительные возможности
Инструмент-генератор позволяет проделывать дополнительные трюки. Можно повернуть QR-код перед добавлением изображения и поэкспериментировать с настройками кодирования, чтобы посмотреть, не будет ли какой-то из альтернативных вариантов выглядеть красивее.
Генератор также можно настроить так, чтобы он менял некоторые из тех модулей данных с 95%-ной ошибкой — в QR-кодах достаточно коррекции ошибок, чтобы позволить изменить несколько пикселей и код всё равно считался. (Именно так работают QR-коды с логотипом посередине.) Но на практике это слабо влияет на качество изображения, если ошибка от модулей данных уже диффузирована, зато серьёзно сказывается на том, насколько хорошо код сканируется.
Применение на практике
Всё это работает довольно неплохо, если не заходить слишком далеко, а код будет размещён на большом экране, плакате или похожей поверхности. Если же код напечатан, скажем, на бумажной листовке, которую могут помять, потребуется больше той избыточности, устойчивости и коррекции ошибок, которыми пожертвовали ради красоты. В конечном счёте это компромисс между эстетикой и сканируемостью — и стоит помнить, что если код считывается вашим телефоном с экрана ноутбука, это не значит, что он считается со старого "картофельного" телефона случайного прохожего с распечатки при плохом освещении.
Стоит также учитывать, что инструмент-генератор создаёт крошечные изображения без полей — небольшое поле необходимо для надёжного сканирования QR-кода, а браузеры обычно размывают изображения при увеличении масштаба, если не отключить это через CSS. Поле должно быть противоположного цвета относительно центра трёх больших квадратов-паттернов поиска — обычно это белый цвет, но можно сгенерировать инвертированный QR-код, которому потребуется чёрный фон.