[鸿蒙三方库适配实战] 图像处理框架 G’MIC CLI 的 OpenHarmony 平台迁移实践

摘要:本文详细介绍了如何将功能全面的开源数字图像处理框架 G’MIC CLI 适配到 鸿蒙PC 平台。文章将系统性地讲解如何利用 lycium_plusplus 构建框架,处理 C/C++ 项目在鸿蒙环境下的交叉编译流程,展示如何处理 OpenMP 运行时依赖、zlib 标准库解压支持、CImg 头文件管理以及 HNP 包生成的完整实践。

本文是软件鸿蒙化迁移实践系列文章之一,专注于 C/C++ 原生库的鸿蒙 PC 适配,为开发者提供完整的迁移指南。

GitCode 仓库地址:https://atomgit.com/weixin_62765017/ohos_gmic

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

项目信息说明

项目 说明
名称 G’MIC CLI
开源协议 CeCILL-C
源码版本 3.5.0
目标平台 鸿蒙 PC
依赖项 CMake, CImg, zlib
操作系统平台 WSL Ubuntu 24.04

一、背景介绍

1.0 功能与效果

G’MIC CLI 在本实践中的预期能力如下:

功能:提供功能全面的数字图像处理功能,支持 1000+ 图像滤镜和处理命令,包括色彩调整、几何变换、滤镜效果、图像分析、格式转换等核心功能。

效果:在鸿蒙 PC 上提供与标准 Linux 环境相近的 G’MIC CLI 使用体验,便于在鸿蒙应用开发中实现批量图像处理、自动化滤镜应用、图像格式转换等场景的图像处理功能。

1.1 什么是 OpenHarmony HNP 生态

HNP(Harmony Native Package)是 OpenHarmony 的原生包格式,lycium 是增强型构建框架,支持自动下载源码、交叉编译(arm64-v8a、armeabi-v7a)、一键生成 HNP 包以及开源声明聚合(OAT.xml)。C/C++ 原生库的适配是鸿蒙系统生态建设中的重要一环。

1.2 为什么适配 C/C++ 原生库会有难度

常见挑战包括:

  • 构建系统差异:C/C++ 项目通常使用 CMake、Autotools 等构建系统,需要配置交叉编译工具链(aarch64-linux-ohos-clang/clang++)。
  • OpenMP 运行时依赖:启用 OpenMP 并行计算后,运行时依赖 libomp.so 动态库,鸿蒙系统默认未提供。
  • zlib 标准库支持:G’MIC 标准库(gmic_stdlib.gmic)需要 zlib 解压支持,需要正确配置 zlib 路径。
  • 头文件管理:G’MIC 依赖 CImg.h 模板库(70443 行,3.4MB),需要正确包含在源码中。
  • 标准库文件分发:gmic_stdlib.gmic 需要随包发布到 /usr/share/gmic/ 目录。
  • 构建缓存问题:lycium 使用 hpk_build.csv 跟踪构建状态,需要正确清理缓存才能重新构建。

1.3 G’MIC 简介

G’MIC(GREYC’s Magic for Image Computing)是一个由 David Tschumperlé 开发的功能全面的开源数字图像处理框架。其主要特点包括:

  • 丰富的滤镜库:提供 1000+ 图像处理命令和滤镜效果。
  • 命令行接口:提供强大的 CLI 工具,支持脚本化和批处理。
  • CImg 核心:基于 CImg C++ 图像处理模板库,轻量且高效。
  • 跨平台特性:原生支持 Windows、macOS、Linux,本次适配扩展到 OpenHarmony 平台。
  • 开源地址
    • GitHub: https://github.com/GreycLab/gmic
    • GitCode: https://gitcode.com/weixin_62765017/gmic

二、环境准备

2.0 系统要求

  • 开发环境:Ubuntu 24.04(推荐 WSL 2)
  • 核心工具:CMake(v3.16+)、GCC/G++、Git
  • 构建框架:lycium_plusplus
  • 鸿蒙 SDK:OpenHarmony SDK(提供交叉编译工具链 aarch64-linux-ohos-clang/clang++)
  • 目标架构:arm64-v8a(AArch64)

2.0.1 扩展阅读与参考教程

下方汇总展示了多位老师在鸿蒙 OpenHarmony 适配方面的高质量教程。若在前提准备(环境、工具链、框架)部分还有不清楚的地方,可参考这些文章进一步学习。 以下资源不分先后顺序,均具有参考价值。

资源类型 描述 链接
三方库交叉编译环境(Ubuntu) 在 Ubuntu 中搭建鸿蒙PC 三方库交叉编译构建开发环境 👉 点击查看
三方库交叉编译环境(macOS) 在 macOS 中搭建鸿蒙PC 三方库交叉编译开发环境 👉 点击查看
基础环境搭建 Windows 10 上安装和使用 WSL 2、安装 Ubuntu 24 详细指南 👉 点击查看
Mac 移植指南 鸿蒙PC命令行适配指南(Mac 版) 👉 点击查看
Win 移植指南 鸿蒙PC 生态三方软件移植:开发环境搭建及三方库移植指南 👉 点击查看
全流程适配指南 OpenHarmony Linux 命令行工具适配实战:基于 Cursor × WSL 的 tree 2.2.1 交叉编译与 HNP 打包全流程指南 👉 点击查看
官方构建文档 新脚手架:社区维护的鸿蒙PC 生态命令行工具构建框架 lycium_plusplus(原 build 仓库为旧方式,请以本仓库为准) 👉 点击查看

2.1 lycium_plusplus 框架

lycium_plusplus 是本次适配工作的核心工具,主要用于统一管理各类第三方库的构建流程,通过规范编译、依赖与打包逻辑,实现三方库在目标平台上高效、稳定地编译与集成,是整个适配环节中保障构建一致性与可维护性的关键支撑。

# 克隆 lycium_plusplus 项目
git clone https://gitcode.com/OpenHarmonyPCDeveloper/lycium_plusplus.git
cd lycium_plusplus

2.2 CMake 与交叉编译环境

由于 G’MIC 是 C/C++ 项目,需要 CMake 和 OpenHarmony SDK 提供的交叉编译工具链。

# 安装 CMake
sudo apt-get install -y cmake

# 验证安装
cmake --version

# 配置 OpenHarmony SDK 环境变量
export OHOS_SDK=/home/weishuo/ohos-sdk/linux

三、实战:以 G’MIC 为例的适配步骤

3.1 创建项目目录结构

在 lycium_plusplus/thirdparty/ 目录下为 G’MIC 创建专属目录。

cd lycium_plusplus/thirdparty
mkdir -p gmic
cd gmic

3.2 创建 HPKBUILD 文件

HPKBUILD 作为 lycium 框架的核心构建脚本,完整定义了三方库的元信息配置及下载、编译、打包等全流程构建逻辑。

#!/bin/bash

pkgname=gmic
pkgver=3.5.0
pkgrel=0
pkgdesc="A full-featured open-source framework for digital image processing (CLI version)"
url="https://gmic.eu"
archs=("arm64-v8a")
license=("CeCILL-C")
depends=()
makedepends=("cmake")
autounpack=false
downloadpackage=false
buildtools="cmake"
srcpath="${LYCIUM_ROOT}/../Projects/${pkgname}"
builddir="${pkgname}-${pkgver}"

prepare() {
    if [ -d "$srcpath" ]; then
        echo "Using local source from: $srcpath"
        mkdir -p "$builddir"
        cp -rf "$srcpath"/* "$builddir/"
        find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
        find "$builddir" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
        echo "Prepare completed in: $builddir"
    else
        echo "ERROR: Source not found at $srcpath"
        exit 1
    fi
}

build() {
    cd "$builddir"
    cmake "$@" \
        -B"$ARCH-build" \
        -S. \
        -DCMAKE_BUILD_TYPE=Release \
        -DCMAKE_INSTALL_PREFIX="/usr" \
        -DBUILD_CLI=ON \
        -DBUILD_LIB=OFF \
        -DBUILD_LIB_STATIC=ON \
        -DBUILD_MAN=OFF \
        -DBUILD_BASH_COMPLETION=OFF \
        -DENABLE_DYNAMIC_LINKING=OFF \
        -DENABLE_LTO=OFF \
        -DENABLE_OPENMP=OFF \
        -DENABLE_ZLIB=ON \
        -DZLIB_INCLUDE_DIR="${OHOS_SDK}/native/sysroot/usr/include" \
        -DZLIB_LIBRARY="${OHOS_SDK}/native/sysroot/usr/lib/aarch64-linux-ohos/libz.so" \
        > "$buildlog" 2>&1

    ret=$?
    if [ $ret -ne 0 ]; then
        echo "CMake configuration failed!"
        cat "$buildlog" >&2
        cd "$OLDPWD"
        return $ret
    fi

    cd "$ARCH-build"
    $MAKE VERBOSE=1 >> "$buildlog" 2>&1
    ret=$?

    cd "$OLDPWD"
    return $ret
}

check() {
    echo "The test must be on an OpenHarmony device!"
}

package() {
    : ${destdir:=${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}}

    mkdir -p "${destdir}/usr/bin"
    _gmic_bin="${LYCIUM_ROOT}/../thirdparty/${pkgname}/${builddir}/${ARCH}-build/gmic"
    if [ -f "$_gmic_bin" ]; then
        cp -f "$_gmic_bin" "${destdir}/usr/bin/gmic"
        chmod +x "${destdir}/usr/bin/gmic"
        echo "  ✅ Installed gmic binary"
    else
        echo "  ❌ gmic binary not found at $_gmic_bin"
        return 1
    fi

    mkdir -p "${destdir}/usr/share/gmic"
    _gmic_stdlib="${LYCIUM_ROOT}/../thirdparty/${pkgname}/${builddir}/src/gmic_stdlib.gmic"
    if [ -f "$_gmic_stdlib" ]; then
        cp -f "$_gmic_stdlib" "${destdir}/usr/share/gmic/gmic_stdlib.gmic"
        echo "  ✅ Installed gmic_stdlib.gmic"
    fi

    find "${destdir}" -name "*.bak" -type f -delete 2>/dev/null || true
    find "${destdir}" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true

    return 0
}

archive() {
    export HNP_TOOL="${HNP_TOOL:-${OHOS_SDK}/toolchains/hnpcli}"

    mkdir -p ${LYCIUM_ROOT}/output/$ARCH

    pushd ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} > /dev/null 2>&1
    tar -zcf ${LYCIUM_ROOT}/output/$ARCH/${pkgname}_${pkgver}.tar.gz .
    echo "Archive completed: ${LYCIUM_ROOT}/output/$ARCH/${pkgname}_${pkgver}.tar.gz"
    popd > /dev/null 2>&1

    if [ -f "${HNP_TOOL}" ]; then
        cp ${LYCIUM_ROOT}/../thirdparty/${pkgname}/hnp.json ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/
        ${HNP_TOOL} pack \
            -i ${LYCIUM_ROOT}/usr/${pkgname}/${ARCH} \
            -o ${LYCIUM_ROOT}/output/$ARCH/
        echo "Archive completed: ${LYCIUM_ROOT}/output/$ARCH/${pkgname}.hnp"
    else
        echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
    fi
}

cleanbuild() {
    echo "Cleaning build artifacts for ${pkgname}..."
    rm -rf "${LYCIUM_ROOT}/../thirdparty/${pkgname}/${builddir}"
    rm -rf "${LYCIUM_ROOT}/output/${pkgname}"*
    rm -rf "${LYCIUM_ROOT}/usr/${pkgname}"
    echo "Clean completed"
}

3.3 创建 hnp.json(包元数据)

hnp.json 文件用于描述 HNP 包的元信息,类似于 package.json。

{
    "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"]
    }
}

3.4 创建 README.OpenSource(开源声明)

为了满足开源合规性,需要提供 README.OpenSource 文件来声明许可证和依赖库信息。

[
    {
        "Name": "gmic",
        "License": "CeCILL-C",
        "License File": "https://github.com/GreycLab/gmic/blob/master/COPYING",
        "Version Number": "3.5.0",
        "Owner": "your-email@example.com",
        "Upstream URL": "https://github.com/GreycLab/gmic/archive/refs/tags/v3.5.0.tar.gz",
        "Description": "G'MIC (GREYC's Magic for Image Computing) is a full-featured open-source framework for digital image processing."
    },
    {
        "Name": "CImg",
        "License": "CeCILL-C",
        "License File": "https://github.com/dtschump/CImg/blob/master/LICENCE",
        "Version Number": "3.4.0",
        "Owner": "your-email@example.com",
        "Upstream URL": "https://github.com/dtschump/CImg/archive/refs/tags/v.3.4.0.tar.gz",
        "Description": "CImg Library is a C++ template toolkit for image processing."
    },
    {
        "Name": "zlib",
        "License": "Zlib",
        "License File": "https://github.com/madler/zlib/blob/master/LICENSE",
        "Version Number": "1.3.1",
        "Owner": "your-email@example.com",
        "Upstream URL": "https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.gz",
        "Description": "zlib is a software library used for data compression."
    }
]

3.5 创建 HPKCHECK 检查脚本

HPKCHECK 是 lycium 框架的构建检查脚本,用于在编译前验证环境是否满足构建要求。

#!/bin/bash
# HPKCHECK for G'MIC CLI

HPK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${HPK_DIR}" || exit 1
source ./HPKBUILD > /dev/null 2>&1

logfile="${HPK_DIR}/${pkgname}_${ARCH}_test.log"

checkprepare() {
    return 0
}

openharmonycheck() {
    res=0
    inst_bin="${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/usr/bin"
    
    if [ -x "${inst_bin}/gmic" ]; then
        cd "$inst_bin" || return 1
    else
        echo "no gmic binary in ${inst_bin}" >&2
        return 1
    fi
    
    {
        echo "start test times: $(date)"
        
        echo "=== G'MIC CLI version check ==="
        if [ -x ./gmic ]; then
            ./gmic --version
            res=$(( res | $? ))
        else
            echo "missing ./gmic"
            res=1
        fi
        
        echo "=== G'MIC CLI help check ==="
        if [ -x ./gmic ]; then
            ./gmic --help 2>&1 | head -20
            res=$(( res | $? ))
        else
            echo "missing ./gmic"
            res=1
        fi
        
        echo "=== G'MIC CLI basic test ==="
        if [ -x ./gmic ]; then
            # 测试基本的图像处理命令(创建一个简单的图像)
            ./gmic sp 100,100 v 0 output /tmp/test_gmic.png 2>&1 | head -5
            res=$(( res | $? ))
            # 清理测试文件
            rm -f /tmp/test_gmic.png
        else
            echo "missing ./gmic"
            res=1
        fi
        
        echo "end test times: $(date)"
    } >> "${logfile}" 2>&1
    
    if [ $res -ne 0 ] && [ -n "${LYCIUM_FAULT_PATH}" ]; then
        mkdir -p "${LYCIUM_FAULT_PATH}/${pkgname}"
    fi
    
    cd "${OLDPWD}"
    return $res
}

四、编译流程与完整示例

4.1 环境准备

配置用于前置环境检查与变量设置,通过指定 OpenHarmony SDK 路径、验证 CMake 环境,为 lycium_plusplus 构建三方库提供基础运行环境。

# 1. 确保 OpenHarmony SDK 已安装
export OHOS_SDK=/home/weishuo/ohos-sdk/linux

# 2. 确保 CMake 已安装
cmake --version

4.2 创建项目结构并执行编译

通过目录操作、脚本创建、清理缓存、执行构建指令,完成 lycium_plusplus 中 G’MIC 三方库的从零构建全流程。

cd lycium_plusplus/thirdparty
mkdir -p gmic
cd gmic
# 创建 HPKBUILD 文件(内容见第三章)
vim HPKBUILD

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*

# 开始构建
./build.sh gmic

4.3 构建成功输出示例

4.4 验证产物

构建成功后,编译产物会统一输出至 output 目录,包含标准 tar 压缩包与鸿蒙专用 hnp 格式包。

五、鸿蒙PC 上验证结果(测试)

解压并进入目录,并且查看二进制文件并添加执行权限,执行签名操作。

# 解压到鸿蒙 PC 桌面(路径示例)
tar -zxf gmic_3.5.0.tar.gz

# 进入对应目录
cd /usr/bin

# 查看文件
ls -l

# 在鸿蒙 PC 上若策略要求,可对二进制签名(示例)
binary-sign-tool sign -inFile gmic -outFile gmic -selfSign "1"

# 按需添加执行权限
chmod +x gmic

# 执行测试(直接运行查看版本信息)
./gmic

G’MIC 命令测试,通过极简命令快速验证 G’MIC 在鸿蒙设备上的运行状态,依次检测程序启动、版本信息、图像生成与基础图像处理能力,无需图形界面即可快速判断移植适配是否成功。

# 查看当前 gmic 工具的版本信息
./gmic version

# 加载内置的 Lena 测试图像(标准图像处理测试图)
./gmic sp lena

六、常见问题与解决方案(FAQ)

Q1:构建时报错 “Missing gmic_stdlib_community.h”?

A:这是 CMake 的 FindGMicStdlib.cmake 强制要求的文件。需要从官网下载:

# 下载并保存
wget https://gmic.eu/gmic_stdlib_community375.h -O Projects/gmic/src/gmic_stdlib_community.h

# 或者从已有文件复制
cp gmic_stdlib_community375.h Projects/gmic/src/gmic_stdlib_community.h

Q2:真机运行时报错 “Error loading shared library libomp.so”?

A:这是因为启用了 OpenMP 但鸿蒙系统没有 libomp.so 运行时库。解决方案是在 HPKBUILD 中禁用 OpenMP:

# 在 HPKBUILD 的 cmake 命令中添加
-D ENABLE_OPENMP=OFF \

然后清理缓存并重新构建:

# 清理构建缓存
rm -f lycium/usr/hpk_build.csv
rm -rf thirdparty/gmic/gmic-*
rm -rf lycium/usr/gmic

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

Q3:真机运行时出现 “Could not decompress G’MIC standard library” 警告?

A:这是因为 zlib 未被正确链接。虽然设置了 ENABLE_ZLIB=ON,但 CMake 可能未找到 zlib 头文件。需要在 HPKBUILD 中显式指定 zlib 路径:

# 在 HPKBUILD 的 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" \

然后清理缓存并重新构建。

Q4:修改 HPKBUILD 后 lycium 直接跳过构建?

A:这是 lycium 的构建缓存机制导致的。lycium 使用 hpk_build.csv 文件记录构建状态,如果存在记录则会跳过构建。解决方案是删除缓存文件:

# 删除构建状态缓存
rm -f lycium/usr/hpk_build.csv

# 同时清理旧产物
rm -rf thirdparty/gmic/gmic-*
rm -rf lycium/usr/gmic
rm -rf lycium/output/*/*gmic*

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

Q5:为什么 ./gmic --help 和 ./gmic --version 报错?

A:G’MIC 不使用 -- 开头的标准命令行参数格式。正确的用法是:

# 查看帮助(使用 help 子命令)
./gmic help | less -r

# 查看版本信息(直接运行不带参数即可看到版本)
./gmic

输出中会显示版本信息:

gmic: GREYC's Magic for Image Computing: Command-Line Interface
        Version 3.7.5

Q6:构建时报错 $‘\r’: command not found?

A:这是 Windows 换行符(CRLF)导致的问题。在 WSL + Windows 共享目录环境下,使用某些工具创建的文件会自动带有 CRLF 换行符。解决方案是使用 Python 脚本在 Linux 环境中转换:

# 使用 Python 二进制模式转换
python3 << 'EOF'
import os

files = [
    "/home/weishuo/lycium_plusplus/thirdparty/gmic/HPKBUILD",
    "/home/weishuo/lycium_plusplus/thirdparty/gmic/HPKCHECK"
]

for filepath in files:
    with open(filepath, "rb") as f:
        content = f.read()
    content = content.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
    with open(filepath, "wb") as f:
        f.write(content)
    print(f"Fixed: {filepath}")

print("All files fixed!")
EOF

Q7:如何验证 gmic 是否正确使用了 zlib?

A:运行 gmic 时如果不出现 “Could not decompress” 警告,说明 zlib 已正确链接。也可以使用 ldd 命令检查(在构建环境中):

# 检查动态链接库
ldd thirdparty/gmic/gmic-3.5.0/arm64-v8a-build/gmic

# 应该能看到 libz.so 在链接列表中

在真机上,直接运行 ./gmic 并观察输出即可。

Q8:gmic_stdlib.gmic 文件的作用是什么?必须包含吗?

A:gmic_stdlib.gmic 是 G’MIC 的标准库文件,包含 1000+ 滤镜命令的定义。虽然 gmic 可以运行,但如果没有这个文件:

  • 无法使用标准库中的高级滤镜命令
  • 会显示 “Could not decompress” 警告(如果 zlib 也未正确配置)

七、技术总结

本次成功将 G’MIC CLI 适配至 OpenHarmony 平台,形成了一套可复用的 C/C++ 库鸿蒙移植范式。核心要点如下:

  • 标准化适配模板:建立了 CMake 类项目的 HPKBUILD 配置规范,统一交叉编译与依赖管理流程
  • 关键问题解决:通过禁用 OpenMP 规避运行时依赖、显式配置 zlib 路径确保标准库解压、正确管理 CImg 大型头文件
  • 轻量化部署:精简打包产物,显著降低部署体积,提升鸿蒙设备上的分发效率
  • 通用适配能力:方案可直接迁移至 ImageMagick、GraphicsMagick、FFmpeg 等同类图像/多媒体处理工具的鸿蒙移植

八、结语

本次实践成功将 G’MIC CLI 移植至 鸿蒙PC 平台,验证了 lycium_plusplus 框架对 C/C++ 项目交叉编译的支撑能力。通过规范 HPKBUILD 构建流程、禁用 OpenMP 规避运行时依赖、显式配置 zlib 路径、精简产物体积等关键措施,有效解决了适配中的兼容性与构建问题,为同类开源项目迁移至鸿蒙生态提供了可复用的实践参考,助力鸿蒙原生工具生态的完善与发展。

提示:本文基于 G’MIC 3.5.0 版本进行适配。不同版本的依赖和构建脚本可能有所差异,建议在适配前先熟悉目标项目的 CMakeLists.txt 和构建配置文件。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐