【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
# @邮箱 lovemengx@qq.com
#*****************************************************************************
# @版权
#
# 随意修改复制哈
#
#*****************************************************************************
# 这些 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 <iostream>
#include <unistd.h>
#include <zbar.h>
#include <sys/stat.h>
#include <string.h>
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】增加第三方开源库 - 二维码开源库 zbar的更多相关文章
- 二维码开源库zbar、zxing使用心得
首先说明我的测试场景是“识别打印在纸上的二维码”,在扫描结果中寻找二维码并进行识别,而不是直接让摄像头对着二维码扫描. zbar和zxing用的都是自己从github上clone的c++源码/接口编译 ...
- C++二维码相关库编译
一.瞎想 坐在地铁上闲来无聊,突然想到了二维码,顺手就百度了下相关的资料,目前C++二维码相关的库不多,也就zbar(开源中国上下了半天也没下载下来).zxing,不过这两个库据说都是解析二维码的,不 ...
- day111:MoFang:邀请好友流程&生成邀请好友二维码&第三方应用识别二维码&本地编译测试&记录邀请人信息
目录 1.邀请业务逻辑流程图 2.邀请好友-前端 3.邀请好友-后端接口(生成二维码) 4.前端获取后端生成的二维码 5.前端长按页面,保存图片到相册 6.客户端通过第三方识别微信二维码,服务端提供对 ...
- 个性二维码开源专题<替换元素点>
基础方法:ChangeFillShape //修改填充形状 ChangeFillShape(...) // 摘要: // 修改填充形状 // // 参数: // g: // 图形画板 // // Fo ...
- 个性二维码开源专题<替换定位点>
基础方法: ChangeFillShape //修改填充形状 ChangeFillShape(...) // 摘要: // 修改填充形状 // // 参数: // g: // 图形画板 // // F ...
- 个性二维码开源专题<液化/圆角/效果>
基础方法: ChangeFillShape //修改填充形状 ChangeFillShape(...) // 摘要: // 修改填充形状 // // 参数: // g: // 图形画板 // // F ...
- Android二维码开源项目zxing用例简化和生成二维码、条形码
上一篇讲到:Android二维码开源项目zxing编译,编译出来后有一个自带的測试程序:CaptureActivity比較复杂,我仅仅要是把一些不用的东西去掉,用看起来更方便,二维码和条形码的流行性自 ...
- Javascript 二维码生成库:QRCode
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 二维码开源库ZBar-吐槽篇
前不久在网上看到一篇文章<QR-Decoder-OV5640 二维码识别> ,是某开发板的教程.记得对应的开发板以前购买过,当初只是为了看OV5640的JPG的输出效果,结果由于公司奇葩的 ...
- 二维码开源库ZBar-MDK STM32F429移植
前两篇文章已经实现ZBar在Windows平台下的编译和使用,本文将介绍如何把ZBar移植到STM32F429,IDE使用MDK. 1. MDK工程设置 (1)不勾选Use MicroLIB ,使用I ...
随机推荐
- 接入监控视频,为啥还需要对接厂商的SDK呢,不是有onvif这样的标准协议吗?
不少人问过我这个问题,这真是一个好问题. 我举两个例子,让您仔细品: ① 快速打开视频和极致操控的问题. onvif协议很科班,但厂商的sdk可能会给你一些独特的方法,譬如先make一个I帧,这样第一 ...
- 陪你去看 Lodash.js 起步
lodash 起步(数组) Lodash 是一个较为流行的 JavaScript 的实用工具库. 在开发过程中如果能熟练使用一些工具库提供的方法,有利于提高开发效率. 笔者从 API 上入手,不分析其 ...
- 32bit和64bit系统的区别,运行机制浅析
32bit:内存的最大寻址空间是2^32=4G,就是说32位系统的处理器最大只支持到4G内存 64bit:内存的最大寻址空间是2^64,大于1亿GB,但是实际上支持不到那么大的内存,大概是2^40+ ...
- 5种GaussDB ETCD服务异常实例分析处理
摘要:一文带你细数几种ETCD服务异常实例状态. 本文分享自华为云社区<[实例状态]GaussDB ETCD服务异常>,作者:酷哥 . 首先确认是否是虚拟机.网络故障 虚拟机故障导致ETC ...
- Go语言核心36讲08
在上一篇文章,我们一直都在围绕着可重名变量,也就是不同代码块中的重名变量,进行了讨论. 还记得吗?最后我强调,如果可重名变量的类型不同,那么就需要引起我们的特别关注了,它们之间可能会存在"屏 ...
- 刚哥谈架构(八)- 为你的应用选择合适的API
前言: 架构师的主要活动是做出正确的技术决策.选择合适的API是一项重要的技术决策.那么今天就看看API的选择问题. 应用程序编程接口(API)是一种计算接口,它定义了多个软件中介之间的交互.它定义了 ...
- (工具) 性能测试基准软件 lmBench (待补充)
1. lmBench 介绍 Lmbench是一套简易,可移植的,符合ANSI/C标准为UNIX/POSIX而制定的微型测评工具.一般来说,它衡量两个关键特征:反应时间和带宽.Lmbench旨在使系统开 ...
- AWS启示录:创新作帆,云计算的征途是汪洋大海
全文13100字,预计阅读时间15到20分钟. 开篇:创新是AWS发展的最持久驱动力 云计算,新世纪以来最伟大的技术进步之一,从2006年 Amazon Web Service(以下简称AWS)初创时 ...
- 将 Vue.js 项目部署至静态网站托管,并开启 Gzip 压缩
摘要:关于使用 Nginx 开启静态网站 Gzip 压缩的教程已经有很多了,但是好像没几个讲怎么在对象存储的静态网站中开启 Gzip 压缩.其实也不复杂,我们一起来看下~ 本文分享自华为云社区< ...
- 【Java EE】Day09 JavaScript基础
一.JavaScript简介 二.JavaScript语法 三.JavaScript对象