Недавно появилась идея сэкономить на ТСД на складе и попробовать использовать вместо них обычные дешёвые мобильники (даже без пылезащиты). Интерфейс планирую реализовать в виде веб-приложения (обычные веб-странички, HTML + CSS + JS).
Для того, чтобы всё получилось, необходимо научить веб-странички сканировать штрихкода через камеру телефона. Получить данные с камеры достаточно просто. Основная работа состоит в обработке кадра. Под катом обзор существующих готовых решений и много картинок.
![](https://habrastorage.org/r/w1560/webt/io/0j/k6/io0jk6wvcbbaggyfgljan3et6pi.png)
Ссылки:
В результатах поиска — это первый вариант. Библиотека оснащена алгоритмом поиска штрихкода на картинке. Поддерживает одномерные штрихкоды: EAN, CODE 128, CODE 39, EAN 8, UPC-A, UPC-C, I2of5, 2of5, CODE 93, CODABAR. Поддерживает установку через NPM или Bower. Интерфейс библиотеки состоит из одного объекта «Quagga», содержащего 7 методов, всё достаточно просто.
На сайте проекта присутствует страничка, где можно загрузить образцы и попробовать библиотеку в деле. Пробуем образец №1. Необходимо указать некоторые настройки, ок, не вопрос.
![](https://habrastorage.org/r/w780q1/webt/-p/m7/_9/-pm7_9oe-qex2z5fddhoddhaxuq.jpeg)
В результате запуска определить штрихкод не удалось, но расположение штрихкода определено неплохо.
Пробуем образец №2. Как-то безрадостно.
![](https://habrastorage.org/r/w780q1/webt/xl/jg/eo/xljgeookkbe4ab7l9ofz5e3l5fc.jpeg)
Пробуем изменить настройки — поставить «Patch-Size» --> «Large». Нет. Правильный результат даёт, если поставить `Resolution (long side) = 800px`. Однако в действительности наибольшая сторона 640 пикселей.
![](https://habrastorage.org/r/w780q1/webt/0a/sw/r4/0aswr4dkegtrqsqiwzt50kondse.jpeg)
Возможно он лучше работает с картинками высокого разрешения. Хорошо, делаем третий образец (образец №3).
![](https://habrastorage.org/r/w780q1/webt/mq/c_/qq/mqc_qqzpst6k7365t5mdpclkwbs.jpeg)
Честно говоря я не знаю какой это тип штрихкода и попробовал все настройки — ШК не определился. Хорошо, давайте попробуем ещё один образец высокого разрешения (образец №4):
![](https://habrastorage.org/r/w780q1/webt/mx/xu/tz/mxxutzfwpobe2l9wvuvmvlpdcuq.jpeg)
Почему-то ни с какими настройками результата добиться не удалось.
Попробуем «чистый» образец от следующей библиотеки (образец №5):
![](https://habrastorage.org/r/w780q1/webt/rz/wa/-g/rzwa-gpmqae8rodphs0al8uy-6i.jpeg)
Этот распознался.
Ссылки:
Это вторая в выдаче библиотека. Знает форматы: Code128 (UCC/EAN-128), Code93, Code39, Standard/Industrial 2 of 5, Interleaved 2 of 5, Codabar, EAN-13. Поддерживает установку через NPM, или можно просто подключить вот так:
Или можно скачать всего один файлик: javascript-barcode-reader.min.js размером 10 445 байт.
У проекта есть страничка с примерами, однако картинки получены путём генерации кодов, а не с камеры. Нам такое не пойдёт.
Образец №1. Библиотека выдаёт в консоль «Error: Failed to extract barcode!».
Образец №2. Библиотека выдаёт в консоль «Error: Failed to extract barcode!».
Образец №3. Библиотека выдаёт в консоль «Error: Failed to extract barcode!».
Образец №4. Библиотека выдаёт в консоль «601».
Хмм… может библиотека подключена неправильно? Попробуем вот такой образец:
![](https://habrastorage.org/r/w780q1/webt/18/k2/qf/18k2qf0muydqywwcsfajtaygkjw.jpeg)
Образец №5. Библиотека выдаёт в консоль «10023». Прикольно.
Сайт проекта
Ядро библиотеки написано на WebAssembly (WASM) и только обёртки на JavaScript, что не так интересно. Знает форматы:
1D: Code 39, Code 93, Code 128, Codabar, EAN-8, EAN-13, UPC-A, UPC-E, Interleaved 2 of 5 (ITF), Industrial 2 of 5 (Code 2 of 5 Industry, Standard 2 of 5, Code 2 of 5), ITF-14;
2D: PDF417, QR Code, DataMatrix, Aztec.
Это платная библиотека, доступна по подписке, все типы штрихкодов стоят 2199$ в год, если только одномерные коды, то стоимость уменьшается до 1099$ в год. Есть страничка1 и страничка2 для экспериментов.
Образец №1. Да! Ответ правильный. Область обведена достаточно чётко.
![](https://habrastorage.org/r/w780q1/webt/c6/7x/l1/c67xl155yiqvzeidzbez86qmypm.jpeg)
Образец №2. Да. Ответ снова правильный. Область тоже обведена достаточно чётко.
![](https://habrastorage.org/r/w780q1/webt/qg/fj/zx/qgfjzxy76civluw4xohwfs_jmkk.jpeg)
Образец №3. Теперь мы знаем тип этого штрихкода.
![](https://habrastorage.org/r/w780q1/webt/yl/e6/ku/yle6kudwskpqedstrgnpxe9sy1m.jpeg)
Образец №4. Ответ тоже верный.
![](https://habrastorage.org/r/w780q1/webt/7p/-n/2q/7p-n2qoci_-o9lricvctress8io.jpeg)
А ещё, судя по всему, можно вот так:
![](https://habrastorage.org/r/w780q1/webt/xo/qt/16/xoqt16_omh42gqs4ozqy2bbdth4.jpeg)
Однако первый образец распознан с ошибкой. И попробуем ещё вот так (оригинал картинки очень размыт):
![](https://habrastorage.org/r/w780q1/webt/or/oc/c1/orocc1vdwbgbmbo9dwtelvvvplw.jpeg)
Теперь мы знаем, что существует хотя бы одна работающая библиотека, хоть и платная.
Ссылки:
Простая маленькая библиотека. Знает только один формат штрихкодов: UPC. Если к коду такого типа вначале дописать ноль, то получится EAN-13.
Пробуем первый образец:
![](https://habrastorage.org/r/w780q1/webt/nj/cd/fx/njcdfxnuebjeozr1amoerbqzjkw.jpeg)
Результат: 000204892734. Образец распознан.
Берём образец №2 (EAN-13). Только чтоб заработало, необходимо строку 32 скрипта написать так:
Результат: XXXXXXXXXXXX. Образец не распознан.
Берём следующий:
![](https://habrastorage.org/r/w780q1/webt/xh/ix/qn/xhixqntwiz1d1koq0-rnrrvkcpe.jpeg)
Результат: XXXXXXXXXXXX. Не распознан.
Давайте попробуем что-то простое:
![](https://habrastorage.org/r/w780q1/webt/hn/an/ye/hnanyew6_5gyh-jfwievsuisrnk.jpeg)
Результат: не распознан. Возможно ему нужно подавать так, чтобы кроме штрихкода на картинке ничего не было, исключая и лишнее пространство.
![](https://habrastorage.org/r/w780q1/webt/gh/aj/3z/ghaj3zse-zdrot8glhg5jazjf-m.jpeg)
Результат: 022334545453.
И ещё один EAN-13:
![](https://habrastorage.org/r/w780q1/webt/eo/2k/kd/eo2kkdcntaiuw5pjy2nrovjy5bk.jpeg)
Частично распознан.
GitHub
Ещё одна бесплатная библиотека, с небольшим обращением от автора:
Образец №1. Область и тип определены верно. Код распознался с ошибкой.
![](https://habrastorage.org/r/w780q1/webt/go/r9/6p/gor96pdzholdhijj9ptayw3bmdg.jpeg)
Образец №2. Хороший результат. Правильно распознаны: область, тип штрихкода и сам штрихкод.
![](https://habrastorage.org/r/w780q1/webt/yc/9s/ej/yc9sejeg6xtoh8s0z3dx1h9ai2q.jpeg)
Образец №3. Отрицательно. Под углом не умеет.
![](https://habrastorage.org/r/w780q1/webt/pv/fd/dy/pvfddyagpb0czyvs80qbboio9nm.jpeg)
Образец №4. Очень хорошо, образец распознан.
![](https://habrastorage.org/r/w780q1/webt/yd/1n/bi/yd1nbi7da4ut2fhf6olcuqetgdw.jpeg)
Образец №5. Образец распознан.
![](https://habrastorage.org/r/w780q1/webt/u3/km/pz/u3kmpzt9mw43r97uqvikjagn1io.jpeg)
Ну что ж, похвально. Последние изменения в библиотеке произошли 3 года назад.
Ссылки:
Бесплатная библиотека (лицензия MIT). Знает следующие типы одномерных штрихкодов: Code-128, Code-93, Code-39, Codabar, EAN-13. Умеет распознавать QR-коды. На странице проекта есть возможность попробовать библиотеку.
Образец №1: Не распознан.
![](https://habrastorage.org/r/w780q1/webt/bg/br/h3/bgbrh33o3j2d7mckyyid4a9fr64.jpeg)
Образец №2: Распознан правильно.
![](https://habrastorage.org/r/w780q1/webt/6w/ve/_r/6wve_rjiolzro21msmngk6qynks.jpeg)
Образец №3: Не распознан.
Образец №4: Не распознан.
Образец №5: Распознан правильно.
![](https://habrastorage.org/r/w780q1/webt/gc/ws/bj/gcwsbjblwo-paiyu4btre7adrji.jpeg)
Возможность распознавать QR-коды представляется интересной, поэтому мной было собрано 6 образцов для тестирования этой и последующих библиотек:
![](https://habrastorage.org/r/w1560/webt/h9/yq/2k/h9yq2kf1p4m8mee5oshl15iv4ug.png)
Образец №1: ничего.
Образец №2: Ничего.
Образец №3: Ничего.
Образец №4: Ничего.
Образец №5: Ничего.
Образец №6: Распознан.
![](https://habrastorage.org/r/w780q1/webt/_u/6f/js/_u6fjs3o9lpvwzqfuhbhx4rpa3k.jpeg)
Страница проекта
Бесплатная библиотека. Заявлена генерация и распознавание QR-кодов. На странице проекта есть возможность попробовать библиотеку.
Ни один из шести образцов не был распознан. На странице есть генератор QR-кодов, вот полученные с помощью этого генератора коды распознаются.
![](https://habrastorage.org/r/w780q1/webt/49/l8/2q/49l82ql19t1baujwfbmlrses5ju.jpeg)
UPD. Совместными усилиями в комментариях (спасибо TiesP ) удалось установить, что алгоритм работает, просто не умеет определять ориентацию кода. С учётом этого новые результаты такие:
Образец №1 — не распознан.
Образец №2 — не распознан.
Образец №3 — не распознан.
Образец №4 — не распознан.
Образец №5 — распознан.
Образец №6 — распознан.
![](https://habrastorage.org/r/w780q1/webt/qb/-z/rk/qb-zrk4uxsdbhxorittobwcpmrs.jpeg)
Видимо есть ещё какие-то ограничения к фону, так как на бумаге определился и мой образец и образец, предоставленный в комментариях:
![](https://habrastorage.org/r/w780q1/webt/k2/nn/35/k2nn35ybxmpatwytqcwhlsuzeso.jpeg)
Это всё что я нашёл. Находил несколько реализаций, основанных на одной из вышеприведённых, например вот эта. Повторю, что основной критерий поиска — это вся работа должна выполняться на клиентской стороне через браузер и без дополнительной установки чего либо. То есть решение должно быть реализовано на JavaScript и/или Wasm (поэтому ZBar не подходит).
Если вам известна библиотека, отвечающая данным требованиям, и отсутствующая в статье — просьба сообщить.
Полученный рейтинг библиотек таков:
![](https://habrastorage.org/r/w780q1/webt/hh/zn/__/hhzn__jmei4ovxwxcfgn1uhid6s.jpeg)
Статья состоялась благодаря интернет-магазину освещения Дивайн Лайт.
Для того, чтобы всё получилось, необходимо научить веб-странички сканировать штрихкода через камеру телефона. Получить данные с камеры достаточно просто. Основная работа состоит в обработке кадра. Под катом обзор существующих готовых решений и много картинок.
![](https://habrastorage.org/webt/io/0j/k6/io0jk6wvcbbaggyfgljan3et6pi.png)
quaggaJS
Ссылки:
В результатах поиска — это первый вариант. Библиотека оснащена алгоритмом поиска штрихкода на картинке. Поддерживает одномерные штрихкоды: EAN, CODE 128, CODE 39, EAN 8, UPC-A, UPC-C, I2of5, 2of5, CODE 93, CODABAR. Поддерживает установку через NPM или Bower. Интерфейс библиотеки состоит из одного объекта «Quagga», содержащего 7 методов, всё достаточно просто.
На сайте проекта присутствует страничка, где можно загрузить образцы и попробовать библиотеку в деле. Пробуем образец №1. Необходимо указать некоторые настройки, ок, не вопрос.
![](https://habrastorage.org/webt/-p/m7/_9/-pm7_9oe-qex2z5fddhoddhaxuq.jpeg)
В результате запуска определить штрихкод не удалось, но расположение штрихкода определено неплохо.
Пробуем образец №2. Как-то безрадостно.
![](https://habrastorage.org/webt/xl/jg/eo/xljgeookkbe4ab7l9ofz5e3l5fc.jpeg)
Пробуем изменить настройки — поставить «Patch-Size» --> «Large». Нет. Правильный результат даёт, если поставить `Resolution (long side) = 800px`. Однако в действительности наибольшая сторона 640 пикселей.
![](https://habrastorage.org/webt/0a/sw/r4/0aswr4dkegtrqsqiwzt50kondse.jpeg)
Возможно он лучше работает с картинками высокого разрешения. Хорошо, делаем третий образец (образец №3).
![](https://habrastorage.org/webt/mq/c_/qq/mqc_qqzpst6k7365t5mdpclkwbs.jpeg)
Честно говоря я не знаю какой это тип штрихкода и попробовал все настройки — ШК не определился. Хорошо, давайте попробуем ещё один образец высокого разрешения (образец №4):
![](https://habrastorage.org/webt/mx/xu/tz/mxxutzfwpobe2l9wvuvmvlpdcuq.jpeg)
Почему-то ни с какими настройками результата добиться не удалось.
Попробуем «чистый» образец от следующей библиотеки (образец №5):
![](https://habrastorage.org/webt/rz/wa/-g/rzwa-gpmqae8rodphs0al8uy-6i.jpeg)
Этот распознался.
javascript-barcode-reader
Ссылки:
Это вторая в выдаче библиотека. Знает форматы: Code128 (UCC/EAN-128), Code93, Code39, Standard/Industrial 2 of 5, Interleaved 2 of 5, Codabar, EAN-13. Поддерживает установку через NPM, или можно просто подключить вот так:
<script src="//unpkg.com/javascript-barcode-reader/dist/javascript-barcode-reader.min.js"></script>
Или можно скачать всего один файлик: javascript-barcode-reader.min.js размером 10 445 байт.
У проекта есть страничка с примерами, однако картинки получены путём генерации кодов, а не с камеры. Нам такое не пойдёт.
Код для тестирования библиотеки
barcode-scan.html
barcode-scan.html
<html>
<head>
<meta http-equiv="content-language" content="ru" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="//unpkg.com/javascript-barcode-reader/dist/javascript-barcode-reader.min.js"></script>
<script type="text/javascript" src="barcode-scan.js"></script>
</head>
<body onload='onLoadPage()'>
<img id="img1" src="scan02.png" />
</body>
</html>
barcode-scan.html
function onLoadPage() {
Image = document.getElementById('img1');
javascriptBarcodeReader(
Image /* Image ID || HTML5 Image || HTML5 Canvas || HTML5 Canvas ImageData || Image URL */,
{
barcode: 'EAN-13', // 'Code-39'
type: 'industrial', // задаётся для типа "Code-2of5", может быть "industrial" или "Interleaved"
}
)
.then(code => {
console.log(code)
})
.catch(err => {
console.log(err)
});
}
Образец №1. Библиотека выдаёт в консоль «Error: Failed to extract barcode!».
Образец №2. Библиотека выдаёт в консоль «Error: Failed to extract barcode!».
Образец №3. Библиотека выдаёт в консоль «Error: Failed to extract barcode!».
Образец №4. Библиотека выдаёт в консоль «601».
Хмм… может библиотека подключена неправильно? Попробуем вот такой образец:
![](https://habrastorage.org/webt/18/k2/qf/18k2qf0muydqywwcsfajtaygkjw.jpeg)
Образец №5. Библиотека выдаёт в консоль «10023». Прикольно.
Dynamsoft Barcode Reader
Сайт проекта
Ядро библиотеки написано на WebAssembly (WASM) и только обёртки на JavaScript, что не так интересно. Знает форматы:
1D: Code 39, Code 93, Code 128, Codabar, EAN-8, EAN-13, UPC-A, UPC-E, Interleaved 2 of 5 (ITF), Industrial 2 of 5 (Code 2 of 5 Industry, Standard 2 of 5, Code 2 of 5), ITF-14;
2D: PDF417, QR Code, DataMatrix, Aztec.
Это платная библиотека, доступна по подписке, все типы штрихкодов стоят 2199$ в год, если только одномерные коды, то стоимость уменьшается до 1099$ в год. Есть страничка1 и страничка2 для экспериментов.
Образец №1. Да! Ответ правильный. Область обведена достаточно чётко.
![](https://habrastorage.org/webt/c6/7x/l1/c67xl155yiqvzeidzbez86qmypm.jpeg)
Образец №2. Да. Ответ снова правильный. Область тоже обведена достаточно чётко.
![](https://habrastorage.org/webt/qg/fj/zx/qgfjzxy76civluw4xohwfs_jmkk.jpeg)
Образец №3. Теперь мы знаем тип этого штрихкода.
![](https://habrastorage.org/webt/yl/e6/ku/yle6kudwskpqedstrgnpxe9sy1m.jpeg)
Образец №4. Ответ тоже верный.
![](https://habrastorage.org/webt/7p/-n/2q/7p-n2qoci_-o9lricvctress8io.jpeg)
А ещё, судя по всему, можно вот так:
![](https://habrastorage.org/webt/xo/qt/16/xoqt16_omh42gqs4ozqy2bbdth4.jpeg)
Однако первый образец распознан с ошибкой. И попробуем ещё вот так (оригинал картинки очень размыт):
![](https://habrastorage.org/webt/or/oc/c1/orocc1vdwbgbmbo9dwtelvvvplw.jpeg)
Теперь мы знаем, что существует хотя бы одна работающая библиотека, хоть и платная.
tobytailor get_barcode_from_image.js
Ссылки:
Простая маленькая библиотека. Знает только один формат штрихкодов: UPC. Если к коду такого типа вначале дописать ноль, то получится EAN-13.
Пробуем первый образец:
![](https://habrastorage.org/webt/nj/cd/fx/njcdfxnuebjeozr1amoerbqzjkw.jpeg)
Результат: 000204892734. Образец распознан.
Берём образец №2 (EAN-13). Только чтоб заработало, необходимо строку 32 скрипта написать так:
ctx.drawImage(img, 0, 0, width, height); // было так: ctx.drawImage(img, 0, 0);
Результат: XXXXXXXXXXXX. Образец не распознан.
Берём следующий:
![](https://habrastorage.org/webt/xh/ix/qn/xhixqntwiz1d1koq0-rnrrvkcpe.jpeg)
Результат: XXXXXXXXXXXX. Не распознан.
Давайте попробуем что-то простое:
![](https://habrastorage.org/webt/hn/an/ye/hnanyew6_5gyh-jfwievsuisrnk.jpeg)
Результат: не распознан. Возможно ему нужно подавать так, чтобы кроме штрихкода на картинке ничего не было, исключая и лишнее пространство.
![](https://habrastorage.org/webt/gh/aj/3z/ghaj3zse-zdrot8glhg5jazjf-m.jpeg)
Результат: 022334545453.
И ещё один EAN-13:
![](https://habrastorage.org/webt/eo/2k/kd/eo2kkdcntaiuw5pjy2nrovjy5bk.jpeg)
Частично распознан.
EddieLa BarcodeReader
GitHub
Ещё одна бесплатная библиотека, с небольшим обращением от автора:
If you like and/or use this project for commercial purposes consider donating to support my work.Знает форматы: Code128, Code93, Code39, Standard/Industrial 2 of 5, Interleaved 2 of 5, Codabar and EAN-13. Имеет страницу для экспериментов.
Если вам нравится и/или вы используете этот проект в коммерческих целях, рассмотрите возможность пожертвования для поддержки моей работы.
Образец №1. Область и тип определены верно. Код распознался с ошибкой.
![](https://habrastorage.org/webt/go/r9/6p/gor96pdzholdhijj9ptayw3bmdg.jpeg)
Образец №2. Хороший результат. Правильно распознаны: область, тип штрихкода и сам штрихкод.
![](https://habrastorage.org/webt/yc/9s/ej/yc9sejeg6xtoh8s0z3dx1h9ai2q.jpeg)
Образец №3. Отрицательно. Под углом не умеет.
![](https://habrastorage.org/webt/pv/fd/dy/pvfddyagpb0czyvs80qbboio9nm.jpeg)
Образец №4. Очень хорошо, образец распознан.
![](https://habrastorage.org/webt/yd/1n/bi/yd1nbi7da4ut2fhf6olcuqetgdw.jpeg)
Образец №5. Образец распознан.
![](https://habrastorage.org/webt/u3/km/pz/u3kmpzt9mw43r97uqvikjagn1io.jpeg)
Ну что ж, похвально. Последние изменения в библиотеке произошли 3 года назад.
WebCodeCamJS
Ссылки:
Бесплатная библиотека (лицензия MIT). Знает следующие типы одномерных штрихкодов: Code-128, Code-93, Code-39, Codabar, EAN-13. Умеет распознавать QR-коды. На странице проекта есть возможность попробовать библиотеку.
Образец №1: Не распознан.
![](https://habrastorage.org/webt/bg/br/h3/bgbrh33o3j2d7mckyyid4a9fr64.jpeg)
Образец №2: Распознан правильно.
![](https://habrastorage.org/webt/6w/ve/_r/6wve_rjiolzro21msmngk6qynks.jpeg)
Образец №3: Не распознан.
Образец №4: Не распознан.
Образец №5: Распознан правильно.
![](https://habrastorage.org/webt/gc/ws/bj/gcwsbjblwo-paiyu4btre7adrji.jpeg)
Возможность распознавать QR-коды представляется интересной, поэтому мной было собрано 6 образцов для тестирования этой и последующих библиотек:
![](https://habrastorage.org/webt/h9/yq/2k/h9yq2kf1p4m8mee5oshl15iv4ug.png)
Образец №1: ничего.
Образец №2: Ничего.
Образец №3: Ничего.
Образец №4: Ничего.
Образец №5: Ничего.
Образец №6: Распознан.
![](https://habrastorage.org/webt/_u/6f/js/_u6fjs3o9lpvwzqfuhbhx4rpa3k.jpeg)
Web QR
Страница проекта
Бесплатная библиотека. Заявлена генерация и распознавание QR-кодов. На странице проекта есть возможность попробовать библиотеку.
Ни один из шести образцов не был распознан. На странице есть генератор QR-кодов, вот полученные с помощью этого генератора коды распознаются.
![](https://habrastorage.org/webt/49/l8/2q/49l82ql19t1baujwfbmlrses5ju.jpeg)
UPD. Совместными усилиями в комментариях (спасибо TiesP ) удалось установить, что алгоритм работает, просто не умеет определять ориентацию кода. С учётом этого новые результаты такие:
Образец №1 — не распознан.
Образец №2 — не распознан.
Образец №3 — не распознан.
Образец №4 — не распознан.
Образец №5 — распознан.
Образец №6 — распознан.
![](https://habrastorage.org/webt/qb/-z/rk/qb-zrk4uxsdbhxorittobwcpmrs.jpeg)
Видимо есть ещё какие-то ограничения к фону, так как на бумаге определился и мой образец и образец, предоставленный в комментариях:
![](https://habrastorage.org/webt/k2/nn/35/k2nn35ybxmpatwytqcwhlsuzeso.jpeg)
Итог
Это всё что я нашёл. Находил несколько реализаций, основанных на одной из вышеприведённых, например вот эта. Повторю, что основной критерий поиска — это вся работа должна выполняться на клиентской стороне через браузер и без дополнительной установки чего либо. То есть решение должно быть реализовано на JavaScript и/или Wasm (поэтому ZBar не подходит).
Если вам известна библиотека, отвечающая данным требованиям, и отсутствующая в статье — просьба сообщить.
Полученный рейтинг библиотек таков:
![](https://habrastorage.org/webt/hh/zn/__/hhzn__jmei4ovxwxcfgn1uhid6s.jpeg)
Статья состоялась благодаря интернет-магазину освещения Дивайн Лайт.