Windows 系统上使用 ZBar

发布于 2022-01-02


ZBar 是个开源的 C 语言识别 条形码、二维码的库。同事对比发现它的识别准确率比另外一个库 ZXing 要好。

ZBar本身是在 Linux/Unix 平台上开发的,网上有关介绍 ZBar 的使用是在 Android/iOS 平台上的比较多,Windows上的介绍比较少,故写篇博客总结一下。

集成 ZBar 库

因为 ZBar 是在 Linux/Unix 平台上开发的,因此想通过源码移植的方式使用难度比较大。在 Windows 上比较方便的集成 ZBar 库的方式是直接使用官方提供给 Windows 平台已经编译好的 dll。

ZBar download 页面可以下载到已经编译好的 Windows Installer。下载安装后就在安装目录里面找到集成 ZBar 所需要的 头文件、lib、dll。

Zbar 支持的格式

Zbar 支持识别图片的格式可以从 convert.c 文件里找到定义。格式不是很多,像比较通用的 png、jpg 格式,还需要额外的库支持。

官方 demo

ZBar 库源码里面 examples 目录一个 scan_image 的例子。另外还有 zbarcam、zbarimg 两个小工具。zbarcam 是从摄像头中获取图像数据来识别条形码、二维码。zbarimg 是读取磁盘图片文件来识别条形码、二维码。这个两个工具的源码也在库中。

集成 ImageMagick

从 zbarimg 这个工具的源码可以看到,为了支持多种图片格式,zbarimg 引入了 ImageMagick 这个图片处理库支持,把其他格式图片转换成 Zbar 内部支持的 GREY 格式。

同样的,ImageMagick 也是基于 Linux/Unix 平台上开发的,也可以安装官方预编译好的二进制文件到 Windoows 平台。

ImageMagick download 页面可以下载到已经编译好的 Windows Binary Release。下载安装后就在安装目录里面找到集成 ImageMagick 所需要的 头文件、lib、dll。

使用 ImageMagick 之前,需要先在代码初始化一下 ImageMagick 的路径:

Magick::InitializeMagick(image_magick_bin_path);

新的版本,如果是通过安装的,dll内部是从注册表中定位ImageMagick 的路径。

识别图片

虽然 Zbar 是 C 语言实现的,但是它处理提供 C 接口,还提供了更方便的 C++ 接口。

  // 把原始的图片数据构造成 Magick::Blob 类型
  Magick::Blob blob(image_data, image_data_length);

  // 通过 Magick::Blob 构造 Magick::Image
  Magick::Image image(blob);

  // 获得图片的宽和高
  size_t width = image.columns();
  size_t height = image.rows();

  // 把原始图片转换成 Zbar 内部支持的 gray 格式
  Magick::Blob gray_blob;
  image.modifyImage();
  image.write(&gray_blob, "GRAY", 8);
  const void *gray_blob_data = gray_blob.data();
  size_t gray_image_size = width * height;

  // 构造成 zbar::Image
  zbar::Image gray_image(width, height, "Y800", gray_blob_data,
                         gray_image_size);

  // 通过 zbar::ImageScanner 对象识别图片
  zbar::ImageScanner scanner;
  int scan_result = scanner.scan(gray_image);
  if (scan_result <= 0) {
    return false;
  }

  // 读取识别后的结果
  for (zbar::Image::SymbolIterator symbol = gray_image.symbol_begin();
       symbol != gray_image.symbol_end(); ++symbol) {
     cout << "decoded " << symbol->get_type_name()
             << " symbol \"" << symbol->get_data() << '"' << endl;
  }
  gray_image.set_data(NULL, 0);

参考