Пандемия, осеннее обострение, зима близко и QR коды на каждом шагу, роботы наступают, рутина работы затягивает. Хочешь покушать — покажи картинку. Скучную и квадратную, для робота, не для человека. Только единицы могут ее читать, и только избранные рисовать. Вон на прошлой неделе как хабр qr кодом бомбануло!
Идея
А что если оживить и “очеловечить” QR код, сделать его не только для робота, но и для человека? Такая мысль мне не приходила, до тех пор пока я не наткнулся на статью про генерацию фотомозаик в виде QR кодов, наткнулся совершенно случайно, в процессе изучения вопроса генерации изображений для приложения по расчету параметров для варки пива. “QR кодная Мона Лиза” из этой статьи меня покорила своей причастностью к текущим реалиям.
И появилась идея. А если есть идея, то можно быстро сделать вечерний спайк на коленке и проверить ее работоспособность - “тыж программист”. Увы, спайк получился так себе, QR код читался через раз и выглядел отвратно, но идея не отпускала. Уж очень хотелось взять этот скучный ковидный QR код и сделать его прикольным, чтобы люди проверяющие его в кафе или торговом центре улыбнулись и настроение их улучшилось.
Так вечерний спайк превратился в ночной ресерч. И к утру, я нашел две вещи достойные внимания и работы над ними. Это были “halftone qr codes” и “Aesthetic QR codes”. А еще перелопатил кучу коммерчески успешных приложений которые умеют рисовать QR по всякому: рисуют классно, красиво, стабильно и… скучно.
Реализация день первый
Так я предложил коллеге по работе устроить крафтовый хакатон выходного дня, отпроситься у домашних, отложить все дела, засесть в, ставшем уже родным, офисе и покодить неведомую фигню на стеке который сами выберем.
Мы выбрали Next.js от Vercel. Так как на React уже что-то писали и очень хотелось пощупать как работает их реализация serverless, а еще хотелось ощутить степень интеграции с гитхабом и прочие неведомые плюшки. Так же рассматривали возможность сделать нативные приложения используя react-native, но вовремя поняли, что за выходные этого не реализовать, а веб приложение всегда можно поместить на рабочий стол в пару тачей.
Название родилось быстро, сошлись на 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, которая стала фундаментом в дизайне нашего приложения и сэкономила кучу времени.
Еще захотелось добавить шаринг во все что можно, для этого мы использовали addthis, но мы не смогли добавить его в Next на уровне кода. Причину искать долго не стали. А просто использовали cloudflare apps и добавили addthis не через код. И оно работает, что удивительно. (Кстати, кто знает напишите, этот гад посылает запрос, но ничего не отрисовывает. Или подскажите в комментах хорошую альтернативу для шаринга)
Для аналитики мы взяли plausible.io это легковесное решение, которое пилят два разработчика и она тоже серверлесс. Но можно и у себя развернуть на большом, настоящем, железном сервачке.
В итоге первого дня разработки у нас было локализованное на два языка приложение, которое выглядело не отвратно, и даже минимально работало. Был выстроен удобный “пайплайн” разработки благодаря интеграции Vercel проекта с репозиторием и деплоем в прод по коммиту в мастер.
А еще был план на следующий день. Который мы просто записали в readme репозитория, да и весь TODO вели там же в одном файлике. Без трелл, планнеров джир и прочих сложных энтерпрайз штуковин.
Реализация день второй
В первый день работы над приложением мы реально кайфанули от разработки и прощупывания стека технологий, даже проблема с канвасом (которую не могут решить с 2019 года sic!) казалась не ущербностью, а просто технической недоработкой, на которую можно закрыть глаза.
На второй день было запланировано сделать галерею шаблонов для QR кода, генерацию из любой картинки. Сохранение как png, шаринг готовой картинки и, может быть, считывание готового QR кода и генерация нового с картинкой. А еще нужно было сделать редирект писем на личную почту с доменной.
С редиректа и стартовали. И тут выяснился интересный момент, что forwardemail который я успешно использовал для нескольких проектов, не заработал в связке с cloudflare и vercel. А improvmx.com заработал без вопросов. Почему так? Мы, следуя выбранной парадигме хакатона - "работает не трогай", исследовать не стали.
Галерею сделали из стандартного пакета react-image-gallery, тут все прошло гладко.
<ImageGallery
ref={gallery}
additionalClass="img-gallery animate__animated animate__bounceInDown"
items={galleryItems}
infinite={false}
showPlayButton={false}
showFullscreenButton={false}
/>
А вот с генерацией из загружаемой картинки пришлось повозиться. Момент в том что создание QR кодов происходит на сервере, и туда нужно эту картинку передать. По хорошему для этого нужно делать multipart запрос и передавать картинку. Обычно это делают в миделваре для next api routes. Но, хакатон же. В итоге, мы жмем картинку на клиенте и отправляем ее на сервер как json.
А обработанный результат складываем в DO spaces, конечно тут можно было взять хранилище от Amazon. Но под рукой оказался DO, тем более что он просто проксирует Amazon.
В завершении дня мы нашли и починили баг созданием QR кода в котором есть киррилица. Код создавался, но считывалась какая-то ерунда. Оказалось нужно прописать использование многобайтовой кодировки. Одна строчка кода и столько радости, что русский язык заработал:
qrcode.stringToBytes = qrcode.stringToBytesFuncs['UTF-8']
Результат
От второго дня нашего крафтового хакатона мы тоже остались очень довольны. И даже пофантазировали над фичами которые можно еще сделать - цветные qr коды, как это делает visualead, коды из мозаик, аналитика для qr кодов и многое многое другое.
Даже была идея открыть код, но там сейчас все довольно страшненько написано. Сейчас это скорее спайк, без тестов, без документации и с некоторыми явными костылями. И путь от спайка к настоящему продукту долог.
Главный результат в том, что мы получили кучу положительных эмоций от этих двух дней разработки. Мы можем точно сказать что выбранный нами стек отлично подходит для прототипирования приложений и его можно использовать.
Будем рады, если и вам понравится наш эксперимент.
А еще я успел написать статью которую вы сейчас прочитали. Мона Лиза прилагается и улыбается вам сквозь время и пиксели. Спасибо!
PS после публикации выяснилось что есть целое направление искусства, которое занимается созданием красивых QR кодов. И называется оно quick response art. И уже есть реализации генераторов, которые делают коды круто и красиво. Например библиотека amazing-qr. Скорее всего есть еще решения и сервисы. Буду вести и пополнять список под статьей.
amazing-qr - Python QR Code Generator GPLv3
Комментарии (63)
ihost
22.11.2021 11:58+2Cerberuser
22.11.2021 13:40При отправке строки длиннее 106 символов получаю Internal Server Error. Это так и задумано?
SeOd Автор
22.11.2021 13:44+1Скорее нет, чем да. Нужно поставить отбивки и проверки. Мы по логам лямбды видим что кто-то сует большой текст. И знаем о проблеме. Обязательно починим.
Cost_Estimator
22.11.2021 13:40+1Сканер QR (разработчик — TeaCapps), на андроиде. Распознал все три кода из статьи. Классная идея, спасибо )
Кстати, вот рекурсивный QR-кот
SeOd Автор
22.11.2021 13:46Идея старая, мы на новаторство не претендуем) Это такой привет из прошлого на относительно свежем стеке технологий.
Рекурсивный QR кот, мем родился)
Psychorabbi
22.11.2021 16:19+4Хммм, как насчёт qr-кода, перезагружающего устройство при сканировании? Это могло бы помочь побыстрее разобраться с очередями на входах.
KoteMilote
22.11.2021 16:56+5хорошая идея что бы разжиться базой QR кодов о прививках, а потом их можно будет продавать
Medeyko
22.11.2021 18:35А почему вы так щепетильно отнеслись к полосам синхронизации? На картине “QR кодная Мона Лиза” с ними обошлись так же, как и с остальными полями, кроме поисковых и выравнивающего узоров. Вы ориентировались на спецификацию?
Просто, на мой взгляд, полосы синхронизации вносят в картинку заметный диссонанс...
SeOd Автор
22.11.2021 22:03Мы сгенерировали qr код с помощью библиотеки qrcode-generator. И в виде точек совместили с изображением. Он сканировался совсем плохо, потом мы добавили полноразмерные position pattern (поисковые узоры) - это не помогло. А дальше стали добавлять запчасти qr кода до тех пор пока он не сканировался нормально айфоном который был под рукой. Это подход совсем не по спецификации и возможно сейчас из за этого проблемы на некоторых устройствах. Но это все-таки спайк выходного дня.
Medeyko
22.11.2021 22:48По спецификации, насколько я знаю, ищется и анализируется средняя яркость поля, а форма особого значения не имеет. Может, эта информация будет вам чем-то полезна.
А вы error correction level не хотите сделать 'H', а не 'M', как у вас сейчас (библиотека вроде поддерживает, насколько я посмотрел)? Будет несколько лучше сканироваться.
Ещё дешёвый способ улучшить распознавание - увеличить радиус информационных точек. По-моему, если чуть-чуть увеличить, останется красиво, а уровень распознавания вырастет сильно.
SeOd Автор
23.11.2021 11:23Уровень коррекции поставили M, чтоб ссылка на гос услуги влезала. А версию 6 чтобы меньше квадратов было. Размеры точек определяли от обратного, по факту уменьшали их до тех пор пока телефон переставал распознавать. Возможно переборщили, так как iphone хорош в распознавании кодов.
ifap
22.11.2021 18:42+1А что если оживить и “очеловечить” QR код, сделать его не только для робота, но и для человека?
А мсье знает толк в приключениях ;) Рассказываю, что будет если: это не код а непойми что, досвидос, не задерживайте очередь! И особо строгие ревнители устава караульно-постовой службы даже не будут пытаться его сканировать.SeOd Автор
22.11.2021 20:11+2Вполне возможная ситуация. Ну я бы не провоцировал важные инстанции. А вот в паб сходить с таким кодом самое оно.
BloodyKompot
22.11.2021 20:07Классно придумано! Переделал свой qr-сертификат под любимого Doge, теперь черно-белые квадраты радуют глаз))
glooow
22.11.2021 20:07+1Признаться, я не совсем понял, для чего его вообще "очеловечивать". Будет, конечно же, нескучно (как болгенос), но мне кажется это только геморрой лишний. Чем меньше тактов тела требует какое-то действие, тем для тела лучше, а где лучше для тела, там лучше для мозга, а где для мозга лучше, там хорошее настроение и вера в завтрашней день!
SeOd Автор
22.11.2021 20:08+2Правда, не знаю как ответить. Появилась идея и желание, каких то разумных доводов не могу привести.
korsarer
22.11.2021 22:22Я так и не понял. А где ссылка на получившийся сайт? Хочется же поробовать. Или есть только приложение? По запросу "QRART" выходит сайт qrart.com, который кажется не имеет отношения к описанному в статье.
Medeyko
22.11.2021 22:52+2Подождите. Вы это серьёзно? Или я в шутку не врубился? :)
Вы пробовали сканировать изображения из статьи? Они все, кроме "Moza Лиза", дают ссылку https://qrart.app/
Kolobrod72
23.11.2021 00:37Штатный "Сканер" из софта "из коробки" Xiaomi Readme 4X. Ч/б Мону Лизу прочитал легко, цветную - с трудом, а кота - только по увеличенной картинке.
Andy_Big
23.11.2021 08:32Аппаратный сканер штрих-кодов цветную Мону Лизу сканирует 1 раз из 5, черно-белую вообще не получилось ни разу за сотню попыток :)
GT21
23.11.2021 11:09А можно для домохозяек: как этим пользоваться? Начиная с момента как скачать
SeOd Автор
23.11.2021 11:11Качать не нужно. Это просто сайт, который может сделать qr код в виде картинки с текстом или адресом сайта из готовой картинки.
Исходную картинку можно выбрать готовую или подложить свою.
GT21
23.11.2021 11:40Тогда я не нашел ссылку на сайт. Вижу только на гитхаб
vrusua
23.11.2021 13:54подскажите, где Вы нашли ссылку на гитхаб?
GT21
23.11.2021 13:56"amazing-qr - Python QR Code Generator GPLv3"
vrusua
24.11.2021 11:18понял, это один из сторонних примеров на Python, которые вдохновили авторов статьи, а их приложение на NextJS доступно здесь https://qrart.app, на гитхаб, к сожалению, ссылок нет ((
A_Botov
23.11.2021 11:12С неделю назад как раз появилась аналогичная идея, но немного с другой точки зрения. QR код как инструмент оперативной передачи данных в рекламных блоках вижу регулярно, но в последнее время у многих коды вызывают крайне негативные ассоциации. И вот именно с этой точки зрения и именно в данном контексте было бы неплохо наверное заменить скучные коды нужными в рекламном блоке изображениями.
SeOd Автор
23.11.2021 11:17+1Так и есть, я когда искал готовые решение наткнулся только на пару компаний которые делают именно кастомные красивые QR коды. Для рекламных целей можно доработать что-бы совсем красиво было. Вроде бы даже Тема Лебедев у себя на канале ютубном показывал коды которые чел как картины рисовал.
Во нашел, вот этот: https://www.instagram.com/p/CCHmh0OKFgf/
Lexicon
23.11.2021 16:02Под ноду/веб есть модуль https://www.npmjs.com/package/awesome-qr
ИМХО, QR коды в виде картинок глазами уже не так узнаваемы
И красивее почему-то кажутся обычные QR с иконкой в центреSeOd Автор
24.11.2021 11:08Да, верно awesome-qr крутая библиотека, делает примерно то что я хотел. На момент разработки я его, к сожалению, не видел. Одно из быстрых решений его запаковать в лямбду и прицепить к приложению.
Хотелось именно картинок пиксельных. А так да, можно у qr кода поменять глазки, модули красиво отрисовать и картинку в центр добавить. Так в целом все сервисы и делают, это нормальная практика.
fedotovartuom76
23.11.2021 16:37Bing все QR-коды из статьи и комментариев - распознал на лету. Мощная штука на самом деле. Мона Лиза ещё даже полностью в кадр не попала, а он уже считал всё. Трудности у него возникли только с рекурсивным QR-котом из комментов, но через несколько секунд всё-таки прочитал.
Google объектив немного дольше, но справился со всем кроме рекурсивного QR-кота из комментов. Его ни в какую не хочет сканировать. Родная камера ASUS ZenFone 7 справилась аналогично Google объективу.
Grigo52
24.11.2021 11:09Вот было бы смешно, если бы вирусы на телефоны начали передавать через QR коды
SeOd Автор
24.11.2021 11:11Вот тут https://hackaday.com/2020/08/17/fitting-snake-into-a-qr-code/ ребята змейку упаковали в qr, так что сунуть вирус или эксплоит вполне реальная ситуация. А с учетом того что люди научились использовать qr, то пора уже антивирус под это дело пилить.
denisshabr
24.11.2021 16:16+2Почитал пост, почувствовал себя со смузи и вейпом на гироскутере. Стильно, модно, молодёжно, serverless и ещё дофига модных слов чтобы не скучать.
Не понимаю в чём прикол этих serverless бомж-пакетов, зависитеть от них, страдать от того, что что-то там не работает как надо, вместо того чтобы за $5-$10 в год взять VPS. Тем более тот же DO Space стоит $5/месяц и вы их уже платите.
SeOd Автор
24.11.2021 16:36Да, все можно на vps развернуть. Будет работать примерно так же. И свитер сам собой прорастет и борода закудрявится)
Нам, правда, очень понравилось тыкать палочкой serverless стек, в этом точно что то есть. Появилось стойкое ощущение что будущее за облаками, в той или иной реализации.
Chuvi
BinaryEye QR-коды из статьи QR-кодами не посчиитал.
Вот вам и вжух.
SeOd Автор
Ох уж эти баги. ) Нужно глянуть что это за штука BinaryEye, iphone и android норм читает из коробки.
El_Kraken_Feliz
У меня читается, андроид
Chuvi
Решил проверить через Google Объектив.
Во-первых работает, а во-вторых, нашлись похожие изображения. https://habr.com/ru/post/310052/
SeOd Автор
Дык идея полутоновых кодов еще 2013 года. На хабре не видел, спасибо за ссылку! Можно будет применить.
FotoHunter
Яндекс "поиск по фото" и гугл "умная лупа" - увидели мону лизу и не стали читать текст. Зато накидали и оригинальные фото и другие фото с qr-кодами. Видимо алгоритмы этих сайтов в первую очередь видят фото в целом и не воспринимают её как qr код. Только первы qrCat распознался правильно.
vvzvlad
Стандартная эппловская камера тоже.
SeOd Автор
А моделька какая телефона?
xakep2011
"Сканер QR- и штрих-кодов" https://play.google.com/store/apps/details?id=com.teacapps.barcodescanner прочитал без промедлений. Довольно мощное приложение, читает самые хардкорные экземляры.
SeOd Автор
Круто!
Pinkbyte
Странно, именно он у меня как раз Моно Лизу и не осилил, в отличие от встроенного в Firefox-а под андроид сканера...
cepera_ang
У меня читает, только не очень стабильно, надо поиграться с положением/углом, чтобы поймал.
Beanut
Я представляю как проверяющий в кафе сидит пыхтит пытаясь заставить свой сканер считать этот код. Итак день не задался, так еще эти "весельчаки" со своими нескучными QR-кодами.
SeOd Автор
Да, подтверждаю некоторые андроид устройства не всегда читают код. Дочь пришла из школы, провела там всестороннее тестирование на реальных устройствах)
Поправим, скорее всего накосячили в генерации картинки, подсмотрим как у крутых ребят сделано. Может и цвет добавим, но на это не буду загадывать.
mitasamodel
QR Droid Private + LG V30 ничего не прочитали
А вот это прочиталось (отсюда):
SeOd Автор
Ну так ручной труд не победить, да там есть проблема с генерацией. Мы о ней знаем, даже примерно понятно как чинить.
Medeyko
Либо какая-то совсем допотопная версия BinaryEye, либо у Вас что-то с экраном или с камерой. У меня совершенно без проблем прочитал всё, в том числе и на запасном дешёвом телефоне с не самой лучшей камерой.
Fullmoon
У меня специализированное приложение прочитало (правда, с цветным повозилось), а вот родная самсунговская камера слишком универсальная, и вместо кода в первую очередь полезла определять лицо.
SeOd Автор
запала на Мона Лизу) Мы тут в логах обнаружили что пришел чат бот и давай к лямбдам приставать. То им текст введет, то картинку подсунет, я подозреваю что у них там уже отношения. Вроде надо и забанить, а вдруг это любовь...
Kazehay
Забаньте. Любовь не знает преград, а вот неразумным не стоит делать лишних поблажек))