ImageKnife/README.md

18 KiB

ImageKnife

ImageKnife is a specially crafted image loading and caching library for OpenHarmony, optimized for efficiency, lightness, and simplicity.

Introduction

This project is a self-developed version for OpenHarmony, inspired by the open-source Glide library. It sports the following features:

  • Customizable memory cache strategy with adjustable cache size (default LRU)
  • Disk L2 cache for downloaded images
  • Custom implementation for image acquisition and network downloading
  • Listening for progress of network downloads through callbacks
  • Image options for borders and rounded corners
  • Image scaling with objectFit, including auto-adapting height
  • Image scaling through transformation
  • Concurrent request management with priority queuing
  • No requests made for images whose lifecycle has been destroyed
  • Custom cache keys
  • Custom HTTP request headers
  • writeCacheStrategy for controlling cache storage (memory or file)
  • Preloading images with preLoadCache
  • Loading images exclusively from cache with onlyRetrieveFromCache
  • Support for image transformations such as blurring and highlighting

Planned features:

  • Memory downsampling optimization to save memory usage
  • Support for custom image decoding

Note: The 3.x version has been significantly restructured from the 2.x version, mainly in the following aspects:

  • Use of the Image component instead of the Canvas component for rendering
  • Refactored dispatch logic to control the number of concurrent requests and support priority in request queuing
  • Support for custom memory cache strategies and sizes through initMemoryCache
  • Support for custom implementation of image acquisition/network downloading through options

Therefore, there are some differences in APIs and capabilities, which mainly include the following:

  • The drawLifeCycle API is not supported; images are drawn manually through the canvas.
  • In the new version, parameters such as mainScaleType and border are consistent with the system Image component.
  • GIF/WebP animation playback and control (implemented by ImageAnimator).
  • Anti-aliasing related parameters.

How to Install

ohpm install @ohos/imageknife

// If file caching is required, initialize the file cache in advance.
await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)

How to Use

1. Displaying a Local Resource Image

ImageKnifeComponent({
  ImageKnifeOption: new ImageKnifeOption({
    loadSrc: $r("app.media.app_icon"),
    placeholderSrc: $r("app.media.loading"),
    errorholderSrc: $r("app.media.app_icon"),
    objectFit: ImageFit.Auto
  })
}).width(100).height(100)

2. Displaying a File from Local Context Files

ImageKnifeComponent({
  ImageKnifeOption: new ImageKnifeOption({
    loadSrc: this.localFile,
    placeholderSrc: $r("app.media.loading"),
    errorholderSrc: $r("app.media.app_icon"),
    objectFit: ImageFit.Auto
  })
}).width(100).height(100)

3. Displaying a Network Image

ImageKnifeComponent({
  ImageKnifeOption: new ImageKnifeOption({
    loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
    placeholderSrc: $r("app.media.loading"),
    errorholderSrc: $r("app.media.app_icon"),
    objectFit: ImageFit.Auto
  })
}).width(100).height(100)

4. Downloading an Image with Custom Options

ImageKnifeComponent({
  ImageKnifeOption: new ImageKnifeOption({
    loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
    placeholderSrc: $r("app.media.loading"),
    errorholderSrc: $r("app.media.app_icon"),
    objectFit: ImageFit.Auto,
    customGetImage: custom
 })
}).width(100).height(100)

// Custom implementation of the image acquisition method, such as custom network download。
@Concurrent
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> {
  console.info("ImageKnife:: custom download: " + src)
  // Example of hardcoding to read from a local file. You can also request a network image.
  return context.resourceManager.getMediaContentSync($r("app.media.bb").id).buffer as ArrayBuffer
}

5. Listening for Network Download Progress

ImageKnifeComponent({
  ImageKnifeOption: new ImageKnifeOption({
    loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
    progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)}
  })
}).width(100).height(100)

6. Setting Border Options

ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
{
   loadSrc: $r("app.media.rabbit"),
   border: {radius:50}
  })
}).width(100).height(100)

7. Setting Image Transformation Options

ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
{
   loadSrc: $r("app.media.rabbit"),
   border: {radius:50},
   transformation: new BlurTransformation(3)
  })
}).width(100).height(100)

Multiple combined transformation usages:

let transformations: collections.Array<PixelMapTransformation> = new collections.Array<PixelMapTransformation>();
transformations.push(new BlurTransformation(5));
transformations.push(new BrightnessTransformation(0.2));
ImageKnifeComponent({
  imageKnifeOption: new ImageKnifeOption({
  loadSrc: $r('app.media.pngSample'),
  placeholderSrc: $r("app.media.loading"),
  errorholderSrc: $r("app.media.app_icon"),
  objectFit: ImageFit.Contain,
  border: { radius: { topLeft: 50, bottomRight: 50 } }, // Rounded corner settings
  transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // Graphic transformation group
})
}).width(300)
  .height(300)
  .rotate ({angle: 90}) // Rotate by 90 degrees.
  .contrast(12) // Contrast filter

Other transformation-related properties can be stacked to achieve combined transformation effects.

Example of circular cropping transformation:

ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
  {
  loadSrc: $r('app.media.pngSample'),
  objectFit: ImageFit.Cover,
  border: { radius: 150 }
})
}).width(300)
  .height(300)

Example of Circular cropping with border transformation:

ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
  {
  loadSrc: $r('app.media.pngSample'),
  objectFit: ImageFit.Cover,
  border: { radius: 150, color: Color.Red, width: 5 }
})
}).width(300)
  .height(300)

Example of contrast filtering transformation:

ImageKnifeComponent({
  imageKnifeOption: new ImageKnifeOption({
    loadSrc: $r('app.media.pngSample')
  })
}).width(300)
  .height(300)
  .contrast(12)

Example of rotation transformation:

ImageKnifeComponent({
  imageKnifeOption: new ImageKnifeOption({
    loadSrc: $r('app.media.pngSample')
  })
}).width(300)
  .height(300)
  .rotate({angle:90})
  .backgroundColor(Color.Pink)

8. Listening for Image Loading Success and Failure

ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
{
   loadSrc: $r("app.media.rabbit"),
   onLoadListener:{
    onLoadStart:()=>{
     this.starTime = new Date().getTime()
     console.info("Load start: ");
    },
    onLoadFailed: (err) => {
     console.error("Load Failed Reason: " + err + "  cost " + (new Date().getTime() - this.starTime) + " milliseconds");
    },
    onLoadSuccess: (data, imageData) => {
     console.info("Load Successful: cost " + (new Date().getTime() - this.starTime) + " milliseconds");
     return data;
    },
    onLoadCancel(err){
      console.info(err)
    }
   }
  })
}).width(100).height(100)

9. Use of syncLoad

syncLoad sets whether to load the image synchronously. By default, the image is loaded asynchronously. When loading a small image, you are advised to set syncLoad to true so that the image loading can be quickly completed on the main thread.

ImageKnifeComponent({
        imageKnifeOption:new ImageKnifeOption({
          loadSrc:$r("app.media.pngSample"),
          placeholderSrc:$r("app.media.loading")
        }),syncLoad:true
      })

10. Use of ImageKnifeAnimatorComponent

ImageKnifeAnimatorComponent({
        imageKnifeOption:new ImageKnifeOption({
          loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
          placeholderSrc:$r('app.media.loading'),
          errorholderSrc:$r('app.media.failed')
        }),animatorOption:this.animatorOption
      }).width(300).height(300).backgroundColor(Color.Orange).margin({top:30})

11.图片降采样 示例

ImageKnifeComponent({
        imageKnifeOption:new ImageKnifeOption({
          loadSrc:$r("app.media.pngSample"),
          placeholderSrc:$r('app.media.loading'),
          errorholderSrc:$r('app.media.failed'),
          downsampleOf: DownsampleStrategy.NONE
        }),animatorOption:this.animatorOption
      }).width(300).height(300)

Reuse Scenario

Clear the component content in the aboutToRecycle lifecycle and trigger image loading through watch observeration.

Available APIs

ImageKnife

Component Parameter Description
ImageKnifeComponent ImageKnifeOption Image display component.
ImageKnifeAnimatorComponent ImageKnifeOption, AnimatorOption Animated image control component.

AnimatorOption

Parameter Type Description
state AnimationStatus Playback status. Optional.
iterations number Number of playback times. Optional.
reverse boolean Playback order. Optional.
onStart ()=>void Triggered when the animation starts. Optional.
onFinish ()=>void Triggered when the animation finishes or stops. Optional.
onPause ()=>void Triggered when the animation pauses. Optional.
onCancel ()=>void Triggered when the animation is canceled, that is, when it is reset to its initial state. Optional.
onRepeat ()=>void Triggered when the animation repeats. Optional.

ImageKnifeOption

Parameter Type Description
loadSrc string, PixelMap, Resource Main image.
placeholderSrc PixelMap, Resource Placeholder image. Optional.
errorholderSrc PixelMap, Resource Error image. Optional.
objectFit ImageFit How the main image is resized to fit its container. Optional.
placeholderObjectFit ImageFit How the placeholder image is resized to fit its container. Optional.
errorholderObjectFit ImageFit How the error image is resized to fit its container. Optional.
writeCacheStrategy CacheStrategyType Cache writing strategy. Optional.
onlyRetrieveFromCache boolean Whether to skip network and local requests. Optional.
customGetImage (context: Context, src: string Custom image download. Optional.
border BorderOptions Border corner. Optional.
priority taskpool.Priority Load priority. Optional.
context common.UIAbilityContext Context. Optional.
progressListener (progress: number)=>void Progress. Optional.
signature String Custom cache signature. Optional.
headerOption Array<HeaderOptions> Request headers. Optional.
transformation PixelMapTransformation Image transformation. Optional.
drawingColorFilter ColorFilter Drawing color filter. Optional.
onComplete (event:EventImage | undefined)=>void Callback for image loading completion. Optional.
onLoadListener onLoadStart:()=>void,onLoadSuccess:(data:string|Pixelmap)=>void Callback for image loading events. Optional.
downsampleOf DownsampleStrategy 降采样(可选)

降采样类型

类型 相关描述
NONE 不进行降采样
AT_MOST 请求尺寸大于实际尺寸不进行放大
FIT_CENTER_MEMORY 两边自适应内存优先
FIT_CENTER_QUALITY 两边自适应质量优先
CENTER_OUTSIDE_MEMORY 宽高缩放比最大的比例,进行缩放适配内存优先
CENTER_OUTSIDE_QUALITY 宽高缩放比最大的比例,进行缩放适配质量优先
AT_LEAST 根据宽高的最小的比例,进行适配

ImageKnife

Parameter Type Description
initMemoryCache newMemoryCache: IMemoryCache Initializes a custom memory cache strategy.
initFileCache context: Context, size: number, memory: number Initializes the file cache size and quantity
preLoadCache loadSrc: string I ImageKnifeOption Preloads and returns the file cache path.
getCacheImage loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) Obtains resources from memory or file cache.
addHeader key: string, value: Object Adds a global HTTP request header.
setHeaderOptions Array Sets global HTTP request headers.
deleteHeader key: string Deletes a global HTTP request header.
setCustomGetImage customGetImage?: (context: Context, src: string PixelMap
setEngineKeyImpl IEngineKey Sets a global cache key generation strategy.
putCacheImage url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string Writes to the memory disk cache.
removeMemoryCache url: string Removes an entry from the memory cache.
removeFileCache url: string Removes an entry from the file cache.

Graphics tRansformation Types (GPUImage Dependency Required)

Type Description
BlurTransformation Blurs the image.
BrightnessTransformation Applies a brightness filter.
CropSquareTransformation Crops the image to a square.
CropTransformation Crops the image to a custom rectangle.
GrayScaleTransformation Applies a grayscale filter.
InvertTransformation Applies an inversion filter.
KuwaharaTransformation Applies a Kuwahara filter (requires GPUImage).
MaskTransformation Applies a mask.
PixelationTransformation Applies a pixelation filter (requires GPUImage).
SepiaTransformation Applies a sepia filter (requires GPUImage).
SketchTransformation Applies a sketch filter (requires GPUIImage).
SwirlTransformation Applies a swirl filter (requires GPUImage).
ToonTransformation Applies a cartoon filter (requires GPUImage).
VignetterTransformation Applies a vignette filter (requires GPUImage).

Downloading and Installing the GPUImage Dependency

Method 1: In the Terminal window, run the following command to install the third-party HAR. DevEco Studio will automatically add the HAR as a dependency to the oh-package.json5 file of the project.

    ohpm install @ohos/gpu_transform

Method 2: Set the third-party HAR as a dependency in the oh-package.json5 file of the project. The following is a configuration example:

    "dependencies": {
      "@ohos/gpu_transform": "^1.0.2"
    }

Constraints

This project has been verified in the following version:

DevEco Studio: 5.0 Canary3 (5.0.3.502), SDK: API 12 (5.0.0.31)

How to Contribute

If you find any problem during the use, submit an Issue or a PR to us.

License

This project is licensed under Apache License 2.0.

Known Issues

  • The ImageFit attribute cannot be set for the ImageKnifeAnimator component.
  • The border attribute of the ImageKnifeAnimator component cannot make the image rounded corners.