Генерируем цветной QR-код с логотипом на Java. Специфика генерирования цветных QR кодов Генератор цветных qr кодов

Автор блога Hack A Day Брайан Бенчофф (Brian Benchoff) разобрался в алгоритме генерации QR-кодов (стандарт ISO 18004) и составил инструкцию , как можно внедрить в QR-код произвольное изображение. Например, логотип фирмы.

Для работы использовались генератор QR-кодов и Microsoft Paint для попиксельного редактирования.

Шестая версия QR-кодов представляет собой квадрат со стороной 41 пиксел.

На картинке показан шаблон QR. На нём чёрные пикселы всегда обязаны быть чёрными, а белые обязаны быть белыми. Серая зона свободна для творчества.

Серое пространство разделяется на 172 восьмипиксельных участка, как показано ниже.

Некоторые зоны разбиты на две части и разнесены в пространстве, они соединяются чёрными линиями. Как показывает опыт, около 30% зон могут быть заполнены случайной информацией , и телефон всё равно сможет раскодировать информацию. Таким образом, из наших 172 зон можно использовать примерно 51 штуку, придавая любую форму и цвет.

То есть можно нарисовать рисунок размером 51 пиксел. Например, вот логотип Hack A Day.

Важно сделать контрастный контур, чтобы логотип отделялся от разнородного фона. Если поместить этот логотип на шаблок QR-кода, получится примерно такая картина.

Теперь нужно подсчитать, какое количество восьмипиксельных зон затронуто логотипом. Похоже, что не больше 51 штуки, так что всё нормально, поэтому можно переходить к следующему этапу: генерации настоящего QR-кода поверх этой картинки. Открываем вышеупомянутый генератор QR-кодов , выбираем шестую версию, уровень коррекции ошибок и указываем информацию для закодирования (http://www.hackaday.com). Поверх полученного кода вставляем логотип.

Вот такую штуку уже можно печатать на визитках.

Чтобы делать по-настоящему красивые логотипы, можно взять QR-код большего размера. Например, 14-й версии со стороной квадрата 73 пиксела. При определённых условиях можно даже залезать в служебную зону на границе.

IBM выглядит реально красиво в этом размере. Для сравнения, IBM в QR v6 не столь впечатляет.

Заметьте, что пикселы можно делать любого цвета: белого, чёрного, красного или лилового, важен только контраст между ними. Поскольку в данном логотипе буквы IBM относительно тёмные, то алгоритм воспримет их как чёрные. Использование цвета - удобный приём, который позволяет избавиться от контрастной границы и, таким образом, экономит пространство для логотипа.

Если бы у логотипа Firefox была белая граница, то он бы покрыл больше 30% площади изображения. А с использованием цвета он покрывает меньше 30% и этот QR-код прекрасно считывается.

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

UPD. В Android Market появилось приложение MeCode Beta , которое позволяет генерировать произвольные штрих-коды на телефоне, в том числе и с логотипами. Очень удобная вещь - можно вывести картинку на экран и обмениваться информацией с другими телефонами.

Некоторое время назад мне потребовалось генерировать несколько QR-кодов для каждого пользователя системы. А чтобы было интересно сканировать этот код, было решено добавить в него логотип.

Предисловие
QR-коды можно встретить везде, но как их отличить друг от друга? QR-коды всё время завоёвывают популярность, и нет-нет, да и встретятся несколько штук рядом. Зрелище это не из приятных - какой сканировать первым? И вообще, зачем сканировать то, от чего начинает рябить в глазах?
Решением такой задачи может служить персонализирование QR-кода: нестандартные цвета, логотип, или пояснительная надпись немного ниже самого кода, по которой можно понять - интересно ли зрителю это или нет.
Навеняка многие видели красивые QR-коды (а кто не видел, может посмотреть на хабре или на стороннем ресурсе), но мне стоит оговориться - чтобы создать такой, нужно вложить либо большие ресурсы в алгоритм генерации картинки, либо нарисовать такой код в фотошопе, но это будет единичный экземпляр, и для большинства из нас он не годится (если, конечно, есть вообще необходимость генерировать их самому).
Как это реализовано?
Создатели QR-кодов не расчитывали, что мы будем вставлять свои картинки в закодированные сообщения, коими являются сами коды, но они предусмотрели возможность высокого объёма восстановительной информации - код может содержать до 30% последней. Чем её больше - тем гуще картинка, но больше шансов, что пользователь раскодирует испорченный код. А портить мы его будем логотипом.
Для генерации кода использовалась библиотека ZXing - это open source библиотека для обработки различных 1D/2D штрихкодов, которая, кроме Java, имеет порты на другие языки.
Особенностью этой библиотеки является то, что она разбита на модули и распространяется в исходных кодах, которые необходимо компилировать. Но, к счастью, она есть в мавен репозитории - модуль core использовался для генерации, и модуль java se использовался для валидации кодов.
Для работы с графикой были использованы стандартные классы из пакета java.awt (JavaSE).
За дело!
Для экспериментов была сделана небольшаю консольная программа, которую можно найти на гитхабе - репозиторий опытного образца , которую я и разберу в этом разделе.

Тот, кому просто нужен QR-код, может написать следующее:
BitMatrix matrix = new MultiFormatWriter().encode("text to encode", BarcodeFormat.QR_CODE, width, height); MatrixToImageWriter.writeToFile(matrix, filename.substring(filename.lastIndexOf(".")+1), new File(filename));
В противном случае так делать не стоит - по умолчанию библиотека добавит мало восстановительной информации, и даже если после вставки логотипа картинка расшифруется у нас на компьютере, то с фотокамеры она уже может считаться неправильно. По-этому будет хорошим тоном добавить максимум восстановительной информации, а раз мы будем изменять цвета и картинку, то не нужно спешить сохранять результат:
Hashtable hintMap = new Hashtable(); hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); QRCodeWriter qrCodeWriter = new QRCodeWriter(); BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, hintMap);
Создание картинки из матрицы кода делается в цикле - создаём картинку соответствующего размера и, проходя матрицу кода, отображаем наличие бита в матрице на картинку как информативный пиксель. Во время этого действа можно задать цвет фона и цвет кода:
int matrixWidth = bitMatrix.getWidth(); BufferedImage image = new BufferedImage(matrixWidth, matrixWidth, BufferedImage.TYPE_INT_RGB); image.createGraphics(); Graphics2D graphics = (Graphics2D) image.getGraphics(); graphics.setColor(Color.white); graphics.fillRect(0, 0, matrixWidth, matrixWidth); Color mainColor = new Color(51, 102, 153); graphics.setColor(mainColor); //Write Bit Matrix as image for (int i = 0; i < matrixWidth; i++) { for (int j = 0; j < matrixWidth; j++) { if (bitMatrix.get(i, j)) { graphics.fillRect(i, j, 1, 1); } } }
Ну вот, теперь, когда мы оперируем картинкой, а не матрицей единиц и нулей, нам очень даже удобно и логотип в центр поместить, предварительно поправив его разрешение, чтобы не перекрывать весь код в случае слишком большого размера:
BufferedImage logo = ImageIO.read(this.getLogoFile()); double scale = calcScaleRate(image, logo); logo = getScaledImage(logo, (int)(logo.getWidth() * scale), (int)(logo.getHeight() * scale)); graphics.drawImage(logo, image.getWidth()/2 - logo.getWidth()/2, image.getHeight()/2 - logo.getHeight()/2, image.getWidth()/2 + logo.getWidth()/2, image.getHeight()/2 + logo.getHeight()/2, 0, 0, logo.getWidth(), logo.getHeight(), null); private BufferedImage getScaledImage(BufferedImage image, int width, int height) throws IOException { int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); double scaleX = (double)width/imageWidth; double scaleY = (double)height/imageHeight; AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY); AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR); return bilinearScaleOp.filter(image, new BufferedImage(width, height, image.getType())); }
После нашего надругательства над кодом, обязательно стоит его проверить на правильность - хватит ли восстановительной информации для идеальной фотокамеры? И если хватит, то пора сохранить катинку и отдать её пользователю:
if (isQRCodeCorrect(content, image)) { ImageIO.write(image, imageFormat, this.getGeneratedFileStream()); } private boolean isQRCodeCorrect(String content, BufferedImage image){ boolean result = false; Result qrResult = decode(image); if (qrResult != null && content != null && content.equals(qrResult.getText())){ result = true; } return result; } private Result decode(BufferedImage image){ if (image == null) { return null; } try { LuminanceSource source = new BufferedImageLuminanceSource(image); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); Result result = new MultiFormatReader().decode(bitmap, Collections.EMPTY_MAP); return result; } catch (NotFoundException nfe) { return null; } }

Поставленная цель достигнута - QR код сгенерирован. Спасибо за внимание!

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

Но одна из самых частых причин, почему QR получают маленькое количество сканов, — это недостаточный контраст между цветами переднего и заднего плана.

Почему контраст так важен при генерировании QR кодов?

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

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

Какой должен быть контраст?

Тональный контраст и оттеночный контраст

Чаще всего стандартные QR коды создаются черно-белыми (тональный контраст) и именно под сканирование таких qr разрабатываются мобильные приложения. Данные ридеры не способны различать оттенки цветов, они «видят» исключительно разницу двух противоположных цветов. В таком случае не прогадаешь, потому что черный и белый – контрастные цвета.

Если же вы генерируете цветной QR код (оттеночный контраст), то крайне важно учесть, чтобы разница в цветах была достаточно большой (например, красный и зеленый, красный и черный, красный и синий, желтый и синий), для того чтобы ридер смог «увидеть» два оттенка. Те цвета, которые видит глаз человека, диаметрально отличаются от восприятия цветов мобильным устройством. Поэтому обратите внимание на яркость одного из выбранных вами оттенков. Если два цвета будут похожи (оранжевый и желтый), в них не будет достаточно контраста, тогда ридер не сможет определить зашифрованную информацию.

Когда тонального контраста будет достаточно?

Количество тонального контраста для того, чтобы обеспечить быстрое и надежное сканирование, зависит от нескольких факторов:

  • Окружающий свет (даже черно-белые изображения могут быть не отсканированы при темном освещении).
  • Поверхность отражения (блестящая поверхность будет отражать белый цвет, не стоит выбирать белый фон, если вы хотите для переднего плана выбрать блестящие оттенки).
  • Расстояние сканирования (чем дальше расположен QR, чем меньше он виден камере, тем более выраженное контрастное различие должно быть между передним и задним планом).
  • Качество камеры (некоторые камеры имеют особые тональные диапазоны).

Поэтому лучше всего выбирать стандартный уровень контрастности, который будет работать в условиях сканирования любыми ридерами. Безопасный уровень контрастности должен быть не меньше 40%. При такой процентной разнице QR ридер сможет точно различить два цвета.

Традиционные черно-белые коды имеют наибольшую вероятность распознавания при условиях, если тональный контраст 100% (белый – 0%, черный – 100%).

Как быть с перевернутыми кодами?

Перевернутые – это такие коды, для переднего плана которых выбран более светлый оттенок, а для заднего – более темный. С такими изображениями нужно быть аккуратным, так как на данный момент небольшое количество ридеров может их отсканировать. Если вы генерируете коды такого вида, обязательно протестите их перед тем, как внедрять в маркетинговую кампанию.

Контраст для генерирования цветных кодов

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

Для того чтобы цветной QR код был действительно эффективным, важно, чтобы его мог отсканировать любой ридер. Поэтому при генерации стоит обращать особое внимание на контраст цветов. Потому что контраст – это один из ключевых параметров, который влияет на «читабельность».

*Обязательно учитывайте параметр контраста при создании дизайнерских и брендированных QR кодов.

На днях нас посетила забавная идея — провести анализ QR-кодов, которые генерируют пользователи . Результаты оказались, с одной стороны, несколько предсказуемыми, с другой — удивили, а с третьей — даже повеселили.

О прозаичном

Наиболее часто пользователи зашифровывают имена, данные со своих визиток, адреса электронных ящиков или ссылки на сайты. Причем среди банальных (а-ля Иванов Сергей и Соколова Татьяна) были замечены и весьма своеобразные имена-фамилии. Особенно запомнились Кадыгроб Денис, Шалава Ольга Николаевна (интересно, фамилия девичья или уже «по мужу»), Пидосюк Олег Александрович и Попандопуло Вячеслав.

Во вторую, достаточно обширную категорию, входят коды «ни о чем»: «тест», «йцуке», «123456», «qwerty» «ляляля», «+++++» и им подобные. Ну, что здесь скажешь? Фантазия, увы, дана не всем.

На третьем месте по популярности — коды-выражения чувств. Встречалось и английское «I love you», и немецкое «Ich liebe dich», и французское "Je T"aime. Рядом с зашифрованными «Солнце, я тебя люблю» и «Зайчонок, ты лучше всех» успешно соседствуют «Марсель, дурак» и «Ты какашка тратата».

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

Не обошлось и без политических настроений, причем здесь, скорее всего, постарались братья белорусы: «Луку в жопу», «Бацьку ф топку» и известное сегодня каждому белорусу «ШОС». А россияне подкачали: кодов про кого-нибудь из четы Путин-Медведев ни разу не встретилось.

Многие пользователи генерировали строчки из стихотворений. Лидером стало «Наша Таня громко плачет» — про рыдающую девочку вспомнили аж 5 раз. Гораздо хуже обстоят дела со школьной программой: если Пушкина еще кто-то знает («Я к вам пишу, чего же боле»), то Лермонтова, Есенина или Некрасова незаслуженно позабыли вообще. Также странно, что никому не пришло в голову сгенерировать строчки песен. Из «музыкальных» QR-кодов было «выловлено» лишь «Ослик, суслик, паукан и мокренькая кисонька» и «до ре ми фа соль ля си». Последний код, кстати, привлек своей кроваво-красной расцветкой и угрожающей, написанной на самом коде, фразой — «Убью». Лишнее подтверждение тому, как наши ожидания нередко полностью расходятся с полученным.

Переходим к оригинальному


Намного реже встречаются QR-коды, создатели которых проявили долю фантазии и юмора. Но они есть. Нам удалось «отловить»:
  • призыв «Вступайте в ряды натуралов»
  • предупреждение «Отжим денежных средств у государства. Внимание опасность!»
  • «план на будущее» «Я скоро пойду на базар и куплю самовар. Буду пить чай»
  • удивление «а ты не поленился расшифровать»
  • мольбу «А если ошибка? Если бы ошибка… Только бы ошибка...».

Некоторые пользователи с помощью QR-генератора умудряются вести между собой диалоги:

  • «Придешь сегодня?»
  • «Приходи сегодня»
  • «Кароче Катя чота молчит =(Мы опять нажремся с тобой»

Наверное, Катя представляла вечер совсем по-другому, вот и молчит. Попробуйте предложить «ужин и массаж», глядишь, леди и согласится.

  • «Кукуся сладкая, ты где?»
  • «Я здесь»
  • «А я тут»
  • «Может, кофе?»
  • «Может, сразу?»

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

И уж не знаем, можно ли отнести один из сгенерированных кодов к «оригинальным… Но теперь мы — обладатели данных кредитки. Все же нашим посетителям не мешало бы быть поосторожнее.

Персонально для разработчиков

Некоторые пользователи генерировали коды, предназначающиеся разработчикам генератора . Один не поленился экспрессивно сообщить «Задрал ты уже со своими кр кодами!», другой возмутился тем, что «слишком много у этого генератора настроек» (уж простите, скучных черно-белых квадратов и так вокруг хватает). Но гораздо больше было приятных посланий: «Супер-генератор», «Прикольно, мне нравится», «Привет разработчикам — прога зашибись», «Пацаны, пешите исчо» (кстати, да, над генератором идет постоянная работа и в планах — выпуск новых версий). В общем, как бы там ни было, внимание к нашим персонам всегда прельщает.


В заключение хочется особо отметить некоторых пользователей, в частности, наших уже постоянных «клиентов». Практически каждый день генерируются коды, посвященные Дарвиновскому музею и его сайту www.darwin.museum.ru . Кстати, в Дарвиновском музее владельцам устройств с приложениями, распознающими QR-коды, не понадобится экскурсовод — вся необходимая информация зашифрована в развешенных повсюду кодах. А также невероятную активность проявляет интернет-магазин самогонных аппаратов, который зашифровывает не только данные о продаваемых моделях, но и знакомит с народной мудростью в духе «Самогон ваш враг, гоните его сами». Этот ресурс стал первым среди тех, кто разместил у себя