Ох уж эти QR-коды

74a1e0a7b8588deed7efb536e4a7602d.jpg

Пандемия, осеннее обострение, зима близко и QR-коды на каждом шагу, роботы наступают, рутина работы затягивает. Хочешь покушать покажи картинку. Скучную и квадратную, для робота, не для человека. Только единицы могут ее читать, и только избранные рисовать. Вон на прошлой неделе как хабр QR-кодом бомбануло!

Идея

А что если оживить и «очеловечить» QR-код, сделать его не только для робота, но и для человека? Такая мысль мне не приходила, до тех пор пока я не наткнулся на статью про генерацию фотомозаик в виде QR-кодов, наткнулся совершенно случайно, в процессе изучения вопроса генерации изображений для приложения по расчету параметров для варки пива. «QR-кодная Мона Лиза» из этой статьи меня покорила своей причастностью к текущим реалиям.

Moza ЛизаMoza Лиза

И появилась идея. А если есть идея, то можно быстро сделать вечерний спайк на коленке и проверить ее работоспособность — «тыж программист». Увы, спайк получился так себе, QR-код читался через раз и выглядел отвратно, но идея не отпускала. Уж очень хотелось взять этот скучный ковидный QR-код и сделать его прикольным, чтобы люди проверяющие его в кафе или торговом центре улыбнулись и настроение их улучшилось.

Так вечерний спайк превратился в ночной ресерч. И к утру, я нашел две вещи достойные внимания и работы над ними. Это были «halftone qr codes» и «Aesthetic QR codes». А еще перелопатил кучу коммерчески успешных приложений которые умеют рисовать QR по всякому: рисуют классно, красиво, стабильно и… скучно.

Реализация день первый

Так я предложил коллеге по работе устроить крафтовый хакатон выходного дня, отпроситься у домашних, отложить все дела, засесть в, ставшем уже родным, офисе и покодить неведомую фигню на стеке который сами выберем. 

Мы выбрали Next.js от Vercel. Так как на React уже что-то писали и очень хотелось пощупать как работает их реализация serverless, а еще хотелось ощутить степень интеграции с гитхабом и прочие неведомые плюшки. Так же рассматривали возможность сделать нативные приложения используя react-native, но вовремя поняли, что за выходные этого не реализовать, а веб приложение всегда можно поместить на рабочий стол в пару тачей.

yarn create next-appyarn create next-app

Название родилось быстро, сошлись на QRART, Мона Лиза сыграла в этом не последнюю роль, да и pixel ART тоже проходил рядом. Купили домен и проксировали его через cloudflare на проект в vercel, для того чтобы еще на уровне dns отсечь ботов и всякую агрессивную нечисть. Проксирование оказалось очень простым и как приятное дополнение мы получили бесплатный https из коробки. Оказалось что можно не поднимать сервачок с убунтой, и не шаманить с letsencrypt, certbot-том и апачем. Что все просто работает, фактически на острие технологий.

За первую половину дня мы напилили спайк, который брал урл, превращал его в qr-код используя библиотеку qrcode-generator в npm и отрисовывал на канвас результат. 

Технически идея и реализация получилась простая. Мы делаем картинку в градациях серого и поверх нее рисуем точки или по правильному модули QR-кода, по факту точки черного и белого цвета. По умолчанию мы используем средний уровень коррекции ошибок, в котором можно восстановить 15 процентов информации. А размер QR-кода 6, это значит что в нем будет 41 модуль или точка, такой размер лучше всего подходит для визуального представления картинок. Конечно есть ограничения по размеру данных, но ссылка с ГосУслуг влезает. Вот тут можно посмотреть таблицу вместимости.

Дальше лучше в демке смотреть.Дальше лучше в демке смотреть.

Локально все работало просто прекрасно, и мы попробовали задеплоить в облако. И обломались, оказалось что с 2019 года vercel не может подружить библиотеки канваса с лямбдами. Добро пожаловать в мир сервелесс. Ну ничего, ничего, поставили подпорку — все заработало, хакатон как никак.

Ближе к концу первого дня у нас было приложение которое умело генерить QR-код по урлу или тексту, и сращивать его с картинкой, которую предварительно мы переводили в оттенки серого. Спайк работал. 

Захотелось локализацию и в Next она есть из коробки, да еще и с определением локалей, что очень и очень удобно. Называется это i18n-routing.

UI нашего спайка выглядел не особо, да и мы не дизайнеры. Но мы очень любим игры, старенькие nes«совские. И оказалось, есть готовая библиотека NES.css, которая стала фундаментом в дизайне нашего приложения и сэкономила кучу времени.

NES ностальгияNES ностальгия

Еще захотелось добавить шаринг во все что можно, для этого мы использовали addthis, но мы не смогли добавить его в Next на уровне кода. Причину искать долго не стали. А просто использовали cloudflare apps и добавили addthis не через код. И оно работает, что удивительно.  (Кстати, кто знает напишите, этот гад посылает запрос, но ничего не отрисовывает. Или подскажите в комментах хорошую альтернативу для шаринга)

Расшарить во все!Расшарить во все!

Для аналитики мы взяли plausible.io это легковесное решение, которое пилят два разработчика и она тоже серверлесс. Но можно и у себя развернуть на большом, настоящем, железном сервачке.

В итоге первого дня разработки у нас было локализованное на два языка приложение, которое выглядело не отвратно, и даже минимально работало. Был выстроен удобный «пайплайн» разработки благодаря интеграции Vercel проекта с репозиторием и деплоем в прод по коммиту в мастер. 

А еще был план на следующий день. Который мы просто записали в readme репозитория, да и весь TODO вели там же в одном файлике. Без трелл, планнеров джир и прочих сложных энтерпрайз штуковин.

Реализация день второй

В первый день работы над приложением мы реально кайфанули от разработки и прощупывания стека технологий, даже проблема с канвасом (которую не могут решить с 2019 года sic!) казалась не ущербностью, а просто технической недоработкой, на которую можно закрыть глаза.

На второй день было запланировано сделать галерею шаблонов для QR-кода, генерацию из любой картинки. Сохранение как png, шаринг готовой картинки и, может быть, считывание готового QR-кода и генерация нового с картинкой. А еще нужно было сделать редирект писем на личную почту с доменной.

С редиректа и стартовали. И тут выяснился интересный момент, что forwardemail который я успешно использовал для нескольких проектов, не заработал в связке с cloudflare и vercel. А improvmx.com заработал без вопросов. Почему так? Мы, следуя выбранной парадигме хакатона — «работает не трогай», исследовать не стали.

Галерею сделали из стандартного пакета react-image-gallery, тут все прошло гладко.

Котиков мало не бывает!Котиков мало не бывает!

А вот с генерацией из загружаемой картинки пришлось повозиться. Момент в том что создание QR-кодов происходит на сервере, и туда нужно эту картинку передать. По хорошему для этого нужно делать multipart запрос и передавать картинку. Обычно это делают в миделваре для next api routes. Но, хакатон же. В итоге, мы жмем картинку на клиенте и отправляем ее на сервер как json.

Не, ну а чо?Не, ну, а чо?

А обработанный результат складываем в DO spaces, конечно тут можно было взять хранилище от Amazon. Но под рукой оказался DO, тем более что он просто проксирует Amazon.

В завершении дня мы нашли и починили баг созданием QR-кода в котором есть киррилица. Код создавался, но считывалась какая-то ерунда. Оказалось нужно прописать использование многобайтовой кодировки. Одна строчка кода и столько радости, что русский язык заработал:

qrcode.stringToBytes = qrcode.stringToBytesFuncs['UTF-8']

Результат

От второго дня нашего крафтового хакатона мы тоже остались очень довольны. И даже пофантазировали над фичами которые можно еще сделать — цветные qr-коды, как это делает visualead, коды из мозаик, аналитика для qr-кодов и многое многое другое.

Даже была идея открыть код, но там сейчас все довольно страшненько написано. Сейчас это скорее спайк, без тестов, без документации и с некоторыми явными костылями. И путь от спайка к настоящему продукту долог.

Главный результат в том, что мы получили кучу положительных эмоций от этих двух дней разработки. Мы можем точно сказать что выбранный нами стек отлично подходит для прототипирования приложений и его можно использовать.

Будем рады, если и вам понравится наш эксперимент.

Mono ЛизаMono Лиза

А еще я успел написать статью которую вы сейчас прочитали. Мона Лиза прилагается и улыбается вам сквозь время и пиксели. Спасибо!

© Habrahabr.ru