图片裁剪编辑原生模块
Access rate limit exceeded. Please log in to continue.
@hxa-rn/react-native-image-editor
本项目基于 react-native-image-editor 开发。如果在使用过程中有任何问题,可以在 GitCode Issues 提交 Issue,会及时跟进。
项目介绍
@react-native-community/image-editor 提供图片裁剪能力:按调用方给出的偏移与尺寸从原图取矩形区域,可选地缩放到目标展示尺寸,并按指定格式(png / jpeg / webp)另存到应用缓存目录。
架构形态(务必先读):本仓在上游 Android / iOS 实现之外补齐了 HarmonyOS 平台实现,落成一个 ArkTS + C++ TurboModule(RNCImageEditor):裁剪矩形与 EXIF Orientation 换算以上游 Android ImageEditorModuleImpl.kt 为语义基准,displaySize 与 resizeMode 的缩放语义以 iOS RCTImageUtils.mm 的 RCTTargetRect 为基准。
| 面 | 鸿蒙侧处置 |
|---|---|
| 本地路径裁剪 | file:// 与裸绝对路径均支持;裁剪矩形越界显式拒绝并给出可读原因 |
| 远程图片裁剪 | 支持 http(s) 下载后裁剪,可透传自定义请求头;下载失败携带底层原因 |
| data URI 裁剪 | 支持 data: 内联 Base64;内容损坏时显式拒绝 |
| 缩放与 resizeMode | displaySize 双维均大于 0 时触发缩放,contain / cover / stretch / center 四档,未知值回落 cover |
| 输出格式 | png / jpeg / webp 显式指定,MIME 与文件扩展名同步;未知格式回落源图 MIME 而非报错 |
| EXIF | JPEG 输出执行 EXIF 白名单拷贝;裁剪矩形按原图 EXIF Orientation 换算到解码坐标系 |
| Android 专属 URI | content:// 与 android.resource:// 在鸿蒙无对应物,显式拒绝并说明原因 |
| 结果落盘 | 结果写入应用缓存目录、文件名带 ReactNative_cropped_image_ 前缀,模块生命周期结束时按该前缀清理 |
- 上游基线:上游 npm
@react-native-community/image-editor4.3.1(callstack/react-native-image-editor) - 当前发布版本:4.3.1(与上游基线同号)—— npm 包名为
@hxa-rn/react-native-image-editor;上游基线为 4.3.1,JS 公开面(ImageEditor.cropImage)不变。 - 4.3.1 与 4.3.0 的区别:修复本地 JPEG EXIF Orientation 读取回退和输出方向保留;npm 包内的 HAR 改为打包时从当前鸿蒙源码重建。
4.3.0不含这些修复,请使用4.3.1。 - 本库同时提供 ETS 侧与 C++ 侧 codegen 产物,支持 RNOH autolink,宿主无需手动注册 Package 或手动链接 CMake。
- 鸿蒙侧实现:npm 包内的
harmony/image_editor.har是包含 ArkTS/C++ 源码的 HAR;HAR 内部 ohpm 模块名为@oh-rn/image-editor。
鸿蒙使用者必读(3 条,不读会误判)
1.
quality的合法区间是 0~1 的小数 内部按trunc(quality * 100)使用。传80会得到 8000 而越界被拒,不等价于 0.8;越界时逐字报quality must be a number between 0 and 1。2. 不同宽高比缩放是「居中收缩」不是「拉伸」 源图 400×300 全图裁剪、目标 100×100 时,实际裁剪矩形为 (50, 0, 300×300)(左右各裁去 50 像素)再缩到 100×100。
3. 结果文件需要调用方自行清理 裁剪结果落在应用缓存目录,模块生命周期结束时按前缀清理;若调用方需要长期保留,请自行复制到持久目录。
集成指南
1. 从 npm 安装适配包
npm install @hxa-rn/react-native-image-editor@4.3.2 --save-exact --legacy-peer-deps
源码对应 GitCode 的 br_rnoh0.72 分支。
2. JS 导入与包名
第 1 步的 npm install 已在宿主 RN 工程根目录的 package.json 中写入以下依赖,无需手动添加,可打开该文件确认:
{
"dependencies": {
"@hxa-rn/react-native-image-editor": "4.3.1"
}
}
| 包 | 作用 |
|---|---|
@hxa-rn/react-native-image-editor |
鸿蒙适配 npm 包:JS/类型、harmony/image_editor.har 与 codegen 产物 |
@oh-rn/image-editor |
HAR 内部 ohpm 模块名,只用于 HarmonyOS 工程依赖和 ETS import |
在调用裁剪的业务代码文件(如 App.tsx)中照常导入上游包名,不用改:
import ImageEditor from '@react-native-community/image-editor';
RNOH 打 bundle 时,createHarmonyMetroConfig 会按适配包 package.json 里的 harmony.alias 把上游包名重定向到本包;宿主根目录的 metro.config.js 需合并 RNOH Metro 配置(RNOH 工程模板默认如此)。
安装后 node_modules/@hxa-rn/react-native-image-editor/harmony/image_editor.har 应正常存在。
3. 接入鸿蒙原生模块
在宿主鸿蒙工程 harmony/entry/oh-package.json5 的 dependencies 中加入(第一行是宿主已有的 RNOH 依赖,下例为 RNOH 官方预编译包,与本仓示例相同;保持宿主原值即可):
{
dependencies: {
"@rnoh/react-native-openharmony": "file:../../node_modules/@react-native-oh/react-native-harmony/react_native_openharmony_release.har",
"@oh-rn/image-editor": "../../node_modules/@hxa-rn/react-native-image-editor/harmony/image_editor.har",
},
}
宿主 harmony/build-profile.json5 需在 app.products[] 的 buildOption.strictMode 中开启 useNormalizedOHMUrl(RNOH 要求,RNOH 工程模板默认已开启):
"buildOption": {
"strictMode": {
"useNormalizedOHMUrl": true
}
}
然后在宿主 RN 工程根目录执行:
cd harmony
ohpm install
不需要手动注册 RNPackage,也不需要手动改 CMakeLists:@hxa-rn/react-native-image-editor 的 package.json 自带 harmony.alias / harmony.autolinking 字段(ETS 侧 etsPackageClassName: ImageEditorPackage、C++ 侧 cppPackageClassName: ImageEditorPackage),宿主 harmony/hvigorfile.ts 的 createRNOHModulePlugin 开启 autolinking 时(RNOH 工程模板默认如此),RNOH 自动链接机制能直接发现并接入。
4. 声明网络权限(远程图片裁剪时需要)
🔴 本库 HAR 已在自身 module.json5 声明 ohos.permission.INTERNET(用于「远程图片裁剪」下载源图),仅使用本地路径 / data URI 裁剪的宿主无需额外配置;若宿主整体权限清单由自身 module.json5 统一管理,请确认该权限未被移除。
5. 生成鸿蒙侧 JS Bundle
在宿主 RN 工程根目录按普通 RN 三方库流程打包即可:
npx react-native bundle-harmony --dev false
产物默认写入 harmony/entry/src/main/resources/rawfile/bundle.harmony.js。
使用说明
调用 ImageEditor.cropImage(uri, cropData),返回 Promise:
import ImageEditor from '@react-native-community/image-editor';
const result = await ImageEditor.cropImage(uri, {
offset: { x: 10, y: 20 },
size: { width: 200, height: 150 },
});
// result: { path, uri, name, width, height, size, type, base64? }
缩放到目标展示尺寸
displaySize 双维均大于 0 时触发缩放,resizeMode 决定构图方式。
await ImageEditor.cropImage(uri, {
offset: { x: 0, y: 0 },
size: { width: 60, height: 40 },
displaySize: { width: 100, height: 100 },
resizeMode: 'contain',
});
指定输出格式并取 base64
format 支持 png / jpeg / webp;includeBase64 开启后结果附带 base64 串。
await ImageEditor.cropImage(uri, {
offset: { x: 0, y: 0 },
size: { width: 100, height: 100 },
format: 'webp',
includeBase64: true,
});
接口文档
以下覆盖本库全部对外符号(JS 侧公开面 + 鸿蒙原生侧 TurboModule)。JS 侧 API 与上游 Android / iOS 实现同签名;鸿蒙侧差异集中在 URI 方案与解码期行为,逐项见「约束与限制」。
公开接口
公开面 = 1 个类 ImageEditor(default export)+ 1 个静态方法 cropImage,另有 2 个类型 ImageCropData / CropResult(在 src/types.ts 导出)。
| 接口 | 分类 | 说明 |
|---|---|---|
ImageEditor.cropImage(uri, cropData) |
Promise<CropResult> |
按 offset/size 裁剪,可选缩放与格式转换,结果写入应用缓存目录 |
入参 cropData
| 接口 | 分类 | 说明 |
|---|---|---|
offset |
{x, y} |
必填。裁剪区左上角(原图坐标系) |
size |
{width, height} |
必填。裁剪区尺寸(原图坐标系) |
displaySize |
{width, height} |
可选。裁剪后缩放到的目标尺寸,双维均大于 0 才触发 |
resizeMode |
'contain'|'cover'|'stretch'|'center' |
可选。缩放构图方式,未知值回落 cover |
quality |
number |
可选。压缩质量,0~1 的小数,越界被拒 |
format |
'png'|'jpeg'|'webp' |
可选。输出格式,未知值回落源图 MIME |
includeBase64 |
boolean |
可选,默认 false。结果是否附带 base64 串 |
headers |
Record<string,string>|Headers |
可选。远端图片请求头 |
返回 CropResult
| 接口 | 分类 | 说明 |
|---|---|---|
path |
string |
结果文件路径(应用缓存目录) |
uri |
string |
结果 URI(file:// 前缀) |
name |
string |
文件名,扩展名随输出格式变化 |
width / height |
number |
结果宽 / 高(像素) |
size |
number |
结果文件字节数 |
type |
'image/jpeg'|'image/png'|'image/webp' |
结果 MIME 类型 |
base64 |
string(可选) |
仅当 includeBase64: true 时附带 |
快速验证(运行 Example)
前置条件
| 依赖 | 版本要求 |
|---|---|
| Node.js | >= 18(示例工程 engines 要求) |
| DevEco Studio | 6.1.1 及以上(示例 targetSdkVersion 为 6.1.1(24)) |
| HarmonyOS SDK | API 18+(example/harmony 的 compatibleSdkVersion 为 5.1.0(18)) |
| 路径 | Windows 下仓库根目录的完整路径不超过 40 个字符,否则原生构建的中间文件路径会超过系统上限;已克隆到长路径时,把整个仓库目录移到短路径即可(仓内引用都是相对路径) |
运行步骤
1. 克隆仓库
git clone -b br_rnoh0.72 https://gitcode.com/hxa-rn/react-native-image-editor.git
cd react-native-image-editor
Windows 下可在克隆时指定短目录名,例如 git clone -b br_rnoh0.72 https://gitcode.com/hxa-rn/react-native-image-editor.git C:\r。
2. 进入 example 目录,安装依赖
cd example
npm install --legacy-peer-deps
Example 从 npm 公仓安装 @hxa-rn/react-native-image-editor@4.3.2,不需要在仓根执行 npm pack。
3. 生成 JS Bundle
npm run dev
产物:harmony/entry/src/main/resources/rawfile/bundle.harmony.js
4. 用 DevEco Studio 打开鸿蒙工程
- 打开 DevEco Studio,选择
example/harmony目录 - 首次构建请在 File → Project Structure → Signing Configs 勾选 Automatically generate signature,Apply 后 Sync
- 等待 Sync 完成
5. 编译并运行 HAP
在 DevEco Studio 中点击运行按钮,将 HAP 安装到设备。
example_auto(自动化用例工程)步骤相同,把 example 换成 example_auto 即可,两者的依赖与构建输出相互独立。
注意:Example 已预置 Package 注册、Metro alias 与 HAR 依赖,无需手动 Link。编 HAP 前必须先执行
npm run dev;改过 JS 后重新执行再运行。Sync 时harmony/hvigorfile.ts会用 DevEco 自带的 Node 再核对一遍依赖与 Bundle(已完成的部分自动跳过),Build Output 里能看到「[1/5]…[5/5]」准备日志;Sync 报错时找「[失败]」开头的那行,按提示处理后再 Sync。
从当前源码打包适配包
维护者打包前,将 DEVECO_SDK_HOME 设置为 DevEco Studio 的 sdk 目录,然后在仓库根目录执行:
npm install --legacy-peer-deps
npm pack
npm pack 会先编译当前鸿蒙源码生成 harmony/image_editor.har,再执行类型检查和 JS 构建;任何一步失败都会中止打包。HAR 是生成物,不再提交到源码仓库,避免源码已修复而 npm 包仍携带旧实现。
上述操作只生成本地验证用 npm 包,不会上传 npm。包的版本号取自 package.json;registry 上已有同号版本时不能覆盖,本地包只用于验证当前源码。
验证步骤:
- 将
example/或example_auto/复制到独立验证目录,先按常规步骤安装该示例的依赖。 - 在复制出的示例根目录安装本次生成的 tgz(将下面路径替换为实际路径):
npm install --no-save --package-lock=false --legacy-peer-deps /path/to/hxa-rn-react-native-image-editor-<版本>.tgz
npm run dev
- 确认
node_modules/@hxa-rn/react-native-image-editor/harmony/image_editor.har来自本次本地包,再编译运行该示例。验证记录需注明使用的 tgz 和源码 commit。
仓库里的两个示例依赖固定为 npm 上已发布的版本;新版本发布并验证后再更新。
约束与限制
兼容性:
| 项 | 值 |
|---|---|
| 示例工程最低兼容 API | compatibleSdkVersion 5.1.0(18) |
| 示例工程目标 API | targetSdkVersion 6.1.1(24) |
HAR 模块 deviceTypes |
default / tablet / 2in1 |
| 上游 SDK 版本 | @react-native-community/image-editor@4.3.1 |
| RN / RNOH | RN 0.72.5 + @react-native-oh/react-native-harmony@0.72.139 |
权限:
ohos.permission.INTERNET(联网)—— HAR 已在自身module.json5声明,用于「远程图片裁剪」下载源图;仅本地路径 / data URI 裁剪场景不会触发联网。- 读取宿主沙箱外的本地图片路径时,路径可读性由调用方自行保证,与本库权限声明无关。
使用约束:
| 项 | 约束 |
|---|---|
| Android 专属 URI 方案 | content:// 与 android.resource:// 在 HarmonyOS 无对应物,显式拒绝并给出可读原因,属平台真限制(上游同源)。 |
quality 取值区间 |
合法区间为 0~1 的小数;传 80 会越界被拒而不是等价于 0.8(与上游同源)。 |
| 未做解码期降采样 | 未使用 DecodingOptions.desiredRegion / sampleSize,大图裁剪的内存占用偏高,中低端机型需关注。 |
| 结果文件生命周期 | 结果落在应用缓存目录,模块生命周期结束时按 ReactNative_cropped_image_ 前缀清理;需长期保留请自行复制走(与上游语义一致)。 |
| RNOH 与宿主 | 随宿主 RN 鸿蒙工程以 ArkTS 源码编译,需宿主 harmony/build-profile.json5 开启 buildOption.strictMode.useNormalizedOHMUrl;不引入 NAPI 侧自定义逻辑,不依赖特定芯片或传感器。 |
开源 License
本项目基于 MIT 开源。
问题反馈渠道
使用过程中遇到问题,请在 GitCode Issues 提交反馈,会及时跟进。