20 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:{
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: {
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: {
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: {
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: {
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:
{
loadSrc: $r("app.media.rabbit"),
border: {radius:50}
}
}).width(100).height(100)
7. Setting Image Transformation Options
ImageKnifeComponent({ 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: {
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:
{
loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Cover,
border: { radius: 150 }
}
}).width(300)
.height(300)
Example of Circular cropping with border transformation:
ImageKnifeComponent({ 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: {
loadSrc: $r('app.media.pngSample')
}
}).width(300)
.height(300)
.contrast(12)
Example of rotation transformation:
ImageKnifeComponent({
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:
{
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:{
loadSrc:$r("app.media.pngSample"),
placeholderSrc:$r("app.media.loading")
},syncLoad:true
})
10. Use of ImageKnifeAnimatorComponent
ImageKnifeAnimatorComponent({
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})
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?: (req?: ImageKnifeRequest) => void,onLoadSuccess?: (data: string | PixelMap | undefined, imageData: ImageKnifeData, req?: ImageKnifeRequest) => void,onLoadFailed?: (err: string, req?: ImageKnifeRequest) => void,onLoadCancel?: (res: string, req?: ImageKnifeRequest) => void | Callback for image loading events. Optional. |
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. |
getCacheLimitSize | cacheType?: CacheStrategy | Gets the upper limit size of the specified cache |
getCurrentCacheNum | cacheType?: CacheStrategy | Gets the number of images currently cached in the specified cache |
getCurrentCacheSize | cacheType?: CacheStrategy | Gets the current size of the specified cache |
Description of the callback interface
Callback interface | Callback field | Description of callback data |
---|---|---|
onLoadStart | req: ImageKnifeRequest | The req return field contains information about the image request, such as the url of the image and the width and height of its components, while ImageKnifeRequest contains ImageKnifeData, which contains the start of the request and the point at which it checks the memory cache |
onLoadSuccess | data: string | PixelMap | undefined, imageData: ImageKnifeData, req?: ImageKnifeRequest | data: The result data is loaded successfully. imageData: information stored in the cache of the image, req: information of the image request, and ImageKnifeData, including the original size of the image in the request, image decoding size, format, picture frame, request end time, disk check time, network request start and end, image decoding start and end and other time points |
onLoadFailed | err: string, req?: ImageKnifeRequest | err: indicates error information. req: Information of image request. Meanwhile, ImageKnifeData contains the error information of the request (ErrorInfo, TimeInfo). ErrorInfo contains the error phase, error code and the error code of network request. TimeInfo contains the end time of the request, the disk check time, the start and end of the network request, and the start and end of the image decoding |
onLoadCancel | reason: string, req?: ImageKnifeRequest | reason: indicates the reason for canceling the callback. req: Information of image request. Meanwhile, ImageKnifeData contains the error information of the request (ErrorInfo, TimeInfo). ErrorInfo contains the error phase, error code and the error code of network request. TimeInfo contains the end time of the request, the disk check time, the start and end of the network request, the start and end of the image decoding, and the request cancellation |
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: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66)
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.