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
		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調用封裝類的方法實例(代碼有一些刪減,關注方法裏邊的思路就可以了):

	@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類型的數據,要不然一樣崩潰給你看啊啊啊啊啊…。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章