четверг, 8 июля 2010 г.

ZXing. Используем в C# приложениях



Недавно у меня возникла потребность реализовать в одном из своих приложений возможность работы с QR-кодами. После однодневного поиска соответствующей библиотеки мой выбор остановился на ZXing (об этом я писал здесь). В первую очередь, мне требовалась полная поддержка .Net и желательно на C#, что собственно и реализует указанный проект. Сразу хочу сказать, что в использовании библиотека проста до неприличия, но все же, касаемо C#, возникли некоторые трудности, связанные с отсутствием (притом полным) примеров на данном языке. В силу чего у меня и появилась мысль написать данную статью, чтобы сберечь время таким же, как и я разработчикам. Итак, прочтя эту заметку до конца, я думаю, вы легко сможете встроить ZXing в свой проект. Но обо всем по порядку.
Проект поддерживает следующие форматы:
• UPC-A and UPC-E
• EAN-8 and EAN-13
• Code 39
• Code 93
• Code 128
• QR Code
• ITF
• Codabar
• RSS-14 (all variants)
• Data Matrix ('alpha' quality)
• PDF 417 ('alpha' quality)

Проверить качество распознования можно отсюда. Это онлайн декодер, реализованный на ASP.

Скачать последнюю версию ZXing можно отсюда. Хотя сразу оговорюсь, что она нам не понадобится, поскольку поддержки C# в ней нет (в текущей версии 1.5). Впрочем, скачать портированную версию опять же можно с сайта разработчиков из SVN репозиториев. Так что, вероятно, официальная поддержка C# появится в ближайшее время. Оттуда советую взять и документацию. Несмотря на то, что она реализована в версии только для Java, большинство описанных классов совпадает и с шарповской версией, значит, она и здесь будет очень полезна.

Открыв данную версию можно заметить, что отсутствуют многие пространства имен, например отвечающие за работу с Android, но это и понятно. Они нам и не нужны. Рассматривать все классы подробно не вижу смысла, поскольку за меня это уже сделано в документации. В целом, нам потребуются только несколько из них: Reader (в простарнстве имен com.google.zxing) – интерфейс, содержащий объявление всего 2 функций: decode(BinaryBitmap image) и reset();MultiFormatReader - класс, реализующий Reader (если бы мы хотели декодировать только QR формат, то взяли бы QRCodeReader); BinaryBitmap – если коротко, то это класс для внутреннего представления изображения, данный класс наследует от абстрактного Binarizer, который в свою очередь от также абстрактного LuminanceSource. Таким образом нам придется как-то преобразовать изображение из класса Bitmap в LuminanceSource. Сделать это можно, если найти производные от LuminanceSource. В документации говориться сразу о нескольких таких, но в версии для С# ни одного из них не оказалось. Зато появился класс RGBLuminanceSource, он то нам и нужен (но при желании вы, конечно, можете и сами реализовать подобный класс). У него есть несколько конструкторов, самым подходящим для моего приложения оказался RGBLuminanceSource(System.Drawing.Bitmap, int, int).

Итого получаем:

Reader reader = new com.google.zxing.MultiFormatReader();
Bitmap image1 = new Bitmap(selectFile.FileName, true);
LuminanceSource source = new RGBLuminanceSource(image1, image1.Width, image1.Height);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

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

Result result = reader.decode(bitmap);

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

textBox1.Text = result.Text;

Вот собственно и все. Осталось только обработать исключения. В версии для Java их в 2 раза больше. В частности, существуют ChecksumException, FormatException, NotFoundException, являющиеся унаследованными от ReaderException. В версии для C# их нет. Остались только ReaderException, WriterException и ReedSolomonException, к тому же, на сколько я понял, ReedSolomonException является внутренним и на уровень пользовательского кода не допускается, но все-таки лучше перехватить и его.

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

Вот пример работающего приложения.

5 комментариев:

  1. Добрый день!

    Вашим методом пробовали закодировать кириллицу и считывать ее потом? результат корректный получается?

    ОтветитьУдалить
  2. Здравствуйте, да пробовал. Результат не корректный. Судя по информации из wiki проекта дело в самой библиотеке. А еще точнее в том, как она обрабатывает Unicode. В свое время столкнулся с этим, но, как оказалось, гораздо легче и быстрее воспользоваться google api, чем разбираться что и как работает не так. На сколько я помню, проблемы нет в веб версии приложения (по крайней мере на их тестовом сайте все работало), но вот в библиотеке под C# это проблема, как оказалось, не устранена до сих пор.

    ОтветитьУдалить
  3. Где можно прочитать про google api, а то нужна кирилица

    ОтветитьУдалить
  4. я разобрался с кирилицей в этой библиотечке. Для раскодирования надо поправить строковую константу UTF8 на utf-8, а для кодирования надо передать настройку

    var option = new System.Collections.Hashtable();
    option.Add(EncodeHintType.CHARACTER_SET, "utf-8");
    var bm = writer.encode(textBoxBarCode.Text,BarcodeFormat.QR_CODE,300,300, option);

    ОтветитьУдалить
  5. C C# вроде как понятно. А вот с С++ есть некоторые проблемы. Для распознования кодов, там все есть, а вот для формирования кодов не нашел ничего подобного.

    ОтветитьУдалить