开源鸿蒙PC三方库复现:图像处理框架 G’MIC CLI 上鸿蒙

欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/

开源仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_gmic

本篇基于社区作者 Dream-Y.ocean 的《https://dream-yocean.blog.csdn.net/article/details/161322706》整理,结合我自己的复现重新讲述。运行截图复用自原作者公开素材,致谢。

G’MIC 是个什么量级的库

G’MIC(GREYC’s Magic for Image Computing)是法国 GREYC 实验室的 David Tschumperlé 主导的开源数字图像处理框架。它的「卖点」很唬人——号称 1000+ 图像滤镜命令,色彩调整、几何变换、各种艺术滤镜、图像分析、格式转换无所不包,很多专业图像软件(包括 GIMP 的滤镜插件)背后都有它的影子。

它的核心是 CImg——一个轻量的 C++ 图像处理模板库,整个库几乎就是一个巨大的头文件。G’MIC 在 CImg 之上封装了脚本化的命令语言和 CLI 工具。

那么它比前面的 MediaInfo 复杂在哪?我实测下来主要是三点:

  1. OpenMP 并行:G’MIC 为了性能默认开 OpenMP,这会引入运行时库依赖。
  2. 自带标准库需要解压:它有个压缩过的标准库文件,运行时要 zlib 解压。
  3. CImg 巨型头文件:单文件 7 万多行、3MB+,源码拉取或复制时极易出问题。

这三点恰好就是本次适配的三个主战场,下面逐一拆解。

项目 信息
G’MIC CLI
版本 3.5.0
协议 CeCILL-C
依赖 CMake、CImg、zlib
构建系统 CMake
构建主机 WSL Ubuntu 24.04
架构 arm64-v8a

在这里插入图片描述

适配前的调研:先搞清楚它怎么编

我的习惯是动手写 HPKBUILD 之前,先在 Linux 主机上把这个库的原生编译跑通,把它的构建系统、编译开关、依赖关系摸清楚。G’MIC 用 CMake,关键要找的是这几类信息:

  • CMakeLists.txt 在哪:是不是在根目录,还是在某个子目录(这决定 -S 怎么指)。
  • 有哪些编译开关:比如 ENABLE_OPENMPENABLE_ZLIBBUILD_LIBBUILD_CLI 等,每一个都可能影响产物。
  • 依赖谁:G’MIC 依赖 CImg(头文件)、zlib(解压标准库),可选依赖一堆图像格式库(libpng、libjpeg、libtiff、fftw 等)。

调研清楚后我就明确了策略:只保留 CLI 工具和最小必要依赖,可选的格式库先全关掉,能编通再说。这又一次印证系列里的「做减法优先」原则——先用最小功能集编出能跑的产物,再按需把功能加回来,比一上来全开导致一堆找不到的依赖要高效得多。

第一战场:libomp.so 找不到(OpenMP 依赖)

问题现象

G’MIC 默认开 OpenMP 来做多核加速。本机编译没问题,但交叉编译出来的产物拷到鸿蒙真机一跑,直接报:

Error loading shared library libomp.so: No such file or directory

原因很清楚:开了 OpenMP 后,产物运行时会动态依赖 libomp.so(OpenMP 运行时库),而鸿蒙系统默认根本没有这个库。

两条路的权衡

摆在面前有两个选择:

  1. 把 libomp 也交叉编译过来,和 gmic 一起打包分发。这条路能保留多核加速,但要额外适配一个库,还要处理它的签名、rpath 等问题,工作量不小。
  2. 直接关掉 OpenMP。代价是失去并行加速,但 CLI 批处理场景对这个不那么敏感,而且省去一整个库的适配。

我选了更务实的第二条。在 HPKBUILD 的 cmake 命令里加一行:

-D ENABLE_OPENMP=OFF \

关键:改完一定要清缓存

这里有个新手必栽的坑——改了 HPKBUILD 直接重跑 build.sh,lycium 会因为缓存机制直接跳过构建,你以为关了 OpenMP,其实跑的还是旧产物。必须先清缓存:

# 删构建状态记录
rm -f lycium/usr/hpk_build.csv
# 清旧的源码构建目录和产物
rm -rf thirdparty/gmic/gmic-*
rm -rf lycium/usr/gmic

# 再重新构建
./lycium/build.sh gmic

这个「改配方→清缓存→重编」的三连,是贯穿整个系列的肌肉记忆。

经验沉淀:交叉编译第三方库,遇到「运行时缺某个 .so」,第一反应先判断「这个功能我用不用得上」。用不上就从编译开关层面关掉它,比硬着头皮再适配一个依赖库划算得多。

第二战场:标准库解压不了(zlib 链接问题)

问题现象

G’MIC 有个 gmic_stdlib.gmic 标准库文件,里面就是那 1000+ 滤镜命令的定义。这个文件是压缩存储的,运行时要靠 zlib 把它解开。如果 zlib 没正确链上,真机会报警告:

Could not decompress G'MIC standard library

后果是:gmic 本身还能跑,但所有标准库里的高级滤镜命令都用不了,等于废了大半功能。

根因与解法

我虽然在 cmake 里设了 ENABLE_ZLIB=ON,但在交叉编译环境下,CMake 的自动探测没找到 zlib 的头文件和库文件——因为它默认去主机的系统路径找,而我们要的是鸿蒙 SDK sysroot 里的那份。

解法是显式把路径喂给 CMake,别让它猜:

-D ENABLE_ZLIB=ON \
-D ZLIB_INCLUDE_DIR="${OHOS_SDK}/native/sysroot/usr/include" \
-D ZLIB_LIBRARY="${OHOS_SDK}/native/sysroot/usr/lib/aarch64-linux-ohos/libz.so" \

一个好消息:zlib 鸿蒙 SDK 本身就自带,路径就在 sysroot 下,不用我们自己再交叉编译一份 zlib。这省了不少事。

怎么验证 zlib 真的链上了

两个办法:

  1. 看运行输出:真机跑 ./gmic 时不再出现 Could not decompress 警告,就说明 OK 了。
  2. 构建环境里用 ldd 查(注意是在构建机的产物上查,看链接关系):
ldd thirdparty/gmic/gmic-3.5.0/arm64-v8a-build/gmic
# 链接列表里应该能看到 libz.so

第三战场:CImg 巨型头文件的处理

G’MIC 依赖 CImg.h 这个模板库。它的特殊之处在于:不是编译成库,而是以纯头文件形式被 #include 进源码,而且单文件就有 7 万多行、3MB 多。

这带来的实际问题是:源码拉取或从 Windows 复制时,这种大文件容易传输不全、或者被工具截断,结果就是编译时一堆「找不到符号 / 未定义」的诡异报错,而且报错信息往往指向不到真正的根因。

我的处理就是确保 CImg.h 完整就位在源码对应目录里,构建时能被正确 include 到。没什么花活,但要养成「拿到源码先核对关键大文件完整性」的习惯。另外 G’MIC 的 CMake 还会强制要求一个 gmic_stdlib_community.h 文件,如果报 Missing gmic_stdlib_community.h,需要从官网下载对应版本:

wget https://gmic.eu/gmic_stdlib_community375.h -O Projects/gmic/src/gmic_stdlib_community.h

hnp.json:这次多了一项 share

前面 MediaInfo 的 hnp.json 只声明了一个 bin 入口。G’MIC 不一样,它要把标准库文件随包发出去,所以 install 里多了 share

{
    "type": "hnp-config",
    "name": "gmic",
    "version": "3.5.0",
    "description": "A full-featured open-source framework for digital image processing (CLI version)",
    "license": "CeCILL-C",
    "arch": "arm64-v8a",
    "install": {
        "bin": ["usr/bin/gmic"],
        "share": ["usr/share/gmic"]
    }
}

usr/share/gmic 里放的就是那个 gmic_stdlib.gmic 标准库文件。这也提醒我:hnp.json 的 install 字段要随产物结构走——产物不只有可执行文件时,别忘了把数据文件、库文件一并声明,否则装到设备上会缺东西。

完整构建流程

# 1. 准备目录和配方文件
cd lycium_plusplus/thirdparty
mkdir -p gmic
cd gmic
vim HPKBUILD          # 写入构建配方
# 同目录还要放 hnp.json / README.OpenSource / HPKCHECK

# 2. 清缓存(重编必做)
cd ../../lycium
grep -v 'gmic' usr/hpk_build.csv > usr/hpk_build.csv.tmp
mv usr/hpk_build.csv.tmp usr/hpk_build.csv
rm -rf ../thirdparty/gmic/gmic-3.5.0
rm -rf output/*/gmic*

# 3. 开始构建
./build.sh gmic

构建成功后,产物输出到 output/arm64-v8a/,包含 tar.gz 和 hnp 两种格式。

真机验证:注意它独特的命令行风格

# 解压
tar -zxf gmic_3.5.0.tar.gz
cd usr/bin

# 鸿蒙强制签名
binary-sign-tool sign -inFile gmic -outFile gmic -selfSign "1"
chmod +x gmic

# 直接运行就能看到版本信息
./gmic
# 输出类似:
# gmic: GREYC's Magic for Image Computing: Command-Line Interface
#         Version 3.7.5

# 查看版本
./gmic version

# 加载内置 Lena 测试图(图像处理领域的经典测试图)
./gmic sp lena

这里有个我一开始踩的坑:G’MIC 不吃 --help--version 这种 GNU 风格的双横线参数。它自己的风格是:

  • 看帮助:./gmic help | less -r
  • 看版本:直接 ./gmic(不带任何参数)

习惯了标准 GNU 工具的人,很容易在这里以为「程序坏了」,其实只是命令风格不同。适配一个工具,了解它本身的使用约定也是验证环节的一部分。

在这里插入图片描述

常见问题速查(FAQ)

现象 根因 解决
Missing gmic_stdlib_community.h CMake 强制要求该文件 从 gmic.eu 下载对应版本放到 src/
Error loading shared library libomp.so 开了 OpenMP,鸿蒙无此库 -D ENABLE_OPENMP=OFF
Could not decompress G'MIC standard library zlib 没正确链接 显式指定 ZLIB_INCLUDE_DIR / ZLIB_LIBRARY
改完 HPKBUILD 不生效 构建缓存 删 hpk_build.csv 和旧产物
./gmic --help 报错 G’MIC 不用双横线参数 ./gmic help
$'\r': command not found CRLF 换行符 Python 二进制转 LF

小结

G’MIC 这一篇的两个核心收获,都很有「图像/多媒体类库」的代表性:

  1. OpenMP 依赖的取舍 —— 关掉 vs 适配 libomp,按场景务实选择;
  2. zlib 路径的显式喂养 —— 交叉环境别信 CMake 自动探测,把 SDK sysroot 里的路径写死。

再加上 CImg 大头文件的完整性、hnp.json 的 share 声明,这套经验可以直接迁移到 ImageMagick、GraphicsMagick 这类同样依赖图像格式库的工具上。

值得一提的是,从这一篇开始,适配作者换成了 Dream-Y.ocean。接下来两篇他带来的是真正的硬骨头——媒体播放器 mpv 的多层依赖适配,那才是检验适配功力的大考。感谢原创适配作者 Dream-Y.ocean 的开源分享。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐