【OpenWRT】增加第三方开源库 - 二维码开源库 zbar

序言

        第一次开始写博客,在日常学习和工作当中 CSDN 给我帮助很大,因此我也在 CSDN 奉献自己的经验,借此回馈 CSDN 对我的帮助,希望自己的经验可以帮助需要的人,也方便自己后续复习之用,同时亦可以借此丰富自己和完善自己的知识体系。

介绍

        Zbar 是一个二维码和条形码的开源解码库,因为有一个项目没有屏幕但有摄像头,需要解决无线网络联网问题,自然而然的就想到使用摄像头来扫描二维码实现联网。检索网络上发现 zbar 相对来说比较合适,但源码中并未集成 zbar 的 package,因此根据自己对 OpenWRT 的 Makefile 编写规则的理解,借鉴原有的 Makefile 写了一个 Makefile。

       经过在 Tina 系统中实测,该 Makefile 符合 OpenWRT Makefile 编写规则,可以实现自动下载源码、解压、配置并且编译和部署相应的头文件和动静态库到编译环境中,使之第三方可以很容易的引入使用。

正文

Zbar Makefile

#**
#*****************************************************************************
# @文件        Makefile
# @版本        V1.0.0
# @日期        2019-12-05
# @概要        基于 OpenWRT 的第三方开源二维码识别库 zbar Makefile 文件, 
# @作者        lmx 
# @邮箱        [email protected]
#*****************************************************************************
# @版权
#
# 随意修改复制哈
#
#*****************************************************************************

# 这些 makefile 字文件确立软件包加入 OpenWrt 的方式和方法
include $(TOPDIR)/rules.mk

# 1. 根据官方下载链接来配置下载地址、版本号、包名
# 2. 配置完成后编译系统会根据下载地址下载源码包到 dl 文件夹
# https://nchc.dl.sourceforge.net/project/zbar/zbar/0.10/zbar-0.10.tar.bz2
PKG_NAME:=zbar
PKG_VERSION:=0.10
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
PKG_SOURCE_URL:=https://nchc.dl.sourceforge.net/project/zbar/zbar/$(PKG_VERSION)
PKG_BUILD_DIR:=$(COMPILE_DIR)/$(PKG_NAME)-$(PKG_VERSION)

# 一般在软包的基本信息完成后再引入
include $(BUILD_DIR)/package.mk

# 应用程序编译包以 "Package/" 开头,然后接着软件名(可以与软件包名不一样)
# SECTION     : 包的类型
# CATEGORY    : 包的分类,在 make menuconfig 的菜单显示的名字
# TITLE        : 用于在 make menuconfig 对该软件包的简述
# DEPENDS    : 表示依赖其他软件。即如编译或安装需要其他软件时需要说明。如果
#              存在多个依赖,则每个依赖需要用空格分开。依赖前使用+号表示默认
#              为显示,即对象沒有选中时也会显示,使用@则默认为不显示,即当依
#              赖对象选中后才显示。
define Package/libzbar
  SECTION:=utils
  CATEGORY:=zhc_application
  DEPENDS:=
  TITLE:=zbar
endef

# 配置描述信息, make menuconfig 中显示
define Package/libzbar/description
  This is an open source QR code identification Library
endef

# 配置编译选项, 对应 ./configure 命令
CONFIGURE_ARGS+= \
        --disable-video \
        --enable-shared \
        --enable-static \
        --without-imagemagick \
        --without-jpeg \
        --without-python \
        --without-gtk \
        --without-qt \
        --disable-video

# 配置编译方法, 会生成 ipkg-install 为预安装做准备
define Build/Compile
    $(MAKE) -C $(PKG_BUILD_DIR) \
        DESTDIR="$(PKG_INSTALL_DIR)" \
        install
    # 生成    libzbar.provides 文件, 便于其他APP引用
    $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
        all
endef

# 提取其它软件需要用到的头文件和静态动态连接库, 这样才能编译
define Build/InstallDev
    $(INSTALL_DIR) $(1)/usr/include
    $(INSTALL_DIR) $(1)/usr/include/zbar
    $(INSTALL_DIR) $(1)/usr/lib
    $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
    
    $(CP) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/
    $(CP) $(PKG_INSTALL_DIR)/usr/include/zbar/*.h $(1)/usr/include/zbar/
    $(CP) $(PKG_INSTALL_DIR)/usr/lib/libzbar.{a,so*} $(1)/usr/lib/
    $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/* $(1)/usr/lib/pkgconfig/
endef

# 软件包的安装方法(即执行 opkg install 命令时需要释放的文件和目录)
#    包括一系列拷贝编译好的文件到指定位置。
#    调用时会带一个参数,就是嵌入系统的镜像文件系统目录
#    因此 $(1) 表示嵌入系统的镜像目录。一般可以采用下面的方法
# INSTALL_DIR\INSTALL_BIN    : 在 $(TOPDIR)/rules.mk 定义
# INSTALL_DIR    : INSTALL_DIR :=install -d -m0755 意思是创建所属用户可读写其他用户可读可执行的目录
# INSTALL_BIN    : INSTALL_BIN :=install -m0755 意思是编译好的文件存放到镜像文件目录
define Package/libzbar/install
    $(INSTALL_DIR) $(1)/usr/lib
    $(CP) $(PKG_INSTALL_DIR)/usr/lib/lib*.so.* $(1)/usr/lib/
endef

$(eval $(call BuildPackage,libzbar))

例程:

Makefile


include $(TOPDIR)/rules.mk
include $(BUILD_DIR)/kernel.mk

PKG_NAME:=zhc_zbar_demo
PKG_VERSION:=1.0.0
PKG_RELEASE:=1

PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME)

include $(BUILD_DIR)/package.mk
 
define Package/$(PKG_NAME)
  SECTION:=utils
  CATEGORY:=zhc_application
  TITLE:=zbar demo
  DEPENDS:=+libpthread +libstdcpp +libzbar
endef

define Package/$(PKG_NAME)/description
	this zbar demo
endef
 
define Build/Prepare
	mkdir -p $(PKG_BUILD_DIR)
	$(CP) -r ./src/* $(PKG_BUILD_DIR)/
endef

define Build/Compile
	$(MAKE) -C $(PKG_BUILD_DIR)/ \
		ARCH="$(TARGET_ARCH)" \
		AR="$(TARGET_AR)" \
		CC="$(TARGET_CC)" \
		CXX="$(TARGET_CXX)" \
		CFLAGS="$(TARGET_CFLAGS)" \
		LDFLAGS="$(TARGET_LDFLAGS) -lpthread -lzbar "
endef

define Build/Configure
endef

define Package/$(PKG_NAME)/install
	$(INSTALL_DIR) $(1)/usr/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_NAME) $(1)/usr/bin/
endef

$(eval $(call BuildPackage,$(PKG_NAME)))

源码

主要参考 QREnDeCode 即可,

#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace zbar;

class QREnDeCode
{
private:

	ImageScanner	*m_pImageScanner	= NULL;
	Image			*m_pImage			= NULL;
	
public:

	QREnDeCode();
	~QREnDeCode();
	
	bool deCode(unsigned char* pYdata, unsigned int width, unsigned int height, string &result);
};

QREnDeCode::QREnDeCode()
{
	m_pImageScanner = new ImageScanner();
	m_pImage = new Image();
	m_pImage->set_format("Y800");
}

QREnDeCode::~QREnDeCode()
{
	if (m_pImage) {
		delete m_pImage;
	}

	if (m_pImageScanner) {
		delete m_pImageScanner;
	}

}

bool QREnDeCode::deCode(unsigned char* pYdata, unsigned int width, unsigned int height, string &result)
{
	m_pImage->set_size(width, height);
	m_pImage->set_data(pYdata, width * height);

	if (m_pImageScanner->scan(*m_pImage))
	{
		result = m_pImage->symbol_begin()->get_data();
		m_pImageScanner->recycle_image(*m_pImage);
		return true;
	}
	
	return false;
}

// argv[1]: width   argv[2]: heigth   argv[3]: yuvfile
int main(int argc, char *argv[])
{
	unsigned int 	width 		= 0;
	unsigned int 	heigth 		= 0;
	unsigned char	*pBuffer	= NULL;
	size_t			size		= 0;
	char 			*pYuvFile	= NULL;
	
	if(argc < 3){
		printf("%s width heigth yuvfile(YUV420 planar)", argv[0]);
		return -1;
	}
	
	width 	 = atoi(argv[1]);
	heigth 	 = atoi(argv[2]);
	pYuvFile = argv[3];
	
	printf("width:%d heigth:%d file:[%s]\n", width, heigth, pYuvFile);
	
	struct stat statbuff;
	if(stat(pYuvFile, &statbuff) < 0){
		printf("[err] get file size fail...\n");
		return -2;
	}
	
	if(statbuff.st_size != (width * heigth * 3 / 2)){
		printf("[err] probably not yuv420(planar) file\n");
		return -3;
	}

	size = width * heigth;
	pBuffer = (unsigned char *)malloc(size);
	if(NULL == pBuffer){
		printf("[err] malloc %d byte fail\n", size);
		return -4;
	}
	
	FILE *fp = fopen(pYuvFile, "rb");
	if(NULL == fp){
		printf("[err] open file fail\n");
		return -5;
	}
	
    // 取 YUV 中的 Y 数据, Zbar 只需要明亮度的数据
	memset(pBuffer, 0, size);
	fread(pBuffer, size, 1, fp);
	fclose(fp);

	QREnDeCode  qrDecode;
	string		qrResult;
	
	if(qrDecode.deCode(pBuffer, width, heigth, qrResult) == false){
		printf("decode not data\n");
		return -6;
	}
	
	puts("---------------------------");
	printf("%s", qrResult.c_str());
	puts("\n---------------------------");
	return 0;
}

执行结果:

root@sun8i:/tmp# zhc_zbar_demo 280 280 /mnt/UDISK/qr.yuv
width:280 heigth:280 file:[/mnt/UDISK/qr.yuv]
---------------------------
WIFI:Lovemengx
PASSWORD:1007566569
---------------------------

完整的源代码和二维码YUV文件:(资源待审核)

https://download.csdn.net/download/lovemengx/12032832

补充说明:

        经过实际测试,无论是 Windows 版本还是 Linux 版本,在调用 ImageScanner ::scan (Image& image);接口存在内存泄漏的问题,简略看了下源代码,暂未找到未释放的代码,因此在实际应用过程中,如果未能解决此问题,建议将其独立一个可执行文件,以命令的方式存在,主业务逻辑来调用该命令并解析其返回的结果。

你可能感兴趣的:(OpenWRT)