macOS 上为 Compose Desktop 构建跨架构图像处理 dylib:OpenCV + libraw + libheif 实践指南

一. 前言:为什么你需要自己构建图像处理 .dylib

我正在开发一款桌面端的图像编辑器 Monica(github.com/fengzhizi71...%25EF%25BC%258C "https://github.com/fengzhizi715/Monica)%EF%BC%8C") 它使用的 UI 框架是 Compose Desktop。

在 Compose Desktop 中开发图像处理应用,往往意味着需要同时兼顾跨平台体验与图像处理性能。虽然 Kotlin 提供了丰富的 UI 构建能力,但在涉及图像编解码(如 HEIF)、图像分析(如 OpenCV)甚至 RAW 文件读取时,Java 层本身的能力极为有限,依赖的第三方库要么过于老旧,要么功能单一,性能表现也不尽如人意。

相比之下,C++ 在图像处理领域已经拥有成熟的生态:OpenCV 提供了全面的计算机视觉能力,libraw 支持绝大多数相机 RAW 文件格式,而 libheif 则是处理 HEIC/HEIF 图像的事实标准。这些库本身稳定且高效,但问题在于:它们并非为 Kotlin 或 Java 生态设计,也无法直接在 Compose Desktop 项目中使用。

我尝试过通过 JNI 来调用这些 C++ 库,但很快就会陷入一系列 macOS 特有的问题:

  • 动态库路径错乱(@rpath、@loader_path 混用)
  • 系统架构不一致(Apple Silicon 与 Intel 的 ABI 差异)
  • Homebrew 依赖冲突
  • 打包后 .dylib 丢失等等。

这些都让简单的图像处理功能变得异常复杂,甚至直接影响了应用的可部署性。

另外,macOS 并没有像 Linux 那样统一的包管理方式可以在所有用户机器上复用 .so 文件,因此最终必须将所需的 .dylib 一并打包。也正因如此,构建一个跨架构、自包含、免安装的图像处理 dylib 成为了解决 Compose Desktop 图像处理问题的关键。本文从源码编译 OpenCV、libheif ,结合 CMake 构建 JNI 接口,并修复所有动态库引用,最终得到一个可以直接部署的图像处理模块。

二. 图像处理库的架构概览

在我的图像编辑器 Monica 中,很多核心的图像处理逻辑都是用 OpenCV C++ 实现的,所以我单独创建了一个项目 github.com/fengzhizi71...

它用于实现图像的参数调整(对比度、色调、饱和度、亮度、色温、高光、阴影)、快速验证 OpenCV 算法(如各种滤波、图形增强、形态学操作、模板匹配等)、加载相机 RAW 文件、HEIC 图像等等。

其项目目录结构如下:

makefile 复制代码
MonicaImageProcess/
├── README.md                        # 项目简介
├── LICENSE                          # 项目许可证文件
├── CMakeLists.txt                   # CMake构建脚本(主)
├── include/                         # 项目公共头文件目录
│   ├── colorcorrection/             # 图像调色相关算法模块的头文件目录
│   ├── matchTemplate/               # 模版匹配的头文件目录
│   └── utils/                       # 工具类模块的头文件目录
├── jni/                             # 给 Java/Kotlin 调用的本地算法
│   ├── cn_netdiscovery_monica_opencv_ImageProcess.h   # jni 对应用层暴露接口的头文件
│   └── cn_netdiscovery_monica_opencv_ImageProcess.cpp # jni 对应用层暴露接口的源文件
├── script/                          # 构建脚本
│   ├── build_libheif_deps.sh        # 从源码编译 libheif 及其依赖的库
│   ├── build_opencv_world_4100.sh   # 从源码编译 opencv 库,包含了 contrib
│   └── fix_dylib_dependencies.sh    # macOS 下修复主库引用 opencv 的路径
├── src/                             # 项目主源代码目录
│   └── colorcorrection/             # 图像调色相关算法模块
│       └── ColorCorrection.cpp      # 图像调色相关算法的源文件
│   └── matchTemplate/               # 模版匹配模块
│       └── MatchTemplate.cpp        # 模版匹配相关算法的源文件
│   ├── utils/                       # 工具类模块
│   ├── CMakeLists.txt               # 本地算法的构建脚本
│   └── library.cpp                  # 常规使用 OpenCV 图像算法相关的源文件
├── thirdparty/                      # 外部依赖库
│   └── heif-suite/                  # libheif 库,需要基于 build_libheif_deps.sh 脚本编译,不同的芯片架构编译出来不同,所以没有放
│   └── libraw/                      # libraw 库
│   └── opencv-install/              # opencv 库,需要基于 build_opencv_world_4100.sh 脚本编译,不同的芯片架构编译出来不同,所以没有放
└── .gitignore                       # git 忽略和不追踪的文件

三. 构建目标明确:跨架构、纯离线部署、适配 Compose Desktop

3.1 支持 Apple Silicon 与 Intel 架构双构建

macOS 正处于从 Intel 向 Apple Silicon(M 系芯片)过渡的阶段,但大量用户与开发者仍在使用 Intel 芯片机器。因此,构建的动态库必须支持 aarch64(arm64)与 x86_64 两种架构,以便在所有用户设备上运行。

这意味着所有依赖库(如 libheif、OpenCV)都必须支持交叉编译或分别构建。

编译参数中要精确控制 -arch 和 CMAKE_OSX_ARCHITECTURES,避免自动识别出错。

3.2 完整的纯离线部署能力

在 Compose Desktop 项目中,Native 动态库并不会像 jar 包那样可以通过 Gradle 自动解析依赖。这就要求打包的 .dylib 是:

  • 自包含的,即所有依赖(如 libopencv_world、libz、libaom 等)都已经通过 @loader_path 正确链接。无需 Homebrew、无需 pkgconfig、无需系统路径解析
  • 可以被直接打包进 Compose Desktop 项目中的 resources,通过 System.loadLibrary() 加载。

为实现这一目标,在我们构建的脚本中专门设置了:

  • 所有库使用 -static 或设置 BUILD_SHARED_LIBS=OFF(除 OpenCV)。
  • 通过 install_name_tool 重写 dylib 引用为 @loader_path。
  • 所有编译输出集中放在 install/lib,便于后期打包。

3.3 完全适配 Compose Desktop 项目结构

Compose Desktop 允许通过 JNI 访问 Native 模块,我们构建的图像处理模块 libMonicaImageProcess.dylib:

  • 使用标准 JNI 接口暴露给 Java 层。
  • 提供完整头文件 + 二进制接口,方便 Kotlin 项目直接调用。
  • 通过 Kotlin 自动加载工具集成到桌面应用。

四. 第三方依赖构建:从源码编译 OpenCV + libraw + libheif

为了实现跨架构部署、无系统依赖、以及完整掌控动态库依赖链,我们必须抛弃 Homebrew 或系统预装库,转而采用"从源码编译"的方式构建所有依赖项。这一过程虽然繁琐,但带来的灵活性与稳定性对于生产部署来说是值得的。

本项目依赖的核心第三方库包括:

  • libheif:HEIF/HEIC 编解码核心库,支持 AV1、HEVC 解码。
  • libraw:用于解析 RAW 格式图像(如 .CR2, .NEF, .ARW 等)。
  • OpenCV: 图像处理通用库,负责图像矩阵操作、滤波、模板匹配等。

构建目标

  • 避免任何 Homebrew 路径、pkgconfig 环境污染。
  • 所有输出统一安装到指定的部署路径中。
  • 使用 @loader_path 修复动态链接依赖,方便部署到 Compose Desktop。

4.1 LibRaw

libraw 相对简单,在其官网上提供了 macOS 编译好的二进制版本。可以在 www.libraw.org/download#st... 下载。

将 libraw.a 和相关头文件通过 CMake 链接。

4.2 构建 OpenCV

为避免安装体积膨胀和不必要依赖,我使用 opencv_world 模块,仅包含需要的子模块:

ini 复制代码
  -DOPENCV_ENABLE_NONFREE=OFF
  # 禁用不必要模块
  -DBUILD_opencv_python=OFF
  -DBUILD_opencv_java=OFF
  -DWITH_1394=OFF
  -DWITH_ADE=OFF
  -DWITH_VTK=OFF
  -DWITH_FFMPEG=OFF
  # 精选核心模块
  -DBUILD_LIST="core;imgproc;imgcodecs;highgui;features2d;ml;photo;dnn;objdetect;calib3d;face;xphoto;tracking;videoio;stitching;flann"

此外,OpenCV 的 .dylib 需使用 install_name_tool 修复 @rpath 为 @loader_path。

4.3 构建 libheif 及其依赖

libheif 比较复杂,它依赖多个底层编解码器库(都需手动构建):

  • libde265:HEVC 解码(用于 HEIC)
  • libaom、dav1d:AV1 解码
  • libpng + zlib:图像压缩
  • 可选:x265(未使用)

我使用一个统一脚本 build_libheif_deps.sh 完成这一流程,脚本核心包括:

bash 复制代码
# 1. 下载源码(curl + tar)
# 2. 自动配置 build 和 install 目录
# 3. 统一使用 CFLAGS/CXXFLAGS/LDFLAGS 设置 macOS 部署目标
# 4. 构建顺序:zlib → libpng → aom → dav1d → libde265 → libheif
# 5. 所有库编译为 .a,并统一安装到 ${INSTALL_DIR}

构建结束后,libheif 将链接静态依赖(aom、dav1d、zlib、libde265 等),最终生成 libheif.a 等。

最终产出目录结构示意:

ruby 复制代码
~/Libs/heif-suite/
├── include/             # 所有头文件(libheif + 依赖)
├── lib/
│   ├── libheif.a
│   ├── libde265.a
│   ├── libaom.a
│   ├── libdav1d.a
│   ├── libz.a
│   └── libpng.a

为什么不能用 Homebrew ?

  • 在不同芯片架构下,Homebrew 路径不一样(/opt/homebrew vs /usr/local)
  • 库版本与依赖不统一,容易产生符号冲突
  • 构建产物中可能残留 /opt/ 路径,导致部署失败
  • 无法精准控制 rpath 或符号可见性,给 Java 层带来 JNI 加载错误.

五. 主库构建:CMake 项目配置

完成所有第三方依赖编译之后,接下来就要构建核心的图像处理库------libMonicaImageProcess.dylib。这个动态库将集成所有图像处理功能,并通过 JNI 暴露给 Kotlin Compose Desktop 使用。为了满足跨平台、跨架构部署需求,CMake 项目的设计需要高度模块化、可配置,并支持部署模式切换。

  • 构建一个跨架构兼容的 libMonicaImageProcess.dylib,并打包必要依赖(如 libopencv_world)。
  • 支持开发(DEPLOY_MODE=OFF)与部署(DEPLOY_MODE=ON)两种模式。
  • 灵活集成第三方库,部署时可使用本地静态库而非 pkg-config。
  • 自动处理 RPATH 与 dylib 路径,适配 macOS 的动态库加载机制。
  • 最终输出目录清晰,便于打包。

下面是完整的 cmake 脚本

bash 复制代码
cmake_minimum_required(VERSION 3.30)
project(MonicaImageProcess LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

option(DEPLOY_MODE "Build for release deployment" OFF)

message(STATUS "DEPLOY_MODE = ${DEPLOY_MODE}")
message(STATUS "OS = ${CMAKE_SYSTEM_NAME}, Arch = ${CMAKE_HOST_SYSTEM_PROCESSOR}")

set(THIRDPARTY_DIR "${CMAKE_SOURCE_DIR}/thirdparty")

if(DEPLOY_MODE)
    set(OpenCV_DIR "${THIRDPARTY_DIR}/opencv-install/lib/cmake/opencv4")
endif()

# OpenCV
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

# JNI
set(JAVA_AWT_LIBRARY NotNeeded)
set(JAVA_JVM_LIBRARY NotNeeded)
set(JAVA_INCLUDE_PATH2 NotNeeded)
set(JAVA_AWT_INCLUDE_PATH NotNeeded)
find_package(JNI REQUIRED)
include_directories(${JNI_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/jni)

# LibRaw
if (DEPLOY_MODE)
    set(LIBRAW_INCLUDE_DIR "${THIRDPARTY_DIR}/libraw/include")
    set(LIBRAW_LIB_PATH    "${THIRDPARTY_DIR}/libraw/lib/libraw.a")
    include_directories(${LIBRAW_INCLUDE_DIR})
else()
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(LIBRAW REQUIRED libraw)
    include_directories(${LIBRAW_INCLUDE_DIRS})
    link_directories(${LIBRAW_LIBRARY_DIRS})
endif()

# libheif
if (DEPLOY_MODE)
    set(LIBHEIF_DIR "${THIRDPARTY_DIR}/heif-suite")
    set(LIBHEIF_INCLUDE_DIR "${LIBHEIF_DIR}/include")
    include_directories(${LIBHEIF_INCLUDE_DIR})
    include_directories(${LIBHEIF_INCLUDE_DIR}/libheif)

    set(LIBHEIF_LIB_PATH "${LIBHEIF_DIR}/lib/libheif.a")
    set(LIBHEIF_DEPENDENCIES
            "${LIBHEIF_DIR}/lib/libde265.a"
            "${LIBHEIF_DIR}/lib/libdav1d.a"
            "${LIBHEIF_DIR}/lib/libaom.a"
            "${LIBHEIF_DIR}/lib/libpng.a"
            "${LIBHEIF_DIR}/lib/libz.a"
            )
else()
    pkg_check_modules(LIBHEIF REQUIRED libheif)
    include_directories(${LIBHEIF_INCLUDE_DIRS})
    link_directories(${LIBHEIF_LIBRARY_DIRS})
endif()

# 输出路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/install/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/install/lib)

# 源文件
set(SRC_FILES
        ${CMAKE_SOURCE_DIR}/include/library.h
        ${CMAKE_CURRENT_SOURCE_DIR}/library.cpp

        ${CMAKE_SOURCE_DIR}/jni/cn_netdiscovery_monica_opencv_ImageProcess.h
        ${CMAKE_SOURCE_DIR}/jni/cn_netdiscovery_monica_opencv_ImageProcess.cpp

        ${CMAKE_SOURCE_DIR}/include/colorcorrection/ColorCorrection.h
        ${CMAKE_CURRENT_SOURCE_DIR}/colorcorrection/ColorCorrection.cpp

        ${CMAKE_SOURCE_DIR}/include/matchTemplate/MatchTemplate.h
        ${CMAKE_CURRENT_SOURCE_DIR}/matchTemplate/MatchTemplate.cpp

        ${CMAKE_SOURCE_DIR}/include/utils/JNIUtils.h
        ${CMAKE_CURRENT_SOURCE_DIR}/utils/JNIUtils.cpp

        ${CMAKE_SOURCE_DIR}/include/utils/Utils.h
        ${CMAKE_CURRENT_SOURCE_DIR}/utils/Utils.cpp
        )

# 添加库目标
add_library(${PROJECT_NAME} SHARED ${SRC_FILES})

# macOS 修复 RPATH
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
    set_target_properties(${PROJECT_NAME} PROPERTIES
            BUILD_WITH_INSTALL_RPATH TRUE
            INSTALL_RPATH "@loader_path"
            MACOSX_RPATH ON
            )
endif()

# 链接依赖
if (DEPLOY_MODE)
    target_link_libraries(${PROJECT_NAME}
            ${OpenCV_LIBS}
            ${LIBRAW_LIB_PATH}
            ${LIBHEIF_LIB_PATH}
            ${LIBHEIF_DEPENDENCIES}
            z
            stdc++
            )
else()
    target_link_libraries(${PROJECT_NAME}
            ${OpenCV_LIBS}
            ${LIBRAW_LIBRARIES}
            ${LIBHEIF_LIBRARIES}
            )
endif()

# 后处理 fix_dylib
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
    add_custom_command(
            TARGET ${PROJECT_NAME}
            POST_BUILD
            COMMAND bash ${CMAKE_SOURCE_DIR}/script/fix_dylib_dependencies.sh
            COMMENT "🔧 Fixing dylib dependencies..."
    )
endif()

目前这个脚本只支持 macOS,后续如果要支持 Windows 或 Linux,只需对 DEPLOY_MODE 下的路径配置进行抽象即可,核心逻辑通用。

六. dylib 依赖修复与部署

在 macOS 上构建 C++ 动态库(.dylib)时,虽然可以通过静态链接尽量减少依赖,但像 OpenCV 这样体积庞大且功能丰富的库,我们更倾向于以动态方式引入(例如 libopencv_world.dylib)。这会引出一个经典问题:如何确保动态库在部署到用户机器上也能被正确加载?

macOS 的动态库查找机制较为复杂,核心路径关键词包括:

  • @rpath:运行时搜索路径(Runpath Search Paths)
  • @loader_path:当前加载的可执行文件或 .dylib 所在目录
  • @executable_path:主程序可执行文件路径。

我们主要使用 @loader_path 来实现自包含部署。

6.1 部署目标

  • 所有 .dylib 被拷贝到一个统一目录(如 install/lib)
  • 主库 libMonicaImageProcess.dylib 的依赖路径被重写为相对路径(@loader_path/xxx.dylib)
  • 避免出现系统级依赖路径或编译机的绝对路径污染

6.2 脚本式修复方案:fix_dylib_dependencies.sh

为了自动化地完成依赖库的拷贝与路径修复,我们编写了一个 Shell 脚本:

主要功能:

  • 自动拷贝编译好的 libopencv_world.4.10.0.dylib
  • 设置软链接(libopencv_world.dylib、libopencv_world.410.dylib)以兼容多种版本引用
  • 使用 install_name_tool 重写主库中的依赖路径
  • 更新 OpenCV 自身的 install_name,确保加载路径正确

fix_dylib_dependencies.sh 可以在 github.com/fengzhizi71... 中访问,并且这个脚本已通过 CMake add_custom_command 挂载到构建流程中,自动执行。

6.3 验证修复效果

执行完修复后,可以使用otool -L命令来确认依赖路径:

bash 复制代码
otool -L build/install/lib/libMonicaImageProcess.dylib

输出类似于:

sql 复制代码
libMonicaImageProcess.dylib:
	@rpath/libMonicaImageProcess.dylib (compatibility version 0.0.0, current version 0.0.0)
	@loader_path/libopencv_world.4.10.0.dylib (compatibility version 410.0.0, current version 4.10.0)
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1500.65.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3)

说明 .dylib 已被正确重写为相对路径,具备部署能力。

6.4 最终部署

最后只需将 libMonicaImageProcess.dylib 和它依赖的 .dylib 一同打包到 Kotlin Compose Desktop 应用中,通过 JNI 加载路径指定 @loader_path,即可跨架构无缝运行。

七. Kotlin Compose Desktop 集成

7.1 集成

根据不同的芯片架构,将打包好的 libMonicaImageProcess.dylib 分别拷贝至项目的 resources 文件夹所对应的目录下。

除了 libMonicaImageProcess.dylib 之外,还需要拷贝它依赖的 .dylib。M 系芯片会多一个 libOrbbecSDK.1.9.dylib,因为通过源码构建 OpenCV 时,就会多出一个这样的 dylib。

这个 SDK 是用于支持 Orbbec 深度相机(如 Astra 系列) 的。我猜测 Apple Silicon 下默认使用 Homebrew 安装的一些依赖(如 libusb、libhidapi)更可能被探测为满足 Orbbec 模块条件。

接下来是集成到 Kotlin Compose Desktop 项目中。

编写一个 ImageProcess 类,用于加载图像处理库以及编写 Java 本地开发接口(Java Native Interface),便于Java/Kotlin 代码可以调用 C/C++ 代码。

kotlin 复制代码
object ImageProcess {

    private val loadPath by lazy{
        System.getProperty("compose.application.resources.dir") + File.separator
    }

    val resourcesDir by lazy {
        File(loadPath)
    }

    init {
        // 需要先加载图像处理库,否则无法通过 jni 调用算法
        loadMonicaImageProcess()
    }

    /**
     * 对于不同的平台加载的库是不同的: mac 是 dylib 库、windows 是 dll 库、linux 是 so 库
     */
    private fun loadMonicaImageProcess() {
        if (isMac) {
            System.load("${loadPath}libMonicaImageProcess.dylib")
        } else if (isWindows) {
            System.load("${loadPath}libraw.dll")
            System.load("${loadPath}libde265.dll")
            System.load("${loadPath}aom.dll")
            System.load("${loadPath}heif.dll")
            System.load("${loadPath}opencv_world481.dll")
            System.load("${loadPath}MonicaImageProcess.dll")
        } else {
            System.load("${loadPath}libMonicaImageProcess.so")
        }
    }

    /**
     * 该算法库的版本号
     */
    external fun getVersion():String

    /**
     * 当前使用的 OpenCV 的版本号
     */
    external fun getOpenCVVersion():String

    /**
     * 图像错切
     * @param 沿 x 方向
     * @param 沿 y 方向
     */
    external fun shearing(src: ByteArray, x:Float, y:Float):IntArray

    /**
     * 初始化图像调色模块
     */
    external fun initColorCorrection(src: ByteArray): Long

    /**
     * 图像调色
     */
    external fun colorCorrection(src: ByteArray, colorCorrectionSettings: ColorCorrectionSettings, cppObjectPtr:Long):IntArray

    /**
     * 删除 ColorCorrection
     */
    external fun deleteColorCorrection(cppObjectPtr:Long): Long

    /**
     * 直方图均衡化
     */
    external fun equalizeHist(src: ByteArray):IntArray

    /**
     * 限制对比度自适应直方图均衡
     */
    external fun clahe(src: ByteArray, clipLimit:Double, size:Int):IntArray

    /**
     * gamma 校正
     */
    external fun gammaCorrection(src: ByteArray,k:Float):IntArray

    /**
     * laplace 锐化,主要是 8 邻域卷积核
     */
    external fun laplaceSharpening(src: ByteArray):IntArray

    /**
     * USM 锐化
     */
    external fun unsharpMask(src: ByteArray, radius:Int, threshold:Int, amount:Int):IntArray

    /**
     * 自动色彩均衡
     */
    external fun ace(src: ByteArray, ratio:Int, radius:Int):IntArray

    /**
     * 转换成灰度图像
     */
    external fun cvtGray(src: ByteArray):IntArray

    /**
     * 阈值分割
     */
    external fun threshold(src: ByteArray, thresholdType1: Int, thresholdType2: Int):IntArray

    /**
     * 自适应阈值分割
     */
    external fun adaptiveThreshold(src: ByteArray, adaptiveMethod: Int, thresholdType: Int, blockSize:Int, c:Int):IntArray

    /**
     * 颜色分割
     */
    external fun inRange(src: ByteArray, hmin:Int, smin:Int, vmin:Int, hmax:Int, smax:Int, vmax:Int):IntArray

    /**
     * 实现 roberts 算子
     */
    external fun roberts(src: ByteArray):IntArray

    /**
     * 实现 prewitt 算子
     */
    external fun prewitt(src: ByteArray):IntArray

    /**
     * 实现 sobel 算子
     */
    external fun sobel(src: ByteArray):IntArray

    /**
     * 实现 laplace 算子
     */
    external fun laplace(src: ByteArray):IntArray

    /**
     * 实现 canny 算子
     */
    external fun canny(src: ByteArray, threshold1:Double, threshold2: Double, apertureSize:Int):IntArray

    /**
     * 实现 LoG 算子
     */
    external fun log(src: ByteArray):IntArray

    /**
     * 实现 DoG 算子
     */
    external fun dog(src: ByteArray, sigma1:Double, sigma2:Double, size:Int):IntArray

    /**
     * 轮廓分析
     */
    external fun contourAnalysis(src: ByteArray, binary: ByteArray, scalar:IntArray, contourFilterSettings: ContourFilterSettings, contourDisplaySettings: ContourDisplaySettings):IntArray

    /**
     * 实现高斯滤波
     */
    external fun gaussianBlur(src: ByteArray, ksize:Int, sigmaX: Double = 0.0, sigmaY: Double = 0.0):IntArray

    /**
     * 实现中值滤波
     */
    external fun medianBlur(src: ByteArray, ksize:Int):IntArray

    /**
     * 实现高斯双边滤波
     */
    external fun bilateralFilter(src: ByteArray, d:Int, sigmaColor:Double, sigmaSpace:Double):IntArray

    /**
     * 实现均值迁移滤波
     */
    external fun pyrMeanShiftFiltering(src: ByteArray, sp: Double, sr: Double):IntArray

    /**
     * 形态学操作
     */
    external fun morphologyEx(src: ByteArray, morphologicalOperationSettings: MorphologicalOperationSettings):IntArray

    /**
     * 模版匹配
     */
    external fun matchTemplate(src: ByteArray, template: ByteArray, scalar:IntArray, matchTemplateSettings: MatchTemplateSettings):IntArray

    /**
     * 解码相机拍摄的图片,例如 cr2、cr3 格式的图像
     */
    external fun decodeRawToBuffer(path: String): RawImage?

    /**
     * 解码 heif 格式的图像
     */
    external fun decodeHeif(path: String): HeifImage?
}

7.2 结果展示与测试

由于篇幅原因,仅展示部分使用图像处理库实现的截图。

八. 总结与展望

本文详细记录了在 macOS 平台上为 Compose Desktop 构建一个高性能、跨架构兼容的图像处理动态库(.dylib)的全过程。其实,我自己花了好几周才搞定的整个过程,所以我觉得有必要把踩过的坑完整记录下来:

  • 从源码构建 libheif、OpenCV 等多个复杂第三方图像库
  • 使用纯 CMake 管理构建逻辑,支持 Intel + Apple Silicon 双架构
  • 构建过程中避开 Homebrew,确保部署时不依赖系统安装环境
  • 自动修复 .dylib 依赖路径,确保最终部署无需手工介入
  • 成功将 .dylib 集成进 Kotlin Compose Desktop 应用,实现调用和图像处理功能

这一过程不仅解决了跨平台图像处理的实际问题,也为 macOS 桌面软件开发者提供了一套可复制、可扩展的动态库构建 + 部署方案

最后,该项目的地址: github.com/fengzhizi71...

相关推荐
写代码的小球13 分钟前
求模运算符c
算法
大千AI助手4 小时前
DTW模版匹配:弹性对齐的时间序列相似度度量算法
人工智能·算法·机器学习·数据挖掘·模版匹配·dtw模版匹配
彭祥.5 小时前
Jetson边缘计算主板:Ubuntu 环境配置 CUDA 与 cudNN 推理环境 + OpenCV 与 C++ 进行目标分类
c++·opencv·分类
YuTaoShao5 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
生态遥感监测笔记5 小时前
GEE利用已有土地利用数据选取样本点并进行分类
人工智能·算法·机器学习·分类·数据挖掘
刘海东刘海东6 小时前
结构型智能科技的关键可行性——信息型智能向结构型智能的转变(修改提纲)
人工智能·算法·机器学习
pumpkin845147 小时前
Rust 调用 C 函数的 FFI
c语言·算法·rust
挺菜的7 小时前
【算法刷题记录(简单题)003】统计大写字母个数(java代码实现)
java·数据结构·算法