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

Java 调用 C++ 动态库(DLL)完整实践:有图像有实体处理场景

  Java 调用 C++ 动态库(DLL)完整实践:无图像无实体处理场景
  这里主要介绍如何通过 JNI(Java Native Interface)在 Java 中调用一个用 C++ 编写的校色算法库。不涉及图像和 java 实体处理。环境如下:

  • 系统:Windows 10
  • JDK:1.8
  • IDE:Visual Studio 2022
  • Java 构建工具:Maven
  • 目标平台:x64

一、整体目标

  Java 端通过 JNI 调用算法提供的动态库,实现图像缺色偏色检测功能。为了方便,我把所有的依赖库都放在了 jdk 的 bin 目录,这样我在调用的时候只需要导入我的自己生成的 jni 库就可以,如果需要频繁切换 jdk,那建议自己配置 java.library.path 或将依赖库放到独立目录中 ,处理好动态库的依赖关系即可。


二、准备工作

1. C++ 头文件(API 定义)

  这是算法的头文件,jni 层需要根据他的方法调用即可。建议和 java 的方法保持一致,不保持一致也可以,自己在 jni 层处理好就可以。

头文件方法定义:

 //  版本号COLORCAST_API int ColorCastGetVersion(char* pOutBuf, int nOutBufSize);COLORCAST_API ColorCastResults analyzeImageColorCast(unsigned char* pData, int pw, int ph, int pchannels,double skin_ratio_threshold = 0.1, double C_threshold = 20.0,double Red_threshold = 18.0, double Green_threshold = 5.0,double Yellow_threshold = 30.0, double Blue_threshold = 5.0,double face_threshold = 0.5);COLORCAST_API ContrastColorCastResults contrastImageColorCast(unsigned char* tData, int tw, int th, int tchannels,unsigned char* pData, int pw, int ph, int pchannels,int YCrCb_cbmax = 125,int ROIwidthDiv = 6,int ROIheightDiv = 100,double USwidthRatio = 0.5,double USheightRatio = 0.01);

结构头文件:


// 偏色对比结果(双图比对)
struct ContrastColorCastResults {// 红色比对色偏指数double Red_Contrast = 999;// 绿色比对色偏指数double Green_Contrast = 999;// 黄色比对色偏指数double Yellow_Contrast = 999;// 蓝色比对色偏指数double Blue_Contrast = 999;// ROI偏色占比double ColorCast_ratio = 999;
};

2. Java 接口类定义

  这里示例图像的三种传输方式:

  1. Java 层将图像转换为 BGR 格式的 byte[],直接传给 JNI;
  2. Java 层传原始图像数据,JNI 使用 OpenCV 解码;
  3. Java 层传递文件路径,JNI 自行读取文件内容。
package com.emp.empxmrz.util;import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;/**** @title* @author shijiangyong* @date 2025/8/27 11:23**/
public class ColorCastDetExampleJni {static {System.loadLibrary("ColorCastDetExampleJni");}// 获取版本号public static native int getVersion(byte[] buffer, int bufSize);// 对比图偏色检测// 传图片数据,处理成BGR格式public static native ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCast(byte[] tData, int tw, int th, int tchannels,byte[] photoData, int pw, int ph, int pchannels,int yCrCbCbmax, int roiWidthDiv, int roiHeightDiv,double usWidthRatio, double usHeightRatio);// 传原图片数据,不转格式public static native ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastOri(byte[] tData,byte[] photoData,int yCrCbCbmax, int roiWidthDiv, int roiHeightDiv,double usWidthRatio, double usHeightRatio);// 传图片本地路径public static native ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastByPath(String tData,String photoData,int yCrCbCbmax, int roiWidthDiv, int roiHeightDiv,double usWidthRatio, double usHeightRatio);@Datapublic static class ContrastColorCastResults {@Schema(description = "红色比对偏色指数")public double redContrast;@Schema(description = "绿色比对偏色指数")public double greenContrast;@Schema(description = "黄色比对偏色指数")public double yellowContrast;@Schema(description = "蓝色比对偏色指数")public double blueContrast;@Schema(description = "ROI区域偏色占比")public double colorCastRatio;}
}

三、生成 JNI 头文件

构建项目之后执行下面的命令。
javah -classpath target/classes -d src/main/jni com.emp.empxmrz.util.ColorCastDetExampleJni

  这会生成 com_emp_empxmrz_util_ColorCastDetExampleJni.h 和 com_emp_empxmrz_util_ColorCastDetExampleJni_ContrastColorCastResults.h,它定义了 JNI 接口供 C++ 实现。生成之后不能随便移动类的位置或修改包名、类名等,如果必须调整的话,需要重新生成。

生成的头文件大概如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_emp_empxmrz_util_ColorCastDetExampleJni */#ifndef _Included_com_emp_empxmrz_util_ColorCastDetExampleJni
#define _Included_com_emp_empxmrz_util_ColorCastDetExampleJni
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_emp_empxmrz_util_ColorCastDetExampleJni* Method:    getVersion* Signature: ([BI)I*/
JNIEXPORT jint JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_getVersion(JNIEnv *, jclass, jbyteArray, jint);/** Class:     com_emp_empxmrz_util_ColorCastDetExampleJni* Method:    contrastImageColorCast* Signature: ([BIII[BIIIIIIDD)Lcom/emp/empxmrz/util/ColorCastDetExampleJni/ContrastColorCastResults;*/
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCast(JNIEnv *, jclass, jbyteArray, jint, jint, jint, jbyteArray, jint, jint, jint, jint, jint, jint, jdouble, jdouble);/** Class:     com_emp_empxmrz_util_ColorCastDetExampleJni* Method:    contrastImageColorCastOri* Signature: ([B[BIIIDD)Lcom/emp/empxmrz/util/ColorCastDetExampleJni/ContrastColorCastResults;*/
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastOri(JNIEnv *, jclass, jbyteArray, jbyteArray, jint, jint, jint, jdouble, jdouble);/** Class:     com_emp_empxmrz_util_ColorCastDetExampleJni* Method:    contrastImageColorCastByPath* Signature: (Ljava/lang/String;Ljava/lang/String;IIIDD)Lcom/emp/empxmrz/util/ColorCastDetExampleJni/ContrastColorCastResults;*/
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastByPath(JNIEnv *, jclass, jstring, jstring, jint, jint, jint, jdouble, jdouble);#ifdef __cplusplus
}
#endif
#endif

四、JNI 实现(C++)

  这是 jni 的头文件实现,因为我是要调用多个算法,所以使用 vs 创建了一个解决方案,里面创建了多个项目,每个项目都是一种算法的 jni 层,根据自己的实际情况操作就可以,实现类中需要包含算法头文件和 jni 头文件,java实体的头文件不用添加。项目结构大致如下:

cpp 完整代码如下:

#include "ColorCast.h"
#include "com_emp_empxmrz_util_ColorCastDetExampleJni.h"#include <iostream>
#include <stdexcept>
#include <string>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>void native_log(const std::string& message) {std::cerr << "[NativeLog] " << message << std::endl;
}void throwJavaException(JNIEnv* env, const char* message) {jclass exceptionCls = env->FindClass("java/lang/RuntimeException");if (exceptionCls != nullptr) {env->ThrowNew(exceptionCls, message);}
}void throwIllegalArgument(JNIEnv* env, const char* message) {jclass exClass = env->FindClass("java/lang/IllegalArgumentException");if (exClass != nullptr) {env->ThrowNew(exClass, message);}
}JNIEXPORT jint JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_getVersion(JNIEnv* env, jobject obj, jbyteArray buffer, jint bufSize) {try {jboolean isCopy = JNI_FALSE;jbyte* bufPtr = env->GetByteArrayElements(buffer, &isCopy);if (bufPtr == nullptr) {throwJavaException(env, "Failed to get buffer pointer");return 0;}// 写入版本号int len = ColorCastGetVersion(reinterpret_cast<char*>(bufPtr), static_cast<int>(bufSize));// 写成功,手动同步数据回 Javaenv->ReleaseByteArrayElements(buffer, bufPtr, 0);return len; }catch (const std::exception& e) {native_log(e.what());throwJavaException(env, e.what());return 0;}
}// 构造 ContrastColorCastResults Java 对象
jobject createContrastColorCastResults(JNIEnv* env, const ContrastColorCastResults& result) {jclass cls = env->FindClass("com/emp/empxmrz/util/ColorCastDetJni$ContrastColorCastResults");if (cls == nullptr) {throwJavaException(env, "Failed to find ContrastColorCastResults class");return nullptr;}jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");if (constructor == nullptr) {throwJavaException(env, "Failed to get constructor for ContrastColorCastResults");return nullptr;}jobject obj = env->NewObject(cls, constructor);env->SetDoubleField(obj, env->GetFieldID(cls, "redContrast", "D"), result.Red_Contrast);env->SetDoubleField(obj, env->GetFieldID(cls, "greenContrast", "D"), result.Green_Contrast);env->SetDoubleField(obj, env->GetFieldID(cls, "yellowContrast", "D"), result.Yellow_Contrast);env->SetDoubleField(obj, env->GetFieldID(cls, "blueContrast", "D"), result.Blue_Contrast);env->SetDoubleField(obj, env->GetFieldID(cls, "colorCastRatio", "D"), result.ColorCast_ratio);return obj;
}JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCast
(JNIEnv* env, jobject obj,jbyteArray templateData, jint tw, jint th, jint tchannels,jbyteArray photoData, jint pw, jint ph, jint pchannels,jint cbmax, jint roiWidthDiv, jint roiHeightDiv,jdouble usWidthRatio, jdouble usHeightRatio) {try {jbyte* tData = env->GetByteArrayElements(templateData, nullptr);jbyte* pData = env->GetByteArrayElements(photoData, nullptr);ContrastColorCastResults result = contrastImageColorCast(reinterpret_cast<unsigned char*>(tData), tw, th, tchannels,reinterpret_cast<unsigned char*>(pData), pw, ph, pchannels,cbmax, roiWidthDiv, roiHeightDiv, usWidthRatio, usHeightRatio);env->ReleaseByteArrayElements(templateData, tData, 0);env->ReleaseByteArrayElements(photoData, pData, 0);// 将 ContrastColorCastResults 映射到 Java 对象return createContrastColorCastResults(env, result);}catch (const std::exception& e) {native_log(e.what());throwJavaException(env, e.what());return nullptr;}
}JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastOri
(JNIEnv* env, jobject obj,jbyteArray templateData, jbyteArray photoData,jint cbmax, jint roiWidthDiv, jint roiHeightDiv,jdouble usWidthRatio, jdouble usHeightRatio) {try {if (templateData == nullptr) {throwIllegalArgument(env,"templateData is null");return nullptr;}if (photoData == nullptr) {throwIllegalArgument(env, "photoData is null");return nullptr;}jsize tempLen = env->GetArrayLength(templateData);if (tempLen <= 0) {throwIllegalArgument(env, "templateData is null");return nullptr;}jsize photoLen = env->GetArrayLength(photoData);if (photoLen <= 0) {throwIllegalArgument(env, "photoData is null");return nullptr;}// Zero-copy: 获取 JVM 中的数据指针(映射)jbyte* tData = env->GetByteArrayElements(templateData, nullptr);if (tData == nullptr) {throwJavaException(env, "templateData Failed to get byte array elements");return nullptr;}// Zero-copy: 获取 JVM 中的数据指针(映射)jbyte* pData = env->GetByteArrayElements(photoData, nullptr);if (pData == nullptr) {throwJavaException(env, "photoData Failed to get byte array elements");return nullptr;}// 原图// 构造一个 OpenCV Mat 来包装 byte[] 数据(不复制)cv::Mat tBuf(1, tempLen, CV_8UC1, reinterpret_cast<uchar*>(tData));// 解码为图像cv::Mat tImage = cv::imdecode(tBuf, cv::IMREAD_UNCHANGED);if (tImage.empty()) {env->ReleaseByteArrayElements(photoData, pData, JNI_ABORT);throwJavaException(env, "templateData Failed to decode image");return nullptr;}// 目标图cv::Mat pBuf(1, photoLen, CV_8UC1, reinterpret_cast<uchar*>(pData));cv::Mat pImage = cv::imdecode(pBuf, cv::IMREAD_UNCHANGED);if (pImage.empty()) {env->ReleaseByteArrayElements(templateData, tData, JNI_ABORT);throwJavaException(env, "photoData Failed to decode image");return nullptr;}ContrastColorCastResults result = contrastImageColorCast(reinterpret_cast<unsigned char*>(tImage.data), tImage.cols, tImage.rows, tImage.channels(),reinterpret_cast<unsigned char*>(pImage.data), pImage.cols, pImage.rows, pImage.channels(),cbmax, roiWidthDiv, roiHeightDiv, usWidthRatio, usHeightRatio);// 释放映射,不拷贝回 Java(JNI_ABORT)env->ReleaseByteArrayElements(templateData, tData, JNI_ABORT);env->ReleaseByteArrayElements(photoData, pData, JNI_ABORT);// 将 ContrastColorCastResults 映射到 Java 对象return createContrastColorCastResults(env, result);}catch (const std::exception& e) {native_log(e.what());throwJavaException(env, e.what());return nullptr;}
}JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastByPath
(JNIEnv* env, jobject obj,jstring templateData,  jstring photoData, jint cbmax, jint roiWidthDiv, jint roiHeightDiv,jdouble usWidthRatio, jdouble usHeightRatio) {try {const char* tImagePath = env->GetStringUTFChars(templateData, nullptr);const char* pImagePath = env->GetStringUTFChars(photoData, nullptr);// 直接用 OpenCV 读取图像cv::Mat tImage = cv::imread(tImagePath);if (tImage.empty()) {env->ReleaseStringUTFChars(templateData, tImagePath); // 释放资源env->ReleaseStringUTFChars(photoData, pImagePath);throwJavaException(env, "Failed to load templateData");return nullptr;}cv::Mat pImage = cv::imread(pImagePath);if (pImage.empty()) {env->ReleaseStringUTFChars(templateData, tImagePath); // 释放资源env->ReleaseStringUTFChars(photoData, pImagePath);throwJavaException(env, "Failed to load photoData");return nullptr;}ContrastColorCastResults result = contrastImageColorCast(reinterpret_cast<unsigned char*>(tImage.data), tImage.cols, tImage.rows, tImage.channels(),reinterpret_cast<unsigned char*>(pImage.data), pImage.cols, pImage.rows, pImage.channels(),cbmax, roiWidthDiv, roiHeightDiv, usWidthRatio, usHeightRatio);env->ReleaseStringUTFChars(templateData, tImagePath);env->ReleaseStringUTFChars(photoData, pImagePath);// 将 ContrastColorCastResults 映射到 Java 对象return createContrastColorCastResults(env, result);}catch (const std::exception& e) {native_log(e.what());throwJavaException(env, e.what());return nullptr;}
}

建议添加异常处理,避免JVM 崩溃,注意资源的释放。


五、Visual Studio 配置

1. 添加包含目录

打开【项目属性】 > C/C++ > 常规 > 附加包含目录

防止编译阶段报错。


2. 添加库目录

打开【链接器】 > 常规 > 附加库目录


3. 添加依赖库

打开【链接器】 > 输入 > 附加依赖项

  告诉编译器如何调用 .dll 中的函数; 出现 JNI 方法未导出错误,可添加 .def 文件显式指定导出符号 ,内容如下,其实就是 jni 头文件方法:

LIBRARY ColorCastDetExampleJni
EXPORTSJava_com_emp_empxmrz_util_ColorCastDetExampleJni_getVersionJava_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastJava_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastOriJava_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastByPath

4.生成 DLL

  编译后会生成 ColorCastDetExampleJni.dllColorCastDetExampleJni.lib,将他们复制到 jdk 的 bin 目录或者你自己定义的目录下, java 就可以直接调用 ColorCastDetExampleJni了。


六、Java 调用测试

工具类 CustomImgUtilsImageProcessor在这篇文章里,Java 图像处理传 JNI 到 C++(OpenCV):两种高效实现方式对比
java 测试结果是否正确,也可以自己封装成接口。

service 层:

package com.emp.empxmrz.service;import com.emp.empxmrz.controller.vo.ColorCastDetExampleReq;
import com.emp.empxmrz.util.ColorCastDetExampleJni;
import com.emp.empxmrz.util.CustomImgUtils;
import com.emp.empxmrz.util.ImageProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;/**** @title* @author shijiangyong* @date 2025/9/15 10:17**/
@Slf4j
@Service
public class ColorCastDetExampleJniServiceImpl implements ColorCastDetExampleJniService{@Overridepublic String getVersion() {byte[] versionBuffer = new byte[12];int result = ColorCastDetExampleJni.getVersion(versionBuffer, versionBuffer.length);String version = "获取版本号失败";if (result == 0) {version = new String(versionBuffer, StandardCharsets.UTF_8).trim();log.info("Algorithm model version number: {}", version);} else {log.warn("Failed to get version number: {} ", result);}return version;}@Overridepublic ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCast(ColorCastDetExampleReq req) {MultipartFile sourceFile = req.getSourceFile();if (sourceFile == null || sourceFile.isEmpty()) {throw new IllegalArgumentException("Source file is null or empty");}MultipartFile targetFile = req.getTargetFile();if (targetFile == null || targetFile.isEmpty()) {throw new IllegalArgumentException("Target file is null or empty");}try {byte[] sourceBytes = ImageProcessor.inputStreamToByteArray(sourceFile.getInputStream());BufferedImage sourceImage = ImageIO.read(new ByteArrayInputStream(sourceBytes));if (sourceImage == null) {throw new RuntimeException("图像读取失败");}byte[] targetBytes = ImageProcessor.inputStreamToByteArray(targetFile.getInputStream());BufferedImage targetImage = ImageIO.read(new ByteArrayInputStream(targetBytes));if (targetImage == null) {throw new RuntimeException("图像读取失败");}byte[] sourceMatrixBGR = CustomImgUtils.getMatrixBGR(sourceImage);byte[] targetMatrixBGR = CustomImgUtils.getMatrixBGR(targetImage);return ColorCastDetExampleJni.contrastImageColorCast(sourceMatrixBGR, sourceImage.getWidth(), sourceImage.getHeight(), sourceImage.getColorModel().getNumColorComponents(),targetMatrixBGR, targetImage.getWidth(), targetImage.getHeight(), targetImage.getColorModel().getNumColorComponents(),req.getYCrCbCbmax(), req.getRoiWidthDiv(), req.getRoiHeightDiv(), req.getUsWidthRatio(), req.getUsHeightRatio());} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastOri(ColorCastDetExampleReq req) {String sourceFileUrl = req.getSourceFileUrl();if (sourceFileUrl == null || sourceFileUrl.isEmpty()) {throw new IllegalArgumentException("Source file url is null or empty");}String targetFileUrl = req.getTargetFileUrl();if (targetFileUrl == null || targetFileUrl.isEmpty()) {throw new IllegalArgumentException("Target file url is null or empty");}try {byte[] sourceMatrixBGR = this.getImageBytes(sourceFileUrl);byte[] targetMatrixBGR = this.getImageBytes(targetFileUrl);return ColorCastDetExampleJni.contrastImageColorCastOri(sourceMatrixBGR, targetMatrixBGR,req.getYCrCbCbmax(), req.getRoiWidthDiv(), req.getRoiHeightDiv(), req.getUsWidthRatio(), req.getUsHeightRatio());} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastByPath(ColorCastDetExampleReq req) {String sourceFileUrl = "E:\\test\\CertifHaed.jpg";String targetFileUrl = "E:\\test\\face_big_homepage.jpg";return ColorCastDetExampleJni.contrastImageColorCastByPath(sourceFileUrl,targetFileUrl,req.getYCrCbCbmax(), req.getRoiWidthDiv(),req.getRoiHeightDiv(), req.getUsWidthRatio(), req.getUsHeightRatio());}/*** http流转BufferedImage* @param req* @return* @throws IOException*/private BufferedImage getBufferedImage(String req) throws IOException {URL url = new URL(req);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(10000);return ImageIO.read(conn.getInputStream());}/*** http流转Byte[]* @param req* @return* @throws IOException*/private byte[] getImageBytes(String req) throws IOException {URL url = new URL(req);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(10000);try (InputStream inputStream = conn.getInputStream()) {return ImageProcessor.inputStreamToByteArray(inputStream);}}
}

controller 层:

package com.emp.empxmrz.controller;import com.emp.empxmrz.controller.vo.ColorCastDetExampleReq;
import com.emp.empxmrz.service.ColorCastDetExampleJniService;
import com.emp.empxmrz.util.ColorCastDetExampleJni;
import com.emp.empxmrz.util.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/**** @title* @author shijiangyong* @date 2025/9/15 10:47**/
@Slf4j
@RestController
@AllArgsConstructor
@Tag(name = "demo示例")
@RequestMapping("/example")
public class ColorCastDetExampleJniController {private final ColorCastDetExampleJniService colorCastDetExampleJniService;@PostMapping("/getVersion")@Operation(summary = "管理后台-获取算法版本")public R<String> getVersion() {return R.ok(colorCastDetExampleJniService.getVersion());}@PostMapping("/contrast/color/castDet")@Operation(summary = "管理后台-偏色检测算法")public R<ColorCastDetExampleJni.ContrastColorCastResults> contrastImageColorCast(ColorCastDetExampleReq req) {return R.ok(colorCastDetExampleJniService.contrastImageColorCast(req));}@PostMapping("/contrast/color/castDetOri")@Operation(summary = "管理后台-偏色检测算法")public R<ColorCastDetExampleJni.ContrastColorCastResults> contrastImageColorCastOri(ColorCastDetExampleReq req) {return R.ok(colorCastDetExampleJniService.contrastImageColorCastOri(req));}@PostMapping("/contrast/color/castDetByPath")@Operation(summary = "管理后台-偏色检测算法")public R<ColorCastDetExampleJni.ContrastColorCastResults> contrastImageColorCastByPath(ColorCastDetExampleReq req) {return R.ok(colorCastDetExampleJniService.contrastImageColorCastByPath(req));}
}

调用示例:

路径去掉 Ori 就是测试上面两个入参,加上 Ori 就是测试下面两个入参,反正到了 java 层,就自己随便玩了。实体类就不贴了。

调试建议

  • 如果报错找不到 ColorCastDetExampleJni.dll,请将该 DLL 放入:
    • 项目运行目录;
    • 或者 jdk/bin 目录;
    • 或者设置 -Djava.library.path
  • 如果 JNI 函数名对应不上,请确保:
    • 包名、类名、方法名匹配;
    • DLL 导出的函数使用 extern "C"
    • JNI 方法未正确导出,可通过.def文件显式指定导出符号。

七、总结

这里介绍 JNI 技术实现了 Java 与 C++ 的深度集成。整个流程分为:
  1. 编写 Java native 接口;
  2. 使用 javah 生成 JNI 头文件;
  3. C++ 实现 JNI 方法;
  4. 配置 Visual Studio 编译动态库;
  5. Java 调用测试。

如果你不想污染自己的JDK bin,可以将 .dll.lib 放到一个统一的目录下,这样的话切换 jdk 比较方便,因为我只使用 jdk8,所以贪图方便放在了 bin 目录,但这是不规范滴 。


文章转载自:

http://rYwK8gor.dshxj.cn
http://z6piVko4.dshxj.cn
http://CaIK9keK.dshxj.cn
http://sDxAiLiH.dshxj.cn
http://ZJAQsLiO.dshxj.cn
http://Pch930Z0.dshxj.cn
http://kZQJsQCh.dshxj.cn
http://QS610p3j.dshxj.cn
http://ngf8scV9.dshxj.cn
http://Ro15W975.dshxj.cn
http://iYZT5vCy.dshxj.cn
http://J8ZHjFxo.dshxj.cn
http://PZw36ref.dshxj.cn
http://YBY35nfc.dshxj.cn
http://yYlvwYbb.dshxj.cn
http://zfnAYOHl.dshxj.cn
http://QylIg8K9.dshxj.cn
http://oSgxWvvj.dshxj.cn
http://r5QSw750.dshxj.cn
http://8FgplYOf.dshxj.cn
http://cETMsCaq.dshxj.cn
http://g6eBuytS.dshxj.cn
http://uG8uwRN6.dshxj.cn
http://Rs9JM1jo.dshxj.cn
http://5z7OUAXP.dshxj.cn
http://kfdXaka3.dshxj.cn
http://OW9Gh6ZQ.dshxj.cn
http://oTWRMNfV.dshxj.cn
http://ZXqIxQon.dshxj.cn
http://L0Gc31wA.dshxj.cn
http://www.dtcms.com/a/386834.html

相关文章:

  • 教育行业智慧文档平台:构建安全合规、高效协同的教学研究与资源共享解决方案
  • 网编day7(网络词典)(部分)
  • CodeBuddy AI 深度体验:模型怎么选不踩坑?
  • MQ高级.
  • 46.Mysql基础及案例
  • 贪心算法应用:文件合并问题详解
  • 什么是“孤块”?
  • 神卓N600 公网盒子公网访问群晖NAS绿联飞牛
  • 浅谈背包DP(C++实现,配合lc经典习题讲解)
  • 虚拟化嵌套支持在云服务器容器化Hyper-V环境的配置标准
  • 修改el-checkbox默认颜色
  • ROS接口信息整理
  • 【C++11】lambda匿名函数、包装器、新的类功能
  • 【Linux系统】深入理解线程,互斥及其原理
  • 1. C++ 中的 C
  • 探讨基于国产化架构的非结构化数据管理平台建设路径与实践
  • C++11移动语义
  • 代码随想录第14天| 翻转、对称与深度
  • 算法改进篇 | 改进 YOLOv12 的水面垃圾检测方法
  • 一个我自己研发的支持k-th路径查询的数据结构-owl tree
  • 首款“MODA”游戏《秘境战盟》将在Steam 新品节中开放公开试玩
  • ε-δ语言(Epsilon–Delta 语言)
  • QCA9882 Module with IPQ4019 Mainboard High-Performance Mesh Solution
  • xv6实验:Ubuntu2004 WSL2实验环境配置(包括git clone网络问题解决方法)
  • ICE-Interactive Connectivity Establishment-交互式连接建立
  • 【代码随想录day 28】 力扣 45.跳跃游戏 II
  • IP核的底层封装
  • 4.PFC原理和双闭环控制
  • 江苏保安员证【单选题】考试题库及答案
  • 71-Python+MySQL 医院挂号问诊管理系统-1