当前位置: 首页 > news >正文

【保姆级教程】zxing通过JNI编译成Java可调用的库

文章目录

  • 前言
  • 一、JNI是什么?
  • 二、前期环境准备
    • 1.依赖工具
    • 2.目录结构规划
  • 三、编译步骤
    • 1、编写Java 层 JNI 接口
    • 2、生成 JNI 头文件
    • 3、编写 C++ 层 JNI 实现(封装 ZXing)
    • 4、编译 C++ 代码生成动态库
  • 四、测试
  • 总结

前言

zxing是一个开源的条码库,支持多种格式的一维条码和二维条码的生成和识别,其中支持的一维条码包括:UPC-A、UPC-E、EAN-13、EAN-8、Code 39、Code93、Code128、CodeBar等;支持的二维条码包括:QR Code(包括Micro QR code)、Data Matrix、Aztec Code和PDF417等。
zxing官方原生支持Java,也有社区维护的c++移植版本。大部分场景下Java原生的zxing库可以满足要求,但部分场景下仍需要把c++版本的zxing编译成.so/.dll库用于Java项目,如高并发与大批量二维码识别场景、对识读性能有极致要求的场景、资源受限的linux场景等。


一、JNI是什么?

JNI(Java Native Interface)是Java中的一个特性,它允许Java代码调用本地(C/C++)代码。对于一些需要使用底层系统功能的应用程序,比如图形库、音频库等,JNI可以提供一种方便的接口。用更容易理解的话解释:JNI就像是一个翻译官,Java说Java的话,c/c++说c/c++的话,而JNI在中间做数据转换、函数调用、内存管理的翻译工作。

二、前期环境准备

1.依赖工具

  • JDK(推荐 1.8+):提供javac(编译 Java)、javah/javac -h(生成 JNI 头文件)
  • C++ 编译器:Windows 用 MinGW-w64/VS,Linux 用 gcc/g++,Mac 用 clang
  • ZXing C++ 源码:下载 ZXing 的 C++ 版本(官方仓库,选择cpp目录)

2.目录结构规划

假设现在有一个Java项目目录结构为:

CoderController/ ├── java/# Java层代码│ └── com/ │ └── example/ │ └── ZXingJNI.java# JNI接口声明│ └── Other.java# JNI接口声明

三、编译步骤

1、编写Java 层 JNI 接口

在 Java的 ZXingJNI.java文件中声明本地方法,定义调用接口(输入 BufferedImage / 字节数组,输出 QR 码内容)。

// java/com/example/ZXingJNI.javapackagecom.example;importjava.awt.image.BufferedImage;/** * JNI封装ZXing C++的QR码解码类 */publicclassZXingJNI{// 加载动态链接库(名称与后续编译的库一致,如libzxingjni.so/zxingjni.dll)static{System.loadLibrary("zxingjni");}/** * 本地方法:解码BufferedImage中的QR码 * @param pixels 图像像素数组(int[],ARGB格式) * @param width 图像宽度 * @param height 图像高度 * @return QR码内容,解码失败返回null */publicnativeStringdecodeQRCode(int[]pixels,intwidth,intheight);/** * 封装方法:直接传入BufferedImage解码(简化调用) * @param image 待解码图像 * @return QR码内容 */publicStringdecodeQRCode(BufferedImageimage){intwidth=image.getWidth();intheight=image.getHeight();// 获取ARGB格式的像素数组int[]pixels=newint[width*height];image.getRGB(0,0,width,height,pixels,0,width);// 调用本地方法returndecodeQRCode(pixels,width,height);}}

2、生成 JNI 头文件

通过javac编译 Java 类,并生成 JNI 对应的 C++ 头文件:

# 1. 进入java目录cdCoderController/java/com/example# 2. 编译Java类(生成class文件)javac ZXingJNI.java# 3. 生成JNI头文件javac-hZXingJNI.java

执行后会在本目录生成头文件com_example_ZXingJNI.h,内容如下(核心是本地方法的 C++ 声明):

/* DO NOT EDIT THIS FILE - it is machine generated */#include<jni.h>/* Header for class com_example_ZXingJNI */#ifndef_Included_com_example_ZXingJNI#define_Included_com_example_ZXingJNI#ifdef__cplusplusextern"C"{#endif/* * Class: com_example_ZXingJNI * Method: decodeQRCode * Signature: ([III)Ljava/lang/String; */JNIEXPORT jstring JNICALLJava_com_example_ZXingJNI_decodeQRCode(JNIEnv*,jobject,jintArray,jint,jint);#ifdef__cplusplus}#endif#endif

3、编写 C++ 层 JNI 实现(封装 ZXing)

将生成的com_example_ZXingJNI.h头文件拷贝到zxing的cpp文件里,并新建一个cpp/ZXingJNI.cpp,实现头文件中的本地方法,其目录结构如下:

zxingjniLib/ ├── cpp/# Java层代码│ └── zxing/ │ └── aztec/ │ └── datamatrix/ │ └── maxicode/ │ └── oned/ │ └── pdf417/ │ └── qrcode/ │ └── Barcode.cpp │ └── Barcode.h │ └── ZXingJNI.cpp │ └── com_example_ZXingJNI.h

ZXingJNI.cpp文件核心是将 Java 传入的像素数组转为 ZXing 可处理的格式,调用 ZXing 的 QR 码解码逻辑,其代码如下:

/cpp/ZXingJNI.cpp#include"com_example_ZXingJNI.h"#include"zxing/QRCodeReader.h"#include"zxing/BinaryBitmap.h"#include"zxing/MultiFormatReader.h"#include"zxing/Result.h"#include"zxing/DecodeHints.h"usingnamespacezxing;usingnamespacezxing::qrcode;// JNI实现:解码QR码JNIEXPORT jstring JNICALLJava_com_example_ZXingJNI_decodeQRCode(JNIEnv*env,jobject obj,jintArray pixels,jint width,jint height){// 1. 转换Java像素数组到C++数组(ARGB -> 灰度图)jint*pixelArray=env->GetIntArrayElements(pixels,NULL);if(pixelArray==NULL){returnNULL;// 内存分配失败}// 2. 将ARGB像素转为ZXing需要的灰度字节数组(单通道)unsignedchar*grayData=newunsignedchar[width*height];for(inti=0;i<width*height;i++){jint pixel=pixelArray[i];// 提取RGB并转为灰度(ITU-R BT.601标准)intr=(pixel>>16)&0xFF;intg=(pixel>>8)&0xFF;intb=pixel&0xFF;grayData[i]=(unsignedchar)(0.299*r+0.587*g+0.114*b);}// 3. 配置ZXing解码参数DecodeHintshints(DecodeHints::QR_CODE_HINT);hints.setTryHarder(true);// 尝试更复杂的解码策略hints.setPureBarcode(false);// 4. 创建ZXing图像源并解码std::string resultStr;try{// 创建灰度图像源Ref<LuminanceSource>source=ImageReaderSource::create(grayData,width,height);Ref<BinaryBitmap>bitmap(newBinaryBitmap(newGlobalHistogramBinarizer(source)));// 初始化QR码阅读器QRCodeReader reader;Ref<Result>result=reader.decode(bitmap,hints);resultStr=result->getText()->getText();}catch(conststd::exception&e){// 解码失败(捕获ZXing异常)resultStr="";}// 5. 释放资源delete[]grayData;env->ReleaseIntArrayElements(pixels,pixelArray,0);// 6. 将C++字符串转为Java字符串返回if(resultStr.empty()){returnNULL;}else{returnenv->NewStringUTF(resultStr.c_str());}}

4、编译 C++ 代码生成动态库

以在linux中利用gcc编译为例,说明编译过程

# 进入cpp目录cdzxingjniLib/cpp# 1. 编译ZXing C++源码为静态库(libzxing.a)g++-c-fPIC-std=c++17 -I$JAVA_HOME/include -I$JAVA_HOME/include/linux zxing/**/*.cpp zxing/*.cpp ar rcs libzxing.a *.o# 2. 编译JNI实现文件并链接ZXing静态库,生成动态库g++-shared-fPIC-std=c++17 -I$JAVA_HOME/include -I$JAVA_HOME/include/linux ZXingJNI.cpp-olibzxingjni.so -L.-lzxing

编译成功后会在本目录下生成libzxingjni.so库,将该库拷贝到usr/lib64下就可使用了。

四、测试

在Java中编写测试代码如下:

publicstaticvoidmain(String[]args){if(args.length==0){System.err.println("用法:java -jar zxing-jni.jar <QR码图片路径>");System.exit(1);}try{BufferedImageimage=javax.imageio.ImageIO.read(newFile(args[0]));ZXingJNIdecoder=newZXingJNI();Stringresult=decoder.decodeQRCode(image);if(result!=null){System.out.println("解码结果:"+result);}else{System.out.println("解码失败:未识别到QR码");}}catch(Exceptione){System.err.println("运行异常:"+e.getMessage());e.printStackTrace();}}

总结

本文记录了将zxing的c++代码通过JNI编译成so库的过程,编译完成的库可供Java使用,用于一维条码和二维条码的快速生成与识读。

http://www.jsqmd.com/news/561456/

相关文章:

  • PvZ Toolkit:突破植物大战僵尸限制的终极修改器
  • 让黑苹果安装不再复杂:零基础用户的智能配置解决方案
  • 大模型推理中Prefill与Decode、KV Cache三者说明
  • 用按键控制LED太简单?试试FreeRTOS任务挂起与恢复的三种玩法(附STM32F407完整代码)
  • pnpm+turbo迅速搭建monorepo工程
  • BGP路由优化实战:加速收敛,提升网络稳定性
  • 致远A8+协同管理软件V8.0SP1:如何高效处理待办事项(附常见问题解答)
  • UE4蓝图插件推荐:这5款免费工具让你的开发效率翻倍(附详细使用技巧)
  • WaveTools多账号管理专家:一站式解决开发者多平台账户管理难题
  • 小儿推拿创业选对路:卿雅堂,低风险高回报的社区健康黄金项目 - 中媒介
  • Java 代码质量保障:静态分析与代码审查实践
  • 如何实现70倍实时速度的精准语音转录?WhisperX深度解析
  • RK3588 Camera链路解析:从MIPI/CSI接口到图像数据流的硬件通路
  • Nacos 2.2.0连接达梦数据库踩坑实录:从驱动版本到SQL脚本的完整避坑指南
  • 3865U(Intel_x86) 小主机 安装PVE 9
  • 智能装备研发大装配体操作卡顿?云飞云智能共享云桌面,10人并发无压力
  • 动态规划 -- 最长公共子序列
  • 三步搞定网页资源捕获与高效下载:猫抓插件全攻略
  • Qwerty Learner存储架构进化论:从需求到落地的技术决策指南
  • 深度解析pymobiledevice3:iOS设备调试与管理的Python终极方案
  • 别再瞎找了!高效论文写作全流程AI论文写作工具推荐(2026 最新)
  • CenterPoint实战:基于中心点热力图的三维目标检测与跟踪技术解析
  • Qwen3-TTS开源模型快速上手:5分钟完成中文普通话+粤语+英文三语语音合成
  • DeOldify API速率限制:令牌桶算法实现每用户每小时1000次调用
  • 算力服务器都有哪些功能
  • 如何利用开源数学资源库构建系统化学习路径
  • YOLOv12:以注意力机制重塑实时目标检测的精度与速度边界
  • 三级淋巴结构TLS在癌症中的应用
  • 别再只盯着PID了!用STM32 HAL库的PWM差速,让你的5路红外寻迹小车先跑起来
  • PyTorch 2.5镜像体验:预装全套工具,让AI项目开发效率翻倍