java实现linux下调用c的so动态库的方法

最近项目中用到了java调用linux系统下c的so动态库的需求,实现后我就来总结一波

实现方式:

1.java使用jni调用so库:
需要自己定义native方法,编译.h文件,编写c文件,在linux上编译为so文件,巴拉巴拉。。。
总之比较繁琐,而且写java的去写c,你懂得。。。
2.对jni做了封装的JNA方法:
将c中的类型与Java中的类型做了映射,只需要写一个类,类中的接口extends Library来实例化代码,加载c的.so文件就可以了,怎么样,听起来是不是比jni的调用方式简单很多呢?

前期准备,maven依赖

1.要使用JNA当然需要依赖于其jar包了,那么相应的依赖的引入就必不可少了,依赖如下:

		<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
		<dependency>
			<groupId>net.java.dev.jna</groupId>
			<artifactId>jna</artifactId>
			<version>5.2.0</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna-platform -->
		<dependency>
			<groupId>net.java.dev.jna</groupId>
			<artifactId>jna-platform</artifactId>
			<version>5.2.0</version>
		</dependency>

示例代码

1.so中代码或者是cpp文件中要调用方法的定义:

int ppdetect(char *modelPath,cv::Mat &input_img, int
		 * column, int gpuid, int *boxX, int *boxY, int *boxWidth, int *boxHeight, int
		 *numBox);

2.java中封装代码的实例(注意方法名要与c中定义一致,否则会找不到方法):

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Rect;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

import sun.misc.BASE64Decoder;

public class CallSoUtils {

	/**
	 * 继承Library,用于加载库文件
	 * @author I
	 *
	 */
	public interface PPLibrary extends Library {
	   //linux下代码编译出来的文件实际上是libPPDetectSDK.so文件,但是在代码中需要去掉lib和.so
		PPLibrary INSTANTCE = (PPLibrary) Native.loadLibrary("PPDetectSDK", PPLibrary.class);

		// 此方法为链接库中的方法
		/*
		 * int ppdetect(char *modelPath,cv::Mat &input_img, int
		 * column, int gpuid, int *boxX, int *boxY, int *boxWidth, int *boxHeight, int
		 * *numBox);
		 */
		int ppdetect(String modelPath,long matImgAddress,int column,int gpuid,int[] boxX,
				int[] boxY, int[] boxWidth, int[] boxHeight,IntByReference numBox);
	}
	
	/**
	 * windows下调用add_core_lite.dll文件,可以写全dll文件名,可以是全路径,如果不是全路径需要将dll文件放到jdk
	 * 的bin目录下
	 * @author I
	 *
	 */
	public interface TestDllInterface extends Library {
		TestDllInterface INSTANTCE = (TestDllInterface) Native.loadLibrary("add_core_lite", TestDllInterface.class);
		boolean calcvalptr(int[] paramin, int numb_in,int[] pAns, IntByReference numb_out);
	}
}

3.java调用封装类的方法实例(mvc中controller代码,有一些删减,关注方法里边的思路,或者自己提取到main方法中 也可以):

	@RequestMapping(value = "/ppdec", method = { RequestMethod.POST })
	public String paperSplit(@RequestBody final JSONObject parseObject) {
		String result = "";
		try {
			// base64编码图片信息
			String base64 = parseObject.getString("base64");
			// model 路径 
			String modelPath = parseObject.getString("modelPath");
			Mat matrix = null;
			try {
			  //自定义的实现base64转mat方法
				matrix  = Base2MatTools.base642Mat(base64);
			} catch (IOException e) {
			}
			int column = 3;
			int gpuid = 2
			int[] boxX = new int[3];
			int[] boxY = new int[3];
			int[] boxWidth = new int[3];
			int[] boxHeight = new int[3];
			IntByReference numBox = new IntByReference(0);
			// 使用jna进行算法的调用,mat传递的是地址
			int ret = PPLibrary.INSTANTCE.ppdetect(modelPath, matrix.getNativeObjAddr(),
					column, gpuid, boxX, boxY, boxWidth, boxHeight, numBox);
			List<Rect> rectList = new ArrayList<Rect>();
			if (numBox != null && numBox.getValue() > 0) {
				for (int i = 0; i < numBox.getValue(); i++) {
					int x = boxX[i];
					int y = boxY[i];
					int w = boxWidth[i];
					int h = boxHeight[i];
					Rect rect = new Rect(x, y, w, h);
					rectList.add(rect);
				}
			}
			jsonObject.put("status", "success");
			jsonObject.put("code", "200");
			jsonObject.put("data", rectList);
			return jsonObject.toString();
		} catch (Exception e) {
		}
		return result;
	}

一个demo完成了。

可能好多人弄不懂为什么这样写,那么我就将JNA中java和c的对应关系甩到下边供各位参考

在这里插入图片描述
在这里插入图片描述
这其实只是一个参考,向int& 实际上很可能需要转换的是int[],而不是IntByReference
【注】使用JNA最重要的就是对应类型的转换,要是类型的转换出现错误,分分钟让你jvm崩溃,所以一定要注意哦。
另外,假如传递的是Mat类型的数据注意一定传递的是指针地址,而不是整个Mat类型的数据,要不然一样崩溃给你看啊啊啊啊啊…。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值