ImageKnifePro 源码解读(十二):从 ImageKnife 迁移到 ImageKnifePro
ImageKnife( 两个库的 这意味着大量业务代码在迁移时只需要把 import 路径从 两个库对外看起来相似,内部实现完全不同。 ImageKnife 的 ImageKnifePro 的 这个差异对上层调用者是透明的——两个组件的使用方式完全一样。但如果业务代码依赖了 ImageKnife 内部的 ImageKnife 支持通过 ImageKnifePro 没有 对于只是想替换 HTTP 客户端的场景,可以直接配置 ImageKnife 的 GPU 变换依赖独立的 ImageKnifePro 把 GPU 变换集成到了加载管线中。用户在 ImageKnife 的 GPU 变换可以独立于图片加载使用(比如对已有的 PixelMap 做处理);ImageKnifePro 的变换和加载是绑定的。如果需要对已有 PixelMap 做独立变换,可以把 PixelMap 作为 变换类型的对应关系上,ImageKnife 的 两个库的缓存策略枚举名称有变化。ImageKnife 使用 ImageKnife 的内存缓存是纯 ArkTS 的 ImageKnifePro 的缓存实现在 C++ 层,通过拦截器链的 以下能力在 ImageKnife 中没有对应实现,迁移时属于"新增功能"而非"替换功能"。 预创建组件。 降采样策略。 ImageKnifePro 提供 7 种降采样策略(DEFAULT、FIT_CENTER_MEMORY、FIT_CENTER_QUALITY 等),在解码阶段就把图片缩小到接近显示尺寸。ImageKnife 没有内置降采样,需要在解码后手动缩放。 逐帧解码。 大尺寸动图可以选择 CRC32 校验与 fallbackUrls。 下载数据完整性校验和多域名自动重试。ImageKnife 没有内置这些能力。 自定义 DNS。 静态映射和动态回调两种 DNS 自定义方式。ImageKnife 的网络层直接使用系统 HTTP 请求,没有 DNS 自定义入口。 ImageKnifeView 自绘制组件。 通过 Drawing API 直接绘制,支持 adaptable 宽高自适应。ImageKnife 只有基于 ArkTS Image 的组件。 ImageKnife 的加载回调通过 ImageKnifePro 的加载回调通过 全局加载监听方面,ImageKnifePro 提供了 两个库可以在同一个项目中共存。建议的迁移路径是:先把新页面直接用 ImageKnifePro 开发,旧页面保持不动。等所有页面都迁移完成后,再移除 共存期间需要注意两个库的缓存是独立的。ImageKnife 的文件缓存和 ImageKnifePro 的文件缓存默认写在不同的目录下(ImageKnife 默认 迁移完成后,ImageKnifePro 的 C++ 层实现在性能上有几个明确的优势:网络下载通过 RCP C-API 直接发起,减少了 ArkTS-to-Native 的桥接开销;解码在 C++ 线程中完成,不占用 TaskPool 线程配额;图片通过 DrawableDescriptor 直接设置到 Native 节点上,省去了 ArkTS Image 组件的状态驱动渲染开销。 以上就是本篇内容的所有了~有什么问题欢迎在评论区提出 项目地址:ImageKnifePro@ohos/imageknife)是纯 ArkTS 实现的图片加载库,图形变换依赖独立的 @ohos/gpu_transform 包在 ArkTS 层完成。ImageKnifePro(@ohos/imageknifepro)把核心逻辑下沉到了 C/C++ Native 层,通过 libimageknifepro.so 做网络下载、解码、缓存和变换,ArkTS 侧只保留声明式接口。两个包的 API 表面高度相似,大部分迁移工作是"改依赖 + 调参数",但有几处结构性差异需要逐一处理。一、API 相似——大部分代码不用改
ImageKnife 单例类提供了几乎一样的公开方法。initFileCache、preload、cancel、getCacheImage、putCacheImage、removeAllMemoryCache、removeMemoryCache、removeAllFileCache、removeFileCache、setMaxRequests、addHeader、deleteHeader、setJpegOptimizeDecoding 等接口的签名和语义基本一致。ImageKnifeComponent 的用法也高度重合。两边都用 @ObjectLink imageKnifeOption: ImageKnifeOption 绑定配置,都在 build() 中声明组件。ImageKnifeOption 的字段名称和类型在两个包中大致相同:loadSrc、placeholderSrc、errorholderSrc、signature、httpHeaders、border、objectFit 等。@ohos/imageknife 换成 @ohos/imageknifepro,不需要改动调用方式。二、内部架构差异——ArkTS Image 到 ContentSlot Native
ImageKnifeComponent 内部是一个标准的 ArkTS Image 组件。图片加载完成后得到 PixelMap 或 string(base64),通过 @State 驱动 Image 组件重新渲染。整个加载流程(网络请求、文件缓存读写、解码、图形变换)都在 ArkTS 层或通过 TaskPool 子线程完成。// ImageKnife 的渲染方式(简化)
@State pixelMap: PixelMap | string = '';
build() {
Image(this.pixelMap)
.objectFit(this.imageKnifeOption.objectFit)
}ImageKnifeComponent 内部是一个 ContentSlot。C++ 层直接创建 ArkUI 原生 Image 节点,通过 OH_ArkUI_NodeContent_AddNode 挂载到 ContentSlot 上。PixelMap 在 C++ 层通过 DrawableDescriptor 设置到节点上,不经过 ArkTS 的状态管理机制。// ImageKnifePro 的渲染方式
build() {
ContentSlot(this.rootSlot)
}Image 组件(比如通过 @Link 传递 PixelMap),迁移时需要改用 ImageKnifePro 提供的 getCacheImage 接口获取图片数据。三、customGetImage 到 RegisterLoader
setCustomGetImage 设置全局的自定义下载函数。这个函数接收 Context、src、headers 三个参数,返回 Promise<ArrayBuffer | undefined>。// ImageKnife 的自定义下载
ImageKnife.getInstance().setCustomGetImage(
async (context, src, headers) => {
// 自定义下载逻辑
return arrayBuffer;
}
);setCustomGetImage。它的扩展方式是通过 LoadInterceptor 拦截器链。如果需要自定义下载逻辑,需要在 C++ 层继承 LoadInterceptor 并实现 Resolve 方法,然后通过 ImageKnifeLoader 注册到加载链中。ImageKnifeOption 的 httpHeaders、httpOption(超时、CA 证书路径)、dnsOption 等字段,不需要写自定义拦截器。如果确实需要完全控制下载过程,迁移的工作量会大一些——需要写 C++ 代码而不是 ArkTS 回调。四、GPU 变换的迁移
@ohos/gpu_transform 包。调用方式是在 ArkTS 层创建 GPUImageFilter 子类实例,手动调用 setImageData -> 设置参数 -> getPixelMapBuf 获取结果。整个过程需要调用方管理 GL 环境的创建和销毁。// ImageKnife 的 GPU 变换(简化)
let filter = new GPUImageBlurFilter();
filter.setImageData(pixelMapBuf, width, height);
filter.setBlurRadius(10);
let result = await filter.getPixelMapBuf(width, height);
filter.destroy();ImageKnifeOption 上设置 transformation 或 multiTransformation,框架在解码后自动执行变换。GL 环境的创建和销毁由框架管理,调用方不需要关心。// ImageKnifePro 的变换配置
let option = new ImageKnifeOption();
option.loadSrc = 'https://example.com/image.jpg';
option.transformation = { type: TransformationType.BLUR, f32: [10] };loadSrc 传入 ImageKnifeOption,设置变换后通过 getCacheImage 获取处理后的结果。GPUImageBlurFilter 对应 ImageKnifePro 的 TransformationType.BLUR,GPUImageBrightnessFilter 对应 BRIGHTEN,以此类推。ImageKnifePro 额外提供了 GAUSSIAN_BLUR(CPU 路径的二维高斯模糊)、CROP_CIRCLE、CROP_SQUARE、CROP_CIRCLE_WITH_BORDER、MASK 等 CPU 变换,以及 MIRROR GPU 变换——这些在 ImageKnife 中需要手动实现或依赖其他工具。五、缓存策略的差异
CacheStrategy.Default、CacheStrategy.Memory、CacheStrategy.File;ImageKnifePro 使用 CacheStrategy.DEFAULT、CacheStrategy.MEMORY、CacheStrategy.FILE,多了一个 CacheStrategy.NONE。MemoryLruCache,文件缓存是自实现的 FileCache。用户可以通过 initMemoryCache(newMemoryCache) 替换整个内存缓存实现。MemoryCacheInterceptor 和 FileCacheInterceptor 执行。用户不能替换整个缓存实现,但可以通过自定义拦截器在缓存链中插入额外逻辑。ImageKnifePro 还支持"小端文件缓存"——通过 addSmallEndFileCache 添加多个独立的文件缓存实例,各自独立 LRU。getCacheImage 的返回值也有差异。ImageKnife 返回的 ImageKnifeData.source 可能是 PixelMap 或 string(GIF/WebP 返回 base64 字符串)。ImageKnifePro 返回的 ImageKnifeData 统一包含 PixelMap 数组,动图直接返回多帧 PixelMap,不需要 base64 编码。六、ImageKnifePro 独有的能力
preCreateImageKnifeComponent 在组件渲染前就创建好 Native 节点,列表滚动时零延迟挂载。ImageKnife 没有这个能力。FRAME_MODE 逐帧解码,播放时才解码当前帧,避免一次性解码所有帧撑爆内存。ImageKnife 只有批量解码模式。七、回调与事件的差异
ImageKnifeComponent 的事件属性设置,比如 onLoadStart、onLoadSuccess、onLoadFailed 等。这些回调在 ArkTS 主线程中触发。ImageKnifeOption.onLoadListener 设置。字段名称和语义与 ImageKnife 一致,但 ImageKnifePro 额外提供了 onMemorySuccess、onDownloadSuccess、onDecodeSuccess 三个细粒度回调——分别在内存缓存命中、网络下载完成、图片解码完成时触发。其中后两者在子线程中触发,使用时需要注意线程安全。ImageInfo 的内容也更丰富。ImageKnifePro 的 ImageInfo 包含 requestId(请求唯一标识)、imageSourceFrom(图片来源:内存缓存/文件缓存/网络/本地/PixelMap)、timeInfo(各阶段耗时)、errorInfo(错误码和错误阶段)、transformationInfos(每个变换的耗时和成功状态)等。这些信息在 ImageKnife 中没有对应字段。setGlobalLoadEndCallback,可以监听所有图片请求(包括主图、占位图、缩略图、错误图)的加载结束事件。ImageKnife 没有这个能力。八、渐进式迁移策略
@ohos/imageknife 和 @ohos/gpu_transform 依赖。ImageKnife,ImageKnifePro 默认也是 ImageKnife,但实际存储路径和格式不同),相同 URL 的图片会各下载一次。如果对流量敏感,可以先调用 ImageKnifePro 的 preloadCache 把常用图片预热到新缓存中。