Compare commits

...

25 Commits
master ... 3.x

Author SHA1 Message Date
tyBrave 1153390393 保持英文README不变
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-29 16:42:32 +08:00
tyBrave 7210d5060b 更新README文件
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-29 16:23:38 +08:00
tyBrave 1c7bedc6d5 同步3.x分支代码
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-29 07:31:35 +00:00
tyBrave 5f2e80400a 更改针对接口回调信息需求的审核意见
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-29 15:17:47 +08:00
zgf fd0394a80a 排队队列改为Queue、showPixelMap回调改为同步
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-28 14:39:40 +08:00
tyBrave c5a861f4fe 更改接口回调信息的README
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-25 22:51:18 +08:00
tyBrave b57194cf4c 新增接口回调信息功能
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-25 22:48:53 +08:00
tyBrave 1a2326c691 新增图片加载回调信息demo及其xts
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-25 22:47:25 +08:00
madixin 9c0b4ebace 1.修复并发相同请求,只收到第一个onLoadStart的bug
2.判断是否要排队的条件,修改为大于等于maxRequests

Signed-off-by: madixin <madixin@huawei.com>
2024-10-25 17:17:44 +08:00
zgf 8d4442157c 子线程网络请求和自定义网络改为异步请求、复用场景清空组件内容
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-25 09:02:32 +00:00
zgf a34e20acfa 子线程网络请求和自定义网络改为异步请求、复用场景清空组件内容
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-25 17:01:18 +08:00
zgf 8dd224e7e6 修改CHANGELOG3.0.3正式版本
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-24 17:48:47 +08:00
tyBrave 7f51e9164e 新增onLoadCancel接口回调的demo
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-21 14:30:33 +08:00
tyBrave 41be71bb73 新增从缓存中获取图片的格式大小等的xts
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-21 14:29:46 +08:00
tyBrave 08b36b7803 新增图片颜色变化demo
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-21 14:28:53 +08:00
zgf cde07275c3 自定义网络方法增加请求头参数
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-11 17:52:32 +08:00
zgf 43dd3c528c 样例国际化
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-10 16:51:11 +08:00
zgf 4383fa3659 新增preload预加载和cancel取消加载接口,添加prefetch配合preload接口样例
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-10 11:34:57 +08:00
zgf aa2cd9c1bf 新增reload加载接口和网络恢复重新加载样例
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-09 15:35:06 +08:00
zgf 1787fffea7 3.x分支xts引入文件报错修改
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-09-30 17:10:07 +08:00
zgf 8e773e929a 3.x分支修改CHANGELOG版本号
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-09-30 16:18:59 +08:00
zgf a3ed45a468 3.x分支更新3.1.0版本代码,并且删除适配componentV2装饰器提交
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-09-30 15:28:02 +08:00
zgf ccd4455b83
!392 修改版本号3.0.2-rc.1
Merge pull request !392 from zgf/3.x
2024-09-29 08:30:37 +00:00
zgf 2fc1f4c776 修改版本号3.0.2-rc.1
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-09-29 16:14:21 +08:00
zgf 6dcf2840b3 FileUtil.readFile接口和file格式图片同步关闭fd
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-09-27 09:58:27 +08:00
78 changed files with 5568 additions and 822 deletions

View File

@ -1,3 +1,52 @@
## 3.2.0-rc.1
- Added callback information for image loading
- Added the interface for obtaining the upper limit and size of the current cache and the number of images corresponding to the current cache
- Change the queue from Stack to Queue
- ShowPixelMap callback PixelMap assigns value to Image component to synchronize
## 3.2.0-rc.0
- Rollback the old version V1 decorator. V2 decorator will be provided in version 4.x
- The sub-thread network request is changed to asynchronous, thereby increasing the number of concurrent sub-thread network requests
- Set the concurrency through the setMaxRequests interface under the ImageKnife class
- aboutToRecycle life cycle clear image content
- Fixed bug for receive only the first onLoadStart for concurrent identical requests
- Modify the condition for determining whether to queue to be greater than or equal to maxRequests
## 3.0.3
- Released version 3.0.3
## 3.0.3-rc.0
- Custom network method to add request header parameters
## 3.0.2
- Added new image reloading interface reload
- Added return request preload interface preload
- Added cancel request interface cancel
## 3.0.2-rc.2
- ImageKnifeAnimatorComponent新增开始、结束、暂停的回调事件
- 文件缓存数量负数和超过INT最大值时默认为INT最大值
- 修复宽高不等svg图片显示有毛边
- 部分静态webp图片有delay属性导致识别成动图,改用getFrameCount识别
- 修复加载错误图后未去请求排队队列中的请求
- 子线程本地Resource参数类型转换成number
- 修改使用hilog记录日志默认打开debug级别的日志
- 解码pixelMap默认不可编辑图形变化可编辑
- 修改网络请求超时设置
- 重构代码抽取ImageKnifeDispatcher子线程requestJob相关代码到ImageKnifeLoader中降低函数复杂度
## 3.0.2-rc.1
- release打包关闭混淆
## 3.0.2-rc.0
- FileUtil.readFile接口和file格式图片同步关闭fd
## 3.0.1
- 修复animatorOption属性设置初始化值失效
- 网络请求code为206、204时返回arraybuffer
- ImageKnifeComponent显示非必要文件缓存初始化
- 修复webp静态图无法设置图形变换
## 3.0.1-rc.2 ## 3.0.1-rc.2
- 修复自定义下载失败无失败回调 - 修复自定义下载失败无失败回调
- 增加全局配置自定义下载接口 - 增加全局配置自定义下载接口

288
README.md
View File

@ -1,59 +1,58 @@
# ImageKnife # ImageKnife
**专门为OpenHarmony打造的一款图像加载缓存库致力于更高效、更轻便、更简单。** ImageKnife is a specially crafted image loading and caching library for OpenHarmony, optimized for efficiency, lightness, and simplicity.
## 简介 ## Introduction
本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本 This project is a self-developed version for OpenHarmony, inspired by the open-source [Glide](https://github.com/bumptech/glide) library. It sports the following features:
- 支持自定义内存缓存策略,支持设置内存缓存的大小(默认LRU策略)。 - 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的能力支持option传入border设置边框圆角 - Image options for borders and rounded corners
- 继承Image的能力支持option传入objectFit设置图片缩放包括objectFit为auto时根据图片自适应高度 - Image scaling with **objectFit**, including auto-adapting height
- 支持通过设置transform缩放图片 - Image scaling through transformation
- 并发请求数量,支持请求排队队列的优先级 - Concurrent request management with priority queuing
- 支持生命周期已销毁的图片,不再发起请求 - No requests made for images whose lifecycle has been destroyed
- 自定义缓存key - Custom cache keys
- 自定义http网络请求头 - Custom HTTP request headers
- 支持writeCacheStrategy控制缓存的存入策略(只存入内存或文件缓存) - **writeCacheStrategy** for controlling cache storage (memory or file)
- 支持preLoadCache预加载图片 - Preloading images with **preLoadCache**
- 支持onlyRetrieveFromCache仅用缓存加载 - Loading images exclusively from cache with **onlyRetrieveFromCache**
- 支持使用一个或多个图片变换,如模糊,高亮等 - Support for image transformations such as blurring and highlighting
待实现特性 Planned features:
- gif/webp动图显示与控制 - Memory downsampling optimization to save memory usage
- 内存降采样优化,节约内存的占用 - Support for custom image decoding
- 支持自定义图片解码
注意3.x版本相对2.x版本做了重大的重构主要体现在 Note: The 3.x version has been significantly restructured from the 2.x version, mainly in the following aspects:
- 使用Image组件代替Canvas组件渲染 - Use of the **Image** component instead of the **Canvas** component for rendering
- 重构Dispatch分发逻辑支持控制并发请求数支持请求排队队列的优先级 - Refactored dispatch logic to control the number of concurrent requests and support priority in request queuing
- 支持通过initMemoryCache自定义策略内存缓存策略和大小 - Support for custom memory cache strategies and sizes through **initMemoryCache**
- 支持option自定义实现图片获取/网络下载 - Support for custom implementation of image acquisition/network downloading through options
因此API及能力上目前有部分差异主要体现在 Therefore, there are some differences in APIs and capabilities, which mainly include the following:
- 不支持drawLifeCycle接口通过canvas自会图片 - The **drawLifeCycle** API is not supported; images are drawn manually through the canvas.
- mainScaleTypeborder等参数新版本与系统Image保持一致 - In the new version, parameters such as **mainScaleType** and **border** are consistent with the system **Image** component.
- gif/webp动图播放与控制 - GIF/WebP animation playback and control (implemented by **ImageAnimator**).
- 抗锯齿相关参数 - Anti-aliasing related parameters.
## 下载安装 ## How to Install
``` ```
ohpm install @ohos/imageknife ohpm install @ohos/imageknife
// 如果需要用文件缓存,需要提前初始化文件缓存 // If file caching is required, initialize the file cache in advance.
await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024) await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
``` ```
## 使用说明 ## How to Use
#### 1.显示本地资源图片 #### 1. Displaying a Local Resource Image
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
@ -66,7 +65,7 @@ ImageKnifeComponent({
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 2.显示本地context files下文件 #### 2. Displaying a File from Local Context Files
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
@ -79,7 +78,7 @@ ImageKnifeComponent({
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 3.显示网络图片 #### 3. Displaying a Network Image
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
@ -92,7 +91,7 @@ ImageKnifeComponent({
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 4.自定义下载图片 #### 4. Downloading an Image with Custom Options
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
@ -105,16 +104,16 @@ ImageKnifeComponent({
} }
}).width(100).height(100) }).width(100).height(100)
// 自定义实现图片获取方法,如自定义网络下载 // Custom implementation of the image acquisition method, such as custom network download。
@Concurrent @Concurrent
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> { async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> {
console.info("ImageKnife:: custom download" + src) 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 return context.resourceManager.getMediaContentSync($r("app.media.bb").id).buffer as ArrayBuffer
} }
``` ```
#### 5.监听网络下载进度 #### 5. Listening for Network Download Progress
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
@ -125,7 +124,7 @@ ImageKnifeComponent({
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 6.支持option传入border设置边框圆角 #### 6. Setting Border Options
``` ```
ImageKnifeComponent({ ImageKnifeOption: ImageKnifeComponent({ ImageKnifeOption:
@ -136,7 +135,7 @@ ImageKnifeComponent({ ImageKnifeOption:
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 7.支持option图片变换 #### 7. Setting Image Transformation Options
``` ```
ImageKnifeComponent({ ImageKnifeOption: ImageKnifeComponent({ ImageKnifeOption:
@ -147,29 +146,29 @@ ImageKnifeComponent({ ImageKnifeOption:
} }
}).width(100).height(100) }).width(100).height(100)
``` ```
多种组合变换用法 Multiple combined transformation usages:
``` ```
let transformations: collections.Array<PixelMapTransformation> = new collections.Array<PixelMapTransformation>(); let transformations: collections.Array<PixelMapTransformation> = new collections.Array<PixelMapTransformation>();
transformations.push(new BlurTransformation(5)); transformations.push(new BlurTransformation(5));
transformations.push(new BrightnessTransformation(0.2)); transformations.push(new BrightnessTransformation(0.2));
ImageKnifeComponent({ ImageKnifeComponent({
{ imageKnifeOption: {
loadSrc: $r('app.media.pngSample'), loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Contain, objectFit: ImageFit.Contain,
border: { radius: { topLeft: 50, bottomRight: 50 } }, // 圆角设置 border: { radius: { topLeft: 50, bottomRight: 50 } }, // Rounded corner settings
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组 transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // Graphic transformation group
} }
}).width(300) }).width(300)
.height(300) .height(300)
.rotate({ angle: 90 }) // 旋转90度 .rotate ({angle: 90}) // Rotate by 90 degrees.
.contrast(12) // 对比度滤波器 .contrast(12) // Contrast filter
``` ```
其他变换相关属性,可叠加实现组合变换效果 Other transformation-related properties can be stacked to achieve combined transformation effects.
圆形裁剪变换示例 Example of circular cropping transformation:
``` ```
ImageKnifeComponent({ ImageKnifeOption: ImageKnifeComponent({ ImageKnifeOption:
@ -182,7 +181,7 @@ ImageKnifeComponent({ ImageKnifeOption:
.height(300) .height(300)
``` ```
圆形裁剪带边框变换示例 Example of Circular cropping with border transformation:
``` ```
ImageKnifeComponent({ ImageKnifeOption: ImageKnifeComponent({ ImageKnifeOption:
@ -195,7 +194,7 @@ ImageKnifeComponent({ ImageKnifeOption:
.height(300) .height(300)
``` ```
对比度滤波变换示例 Example of contrast filtering transformation:
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
@ -207,11 +206,11 @@ ImageKnifeComponent({
.contrast(12) .contrast(12)
``` ```
旋转变换示例 Example of rotation transformation:
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: { imageKnifeOption:({
loadSrc: $r('app.media.pngSample') loadSrc: $r('app.media.pngSample')
} }
}).width(300) }).width(300)
@ -220,7 +219,7 @@ ImageKnifeComponent({
.backgroundColor(Color.Pink) .backgroundColor(Color.Pink)
``` ```
#### 8.监听图片加载成功与失败 #### 8. Listening for Image Loading Success and Failure
``` ```
ImageKnifeComponent({ ImageKnifeOption: ImageKnifeComponent({ ImageKnifeOption:
@ -245,8 +244,8 @@ ImageKnifeComponent({ ImageKnifeOption:
} }
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 9.ImageKnifeComponent - syncLoad #### 9. Use of syncLoad
设置是否同步加载图片默认是异步加载。建议加载尺寸较小的本地图片时将syncLoad设为true因为耗时较短在主线程上执行即可 **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({ ImageKnifeComponent({
imageKnifeOption:{ imageKnifeOption:{
@ -255,7 +254,7 @@ ImageKnifeComponent({
},syncLoad:true },syncLoad:true
}) })
``` ```
#### 10.ImageKnifeAnimatorComponent 示例 #### 10. Use of ImageKnifeAnimatorComponent
``` ```
ImageKnifeAnimatorComponent({ ImageKnifeAnimatorComponent({
imageKnifeOption:{ imageKnifeOption:{
@ -265,105 +264,112 @@ ImageKnifeAnimatorComponent({
},animatorOption:this.animatorOption },animatorOption:this.animatorOption
}).width(300).height(300).backgroundColor(Color.Orange).margin({top:30}) }).width(300).height(300).backgroundColor(Color.Orange).margin({top:30})
``` ```
## 接口说明 #### Reuse Scenario
### ImageKnife组件 Clear the component content in the **aboutToRecycle** lifecycle and trigger image loading through watch observeration.
| 组件名称 | 入参内容 | 功能简介 | ## Available APIs
|-----------------------------|---------------------------------|--------| ### ImageKnife
| ImageKnifeComponent | ImageKnifeOption | 图片显示组件 | | Component | Parameter | Description |
| ImageKnifeAnimatorComponent | ImageKnifeOption、AnimatorOption | 动图控制组件 | | --------------------------- | -------------------------------- | ------------ |
| ImageKnifeComponent | ImageKnifeOption | Image display component.|
| ImageKnifeAnimatorComponent | ImageKnifeOption, AnimatorOption| Animated image control component.|
### AnimatorOption参数列表 ### AnimatorOption
| 参数名称 | 入参内容 | 功能简介 | | Parameter | Type | Description |
|-----------------------|-------------------------------------------------------|----------| | ---------- | --------------- | ---------------------------------------- |
| state | AnimationStatus | 播放状态(可选) | | state | AnimationStatus | Playback status. Optional. |
| iterations | number | 播放次数(可选) | | iterations | number | Number of playback times. Optional. |
| reverse | boolean | 播放顺序(可选) | | 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参数列表 ### ImageKnifeOption
| 参数名称 | 入参内容 | 功能简介 | | Parameter | Type | Description |
|-----------------------|-------------------------------------------------------|-----------------| | --------------------- | ----------------------------------------------------- | ------------------------------ |
| loadSrc | string、PixelMap、Resource | 主图展示 | | loadSrc | string, PixelMap, Resource | Main image. |
| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) | | placeholderSrc | PixelMap, Resource | Placeholder image. Optional. |
| errorholderSrc | PixelMap、Resource | 错误图展示(可选) | | errorholderSrc | PixelMap, Resource | Error image. Optional. |
| objectFit | ImageFit | 主图填充效果(可选) | | objectFit | ImageFit | How the main image is resized to fit its container. Optional. |
| placeholderObjectFit | ImageFit | 占位图填充效果(可选) | | placeholderObjectFit | ImageFit | How the placeholder image is resized to fit its container. Optional. |
| errorholderObjectFit | ImageFit | 错误图填充效果(可选) | | errorholderObjectFit | ImageFit | How the error image is resized to fit its container. Optional. |
| writeCacheStrategy | CacheStrategyType | 写入缓存策略(可选) | | writeCacheStrategy | CacheStrategyType | Cache writing strategy. Optional. |
| onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) | | onlyRetrieveFromCache | boolean | Whether to skip network and local requests. Optional.|
| customGetImage | (context: Context, src: string | 自定义下载图片(可选) | | Resource | 错误占位图数据源 | | customGetImage | (context: Context, src: string | Custom image download. Optional. |
| border | BorderOptions | 边框圆角(可选) | | border | BorderOptions | Border corner. Optional. |
| priority | taskpool.Priority | 加载优先级(可选) | | priority | taskpool.Priority | Load priority. Optional. |
| context | common.UIAbilityContext | 上下文(可选) | | context | common.UIAbilityContext | Context. Optional. |
| progressListener | (progress: number)=>void | 进度(可选) | | progressListener | (progress: number)=>void | Progress. Optional. |
| signature | String | 自定义缓存关键字(可选) | | signature | String | Custom cache signature. Optional. |
| headerOption | Array<HeaderOptions> | 设置请求头(可选) | | headerOption | Array\<HeaderOptions> | Request headers. Optional. |
| transformation | PixelMapTransformation | 图片变换(可选) | | transformation | PixelMapTransformation | Image transformation. Optional. |
| drawingColorFilter | ColorFilter | drawing.ColorFilter | 图片变换(可选) | | drawingColorFilter | ColorFilter | Drawing color filter. Optional. |
| onComplete | (event:EventImage | undefined) => voi | 颜色滤镜效果(可选) | | onComplete | (event:EventImage \| undefined)=>void | Callback for image loading completion. Optional. |
| onLoadListener | onLoadStart: () => void、onLoadSuccess: (data: string | PixelMap | undefined) => void、onLoadFailed: (err: string) => void| 监听图片加载成功与失败 | | onLoadListener | onLoadStart:()=>void,onLoadSuccess:(data:string\|Pixelmap)=>void | Callback for image loading events. Optional. |
### ImageKnife接口 ### ImageKnife
| 参数名称 | 入参内容 | 功能简介 | | Parameter | Type | Description |
|------------------|-------------------------------------------------------------------------------------------------------|---------------| | ----------------- | ------------------------------------------------------------ | -------------------------- |
| initMemoryCache | newMemoryCache: IMemoryCache | 自定义内存缓存策略 | | initMemoryCache | newMemoryCache: IMemoryCache | Initializes a custom memory cache strategy. |
| initFileCache | context: Context, size: number, memory: number | 初始化文件缓存数量和大小 | | initFileCache | context: Context, size: number, memory: number | Initializes the file cache size and quantity |
| preLoadCache | loadSrc: string I ImageKnifeOption | 预加载并返回文件缓存路径 | | preLoadCache | loadSrc: string I ImageKnifeOption | Preloads and returns the file cache path. |
| getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 从内存或文件缓存中获取资源 | | getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | Obtains resources from memory or file cache.|
| addHeader | key: string, value: Object | 全局添加http请求头 | | addHeader | key: string, value: Object | Adds a global HTTP request header. |
| setHeaderOptions | Array<HeaderOptions> | 全局设置http请求头 | | setHeaderOptions | Array<HeaderOptions> | Sets global HTTP request headers. |
| deleteHeader | key: string | 全局删除http请求头 | | deleteHeader | key: string | Deletes a global HTTP request header. |
| setCustomGetImage | customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined> | 全局设置自定义下载 | | setCustomGetImage | customGetImage?: (context: Context, src: string | PixelMap |
| setEngineKeyImpl | IEngineKey | 全局配置缓存key生成策略 | | setEngineKeyImpl | IEngineKey | Sets a global cache key generation strategy. |
| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | 写入内存磁盘缓存 | | putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | Writes to the memory disk cache. |
| removeMemoryCache| url: string | ImageKnifeOption | 清理指定内存缓存 | | removeMemoryCache | url: string | Removes an entry from the memory cache. |
| removeFileCache | url: string | ImageKnifeOption | 清理指定磁盘缓存 | | removeFileCache | url: string | Removes an entry from the file cache. |
### 图形变换类型需要为GPUImage添加依赖项 ### Graphics tRansformation Types (GPUImage Dependency Required)
| 类型 | 相关描述 | | Type | Description |
| ---------------------------------- | ----------------------------- | | ------------------------ | ----------------------------- |
| BlurTransformation | 模糊处理 | | BlurTransformation | Blurs the image. |
| BrightnessTransformation | 亮度滤波器 | | BrightnessTransformation | Applies a brightness filter. |
| CropSquareTransformation | 正方形剪裁 | | CropSquareTransformation | Crops the image to a square. |
| CropTransformation | 自定义矩形剪裁 | | CropTransformation | Crops the image to a custom rectangle. |
| GrayScaleTransformation | 灰度级滤波器 | | GrayScaleTransformation | Applies a grayscale filter. |
| InvertTransformation | 反转滤波器 | | InvertTransformation | Applies an inversion filter. |
| KuwaharaTransformation | 桑原滤波器使用GPUIImage | | KuwaharaTransformation | Applies a Kuwahara filter (requires **GPUImage**). |
| MaskTransformation | 遮罩 | | MaskTransformation | Applies a mask. |
| PixelationTransformation | 像素化滤波器使用GPUIImage | | PixelationTransformation | Applies a pixelation filter (requires **GPUImage**).|
| SepiaTransformation | 乌墨色滤波器使用GPUIImage | | SepiaTransformation | Applies a sepia filter (requires **GPUImage**).|
| SketchTransformation | 素描滤波器使用GPUIImage | | SketchTransformation | Applies a sketch filter (requires **GPUIImage**). |
| SwirlTransformation | 扭曲滤波器使用GPUIImage | | SwirlTransformation | Applies a swirl filter (requires **GPUImage**). |
| ToonTransformation | 动画滤波器使用GPUIImage | | ToonTransformation | Applies a cartoon filter (requires **GPUImage**). |
| VignetterTransformation | 装饰滤波器使用GPUIImage | | VignetterTransformation | Applies a vignette filter (requires **GPUImage**). |
## 下载安装GPUImage依赖 ## Downloading and Installing the GPUImage Dependency
方法一在Terminal窗口中执行如下命令安装三方包DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。 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 ohpm install @ohos/gpu_transform
``` ```
方法二: 在工程的oh-package.json5中设置三方包依赖配置示例如下 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": { "dependencies": {
"@ohos/gpu_transform": "^1.0.2" "@ohos/gpu_transform": "^1.0.2"
} }
``` ```
## 约束与限制 ## Constraints
在下述版本验证通过: This project has been verified in the following version:
DevEco Studio 5.0 Canary35.0.3.221--SDK:API12
## 贡献代码 DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66)
使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) ## How to Contribute
给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) 。
## 开源协议 If you find any problem during the use, submit an [Issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) or a [PR](https://gitee.com/openharmony-tpc/ImageKnife/issues) to us.
本项目基于 [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE) ,请自由的享受和参与开源。 ## License
## 遗留问题 This project is licensed under [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE).
- ImageKnifeAnimator组件无法设置ImageFit属性 ## Known Issues
- ImageKnifeAnimator组件设置border属性无法将图片变为圆角
- The **ImageFit** attribute cannot be set for the **ImageKnifeAnimator** component.
- The **border** attribute of the **ImageKnifeAnimator** component cannot make the image rounded corners.

422
README_zh.md Normal file
View File

@ -0,0 +1,422 @@
# ImageKnife
**专门为OpenHarmony打造的一款图像加载缓存库致力于更高效、更轻便、更简单。**
## 简介
本项目参考开源库 [Glide](https://github.com/bumptech/glide) 进行OpenHarmony的自研版本
- 支持自定义内存缓存策略,支持设置内存缓存的大小(默认LRU策略)。
- 支持磁盘二级缓存,对于下载图片会保存一份至磁盘当中。
- 支持自定义实现图片获取/网络下载
- 支持监听网络下载回调进度
- 继承Image的能力支持option传入border设置边框圆角
- 继承Image的能力支持option传入objectFit设置图片缩放包括objectFit为auto时根据图片自适应高度
- 支持通过设置transform缩放图片
- 并发请求数量,支持请求排队队列的优先级
- 支持生命周期已销毁的图片,不再发起请求
- 自定义缓存key
- 自定义http网络请求头
- 支持writeCacheStrategy控制缓存的存入策略(只存入内存或文件缓存)
- 支持preLoadCache预加载图片
- 支持onlyRetrieveFromCache仅用缓存加载
- 支持使用一个或多个图片变换,如模糊,高亮等
待实现特性
- 内存降采样优化,节约内存的占用
- 支持自定义图片解码
注意3.x版本相对2.x版本做了重大的重构主要体现在
- 使用Image组件代替Canvas组件渲染
- 重构Dispatch分发逻辑支持控制并发请求数支持请求排队队列的优先级
- 支持通过initMemoryCache自定义策略内存缓存策略和大小
- 支持option自定义实现图片获取/网络下载
因此API及能力上目前有部分差异主要体现在
- 不支持drawLifeCycle接口通过canvas自会图片
- mainScaleTypeborder等参数新版本与系统Image保持一致
- gif/webp动图播放与控制(ImageAnimator实现)
- 抗锯齿相关参数
## 下载安装
```
ohpm install @ohos/imageknife
// 如果需要用文件缓存,需要提前初始化文件缓存
await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
```
## 使用说明
#### 1.显示本地资源图片
```
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.显示本地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.显示网络图片
```
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.自定义下载图片
```
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)
// 自定义实现图片获取方法,如自定义网络下载
@Concurrent
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> {
console.info("ImageKnife:: custom download" + src)
// 举例写死从本地文件读取,也可以自己请求网络图片
return context.resourceManager.getMediaContentSync($r("app.media.bb").id).buffer as ArrayBuffer
}
```
#### 5.监听网络下载进度
```
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.支持option传入border设置边框圆角
```
ImageKnifeComponent({ ImageKnifeOption:
{
loadSrc: $r("app.media.rabbit"),
border: {radius:50}
}
}).width(100).height(100)
```
#### 7.支持option图片变换
```
ImageKnifeComponent({ ImageKnifeOption:
{
loadSrc: $r("app.media.rabbit"),
border: {radius:50},
transformation: new BlurTransformation(3)
}
}).width(100).height(100)
```
多种组合变换用法
```
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 } }, // 圆角设置
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组
}
}).width(300)
.height(300)
.rotate({ angle: 90 }) // 旋转90度
.contrast(12) // 对比度滤波器
```
其它变换相关属性,可叠加实现组合变换效果
圆形裁剪变换示例
```
ImageKnifeComponent({ ImageKnifeOption:
{
loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Cover,
border: { radius: 150 }
}
}).width(300)
.height(300)
```
圆形裁剪带边框变换示例
```
ImageKnifeComponent({ ImageKnifeOption:
{
loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Cover,
border: { radius: 150, color: Color.Red, width: 5 }
}
}).width(300)
.height(300)
```
对比度滤波变换示例
```
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $r('app.media.pngSample')
}
}).width(300)
.height(300)
.contrast(12)
```
旋转变换示例
```
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $r('app.media.pngSample')
}
}).width(300)
.height(300)
.rotate({angle:90})
.backgroundColor(Color.Pink)
```
#### 8.监听图片加载成功与失败
```
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.ImageKnifeComponent - syncLoad
设置是否同步加载图片默认是异步加载。建议加载尺寸较小的Resource图片时将syncLoad设为true因为耗时较短在主线程上执行即可
```
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:$r("app.media.pngSample"),
placeholderSrc:$r("app.media.loading")
},syncLoad:true
})
```
#### 10.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})
```
#### 11.加载图片回调信息数据 示例
```
ImageKnifeComponent({ ImageKnifeOption: = new ImageKnifeOption({
loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (req) => {
let startCallBackData = JSON.stringify(req?.getImageKnifeData());
},
onLoadFailed: (res, req) => {
let failedBackData = res + ";" + JSON.stringify(req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
let successBackData = JSON.stringify(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
let cancelBackData = res + ";" + JSON.stringify(req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
let render_success = JSON.stringify(Date.now())
}
}
})
}).width(100).height(100)
```
#### 复用场景
在aboutToRecycle生命周期清空组件内容通过watch监听触发图片的加载。
## 接口说明
### ImageKnife组件
| 组件名称 | 入参内容 | 功能简介 |
|-----------------------------|---------------------------------|--------|
| ImageKnifeComponent | ImageKnifeOption | 图片显示组件 |
| ImageKnifeAnimatorComponent | ImageKnifeOption、AnimatorOption | 动图控制组件 |
### AnimatorOption参数列表
| 参数名称 | 入参内容 | 功能简介 |
|------------|-----------------|----------|
| state | AnimationStatus | 播放状态(可选) |
| iterations | number | 播放次数(可选) |
| reverse | boolean | 播放顺序(可选) |
| onStart | ()=>void | 动画开始播放时触发(可选) |
| onFinish | ()=>void | 动画播放完成时或者停止播放时触发(可选) |
| onPause | ()=>void | 动画暂停播放时触发(可选) |
| onCancel | ()=>void | 动画返回最初状态时触发(可选) |
| onRepeat | ()=>void | 动画重复播放时触发(可选) |
### ImageKnifeOption参数列表
| 参数名称 | 入参内容 | 功能简介 |
|-----------------------|---------------------------------------------------------------------------------------------------------------------------------------|---------------|
| loadSrc | string、PixelMap、Resource | 主图展示 |
| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) |
| errorholderSrc | PixelMap、Resource | 错误图展示(可选) |
| objectFit | ImageFit | 主图填充效果(可选) |
| placeholderObjectFit | ImageFit | 占位图填充效果(可选) |
| errorholderObjectFit | ImageFit | 错误图填充效果(可选) |
| writeCacheStrategy | CacheStrategyType | 写入缓存策略(可选) |
| onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) |
| customGetImage | customGetImage?:(context: Context, src: string、PixelMap、Resource ,headers?: Record<string, Object>) => Promise<ArrayBufferundefined> | 自定义下载图片(可选) | | Resource | 错误占位图数据源 |
| border | BorderOptions | 边框圆角(可选) |
| priority | taskpool.Priority | 加载优先级(可选) |
| context | common.UIAbilityContext | 上下文(可选) |
| progressListener | (progress: number)=>void | 进度(可选) |
| signature | String | 自定义缓存关键字(可选) |
| headerOption | Array<HeaderOptions> | 设置请求头(可选) |
| transformation | PixelMapTransformation | 图片变换(可选) |
| drawingColorFilter | ColorFilter | drawing.ColorFilter | 图片变换(可选) |
| onComplete | (event:EventImage | undefined) => voi | 颜色滤镜效果(可选) |
| 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 | 监听图片加载成功与失败 |
### ImageKnife接口
| 参数名称 | 入参内容 | 功能简介 |
|-------------------|-------------------------------------------------------------------------------------------------------|------------------|
| initMemoryCache | newMemoryCache: IMemoryCache | 自定义内存缓存策略 |
| initFileCache | context: Context, size: number, memory: number | 初始化文件缓存数量和大小 |
| reload | request: ImageKnifeRequest | 图片重新加载 |
| preLoad | loadSrc: string I ImageKnifeOption | 预加载返回图片请求request |
| cancel | request: ImageKnifeRequest | 取消图片请求 |
| preLoadCache | loadSrc: string I ImageKnifeOption | 预加载并返回文件缓存路径 |
| getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 从内存或文件缓存中获取资源 |
| addHeader | key: string, value: Object | 全局添加http请求头 |
| setHeaderOptions | Array<HeaderOptions> | 全局设置http请求头 |
| deleteHeader | key: string | 全局删除http请求头 |
| setCustomGetImage | customGetImage?: (context: Context, src: string、PixelMap、Resource ,headers?: Record<string, Object>) => Promise<ArrayBufferundefined> | PixelMap | Resource) => Promise<ArrayBuffer | undefined> | 全局设置自定义下载 |
| setEngineKeyImpl | IEngineKey | 全局配置缓存key生成策略 |
| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | 写入内存磁盘缓存 |
| removeMemoryCache | url: string | ImageKnifeOption | 清理指定内存缓存 |
| removeFileCache | url: string | ImageKnifeOption | 清理指定磁盘缓存 |
| getCacheLimitSize | cacheType?: CacheStrategy | 获取指定缓存的上限大小 |
| getCurrentCacheNum | cacheType?: CacheStrategy | 获取指定缓存的当前缓存图片个数 |
| getCurrentCacheSize | cacheType?: CacheStrategy | 获取指定缓存的当前大小 |
| getCurrentCacheSize | cacheType?: CacheStrategy | 获取指定缓存的当前大小 |
### 回调接口说明
| 回调接口 | 回调字段 | 回调描述 |
|----------------|-------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| onLoadStart | req: ImageKnifeRequest | req返回字段中包含了图片请求的信息如图片的url及其组件的宽高同时ImageKnifeRequest包含了ImageKnifeData其中包含此次请求的开始及其检查内存缓存的时间点 |
| onLoadSuccess | data: string \| PixelMap \| undefined, imageData: ImageKnifeData, req?: ImageKnifeRequest | data:加载成功的结果数据imageData图片的存入缓存中的信息 req图片请求的信息同时其中的ImageKnifeData包含此次请求中图片的原始大小、图片的解码大小、格式、图片帧、请求结束时间、磁盘检查时间、网络请求开始结束、图片解码开始结束等时间点 |
| onLoadFailed | err: string, req?: ImageKnifeRequest | err:错误信息描述req图片请求的信息同时其中的ImageKnifeData包含此次请求错误信息ErrorInfoTimeInfoErrorInfo其中包含了错误阶段、错误码及其网络请求的错误码TimeInfo中包含请求结束时间、磁盘检查时间、网络请求开始结束、图片解码开始结束等时间点 |
| onLoadCancel | reason: string, req?: ImageKnifeRequest | reason:取消回调原因req图片请求的信息同时其中的ImageKnifeData包含此次请求错误信息ErrorInfoTimeInfoErrorInfo其中包含了错误阶段、错误码及其网络请求的错误码TimeInfo中包含请求结束时间、磁盘检查时间、网络请求开始结束、图片解码开始结束及其请求取消等时间点 |
### 图形变换类型需要为GPUImage添加依赖项
| 类型 | 相关描述 |
| ---------------------------------- | ----------------------------- |
| BlurTransformation | 模糊处理 |
| BrightnessTransformation | 亮度滤波器 |
| CropSquareTransformation | 正方形剪裁 |
| CropTransformation | 自定义矩形剪裁 |
| GrayScaleTransformation | 灰度级滤波器 |
| InvertTransformation | 反转滤波器 |
| KuwaharaTransformation | 桑原滤波器使用GPUIImage |
| MaskTransformation | 遮罩 |
| PixelationTransformation | 像素化滤波器使用GPUIImage |
| SepiaTransformation | 乌墨色滤波器使用GPUIImage |
| SketchTransformation | 素描滤波器使用GPUIImage |
| SwirlTransformation | 扭曲滤波器使用GPUIImage |
| ToonTransformation | 动画滤波器使用GPUIImage |
| VignetterTransformation | 装饰滤波器使用GPUIImage |
## 下载安装GPUImage依赖
方法一在Terminal窗口中执行如下命令安装三方包DevEco Studio会自动在工程的oh-package.json5中自动添加三方包依赖。
```
ohpm install @ohos/gpu_transform
```
方法二: 在工程的oh-package.json5中设置三方包依赖配置示例如下
```
"dependencies": {
"@ohos/gpu_transform": "^1.0.2"
}
```
## 约束与限制
在下述版本验证通过:
DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66)
## 贡献代码
使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues)
,当然,也非常欢迎发 [PR](https://gitee.com/openharmony-tpc/ImageKnife/pulls) 共建。
## 开源协议
本项目基于 [Apache License 2.0](https://gitee.com/openharmony-tpc/ImageKnife/blob/master/LICENSE) ,请自由的享受和参与开源。
## 遗留问题
- ImageKnifeAnimator组件无法设置ImageFit属性
- ImageKnifeAnimator组件设置border属性无法将图片变为圆角

View File

@ -17,7 +17,7 @@ import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility'; import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want'; import Want from '@ohos.app.ability.Want';
import window from '@ohos.window'; import window from '@ohos.window';
import { ImageKnife, InitImageKnife, LogUtil } from '@ohos/libraryimageknife'; import { ImageKnife, InitImageKnife } from '@ohos/libraryimageknife';
import { CustomEngineKeyImpl } from '../common/CustomEngineKeyImpl'; import { CustomEngineKeyImpl } from '../common/CustomEngineKeyImpl';
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl'; import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
@ -47,7 +47,6 @@ export default class EntryAbility extends UIAbility {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
LogUtil.mLogLevel = LogUtil.ALL
// 初始化ImageKnife的文件缓存 // 初始化ImageKnife的文件缓存
await InitImageKnife.init(this.context) await InitImageKnife.init(this.context)
ImageKnife.getInstance().setEngineKeyImpl(new CustomEngineKeyImpl()) ImageKnife.getInstance().setEngineKeyImpl(new CustomEngineKeyImpl())

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InfoItem } from './model/DataSourcePrefetching';
import { PageViewModel } from './model/PageViewModel';
import { ImageKnifeComponent, ImageKnife } from '@ohos/libraryimageknife';
import { CommonDataSource, GetSession } from './model/CommonDataSource';
import { rcp } from '@kit.RemoteCommunicationKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
export struct CustomNetImagePage {
@State hotCommendList:CommonDataSource<InfoItem> = new CommonDataSource<InfoItem>([])
aboutToAppear(): void {
ImageKnife.getInstance().setMaxRequests(32)
this.hotCommendList.addData(this.hotCommendList.totalCount(),PageViewModel.getItems())
}
aboutToDisappear(): void {
ImageKnife.getInstance().setMaxRequests(8)
}
build() {
Column() {
WaterFlow() {
LazyForEach(this.hotCommendList,(item: InfoItem)=>{
FlowItem() {
Column(){
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item.albumUrl,
placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.failed"),
customGetImage:custom
}
}).width("50%").height(200)
}
}.height(200)
.backgroundColor("#95efd2")
},(item: string) => item)
}.columnsTemplate("1fr 1fr")
.columnsGap(10)
.rowsGap(5)
.backgroundColor(0xFAEEE0)
.width("100%").height("100%")
}
}
}
// 自定义下载方法
@Concurrent
async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
return new Promise((resolve,reject)=>{
if (typeof src == "string") {
let session = GetSession.session
let req = new rcp.Request(src,"GET");
session.fetch(req).then((response)=>{
if(response.statusCode == 200) {
let buffer = response.body
resolve(buffer)
} else {
reject("rcp code:"+response.statusCode)
}
}).catch((err:BusinessError)=>{
reject("error rcp src:"+src+",err:"+JSON.stringify(err))
})
}
})
}

View File

@ -1,3 +1,17 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AnimatorOption, ImageKnifeAnimatorComponent } from "@ohos/libraryimageknife" import { AnimatorOption, ImageKnifeAnimatorComponent } from "@ohos/libraryimageknife"
@Entry @Entry
@ -5,27 +19,49 @@ import { AnimatorOption, ImageKnifeAnimatorComponent } from "@ohos/libraryimagek
struct ImageAnimatorPage { struct ImageAnimatorPage {
@State animatorOption: AnimatorOption = { @State animatorOption: AnimatorOption = {
state: AnimationStatus.Running, state: AnimationStatus.Running,
iterations: -1 iterations: 1,
onFinish:()=>{
console.log("ImageKnifeAnimatorComponent animatorOption onFinish")
},
onStart:()=>{
console.log("ImageKnifeAnimatorComponent animatorOption onStart")
},
onPause:()=>{
console.log("ImageKnifeAnimatorComponent animatorOption onPause")
},
onCancel:()=>{
console.log("ImageKnifeAnimatorComponent animatorOption onCancel")
},
onRepeat:()=>{
console.log("ImageKnifeAnimatorComponent animatorOption onRepeat")
}
}
@State animatorOption1: AnimatorOption = {
state: AnimationStatus.Initial
}
@State animatorOption2: AnimatorOption = {
state: AnimationStatus.Initial,
reverse: true
} }
build() { build() {
Column(){ Column(){
Flex(){ Flex(){
Button("播放").onClick(()=>{ Button($r('app.string.Play')).onClick(()=>{
this.animatorOption.state = AnimationStatus.Running this.animatorOption.state = AnimationStatus.Running
}) })
Button("暂停").onClick(()=>{ Button($r('app.string.Pause')).onClick(()=>{
this.animatorOption.state = AnimationStatus.Paused this.animatorOption.state = AnimationStatus.Paused
}) })
Button("停止").onClick(()=>{ Button($r('app.string.Stop')).onClick(()=>{
this.animatorOption.state = AnimationStatus.Stopped this.animatorOption.state = AnimationStatus.Stopped
}) })
Button("无限循环").onClick(()=>{ Button($r('app.string.Infinite_loop')).onClick(()=>{
this.animatorOption.iterations = -1 this.animatorOption.iterations = -1
}) })
Button("播放一次").onClick(()=>{ Button($r('app.string.Play_once')).onClick(()=>{
this.animatorOption.iterations = 1 this.animatorOption.iterations = 1
}) })
Button("播放两次").onClick(()=>{ Button($r('app.string.Play_twice')).onClick(()=>{
this.animatorOption.iterations = 2 this.animatorOption.iterations = 2
}) })
} }
@ -36,6 +72,22 @@ struct ImageAnimatorPage {
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
},animatorOption:this.animatorOption },animatorOption:this.animatorOption
}).width(300).height(300).backgroundColor(Color.Orange).margin({top:30}) }).width(300).height(300).backgroundColor(Color.Orange).margin({top:30})
Text($r('app.string.Display_the_first_frame')).fontSize(20)
ImageKnifeAnimatorComponent({
imageKnifeOption:{
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed')
},animatorOption:this.animatorOption1
}).width(200).height(200).backgroundColor(Color.Orange).margin({top:30})
Text($r('app.string.Display_the_last_frame')).fontSize(20)
ImageKnifeAnimatorComponent({
imageKnifeOption:{
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed')
},animatorOption:this.animatorOption2
}).width(200).height(200).backgroundColor(Color.Orange).margin({top:30})
}.width("100%").height("100%") }.width("100%").height("100%")
} }
} }

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { connection } from '@kit.NetworkKit'
import { List } from '@kit.ArkTS'
import { ImageKnifeRequest,ImageKnife,ImageKnifeComponent } from '@ohos/libraryimageknife'
@Entry
@Component
struct ImageKnifeReload {
aboutToAppear(): void {
NetWatchState.init()
}
build() {
Column() {
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:"https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp",
placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed(err,request){
NetWatchState.requestList.add(request)
}
}
}
}).width(200).height(200)
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:"https://img-blog.csdn.net/20140514114029140",
placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed(err,request){
NetWatchState.requestList.add(request)
}
}
}
}).width(200).height(200).margin({top:10})
}.width("100%")
.height("100%")
}
}
class NetWatchState {
public static netConnection: connection.NetConnection | undefined = undefined
public static requestList: List<ImageKnifeRequest> = new List()
static init() {
NetWatchState.netConnection = connection.createNetConnection()
// 注册订阅事件
NetWatchState.netConnection.register(()=>{
})
// 订阅网络能力变化事件。调用register后才能接收到此事件通知
NetWatchState.netConnection.on("netCapabilitiesChange",(data:connection.NetCapabilityInfo)=>{
if(NetWatchState.requestList.length > 0 && data.netHandle.netId >= 100) {
NetWatchState.requestList.forEach((request)=>{
ImageKnife.getInstance().reload(request)
NetWatchState.requestList.remove(request)
})
}
})
}
static cancel(){
if(NetWatchState.netConnection != undefined) {
// 取消订阅
NetWatchState.netConnection.unregister(()=>{})
}
}
}

View File

@ -78,7 +78,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('模糊效果').fontSize(20) Text($r('app.string.Blur_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -91,7 +91,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('高亮效果').fontSize(20) Text($r('app.string.Highlighting_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -104,7 +104,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('灰化效果').fontSize(20) Text($r('app.string.Ashing_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -117,7 +117,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('反转效果').fontSize(20) Text($r('app.string.Inverse_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -130,7 +130,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('动画滤镜效果').fontSize(20) Text($r('app.string.Animation_filter_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -143,7 +143,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('裁剪圆形效果').fontSize(20) Text($r('app.string.Crop_circular_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -156,7 +156,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('裁剪圆形带边框效果').fontSize(20) Text($r('app.string.Crop_circular_with_border_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -168,7 +168,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('对比度效果').fontSize(20) Text($r('app.string.Contrast_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -181,7 +181,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('乌墨色滤波效果').fontSize(20) Text($r('app.string.Black_ink_filtering_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -193,7 +193,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('旋转效果').fontSize(20) Text($r('app.string.Rotate')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -206,7 +206,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('圆角效果').fontSize(20) Text($r('app.string.Corners')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -219,7 +219,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('桑原滤波效果').fontSize(20) Text($r('app.string.Kuwahara_Filter_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -232,7 +232,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('像素化滤波效果').fontSize(20) Text($r('app.string.Pixelated_Filter_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -245,7 +245,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('素描滤波效果').fontSize(20) Text($r('app.string.Sketch_Filter_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -258,7 +258,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('扭曲滤波效果').fontSize(20) Text($r('app.string.Distortion_Filter_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -271,7 +271,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('装饰滤波效果').fontSize(20) Text($r('app.string.Decorative_Filter_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -284,7 +284,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('正方形裁剪效果').fontSize(20) Text($r('app.string.Square_cutting_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -297,7 +297,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('上方裁剪效果').fontSize(20) Text($r('app.string.Top_cutting_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -310,7 +310,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('中间裁剪效果').fontSize(20) Text($r('app.string.Middle_cutting_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -323,7 +323,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('底下裁剪效果').fontSize(20) Text($r('app.string.Bottom_cutting_effect')).fontSize(20)
} }
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
@ -336,7 +336,7 @@ struct ImageTransformation {
}) })
.width(30) .width(30)
.height(30) .height(30)
Text('遮罩效果').fontSize(20) Text($r('app.string.Mask_effect')).fontSize(20)
} }
if (this.isContrast) { if (this.isContrast) {

View File

@ -18,6 +18,10 @@ import router from '@system.router';
@Component @Component
struct Index { struct Index {
getResourceString(res:Resource){
return getContext().resourceManager.getStringSync(res.id)
}
aboutToAppear(): void { aboutToAppear(): void {
@ -26,95 +30,120 @@ struct Index {
build() { build() {
Scroll(){ Scroll(){
Column() { Column() {
Button("测试ImageAnimator组件").onClick(()=>{ Button($r('app.string.Test_ImageAnimator')).onClick(()=>{
router.push({ router.push({
uri: 'pages/ImageAnimatorPage', uri: 'pages/ImageAnimatorPage',
}); });
}) })
Button("测试加载多张相同图片").margin({top:10}).onClick(()=>{ Button($r('app.string.Network_reload')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/ImageKnifeReload',
});
})
Button($r('app.string.preloading_prefetch')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/PrefetchAndCacheCount',
});
})
Button($r('app.string.request_concurrency')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/SetMaxRequestPage',
});
})
Button($r('app.string.Test_multiple_images')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestCommonImage', uri: 'pages/TestCommonImage',
}); });
}) })
Button("测试HSP场景预加载").margin({top:10}).onClick(()=>{ Button($r('app.string.Customize_RCP_network')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/CustomNetImagePage',
});
})
Button($r('app.string.Test_Task_error')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/TestTaskResourcePage',
});
})
Button($r('app.string.Test_HSP')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestHspPreLoadImage', uri: 'pages/TestHspPreLoadImage',
}); });
}) })
Button("单个图片使用").margin({top:10}).onClick(()=>{ Button($r('app.string.Test_SingleImage')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/SingleImage', uri: 'pages/SingleImage',
}); });
}) })
Button("全局自定义下载").margin({top:10}).onClick(()=>{ Button($r('app.string.Test_custom_download')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestSetCustomImagePage', uri: 'pages/TestSetCustomImagePage',
}); });
}) })
Button("多图 + LazyForEach").margin({top:10}).onClick(()=>{ // Button(this.getResourceString($r('app.string.Multiple_images')) + " + LazyForEach").margin({top:10}).onClick(()=>{
router.push({ // router.push({
uri: 'pages/ManyPhotoShowPage', // uri: 'pages/ManyPhotoShowPage',
//
}); // });
}) // })
Button("多图 + reuse + LazyForeach").margin({top:10}).onClick(()=>{ Button(this.getResourceString($r('app.string.Multiple_images')) + " + reuse + LazyForeach").margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/UserPage', uri: 'pages/UserPage',
}); });
}) })
Button("长图显示").margin({top:10}).onClick(()=>{ Button($r('app.string.Display_long_image')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/LongImagePage', uri: 'pages/LongImagePage',
}); });
}) })
Button("缩放图片").margin({top:10}).onClick(()=>{ Button($r('app.string.Image_scaling')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TransformPage', uri: 'pages/TransformPage',
}); });
}) })
Button("消息+List").margin({top:10}).onClick(()=>{ Button(this.getResourceString($r('app.string.Message_list')) + " + List").margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestImageFlash', uri: 'pages/TestImageFlash',
}); });
}) })
Button("自定义缓存key").margin({top:10}).onClick(()=>{ Button($r('app.string.Custom_cache_key')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/SignatureTestPage', uri: 'pages/SignatureTestPage',
}); });
}) })
Button("预加载图片到文件缓存").margin({top:10}).onClick(()=>{ Button($r('app.string.Preloading_images_to_cache')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestPrefetchToFileCache', uri: 'pages/TestPrefetchToFileCache',
}); });
}) })
Button("从缓存获取图片显示").margin({top:10}).onClick(()=>{ Button($r('app.string.Retrieve_image_display_from_cache')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestIsUrlExist', uri: 'pages/TestIsUrlExist',
}); });
}) })
Button("测试单个请求头").margin({top:10}).onClick(()=>{ Button($r('app.string.Test_single_request_header')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestHeader', uri: 'pages/TestHeader',
}); });
}) })
Button("测试写入缓存策略").margin({top:10}).onClick(()=>{ Button($r('app.string.Test_write_cache_strategy')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestWriteCacheStage', uri: 'pages/TestWriteCacheStage',
}); });
}) })
Button("图片变换").margin({top:10}).onClick(()=>{ Button($r('app.string.Image_Transformation')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/ImageTransformation', uri: 'pages/ImageTransformation',
@ -122,7 +151,7 @@ struct Index {
}) })
Button("不同的ObjectFit").margin({top:10}).onClick(()=>{ Button($r('app.string.Different_ObjectFit')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/ObjectFitPage', uri: 'pages/ObjectFitPage',
@ -130,30 +159,50 @@ struct Index {
}) })
Button('测试图片加载成功/失败事件').margin({top:10}).onClick(()=>{ Button($r('app.string.Test_image_loading_success_or_failure_events')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/LoadStatePage', uri: 'pages/LoadStatePage',
}) })
}) })
Button('测试移除图片缓存接口').margin({top:10}).onClick(()=>{ Button($r('app.string.Test_removing_image_cache_interface')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestRemoveCache', uri: 'pages/TestRemoveCache',
}); });
}) })
Button("测试错误图显示").margin({top:10}).onClick(()=>{ Button($r('app.string.Test_error_image_display')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestErrorHolderPage', uri: 'pages/TestErrorHolderPage',
}); });
}) })
Button("测试媒体url").margin({top:10}).onClick(()=>{ Button($r('app.string.Test_media_URL')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/dataShareUriLoadPage', uri: 'pages/dataShareUriLoadPage',
}); });
}) })
Button($r('app.string.test_cache_btn')).margin({ top: 10 }).onClick(() => {
router.push({
uri: 'pages/TestCacheDataPage',
});
})
Button($r('app.string.test_change_color_btn')).margin({ top: 10 }).onClick(() => {
router.push({
uri: 'pages/TestChangeColorPage',
});
})
Button($r('app.string.test_cancel_callback_btn')).margin({ top: 10 }).onClick(() => {
router.push({
uri: 'pages/TestLoadCancelListenerPage',
});
})
Button($r('app.string.test_callback')).margin({ top: 10 }).onClick(() => {
router.push({
uri: 'pages/TestImageKnifeCallbackPage',
});
})
} }
} .width('100%') } .width('100%')
.height('100%') .height('100%')

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InfoItem } from './model/DataSourcePrefetching';
import { PageViewModel } from './model/PageViewModel';
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
import { CommonDataSource } from './model/CommonDataSource';
@Entry
@Component
export struct LazyForEachCache {
@State hotCommendList:CommonDataSource<InfoItem> = new CommonDataSource<InfoItem>([])
aboutToAppear(): void {
this.hotCommendList.addData(this.hotCommendList.totalCount(),PageViewModel.getItems())
}
build() {
Column() {
List({ space: 16 }) {
LazyForEach(this.hotCommendList, (item: InfoItem,index) => {
ListItem() {
Column({ space: 12 }) {
ImageKnifeComponent({
imageKnifeOption:{
loadSrc: item.albumUrl,
placeholderSrc:$r('app.media.loading')
}
}).width(100).height(100)
Text(`${index}`)
}.border({ width: 5 , color: "#000000"})
}
})
}
.cachedCount(5)
.width("100%")
.height("100%")
.margin({ left: 10, right: 10 })
.layoutWeight(1)
}
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InfoItem } from './model/DataSourcePrefetching';
import { PageViewModel } from './model/PageViewModel';
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
import { CommonDataSource } from './model/CommonDataSource';
@Entry
@Component
export struct LazyForEachCount {
@State hotCommendList:CommonDataSource<InfoItem> = new CommonDataSource<InfoItem>([])
aboutToAppear(): void {
this.hotCommendList.addData(this.hotCommendList.totalCount(),PageViewModel.getItems())
}
build() {
Column() {
List({ space: 16 }) {
LazyForEach(this.hotCommendList, (item: InfoItem,index) => {
ListItem() {
Column({ space: 12 }) {
ImageKnifeComponent({
imageKnifeOption:{
loadSrc: item.albumUrl,
placeholderSrc:$r('app.media.loading')
}
}).width(100).height(100)
Text(`${index}`)
}.border({ width: 5 , color: "#000000"})
}
})
}
.cachedCount(30)
.width("100%")
.height("100%")
.margin({ left: 10, right: 10 })
.layoutWeight(1)
}
}
}

View File

@ -45,10 +45,10 @@ struct LoadStatePage {
@State typeValue: string = "" @State typeValue: string = ""
build() { build() {
Column() { Column() {
Text('测试失败场景请先关闭网络,并保证本地没有此网络图片的缓存') Text($r('app.string.TIPS'))
.margin({ top: 20 }) .margin({ top: 20 })
Row() { Row() {
Button('测试失败/成功场景') Button($r('app.string.Test_failure_success'))
.onClick(() => { .onClick(() => {
this.ImageKnifeOption = { this.ImageKnifeOption = {
loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
@ -79,10 +79,12 @@ struct LoadStatePage {
}) })
} }
.margin({ top: 20 }) .margin({ top: 20 })
Text(this.typeValue) Text($r('app.string.image_format',this.typeValue))
Text($r('app.string.image_width',this.currentWidth))
Text($r('app.string.image_height',this.currentHeight))
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(this.currentHeight).width(this.currentWidth) ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(this.currentHeight).width(this.currentWidth)
.margin({ top: 20 }) .margin({ top: 20 })
Button("自定义下载失败").onClick(()=>{ Button($r('app.string.Custom_download_failed')).onClick(()=>{
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: "abc", loadSrc: "abc",
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
@ -107,7 +109,7 @@ struct LoadStatePage {
} }
// 自定义下载方法 // 自定义下载方法
@Concurrent @Concurrent
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> { async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
console.info("ImageKnife:: custom download" + src) console.info("ImageKnife:: custom download" + src)
// 举例写死从本地文件读取,也可以自己请求网络图片 // 举例写死从本地文件读取,也可以自己请求网络图片
return undefined return undefined

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnifeComponent,ImageKnife } from '@ohos/libraryimageknife';
import { CommonDataSource } from './model/CommonDataSource';
@Entry
@Component
struct MaxRequest1 {
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
private data: Array<string> = []
aboutToAppear(): void {
ImageKnife.getInstance().setMaxRequests(8)
for (let index = 0; index < 200; index++) {
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
}
this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
}
build() {
Column() {
WaterFlow() {
LazyForEach(this.hotCommendList,(item: string)=>{
FlowItem() {
Column(){
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item,
placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.failed"),
}
}).width("50%").height(160)
}
}.height(200)
.backgroundColor("#95efd2")
},(item: string) => item)
}.columnsTemplate("1fr 1fr")
.cachedCount(8)
.columnsGap(10)
.rowsGap(5)
.backgroundColor(0xFAEEE0)
.width("100%").height("100%")
}
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnifeComponent,ImageKnife } from '@ohos/libraryimageknife';
import { CommonDataSource } from './model/CommonDataSource';
@Entry
@Component
struct MaxRequest2 {
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
private data: Array<string> = []
aboutToAppear(): void {
ImageKnife.getInstance().setMaxRequests(20)
for (let index = 200; index < 400; index++) {
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
}
this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
}
build() {
Column() {
WaterFlow() {
LazyForEach(this.hotCommendList,(item: string)=>{
FlowItem() {
Column(){
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item,
placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.failed"),
}
}).width("50%").height(160)
}
}.height(200)
.backgroundColor("#95efd2")
},(item: string) => item)
}.columnsTemplate("1fr 1fr")
.cachedCount(20)
.columnsGap(10)
.rowsGap(5)
.backgroundColor(0xFAEEE0)
.width("100%").height("100%")
}
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnifeComponent,ImageKnife } from '@ohos/libraryimageknife';
import { CommonDataSource } from './model/CommonDataSource';
@Entry
@Component
struct MaxRequest3 {
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
private data: Array<string> = []
aboutToAppear(): void {
ImageKnife.getInstance().setMaxRequests(32)
for (let index = 400; index < 600; index++) {
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
}
this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
}
build() {
Column() {
WaterFlow() {
LazyForEach(this.hotCommendList,(item: string)=>{
FlowItem() {
Column(){
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item,
placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.failed"),
}
}).width("50%").height(160)
}
}.height(200)
.backgroundColor("#95efd2")
},(item: string) => item)
}.columnsTemplate("1fr 1fr")
.cachedCount(40)
.columnsGap(10)
.rowsGap(5)
.backgroundColor(0xFAEEE0)
.width("100%").height("100%")
}
}
}

View File

@ -27,7 +27,7 @@ struct ObjectFitPage {
build() { build() {
Column() { Column() {
Button("主图Fill拉伸填充").onClick(()=>{ Button($r('app.string.Main_image_Fill')).onClick(()=>{
this.imageKnifeOption = { this.imageKnifeOption = {
loadSrc: $r("app.media.app_icon"), loadSrc: $r("app.media.app_icon"),
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
@ -36,7 +36,7 @@ struct ObjectFitPage {
} }
}) })
Button("占位图Contain保持比例填充").margin({top:10}).onClick(async () => { Button($r('app.string.Maintain_proportion_filling')).margin({top:10}).onClick(async () => {
ImageKnife.getInstance().removeAllMemoryCache() ImageKnife.getInstance().removeAllMemoryCache()
await ImageKnife.getInstance().removeAllFileCache() await ImageKnife.getInstance().removeAllFileCache()
@ -50,7 +50,7 @@ struct ObjectFitPage {
}) })
Button("错误图None不变化").margin({top:10}).onClick(() => { Button($r('app.string.Error_graph_None')).margin({top:10}).onClick(() => {
this.imageKnifeOption = { this.imageKnifeOption = {
loadSrc: "http://xxxxx", loadSrc: "http://xxxxx",
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { router } from '@kit.ArkUI'
@Entry
@Component
struct PrefetchAndCacheCount {
build() {
Column() {
Button("cacheCount == 5")
.onClick(()=>{
router.pushUrl({url:"pages/LazyForEachCache"})
})
Button("cacheCount == 30")
.margin({top:10})
.onClick(()=>{
router.pushUrl({url:"pages/LazyForEachCount"})
})
Button("prefetch + preload")
.margin({top:10})
.onClick(()=>{
router.pushUrl({url:"pages/PrefetchAndPreload"})
})
}.width("100%")
.height("100%")
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { BasicPrefetcher } from '@kit.ArkUI';
import DataSourcePrefetchingImageKnife, { InfoItem } from './model/DataSourcePrefetching';
import { PageViewModel } from './model/PageViewModel';
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
@Entry
@Component
export struct PrefetchAndPreload {
// 创建DataSourcePrefetchingImageKnife对象具备任务预取、取消能力的数据源
private readonly dataSource = new DataSourcePrefetchingImageKnife(PageViewModel.getItems());
// 创建BasicPrefetcher对象默认的动态预取算法实现
private readonly prefetcher = new BasicPrefetcher(this.dataSource);
build() {
Column() {
List({ space: 16 }) {
LazyForEach(this.dataSource, (item: InfoItem,index:number) => {
ListItem() {
Column({ space: 12 }) {
ImageKnifeComponent({
imageKnifeOption:{
loadSrc: item.albumUrl,
placeholderSrc:$r('app.media.loading')
}
}).width(100).height(100)
Text(`${index}`)
}.border({ width: 5 , color: "#000000"})
}
.reuseId('imageKnife')
})
}
.cachedCount(5)
.onScrollIndex((start: number, end: number) => {
// 列表滚动触发visibleAreaChanged实时更新预取范围触发调用prefetch、cancel接口
this.prefetcher.visibleAreaChanged(start, end)
})
.width("100%")
.height("100%")
.margin({ left: 10, right: 10 })
.layoutWeight(1)
}
}
}

View File

@ -0,0 +1,23 @@
import { router } from '@kit.ArkUI'
@Entry
@Component
struct SetMaxRequestPage {
build() {
Column() {
Button("maxRequest = 8")
.onClick(()=>{
router.pushUrl({url:"pages/MaxRequest1"})
})
Button("maxRequest = 20")
.onClick(()=>{
router.pushUrl({url:"pages/MaxRequest2"})
}).margin({top:20})
Button("maxRequest = 32")
.onClick(()=>{
router.pushUrl({url:"pages/MaxRequest2"})
}).margin({top:20})
}.width("100%")
.height("100%")
}
}

View File

@ -33,9 +33,9 @@ struct SignatureTestPage {
Scroll() { Scroll() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text("key固定为 1").fontSize(15) Text($r('app.string.The_key_fixed_1')).fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("加载") Button($r('app.string.Load'))
.onClick(() => { .onClick(() => {
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: 'https://img-blog.csdn.net/20140514114029140', loadSrc: 'https://img-blog.csdn.net/20140514114029140',
@ -46,9 +46,9 @@ struct SignatureTestPage {
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
}.width('100%').backgroundColor(Color.Pink) }.width('100%').backgroundColor(Color.Pink)
Text("key每次变化时间戳").fontSize(15) Text($r('app.string.The_key_changes_timestamp')).fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("加载") Button($r('app.string.Load'))
.onClick(() => { .onClick(() => {
this.imageKnifeOption2 = { this.imageKnifeOption2 = {
loadSrc: 'https://img-blog.csdn.net/20140514114029140', loadSrc: 'https://img-blog.csdn.net/20140514114029140',

View File

@ -42,7 +42,7 @@ struct SingleImage {
build() { build() {
Scroll(this.scroller) { Scroll(this.scroller) {
Column() { Column() {
Text("本地资源svg图片") Text($r('app.string.Local_SVG'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
@ -56,7 +56,7 @@ struct SingleImage {
.onClick(()=>{ .onClick(()=>{
this.DrawingColorFilter = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN); this.DrawingColorFilter = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN);
}) })
Text("本地context files下文件") Text($r('app.string.Under_context_file'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
@ -67,7 +67,7 @@ struct SingleImage {
objectFit: ImageFit.Contain objectFit: ImageFit.Contain
} }
}).width(100).height(100) }).width(100).height(100)
Text("网络图片") Text($r('app.string.Network_images'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
@ -79,7 +79,7 @@ struct SingleImage {
progressListener:(progress:number)=>{console.info("ImageKnife:: call back progress = " + progress)} progressListener:(progress:number)=>{console.info("ImageKnife:: call back progress = " + progress)}
} }
}).width(100).height(100) }).width(100).height(100)
Text("自定义下载") Text($r('app.string.Custom_network_download'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
@ -88,11 +88,15 @@ struct SingleImage {
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.failed"), errorholderSrc: $r("app.media.failed"),
objectFit: ImageFit.Contain, objectFit: ImageFit.Contain,
headerOption:[{
key:"refer",
value:"xx.xx.xx.xx"
}],
customGetImage: custom, customGetImage: custom,
transformation: new BlurTransformation(10) transformation: new BlurTransformation(10)
} }
}).width(100).height(100) }).width(100).height(100)
Text("pixelMap加载图片") Text($r('app.string.PixelMap_loads_images'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
@ -124,9 +128,11 @@ struct SingleImage {
// 自定义下载方法 // 自定义下载方法
@Concurrent @Concurrent
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> { async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
console.info("ImageKnife:: custom download" + src) let refer = headers!["refer"] as string
console.info("ImageKnife:: custom download" + src,"refer:"+refer)
// 举例写死从本地文件读取,也可以自己请求网络图片 // 举例写死从本地文件读取,也可以自己请求网络图片
return context.resourceManager.getMediaContentSync($r("app.media.startIcon").id).buffer as ArrayBuffer let buffer = context.resourceManager.getMediaContentSync($r("app.media.startIcon").id).buffer as ArrayBuffer
return buffer
} }

View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnife, CacheStrategy, ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
@Entry
@Component
struct TestCacheDataPage {
@State cacheUpLimit: number = 0;
@State currentNum: number = 0;
@State currentSize: number = 0;
@State currentWidth: number = 200
@State currentHeight: number = 200
@State markersLimitText: string = getContext(this).resourceManager.getStringSync($r('app.string.memory'))
@State markersNumText: string = getContext(this).resourceManager.getStringSync($r('app.string.memory'))
@State markersSizeText: string = getContext(this).resourceManager.getStringSync($r('app.string.memory'))
@State ImageKnifeOption: ImageKnifeOption = {
loadSrc: "",
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadFailed: (err) => {
console.error("Load Failed Reason: " + err);
},
onLoadSuccess: (data) => {
return data;
},
},
border: { radius: 50 }
}
aboutToAppear(): void {
ImageKnife.getInstance().initFileCache(getContext(this), 256, 256 * 1024 * 1024, "ImageKnifeCache1")
}
build() {
Column() {
ImageKnifeComponent(
{ imageKnifeOption: this.ImageKnifeOption })
.height(this.currentHeight)
.width(this.currentWidth)
.margin({ top: 10 })
Button($r('app.string.load_memory'))
.onClick(() => {
this.ImageKnifeOption = {
loadSrc: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3e/v3/LqRoLI-PRSu9Nqa8KdJ-pQ/dSqskBpSR9eraAMn7NBdqA.jpg",
objectFit: ImageFit.Contain,
writeCacheStrategy: CacheStrategy.Memory,
border: { radius: 50 },
}
})
Button($r('app.string.load_disk'))
.onClick(() => {
this.ImageKnifeOption = {
loadSrc: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg",
objectFit: ImageFit.Contain,
writeCacheStrategy: CacheStrategy.File,
border: { radius: 50 },
}
})
Text($r('app.string.cur_cache_limit', this.markersLimitText, this.cacheUpLimit))
.fontSize(20)
.margin({ bottom: 8 });
Text($r('app.string.cur_cache_image_num', this.markersNumText, this.currentNum))
.fontSize(20)
.margin({ bottom: 8 });
Text($r('app.string.cur_cache_size', this.markersSizeText, this.currentSize)).fontSize(20).margin({ bottom: 20 });
Button($r('app.string.get_cur_memory_limit')).onClick(() => {
let result = ImageKnife.getInstance().getCacheLimitSize(CacheStrategy.Memory);
this.markersLimitText = getContext(this).resourceManager.getStringSync($r('app.string.memory'))
if (result) {
this.cacheUpLimit = result / (1024 * 1024);
} else {
this.cacheUpLimit = 0;
}
}).margin({ bottom: 8 });
Button($r('app.string.get_img_number_of_cache')).onClick(() => {
let result = ImageKnife.getInstance().getCurrentCacheNum(CacheStrategy.Memory);
this.markersNumText = getContext(this).resourceManager.getStringSync($r('app.string.memory'))
if (result) {
this.currentNum = result;
} else {
this.currentNum = 0;
}
}).margin({ bottom: 8 });
Button($r('app.string.get_cur_memory_size')).onClick(() => {
let result = ImageKnife.getInstance().getCurrentCacheSize(CacheStrategy.Memory);
this.markersSizeText = getContext(this).resourceManager.getStringSync($r('app.string.memory'))
if (result) {
this.currentSize = result / (1024 * 1024);
} else {
this.currentSize = 0;
}
}).margin({ bottom: 8 });
Button($r('app.string.get_cur_disk_limit')).onClick(() => {
let result = ImageKnife.getInstance().getCacheLimitSize(CacheStrategy.File);
this.markersLimitText = getContext(this).resourceManager.getStringSync($r('app.string.disk'))
if (result) {
this.cacheUpLimit = result / (1024 * 1024);
} else {
this.cacheUpLimit = 0;
}
}).margin({ bottom: 8 });
Button($r('app.string.get_img_number_of_disk')).onClick(() => {
let result = ImageKnife.getInstance().getCurrentCacheNum(CacheStrategy.File);
this.markersNumText = getContext(this).resourceManager.getStringSync($r('app.string.disk'))
if (result) {
this.currentNum = result;
} else {
this.currentNum = 0;
}
}).margin({ bottom: 8 });
Button($r('app.string.get_cur_disk_size')).onClick(() => {
let result = ImageKnife.getInstance().getCurrentCacheSize(CacheStrategy.File);
this.markersSizeText = getContext(this).resourceManager.getStringSync($r('app.string.disk'))
if (result) {
this.currentSize = result / (1024 * 1024);
} else {
this.currentSize = 0;
}
}).margin({ bottom: 8 });
}
.height('100%').width('100%').margin({ top: 50 })
}
}

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { drawing, common2D } from '@kit.ArkGraphics2D';
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknife';
@Entry
@Component
struct TestChangeColorPage {
private imageOne: Resource = $r('app.media.ic_test_change_color_png');
private imageTwo: Resource = $r('app.media.ic_test_change_color_png');
@State src: Resource = this.imageOne
@State src2: Resource = this.imageTwo
@State color: common2D.Color = {
alpha: 255,
red: 255,
green: 1,
blue: 1
};
@State DrawingColorFilterFirst: ColorFilter | undefined = undefined
build() {
Column() {
Text($r('app.string.select_color_btn')).margin({ top: 20 })
Row() {
Button($r('app.string.red')).backgroundColor(Color.Red).margin(5).onClick(() => {
this.color = {
alpha: 255,
red: 255,
green: 1,
blue: 1
};
})
Button($r('app.string.yellow')).backgroundColor(Color.Yellow).margin(5).onClick(() => {
this.color = {
alpha: 255,
red: 255,
green: 255,
blue: 1
};
})
Button($r('app.string.green')).backgroundColor(Color.Green).margin(5).onClick(() => {
this.color = {
alpha: 255,
red: 1,
green: 255,
blue: 1
};
})
Button($r('app.string.blue')).backgroundColor(Color.Blue).margin(5).onClick(() => {
this.color = {
alpha: 255,
red: 1,
green: 1,
blue: 255
};
})
}
.width('100%')
.height(50)
.justifyContent(FlexAlign.Center)
Text($r('app.string.master_image')).margin({ top: 20 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.src
}
}).width(110).height(110)
Text($r('app.string.click_img_to_change_color')).margin({ top: 30 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.src,
drawingColorFilter: this.DrawingColorFilterFirst
}
})
.onClick(() => {
this.DrawingColorFilterFirst =
drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN);
}).width(110).height(110)
Text($r('app.string.test_non_svg_color')).margin({ top: 30 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $r('app.media.ic_test_change_color_png'),
drawingColorFilter: drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN)
}
}).width(110).height(110)
Text($r('app.string.test_svg_color')).margin({ top: 30 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $r("app.media.ic_test_change_color_svg"),
drawingColorFilter: drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN)
}
}).width(110).height(110)
}.width('100%').height('100%')
}
}

View File

@ -111,12 +111,12 @@ struct ImageTestPage {
}) })
} }
Row(){ Row(){
Text("点击尺寸加50") Text($r('app.string.Click_on_add'))
.onClick(()=> { .onClick(()=> {
this.imageSize = this.imageSize + 50 this.imageSize = this.imageSize + 50
}) })
.width('50%').backgroundColor(0x88ff0000).textAlign(TextAlign.Center).height(50) .width('50%').backgroundColor(0x88ff0000).textAlign(TextAlign.Center).height(50)
Text("点击尺寸减50") Text($r('app.string.Click_on_reduce'))
.onClick(()=> { .onClick(()=> {
this.imageSize = Math.max(this.imageSize - 50, 0) this.imageSize = Math.max(this.imageSize - 50, 0)
}) })

View File

@ -0,0 +1,412 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnifeComponent, ImageKnifeData, ImageKnifeOption, ImageKnifeRequest } from '@ohos/libraryimageknife';
import { router } from '@kit.ArkUI';
@Entry
@Component
struct TestImageKnifeCallbackPage {
@State imageKnifeOption: ImageKnifeOption = {
loadSrc: "",
objectFit: ImageFit.Contain,
border: { radius: 50 }
};
@State currentWidth: number = 200
@State currentHeight: number = 200
@State url: string | undefined = ""
@State imageType: string | undefined = ""
@State imageWidth: number | undefined = 0
@State imageHeight: number | undefined = 0
@State imageSize: number | undefined = 0
@State componentWidth: number | undefined = 0
@State componentHeight: number | undefined = 0
@State frameNum: number | undefined = 0
@State decodeSize: string | undefined = ""
@State err_msg: string | undefined = ""
@State err_phase: string | undefined = ""
@State err_code: number | undefined = 0
@State http_code: number | undefined = 0
@State reqStartTime: string | undefined = ""
@State reqEndTime: string | undefined = ""
@State reqCancelTime: string | undefined = ""
@State memoryStartTime: string | undefined = ""
@State memoryEndTime: string | undefined = ""
@State diskStartTime: string | undefined = ""
@State diskEndTime: string | undefined = ""
@State netStartTime: string | undefined = ""
@State netEndTime: string | undefined = ""
@State decodeStartTime: string | undefined = ""
@State decodeEndTime: string | undefined = ""
@State renderTime: string | undefined = ""
@State showChild: boolean = true;
build() {
Column() {
Text($r('app.string.img_url', this.url)).fontSize(14)
Text($r('app.string.img_format', this.imageType)).fontSize(14)
Text($r('app.string.img_master_size', this.imageWidth, this.imageHeight, this.imageSize)).fontSize(14)
Text($r('app.string.componentWH', this.componentWidth, this.componentHeight)).fontSize(14)
Text($r('app.string.img_frame', this.frameNum)).fontSize(14)
Text($r('app.string.img_content_size', this.decodeSize)).fontSize(14)
Text($r('app.string.err_msg', this.err_msg)).fontSize(14)
Text($r('app.string.err_phase', this.err_phase)).fontSize(14)
Text($r('app.string.err_code', this.err_code)).fontSize(14)
Text($r('app.string.http_code', this.http_code)).fontSize(14)
Text($r('app.string.req_start_time', this.reqStartTime)).fontSize(14)
Text($r('app.string.req_end_time', this.reqEndTime)).fontSize(14)
Text($r('app.string.req_cancel_time', this.reqCancelTime)).fontSize(14)
Text($r('app.string.memory_start_time', this.memoryStartTime)).fontSize(14)
Text($r('app.string.memory_end_time', this.memoryEndTime)).fontSize(14)
Text($r('app.string.disk_start_time', this.diskStartTime)).fontSize(14)
Text($r('app.string.disk_end_time', this.diskEndTime)).fontSize(14)
Text($r('app.string.net_start_time', this.netStartTime)).fontSize(14)
Text($r('app.string.net_end_time', this.netEndTime)).fontSize(14)
Text($r('app.string.decode_start_time', this.decodeStartTime)).fontSize(14)
Text($r('app.string.decode_end_time', this.decodeEndTime)).fontSize(14)
Text($r('app.string.render_time', this.renderTime)).fontSize(14)
Scroll() {
Column() {
Row() {
Button($r('app.string.Network_images'))
.fontSize(13)
.onClick(() => {
this.destroy();
this.imageKnifeOption = {
loadSrc: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/10/v3/qaEzwkU0QeKb1yehnP2Xig/q7fxAlgMQKup-HUBayRLGQ.jpg",
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
this.analyzeStartCallBackData(data);
},
onLoadFailed: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
this.renderTime = this.formatDate(Date.now());
}
}
}
})
Button($r('app.string.gif'))
.fontSize(13)
.onClick(() => {
this.destroy();
this.imageKnifeOption = {
loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658',
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
this.analyzeStartCallBackData(data);
},
onLoadFailed: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
this.renderTime = this.formatDate(Date.now());
}
}
}
})
Button($r('app.string.local_pic'))
.fontSize(13)
.onClick(() => {
this.destroy();
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
this.analyzeStartCallBackData(data);
},
onLoadFailed: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
this.renderTime = this.formatDate(Date.now());
}
}
}
})
}
Row() {
Button($r('app.string.net_load_failed'))
.fontSize(13)
.onClick(() => {
this.destroy();
this.imageKnifeOption = {
loadSrc: "https://img-blog.csdn.net/20140514114039140",
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
this.analyzeStartCallBackData(data);
},
onLoadFailed: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
this.renderTime = this.formatDate(Date.now());
}
}
}
})
Button($r('app.string.local_load_failed'))
.fontSize(13)
.onClick(() => {
this.destroy();
this.imageKnifeOption = {
loadSrc: 'app.media.xxx',
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
this.analyzeStartCallBackData(data);
},
onLoadFailed: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
this.renderTime = this.formatDate(Date.now());
}
}
}
})
Button($r('app.string.share_load_failed'))
.fontSize(13)
.onClick(() => {
this.destroy();
this.imageKnifeOption = {
loadSrc: 'datashare://ssas',
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
this.analyzeStartCallBackData(data);
},
onLoadFailed: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
this.renderTime = this.formatDate(Date.now());
}
}
}
})
}
Button($r('app.string.test_cancel_callback_btn'))
.fontSize(13)
.onClick(() => {
this.destroy();
this.imageKnifeOption = {
loadSrc: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/bf/v3/lSjrRwFcS-ez6jp1ALSQFg/0n7R7XinSPyrYLqDu_1dfw.jpg",
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
this.showChild = false;
this.analyzeStartCallBackData(data);
},
onLoadFailed: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.getImageKnifeData());
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.getImageKnifeData());
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
this.renderTime = this.formatDate(Date.now());
}
}
}
})
Button($r('app.string.list_pic'))
.fontSize(13)
.onClick(() => {
router.push({
url: 'pages/TestListImageKnifeCallbackPage',
});
})
if (this.showChild) {
ImageKnifeComponent(
{ imageKnifeOption: this.imageKnifeOption })
.height(this.currentHeight)
.width(this.currentWidth)
.margin({ top: 20, bottom: 20 })
}
}
.width('100%')
}
}.alignItems(HorizontalAlign.Start)
}
formatDate(time: number | undefined) {
if (!time) {
return;
}
let date = new Date(time);
const year = date.getFullYear().toString()
let month = (date.getMonth() + 1).toString()
let day = date.getDate().toString()
let hour = date.getHours().toString()
let min = date.getMinutes().toString()
let seconds = date.getSeconds().toString()
let mill = date.getMilliseconds();
return `${year}-${month}-${day} ${hour}:${min}:${seconds}:${mill}`
}
analyzeStartCallBackData(req: ImageKnifeRequest | undefined) {
let data = req?.getImageKnifeData();
if (data) {
if (typeof req?.imageKnifeOption.loadSrc == 'string') {
this.url = req?.imageKnifeOption.loadSrc;
}
this.componentWidth = req?.componentWidth;
this.componentHeight = req?.componentHeight;
this.reqStartTime = this.formatDate(data.timeInfo?.requestStartTime);
this.memoryStartTime = this.formatDate(data.timeInfo?.memoryCheckStartTime);
this.memoryEndTime = this.formatDate(data.timeInfo?.memoryCheckEndTime);
}
}
analyzeSuccessCallBackData(data: ImageKnifeData | undefined) {
if (data) {
this.imageWidth = data.imageWidth;
this.imageHeight = data.imageHeight;
this.imageSize = data.bufSize;
this.frameNum = data.frameCount;
this.decodeSize = JSON.stringify(data.decodeImages);
this.imageType = data.type;
this.reqEndTime = this.formatDate(data.timeInfo?.requestEndTime);
this.diskStartTime = this.formatDate(data.timeInfo?.diskCheckStartTime);
this.diskEndTime = this.formatDate(data.timeInfo?.diskCheckEndTime);
this.netStartTime = this.formatDate(data.timeInfo?.netRequestStartTime);
this.netEndTime = this.formatDate(data.timeInfo?.netRequestEndTime);
this.decodeStartTime = this.formatDate(data.timeInfo?.diskCheckStartTime);
this.decodeEndTime = this.formatDate(data.timeInfo?.diskCheckEndTime);
}
}
analyzeFailedBackData(res: string, data: ImageKnifeData | undefined) {
if (data) {
this.err_msg = res;
this.err_phase = data.errorInfo?.phase;
this.err_code = data.errorInfo?.code;
this.http_code = data.errorInfo?.httpCode;
this.reqEndTime = this.formatDate(data.timeInfo?.requestEndTime);
this.diskStartTime = this.formatDate(data.timeInfo?.diskCheckStartTime);
this.diskEndTime = this.formatDate(data.timeInfo?.diskCheckEndTime);
this.netStartTime = this.formatDate(data.timeInfo?.netRequestStartTime);
this.netEndTime = this.formatDate(data.timeInfo?.netRequestEndTime);
this.decodeStartTime = this.formatDate(data.timeInfo?.diskCheckStartTime);
this.decodeEndTime = this.formatDate(data.timeInfo?.diskCheckEndTime);
this.reqCancelTime = this.formatDate(data.timeInfo?.requestCancelTime)
}
}
destroy() {
this.currentWidth = 200
this.currentHeight = 200
this.url = ""
this.imageType = ""
this.imageWidth = 0
this.imageHeight = 0
this.imageSize = 0
this.componentWidth = 0
this.componentHeight = 0
this.frameNum = 0
this.decodeSize = ""
this.err_msg = ""
this.err_phase = ""
this.err_code = 0
this.http_code = 0
this.reqStartTime = ""
this.reqEndTime = ""
this.reqCancelTime = ""
this.memoryStartTime = ""
this.memoryEndTime = ""
this.diskStartTime = ""
this.diskEndTime = ""
this.netStartTime = ""
this.netEndTime = ""
this.decodeStartTime = ""
this.decodeEndTime = ""
this.renderTime = ""
this.showChild = true;
}
}

View File

@ -28,11 +28,11 @@ struct TestIsUrlExist {
build() { build() {
Column() { Column() {
Flex() { Flex() {
Button("预加载gif图").onClick(() => { Button($r('app.string.Preloading_GIF')).onClick(() => {
this.imageKnifeOption.loadSrc = this.imageKnifeOption.loadSrc =
"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658" "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
}) })
Button("内存缓存获取gif").onClick(() => { Button($r('app.string.Retrieve_GIF_from_memory')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
CacheStrategy.Memory) CacheStrategy.Memory)
@ -40,7 +40,7 @@ struct TestIsUrlExist {
this.source = data !== undefined ? data.source : $r("app.media.startIcon") this.source = data !== undefined ? data.source : $r("app.media.startIcon")
}) })
}) })
Button("文件缓存获取gif").onClick(() => { Button($r('app.string.Retrieve_GIF_from_disk')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
CacheStrategy.File) CacheStrategy.File)
@ -51,11 +51,11 @@ struct TestIsUrlExist {
} }
Flex() { Flex() {
Button("预加载静态图").onClick(() => { Button($r('app.string.Preloading_static_images')).onClick(() => {
this.imageKnifeOption.loadSrc = this.imageKnifeOption.loadSrc =
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp' 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'
}) })
Button("内存缓存获取").onClick(() => { Button($r('app.string.Retrieve_images_from_memory')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
CacheStrategy.Memory) CacheStrategy.Memory)
@ -63,7 +63,7 @@ struct TestIsUrlExist {
this.source = data!.source this.source = data!.source
}) })
}) })
Button("文件缓存获取").onClick(() => { Button($r('app.string.Retrieve_images_from_disk')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
CacheStrategy.File) CacheStrategy.File)

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnifeComponent} from '@ohos/libraryimageknife';
class ArrayElement {
src: string = "";
w: number = 0;
h: number = 0;
}
@Entry
@Component
struct TestListImageKnifeCallbackPage {
private wid: number = 200;
private hig: number = 200;
private dataArray: ESObject[] = [
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg",
"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/78/v3/qQJpAtRGQe2e_VhbGHDgIw/b3zlit99S6GybD3XdNwqJw.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/55/v3/5DZ2LLqYSsK85-shqgLveQ/7ZXcyCWNTvOzQP5FFLBGkg.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3e/v3/LqRoLI-PRSu9Nqa8KdJ-pQ/dSqskBpSR9eraAMn7NBdqA.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/25/v3/jgB2ekkTRX-3yTYZalnANQ/xff_x9cbSPqb7fbNwgJa7A.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fb/v3/alXwXLHKSyCAIWt_ydgD2g/BCCuu25TREOitQxM7eYOEw.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/63/v3/qbe6NZkCQyGcITvdWoZBgg/Y-5U1z3GT_yaK8CBD3jkwg.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/16/v3/fm2tO4TsRH6mv_D_nSSd5w/FscLpLwQQ-KuV7oaprFK2Q.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/89/v3/UAUvtPHqRD-GWWANsEC57Q/zcRJCQebQ322Aby4jzmwmQ.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/30/v3/tUUzzx73R4yp8G--lMhuWQ/EBbcu_dLTT-Jj68XAh6mtA.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/76/v3/EyF6z4FISpCHhae38eEexw/OtyAiu-zSSevNQYvUdtVmA.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/37/v3/12rH1yiEQmK9wlOOcy5avQ/RzBXiEBRRqOC7LRkwNj6VA.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/9a/v3/TpRN4AIzRoyUXIqWdKoE0g/ShOnD_tfS46HDbpSWhbCkQ.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/03/v3/H3X17s8eTdS2w56JgbB5jQ/a45sT-j8Sbe8sSQXTzeYvQ.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/10/v3/qaEzwkU0QeKb1yehnP2Xig/q7fxAlgMQKup-HUBayRLGQ.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/96/v3/rMJJoAflTDSWa1z2pHs2wg/8dOqD0GlQBOCL5AvQok9FQ.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ed/v3/KMO4D6D2QGuVOCLX4AhOFA/ef51xAaLQuK7BsnuD9abog.jpg",
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/d9/v3/FSZH0aTdSqWxeAaxoPvi0g/RqxPxUCXQFiTMBfKTF9kkw.jpg",
"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
'https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/bf/v3/lSjrRwFcS-ez6jp1ALSQFg/0n7R7XinSPyrYLqDu_1dfw.jpg',
'https://img-blog.csdn.net/20140514114029140',
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
$r('app.media.pngSample'),
$r('app.media.rabbit')
]
private data: Array<ArrayElement> = [];
aboutToAppear(): void {
for (let i = 0; i < this.dataArray.length; i++) {
let element: ArrayElement = {
src: this.dataArray[i],
w: this.wid -(i*5),
h: this.hig -(i*5)
}
this.data.push(element);
}
}
build() {
List({ space: 3 }) {
ForEach(this.data, (item: ArrayElement) => {
ListItem() {
ImageKnifeComponent({
imageKnifeOption:
{
loadSrc: item.src,
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (data) => {
console.log("listCache start:{ url:"+data?.imageKnifeOption.loadSrc +",componentWidth:"+data?.componentWidth+",componentHeight:"+data?.componentHeight+"},"
+ JSON.stringify(data?.getImageKnifeData()))
},
onLoadFailed: (res, req) => {
console.log("listCache onLoadFailed:res:" + res + ";" + JSON.stringify(req?.getImageKnifeData()))
},
onLoadSuccess: (data, imageData,req) => {
console.log("listCache onLoadSuccess:" + JSON.stringify(req?.getImageKnifeData()))
},
onLoadCancel: (res, req) => {
console.log("listCache onLoadCancel:res:" + res + ";" + JSON.stringify(req?.getImageKnifeData()))
}
},
border: { radius: 50 },
}
}).height(item.w).width(item.h)
}.width('100%')
}, (item: ArrayElement,index) => (item.src+index))
}.width('100%').height('100%')
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnife, ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
@Entry
@Component
struct TestLoadCancelListenerPage {
@State currentWidth: number = 200
@State currentHeight: number = 200
@State showChild: boolean = true;
@State text: string = "";
@State ImageKnifeOption: ImageKnifeOption = {
loadSrc: "",
objectFit: ImageFit.Contain,
border: { radius: 50 }
};
build() {
Column() {
Text($r('app.string.onLoadCancel_reason', this.text)).margin(20).fontSize(15)
Button($r('app.string.rm_component_of_net'))
.margin(20)
.onClick(() => {
this.clearCache();
this.ImageKnifeOption = {
loadSrc: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/76/v3/EyF6z4FISpCHhae38eEexw/OtyAiu-zSSevNQYvUdtVmA.jpg",
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: () => {
this.showChild = false;
},
onLoadCancel: (res) => {
this.text = res
console.log("TestLoadCancelListenerPage----onLoadCancel> url:" + res)
}
},
border: { radius: 50 }
}
})
Button($r('app.string.component_display'))
.margin(20).onClick(() => {
this.text = "";
this.showChild = true;
this.ImageKnifeOption = {
loadSrc: "",
objectFit: ImageFit.Contain,
border: { radius: 50 }
}
})
Button($r('app.string.rm_component_of_local'))
.margin(20)
.onClick(() => {
this.clearCache();
this.ImageKnifeOption = {
loadSrc: $r('app.media.loading'),
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: () => {
this.showChild = false;
},
onLoadCancel: (res) => {
this.text = res
console.log("TestLoadCancelListenerPage----onLoadCancel> url:" + res)
}
},
border: { radius: 50 }
}
})
if (this.showChild) {
ImageKnifeComponent(
{ imageKnifeOption: this.ImageKnifeOption })
.height(150)
.width(150)
.backgroundColor(Color.Orange)
.margin({ top: 20 })
}
}
.height('100%')
.width('100%')
}
clearCache(){
ImageKnife.getInstance().removeAllMemoryCache();
}
}

View File

@ -32,13 +32,13 @@ struct TestPrefetchToFileCachePage {
} }
build() { build() {
Column() { Column() {
Button("url预加载图片到文件缓存").margin({top:10}).onClick(async ()=>{ Button($r('app.string.Preloading_images_to_file_cache_using_URL')).margin({top:10}).onClick(async ()=>{
await this.preload("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658") await this.preload("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658")
}) })
Button("option预加载图片到文件缓存").margin({top:10}).onClick(async ()=>{ Button($r('app.string.Preloading_images_to_file_cache_using_option')).margin({top:10}).onClick(async ()=>{
await this.preload1("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658") await this.preload1("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658")
}) })
Button("加载图片(预加载后可断网加载)").margin({top:10}).onClick(()=>{ Button($r('app.string.Load_image_offline_after_preloading')).margin({top:10}).onClick(()=>{
this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658" this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"
}) })
ImageKnifeComponent({ ImageKnifeComponent({

View File

@ -29,12 +29,12 @@ struct TestRemoveCache {
build() { build() {
Column() { Column() {
Flex() { Flex() {
Button("预加载gif图").onClick(() => { Button($r('app.string.Preloading_GIF')).onClick(() => {
this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"; this.imageKnifeOption.loadSrc = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658";
this.url = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658"; this.url = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658";
}) })
.margin({left:10}) .margin({left:10})
Button("内存缓存获取gif").onClick(() => { Button($r('app.string.Retrieve_GIF_from_memory')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
CacheStrategy.Memory) CacheStrategy.Memory)
@ -43,7 +43,7 @@ struct TestRemoveCache {
}) })
}) })
.margin({left:10}) .margin({left:10})
Button("文件缓存获取gif").onClick(() => { Button($r('app.string.Retrieve_GIF_from_disk')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", .getCacheImage("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
CacheStrategy.File) CacheStrategy.File)
@ -55,12 +55,12 @@ struct TestRemoveCache {
} }
Flex() { Flex() {
Button("预加载静态图").onClick(() => { Button($r('app.string.Preloading_static_images')).onClick(() => {
this.imageKnifeOption.loadSrc = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'; this.imageKnifeOption.loadSrc = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp';
this.url = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'; this.url = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp';
}) })
.margin({left:10}) .margin({left:10})
Button("内存缓存获取").onClick(() => { Button($r('app.string.Retrieve_images_from_memory')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
CacheStrategy.Memory) CacheStrategy.Memory)
@ -69,7 +69,7 @@ struct TestRemoveCache {
}) })
}) })
.margin({left:10}) .margin({left:10})
Button("文件缓存获取").onClick(() => { Button($r('app.string.Retrieve_images_from_disk')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', .getCacheImage('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
CacheStrategy.File) CacheStrategy.File)
@ -81,19 +81,19 @@ struct TestRemoveCache {
}.margin({ top: 10 }) }.margin({ top: 10 })
Flex() { Flex() {
Button("删除全部缓存").onClick(() => { Button($r('app.string.Delete_all_caches')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.removeAllMemoryCache() .removeAllMemoryCache()
ImageKnife.getInstance() ImageKnife.getInstance()
.removeAllFileCache() .removeAllFileCache()
}) })
.margin({left:5}) .margin({left:5})
Button("删除全部内存缓存").onClick(() => { Button($r('app.string.Delete_all_memory_caches')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.removeAllMemoryCache() .removeAllMemoryCache()
}) })
.margin({left:5}) .margin({left:5})
Button("删除全部文件缓存").onClick(() => { Button($r('app.string.Delete_all_file_caches')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.removeAllFileCache() .removeAllFileCache()
}) })
@ -101,12 +101,12 @@ struct TestRemoveCache {
}.margin({ top: 10 }) }.margin({ top: 10 })
Flex() { Flex() {
Button("删除自定义内存缓存").onClick(() => { Button($r('app.string.Delete_all_custom_memory_caches')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.removeMemoryCache(this.url) .removeMemoryCache(this.url)
}) })
.margin({left:20}) .margin({left:20})
Button("删除自定义文件缓存").onClick(() => { Button($r('app.string.Delete_all_custom_file_caches')).onClick(() => {
ImageKnife.getInstance() ImageKnife.getInstance()
.removeFileCache(this.url) .removeFileCache(this.url)
}) })

View File

@ -27,21 +27,24 @@ struct TestSetCustomImagePage {
aboutToDisappear(): void { aboutToDisappear(): void {
ImageKnife.getInstance().setCustomGetImage() ImageKnife.getInstance().setCustomGetImage()
} }
getResourceString(res:Resource){
return getContext().resourceManager.getStringSync(res.id)
}
build() { build() {
Column() { Column() {
Button("自定义下载a").onClick(()=>{ Button(this.getResourceString($r('app.string.Custom_network_download')) + " a").onClick(()=>{
this.imageKnifeOption ={ this.imageKnifeOption ={
loadSrc: "aaa", loadSrc: "aaa",
placeholderSrc: $r('app.media.loading') placeholderSrc: $r('app.media.loading')
} }
}) })
Button("自定义下载b").onClick(()=>{ Button(this.getResourceString($r('app.string.Custom_network_download')) + " b").onClick(()=>{
this.imageKnifeOption = { this.imageKnifeOption = {
loadSrc: "bbb", loadSrc: "bbb",
placeholderSrc: $r('app.media.loading') placeholderSrc: $r('app.media.loading')
} }
}) })
Button("自定义下载c").onClick(()=>{ Button(this.getResourceString($r('app.string.Custom_network_download')) + " c").onClick(()=>{
this.imageKnifeOption = { this.imageKnifeOption = {
loadSrc: "ccc", loadSrc: "ccc",
placeholderSrc: $r('app.media.loading') placeholderSrc: $r('app.media.loading')
@ -57,8 +60,9 @@ struct TestSetCustomImagePage {
} }
} }
@Concurrent @Concurrent
async function custom(context: Context, src: string | PixelMap | Resource): Promise<ArrayBuffer | undefined> { async function custom(context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>): Promise<ArrayBuffer | undefined> {
console.info("ImageKnife:: custom download" + src) console.info("ImageKnife:: custom download" + src)
// 举例写死从本地文件读取,也可以自己请求网络图片 // 举例写死从本地文件读取,也可以自己请求网络图片
return context.resourceManager.getMediaContentSync($r("app.media.pngSample").id).buffer as ArrayBuffer let buffer = context.resourceManager.getMediaContentSync($r("app.media.pngSample").id).buffer as ArrayBuffer
return buffer
} }

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife"
@ComponentV2
export struct ZuImage {
@Param @Require src: PixelMap | ResourceStr | string | undefined
@Param @Require placeholderSrc: PixelMap | ResourceStr | string | undefined
@Local errorholderSrc: PixelMap | ResourceStr | string | undefined
build() {
if (this.src) {
//当前版本存在bug
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.src,
placeholderSrc: this.placeholderSrc,
errorholderSrc: this.errorholderSrc ?? this.placeholderSrc,
objectFit: ImageFit.Cover
}
})
} else {
Image(this.placeholderSrc)
.objectFit(ImageFit.Cover)
}
}
}
@Entry
@ComponentV2
struct TestTaskResourcePage {
@Local stateMenus: Array<string> = [
"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
'https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/bf/v3/lSjrRwFcS-ez6jp1ALSQFg/0n7R7XinSPyrYLqDu_1dfw.jpg',
'https://img-blog.csdn.net/20140514114029140',
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
]
@Builder
_buildItem(item: string) {
Column({ space: 8 }) {
ZuImage({
src: item,
placeholderSrc: $r("app.media.loading")
}).width(44)
.height(44)
}
}
build() {
Grid() {
ForEach(this.stateMenus, (item: string) => {
GridItem() {
this._buildItem(item)
}
})
}.width("100%")
.columnsTemplate('1fr 1fr 1fr 1fr 1fr')
.rowsGap(24)
.padding({
top: 24,
bottom: 24,
left: 24,
right: 24
})
}
}

View File

@ -35,7 +35,7 @@ struct TestWriteCacheStage {
build() { build() {
Column() { Column() {
Button("写入内存文件缓存").margin({top:10}).onClick(async ()=>{ Button($r('app.string.Write_memory_and_file')).margin({top:10}).onClick(async ()=>{
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc:'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', loadSrc:'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
@ -46,7 +46,7 @@ struct TestWriteCacheStage {
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption1 imageKnifeOption: this.imageKnifeOption1
}).width(200).height(200).margin({top:10}) }).width(200).height(200).margin({top:10})
Button("写入内存缓存").margin({top:10}).onClick(async ()=>{ Button($r('app.string.Write_memory')).margin({top:10}).onClick(async ()=>{
this.imageKnifeOption2 = { this.imageKnifeOption2 = {
loadSrc:"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", loadSrc:"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
@ -57,7 +57,7 @@ struct TestWriteCacheStage {
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption2 imageKnifeOption: this.imageKnifeOption2
}).width(200).height(200).margin({top:10}) }).width(200).height(200).margin({top:10})
Button("写入文件缓存").margin({top:10}).onClick(async ()=>{ Button($r('app.string.Write_file')).margin({top:10}).onClick(async ()=>{
this.imageKnifeOption3 = { this.imageKnifeOption3 = {
loadSrc:'https://img-blog.csdn.net/20140514114029140', loadSrc:'https://img-blog.csdn.net/20140514114029140',
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),

View File

@ -34,12 +34,12 @@ struct TransformPage {
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(200).width(200) ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption }).height(200).width(200)
.transform(this.matrix1) .transform(this.matrix1)
// Image($r('app.media.rabbit')).objectFit(ImageFit.Contain).height(200).width(200).transform(this.matrix1) // Image($r('app.media.rabbit')).objectFit(ImageFit.Contain).height(200).width(200).transform(this.matrix1)
Button("放大").onClick(()=>{ Button($r('app.string.Enlarge')).onClick(()=>{
this.custom_scale = this.custom_scale * 2 this.custom_scale = this.custom_scale * 2
this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale }) this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale })
}) })
Button("缩小").onClick(()=>{ Button($r('app.string.Reduce')).onClick(()=>{
this.custom_scale = this.custom_scale / 2 this.custom_scale = this.custom_scale / 2
this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale }) this.matrix1 = matrix4.identity().scale({ x: this.custom_scale, y: this.custom_scale })
}) })

View File

@ -12,75 +12,36 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { CommonDataSource } from './model/CommonDataSource'
import { UserAvatar } from './User' import { UserAvatar } from './User'
class CommonDataSource <T> implements IDataSource {
private dataArray: T[] = []
private listeners: DataChangeListener[] = []
constructor(element: []) {
this.dataArray = element
}
public getData(index: number) {
return this.dataArray[index]
}
public totalCount(): number {
return this.dataArray.length
}
public addData(index: number, data: T[]): void {
this.dataArray = this.dataArray.concat(data)
this.notifyDataAdd(index)
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
this.listeners.splice(pos, 1);
}
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
this.listeners.push(listener)
}
}
notifyDataAdd(index: number): void {
this.listeners.forEach((listener: DataChangeListener) => {
listener.onDataAdd(index)
})
}
}
@Entry @Entry
@Component @Component
struct Index { struct Index {
@State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([]) @State hotCommendList:CommonDataSource<string> = new CommonDataSource<string>([])
private data:string[] = [ private data:string[] = [
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e2/v3/4zI1Xm_3STmV30aZXWRrKw/6aN7WodDRUiBApgffiLPCg.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/42/v3/2dSQCqERTP2TTPyssOMEbQ/zL1ebnKKQ_ilqTDcwCAkOw.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/78/v3/qQJpAtRGQe2e_VhbGHDgIw/b3zlit99S6GybD3XdNwqJw.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/55/v3/5DZ2LLqYSsK85-shqgLveQ/7ZXcyCWNTvOzQP5FFLBGkg.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3e/v3/LqRoLI-PRSu9Nqa8KdJ-pQ/dSqskBpSR9eraAMn7NBdqA.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/25/v3/jgB2ekkTRX-3yTYZalnANQ/xff_x9cbSPqb7fbNwgJa7A.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fb/v3/alXwXLHKSyCAIWt_ydgD2g/BCCuu25TREOitQxM7eYOEw.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/63/v3/qbe6NZkCQyGcITvdWoZBgg/Y-5U1z3GT_yaK8CBD3jkwg.jpg",
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/16/v3/fm2tO4TsRH6mv_D_nSSd5w/FscLpLwQQ-KuV7oaprFK2Q.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/89/v3/UAUvtPHqRD-GWWANsEC57Q/zcRJCQebQ322Aby4jzmwmQ.jpg",
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/30/v3/tUUzzx73R4yp8G--lMhuWQ/EBbcu_dLTT-Jj68XAh6mtA.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/76/v3/EyF6z4FISpCHhae38eEexw/OtyAiu-zSSevNQYvUdtVmA.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/37/v3/12rH1yiEQmK9wlOOcy5avQ/RzBXiEBRRqOC7LRkwNj6VA.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/9a/v3/TpRN4AIzRoyUXIqWdKoE0g/ShOnD_tfS46HDbpSWhbCkQ.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/03/v3/H3X17s8eTdS2w56JgbB5jQ/a45sT-j8Sbe8sSQXTzeYvQ.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/10/v3/qaEzwkU0QeKb1yehnP2Xig/q7fxAlgMQKup-HUBayRLGQ.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/96/v3/rMJJoAflTDSWa1z2pHs2wg/8dOqD0GlQBOCL5AvQok9FQ.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ed/v3/KMO4D6D2QGuVOCLX4AhOFA/ef51xAaLQuK7BsnuD9abog.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg", "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/d9/v3/FSZH0aTdSqWxeAaxoPvi0g/RqxPxUCXQFiTMBfKTF9kkw.jpg",
"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB", "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
'https://img-blog.csdnimg.cn/20191215043500229.png', 'https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/bf/v3/lSjrRwFcS-ez6jp1ALSQFg/0n7R7XinSPyrYLqDu_1dfw.jpg',
'https://img-blog.csdn.net/20140514114029140', 'https://img-blog.csdn.net/20140514114029140',
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
] ]

View File

@ -32,9 +32,9 @@ struct DataShareUriLoadPage {
build() { build() {
Scroll() { Scroll() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text("获取媒体图库的uri用ImageKnife展示").fontSize(15) Text($r('app.string.Retrieve_media_gallery')).fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("点击加载Uri并展示") Button($r('app.string.Click_load_Uri'))
.onClick(async () => { .onClick(async () => {
let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions(); let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { statfs } from '@kit.CoreFileKit'
import { rcp } from '@kit.RemoteCommunicationKit'
export class CommonDataSource <T> implements IDataSource {
private dataArray: T[] = []
private listeners: DataChangeListener[] = []
constructor(element: []) {
this.dataArray = element
}
public getData(index: number) {
return this.dataArray[index]
}
public totalCount(): number {
return this.dataArray.length
}
public addData(index: number, data: T[]): void {
this.dataArray = this.dataArray.concat(data)
this.notifyDataAdd(index)
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
this.listeners.splice(pos, 1);
}
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
this.listeners.push(listener)
}
}
notifyDataAdd(index: number): void {
this.listeners.forEach((listener: DataChangeListener) => {
listener.onDataAdd(index)
})
}
}
export class GetSession {
static session:rcp.Session = rcp.createSession()
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {ImageKnife, ImageKnifeRequest} from "@ohos/libraryimageknife"
import { IDataSourcePrefetching } from '@kit.ArkUI';
import { HashMap } from '@kit.ArkTS';
const IMADE_UNAVAILABLE = $r('app.media.failed')
export interface InfoItem {
albumUrl: string | Resource
}
export default class DataSourcePrefetchingImageKnife implements IDataSourcePrefetching {
private dataArray: Array<InfoItem>
private readonly requestList: HashMap<number,ImageKnifeRequest> = new HashMap()
private listeners: DataChangeListener[] = [];
constructor(dataArray: Array<InfoItem>) {
this.dataArray = dataArray;
}
public getData(index: number) {
return this.dataArray[index]
}
public totalCount(): number {
return this.dataArray.length
}
public addData(index: number, data: InfoItem[]): void {
this.dataArray = this.dataArray.concat(data)
this.notifyDataAdd(index)
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
this.listeners.splice(pos, 1);
}
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
this.listeners.push(listener)
}
}
notifyDataAdd(index: number): void {
this.listeners.forEach((listener: DataChangeListener) => {
listener.onDataAdd(index)
})
}
async prefetch(index: number): Promise<void> {
let item = this.dataArray[index]
if (typeof item.albumUrl == "string") {
// 图片预加载
let request = ImageKnife.getInstance().preload({
loadSrc:item.albumUrl,
onLoadListener:{
onLoadSuccess:()=>{
// 预加载成功,删除成功请求
this.requestList.remove(index)
},
onLoadFailed:()=>{
// 移除失败请求
this.requestList.remove(index)
}
}
})
this.requestList.set(index,request)
}
}
// 取消请求处理
cancel(index: number) {
if(this.requestList.hasKey(index)) {
// 返回MAP对象指定元素
const request = this.requestList.get(index)
// 取消请求
ImageKnife.getInstance().cancel(request)
// 移除被取消的请求对象
this.requestList.remove(index)
}
}
}

View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InfoItem } from './DataSourcePrefetching'
export class PageViewModel {
private static dataArray: Array<InfoItem> = [
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e2/v3/4zI1Xm_3STmV30aZXWRrKw/6aN7WodDRUiBApgffiLPCg.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/42/v3/2dSQCqERTP2TTPyssOMEbQ/zL1ebnKKQ_ilqTDcwCAkOw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/78/v3/qQJpAtRGQe2e_VhbGHDgIw/b3zlit99S6GybD3XdNwqJw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/55/v3/5DZ2LLqYSsK85-shqgLveQ/7ZXcyCWNTvOzQP5FFLBGkg.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3e/v3/LqRoLI-PRSu9Nqa8KdJ-pQ/dSqskBpSR9eraAMn7NBdqA.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/25/v3/jgB2ekkTRX-3yTYZalnANQ/xff_x9cbSPqb7fbNwgJa7A.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fb/v3/alXwXLHKSyCAIWt_ydgD2g/BCCuu25TREOitQxM7eYOEw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/63/v3/qbe6NZkCQyGcITvdWoZBgg/Y-5U1z3GT_yaK8CBD3jkwg.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/16/v3/fm2tO4TsRH6mv_D_nSSd5w/FscLpLwQQ-KuV7oaprFK2Q.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/89/v3/UAUvtPHqRD-GWWANsEC57Q/zcRJCQebQ322Aby4jzmwmQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/30/v3/tUUzzx73R4yp8G--lMhuWQ/EBbcu_dLTT-Jj68XAh6mtA.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/76/v3/EyF6z4FISpCHhae38eEexw/OtyAiu-zSSevNQYvUdtVmA.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/37/v3/12rH1yiEQmK9wlOOcy5avQ/RzBXiEBRRqOC7LRkwNj6VA.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/9a/v3/TpRN4AIzRoyUXIqWdKoE0g/ShOnD_tfS46HDbpSWhbCkQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/03/v3/H3X17s8eTdS2w56JgbB5jQ/a45sT-j8Sbe8sSQXTzeYvQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/10/v3/qaEzwkU0QeKb1yehnP2Xig/q7fxAlgMQKup-HUBayRLGQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/96/v3/rMJJoAflTDSWa1z2pHs2wg/8dOqD0GlQBOCL5AvQok9FQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ed/v3/KMO4D6D2QGuVOCLX4AhOFA/ef51xAaLQuK7BsnuD9abog.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/d9/v3/FSZH0aTdSqWxeAaxoPvi0g/RqxPxUCXQFiTMBfKTF9kkw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/bf/v3/lSjrRwFcS-ez6jp1ALSQFg/0n7R7XinSPyrYLqDu_1dfw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/8a/v3/ZKzYV5BJTuCk5hCE0y_xNA/8JT95OQnSZSd6_xQQUONhQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/1/v3/sTXb_I7URBKjdMyLDYa19w/qpcwa_FNQmi3-EzjbGsJ8A.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e5/v3/m7wFvw_eQIuDV0Mk0IKi8g/gJU4migzTHKYk5KrgdZbBw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/3f/v3/k_UWbB5_RGW7JemQZ0OQdw/_DUdmaZRQyG-Oyvkb663Bw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/39/v3/rFRN7G_VSo-p4mBjTZtkRw/gBwTI-ieSIqSsSmLNBEcgw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/04/v3/6K8BPYKVQFOr7KCuAG9nog/qKd3pZlrQy2M-feB3ycVPA.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/7d/v3/f0GQFzm1T6eduVeMUhO3Wg/-4cvzIJiRCegjIno3ofIbQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e4/v3/C0xxsSeySxW-2iYR5OEbpQ/f1GlaD3zTeKPX8Vd-M1oVQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/c2/v3/32LCyXN4TuWKWcdf9gAwWw/ej14_BCJQNCaWOKoI9aZAw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fd/v3/LyYJMdMmQNaC5GyBYEZ5Pw/uFLiovypRSagKyIS-UJPVw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/15/v3/MHM9KaWGTgubn6M8-B_6nw/1YO9JyYhTHSBWsoiqYkGZw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/4c/v3/UdYfbv1_QYqn_ulDHp89OA/VkjexMluTqGO3yt3gPK1DA.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/e8/v3/N8blT_7qSK-tRtahIyov7g/M_kjGEEmSzOlTc47Zrfozg.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/28/v3/VS_h3m4YRrSgbgxnqE3vtQ/h-2Q1Qy2SSGEuXM36-Rq_w.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/2e/v3/R-BaM5ToRNGq5rwtNTcnww/Q2e01VHiR2y9KtFaZmpmNQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/88/v3/3djkAJKKTdC539XqMdstSg/wHO7DxvXQS2xbt2Y_-4BNg.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/fb/v3/guw4eiggR3uWjscFTxITYg/TzRB35iPTdCztrZUUaNuFg.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/93/v3/UvSh_f1LT66i0-3hvsYN_A/eYnE3Z8YT5Sk7F-vS2ZmCQ.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/5/v3/tv8Vqf9hQrKpozGeZWg2mw/VEICB-bmQYi0Iv6TGADbhw.jpg"
},
{
albumUrl: "https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/30/v3/4v1Ot5BRR6OFVQ9MGn9Xxg/xrPgRn0LS1ep-r7ewIuwiw.jpg"
},
]
static getItems() {
return PageViewModel.dataArray
}
}

View File

@ -43,6 +43,15 @@
], ],
"when": "always" "when": "always"
} }
},
{
"name": "ohos.permission.GET_NETWORK_INFO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "always"
}
} }
] ]
} }

View File

@ -19,6 +19,618 @@
{ {
"name": "app_permission_READ_IMAGEVIDEO", "name": "app_permission_READ_IMAGEVIDEO",
"value": "获取读媒体资源权限" "value": "获取读媒体资源权限"
},
{
"name": "Test_ImageAnimator",
"value": "Test ImageAnimator component"
},
{
"name": "Test_multiple_images",
"value": "Test loading multiple identical images"
},
{
"name": "Test_Task_error",
"value": "Test placeholder map Task error"
},
{
"name": "Test_HSP",
"value": "Test HSP scene preloading"
},
{
"name": "Test_SingleImage",
"value": "SingleImage"
},
{
"name": "Test_custom_download",
"value": "Global custom download"
},
{
"name": "Multiple_images",
"value": "Multiple images"
},
{
"name": "Display_long_image",
"value": "Display long image"
},
{
"name": "Image_scaling",
"value": "Image scaling"
},
{
"name": "Message_list",
"value": "Message list"
},
{
"name": "Custom_cache_key",
"value": "Custom cache key"
},
{
"name": "Preloading_images_to_cache",
"value": "Preloading images to file cache"
},
{
"name": "Retrieve_image_display_from_cache",
"value": "Retrieve image display from cache"
},
{
"name": "Test_single_request_header",
"value": "Test a single request header"
},
{
"name": "Test_write_cache_strategy",
"value": "Test write cache strategy"
},
{
"name": "Image_Transformation",
"value": "Image Transformation"
},
{
"name": "Different_ObjectFit",
"value": "Different ObjectFit"
},
{
"name": "Test_image_loading_success_or_failure_events",
"value": "Test image loading success/failure events"
},
{
"name": "Test_removing_image_cache_interface",
"value": "Test removing image cache interface"
},
{
"name": "Test_error_image_display",
"value": "Test error image display"
},
{
"name": "Test_media_URL",
"value": "Test media URL"
},
{
"name": "Display_the_first_frame",
"value": "Display the first frame of the animation"
},
{
"name": "Display_the_last_frame",
"value": "Display the last frame of the animation"
},
{
"name": "Play",
"value": "Play"
},
{
"name": "Pause",
"value": "Pause"
},
{
"name": "Stop",
"value": "Stop"
},
{
"name": "Infinite_loop",
"value": "Infinite loop"
},
{
"name": "Play_once",
"value": "Play once"
},
{
"name": "Play_twice",
"value": "Play twice"
},
{
"name": "Local_SVG",
"value": "Local SVG image"
},
{
"name": "Under_context_file",
"value": "Files under context file"
},
{
"name": "Network_images",
"value": "Network images"
},
{
"name": "Custom_network_download",
"value": "Custom network download"
},
{
"name": "PixelMap_loads_images",
"value": "PixelMap loads images"
},
{
"name": "Enlarge",
"value": "Enlarge"
},
{
"name": "Reduce",
"value": "Reduce"
},
{
"name": "Click_on_add",
"value": "Click on the size to add 50"
},
{
"name": "Click_on_reduce",
"value": "Click to reduce size by 50"
},
{
"name": "The_key_fixed_1",
"value": "The key is fixed at 1"
},
{
"name": "The_key_changes_timestamp",
"value": "Key changes every time: timestamp"
},
{
"name": "Load",
"value": "Load"
},
{
"name": "Preloading_images_to_file_cache_using_URL",
"value": "Preloading images to file cache using URL"
},
{
"name": "Preloading_images_to_file_cache_using_option",
"value": "Preloading images to file cache using option"
},
{
"name": "Load_image_offline_after_preloading",
"value": "Load image (can be loaded offline after preloading)"
},
{
"name": "Preloading_GIF",
"value": "Preloading GIF"
},
{
"name": "Retrieve_GIF_from_memory",
"value": "Retrieve GIF from memory cache"
},
{
"name": "Retrieve_GIF_from_disk",
"value": "Retrieve GIF from disk cache"
},
{
"name": "Preloading_static_images",
"value": "Preloading static images"
},
{
"name": "Retrieve_images_from_memory",
"value": "Retrieve images from memory cache"
},
{
"name": "Retrieve_images_from_disk",
"value": "Retrieve images from memory disk"
},
{
"name": "Write_memory_and_file",
"value": "Write to memory and file cache"
},
{
"name": "Write_memory",
"value": "Write to memory cache"
},
{
"name": "Write_file",
"value": "Write to file cache"
},
{
"name": "Main_image_Fill",
"value": "Main image Fill Stretch Fill"
},
{
"name": "Maintain_proportion_filling",
"value": "Maintain proportion filling in the placeholder map 'Include'"
},
{
"name": "Error_graph_None",
"value": "Error graph None remains unchanged"
},
{
"name": "Test_failure_success",
"value": "Test failure/success"
},
{
"name": "Custom_download_failed",
"value": "Custom download failed"
},
{
"name": "Retrieve_media_gallery",
"value": "Retrieve the URI of the media gallery and display it using ImageKnife"
},
{
"name": "Click_load_Uri",
"value": "Click to load Uri and display"
},
{
"name": "Delete_all_caches",
"value": "Delete all caches"
},
{
"name": "Delete_all_memory_caches",
"value": "Delete all memory caches"
},
{
"name": "Delete_all_file_caches",
"value": "Delete all file caches"
},
{
"name": "Delete_all_custom_memory_caches",
"value": "Delete all custom memory caches"
},
{
"name": "Delete_all_custom_file_caches",
"value": "Delete all custom file caches"
},
{
"name": "Blur_effect",
"value": "Blur effect"
},
{
"name": "Highlighting_effect",
"value": "Highlighting effect"
},
{
"name": "Ashing_effect",
"value": "Ashing effect"
},
{
"name": "Inverse_effect",
"value": "Inverse effect"
},
{
"name": "Animation_filter_effect",
"value": "Animation filter effect"
},
{
"name": "Crop_circular_effect",
"value": "Crop circular effect"
},
{
"name": "Crop_circular_with_border_effect",
"value": "Crop circular with border effect"
},
{
"name": "Contrast_effect",
"value": "Contrast effect"
},
{
"name": "Black_ink_filtering_effect",
"value": "Black ink filtering effect"
},
{
"name": "Rotate",
"value": "Rotate"
},
{
"name": "Corners",
"value": "Corners"
},
{
"name": "Kuwahara_Filter_effect",
"value": "Kuwahara filter effect"
},
{
"name": "Pixelated_Filter_effect",
"value": "Pixelated filtering effect"
},
{
"name": "Sketch_Filter_effect",
"value": "Sketch Filter effect"
},
{
"name": "Distortion_Filter_effect",
"value": "Distortion Filter effect"
},
{
"name": "Decorative_Filter_effect",
"value": "Decorative Filter effect"
},
{
"name": "Square_cutting_effect",
"value": "Square cutting effect"
},
{
"name": "Top_cutting_effect",
"value": "Top cutting effect"
},
{
"name": "Middle_cutting_effect",
"value": "Middle cutting effect"
},
{
"name": "Bottom_cutting_effect",
"value": "Bottom cutting effect"
},
{
"name": "Mask_effect",
"value": "Mask effect"
},
{
"name": "TIPS",
"value": "Please shut down the network first and ensure that there is no cache of images from this network in the test failure scenario locally"
},
{
"name": "Network_reload",
"value": "Network recovery reload"
},
{
"name": "preloading_prefetch",
"value": "Dynamic preloading prefetch"
},
{
"name": "image_format",
"value": "picture format%s"
},
{
"name": "image_width",
"value": "image width%d"
},
{
"name": "image_height",
"value": "image height%d"
},
{
"name": "cur_cache_limit",
"value": "%s:current cache limit%fM"
},
{
"name": "cur_cache_image_num",
"value": "%s:current cache image number%d"
},
{
"name": "cur_cache_size",
"value": "%s:current cache size%fM"
},
{
"name": "load_memory",
"value": "memory loaded picture"
},
{
"name": "load_disk",
"value": "disk cache loads images"
},
{
"name": "get_cur_memory_limit",
"value": "gets the current memory cache upper limit"
},
{
"name": "get_img_number_of_cache",
"value": "gets the number of images cached in memory"
},
{
"name": "get_cur_memory_size",
"value": "gets the size of the current cache"
},
{
"name": "get_cur_disk_limit",
"value": "Gets the current disk cache upper limit"
},
{
"name": "get_img_number_of_disk",
"value": "gets the number of images cached on disk"
},
{
"name": "get_cur_disk_size",
"value": "gets the size of the current disk"
},
{
"name": "select_color_btn",
"value": "click to select the color you want to change"
},
{
"name": "click_img_to_change_color",
"value": "click on the image to change the image color"
},
{
"name": "test_non_svg_color",
"value": "test non-SVG images for color change"
},
{
"name": "test_svg_color",
"value": "Test svg picture color change"
},
{
"name": "red",
"value": "red"
},
{
"name": "yellow",
"value": "yellow"
},
{
"name": "green",
"value": "green"
},
{
"name": "blue",
"value": "blue"
},
{
"name": "master_image",
"value": "master image:"
},
{
"name": "rm_component_of_net",
"value": "remove Component - Network load picture"
},
{
"name": "rm_component_of_local",
"value": "remove Component - Local resource picture"
},
{
"name": "component_display",
"value": "recovery component display"
},
{
"name": "onLoadCancel_reason",
"value": "onLoadCancel callback reason:%s"
},
{
"name": "test_cache_btn",
"value": "test data for in cache"
},
{
"name": "test_change_color_btn",
"value": "test change color for image"
},
{
"name": "test_cancel_callback_btn",
"value": "test callback of cancel"
},
{
"name": "memory",
"value": "Memory"
},
{
"name": "disk",
"value": "Disk"
},
{
"name": "Customize_RCP_network",
"value": "Customize RCP network request"
},
{
"name": "request_concurrency",
"value": "Set request concurrency"
},
{
"name": "test_callback",
"value": "test callback data of load pic"
},
{
"name": "gif",
"value": "gif"
},
{
"name": "local_pic",
"value": "local picture"
},
{
"name": "share_pic",
"value": "share picture"
},
{
"name": "net_load_failed",
"value": "netWork load failed"
},
{
"name": "local_load_failed",
"value": "local load failed"
},
{
"name": "share_load_failed",
"value": "shared load failed"
},
{
"name": "list_pic",
"value": "load picture list"
},
{
"name": "img_url",
"value": "url of the service setting:%s"
},
{
"name": "img_format",
"value": "picture format:%s"
},
{
"name": "img_master_size",
"value": "the original width and height of the picture-w%d ,h%d, size%d"
},
{
"name": "componentWH",
"value": "component width and height-w%d ,h%d "
},
{
"name": "img_frame",
"value": "the number of frames of the picture:%d "
},
{
"name": "img_content_size",
"value": "picture decoded width and height size:%s "
},
{
"name": "err_msg",
"value": "error message:%s "
},
{
"name": "err_phase",
"value": "error phase:%s "
},
{
"name": "err_code",
"value": "error code:%d "
},
{
"name": "http_code",
"value": "http code:%d "
},
{
"name": "req_start_time",
"value": "image request start time point:%s "
},
{
"name": "req_end_time",
"value": "the point in time at which the image request ends:%s "
},
{
"name": "req_cancel_time",
"value": "the point at which the image request is cancelled:%s "
},
{
"name": "memory_start_time",
"value": "start checking the memory cache point in time:%s "
},
{
"name": "memory_end_time",
"value": "end Check the memory cache time point:%s "
},
{
"name": "disk_start_time",
"value": "start checking the disk cache point in time:%s "
},
{
"name": "disk_end_time",
"value": "end Check the disk cache time point:%s "
},
{
"name": "net_start_time",
"value": "start time of the network request:%s "
},
{
"name": "net_end_time",
"value": "end time of the network request:%s:%s "
},
{
"name": "decode_start_time",
"value": "decoding start time point:%s "
},
{
"name": "decode_end_time",
"value": "decoding end time point:%s "
},
{
"name": "render_time",
"value": "render successful time:%s "
} }
] ]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>svg细图标</title>
<g id="细图标" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="dot_radiowaves_left_and_right" fill="#000000" fill-rule="nonzero">
<rect id="矩形" opacity="0" x="0" y="0" width="24" height="24"></rect>
<g id="编组" transform="translate(0.000000, 3.000000)" fill-opacity="0.90196079">
<path d="M12,7.01 C11.44,7.01 10.9633333,7.20666667 10.57,7.6 C10.1766667,7.98666667 9.98,8.45333333 9.98,9 C9.98,9.54666667 10.18,10.02 10.58,10.42 C10.98,10.82 11.4533333,11.02 12,11.02 C12.5466667,11.02 13.0133333,10.8233333 13.4,10.43 C13.7933333,10.0366667 13.99,9.56 13.99,9 C13.99,8.44 13.8,7.96666667 13.42,7.58 C13.0333333,7.2 12.56,7.01 12,7.01 Z" id="路径"></path>
<path d="M5.23,9 C5.23,10.1533333 5.50666667,11.2333333 6.06,12.24 C6.61333333,13.2466667 7.37666667,14.0633333 8.35,14.69 C8.53,14.8033333 8.72,14.8333333 8.92,14.78 C9.12,14.7333333 9.27333333,14.6233333 9.38,14.45 C9.49333333,14.27 9.52666667,14.08 9.48,13.88 C9.43333333,13.68 9.33,13.5266667 9.17,13.42 C8.41666667,12.92 7.82333333,12.2833333 7.39,11.51 C6.95666667,10.73 6.74,9.89333333 6.74,9 C6.74,8.10666667 6.95333333,7.26666667 7.38,6.48 C7.80666667,5.69333333 8.40333333,5.05333333 9.17,4.56 C9.34333333,4.44666667 9.45,4.29 9.49,4.09 C9.53,3.89 9.49333333,3.70333333 9.38,3.53 C9.27333333,3.35 9.12,3.23666667 8.92,3.19 C8.72,3.14333333 8.53,3.18333333 8.35,3.31 C7.37666667,3.93666667 6.61333333,4.75 6.06,5.75 C5.50666667,6.75 5.23,7.83333333 5.23,9 Z M14.59,14.45 C14.7033333,14.6233333 14.8533333,14.7333333 15.04,14.78 C15.22,14.8333333 15.4233333,14.8033333 15.65,14.69 C16.29,14.27 16.84,13.7666667 17.3,13.18 C17.7666667,12.5866667 18.1233333,11.9333333 18.37,11.22 C18.6166667,10.5066667 18.74,9.76666667 18.74,9 C18.74,7.83333333 18.47,6.75 17.93,5.75 C17.3833333,4.75 16.6233333,3.93666667 15.65,3.31 C15.47,3.18333333 15.2766667,3.14333333 15.07,3.19 C14.8633333,3.23666667 14.7033333,3.35 14.59,3.53 C14.4766667,3.70333333 14.44,3.88666667 14.48,4.08 C14.52,4.27333333 14.63,4.42666667 14.81,4.54 L14.83,4.56 C15.5833333,5.05333333 16.1766667,5.69333333 16.61,6.48 C17.0433333,7.26666667 17.26,8.10666667 17.26,9 C17.26,9.59333333 17.1633333,10.1666667 16.97,10.72 C16.7766667,11.2666667 16.4966667,11.7733333 16.13,12.24 C15.7633333,12.7066667 15.33,13.1 14.83,13.42 C14.6566667,13.5266667 14.5466667,13.68 14.5,13.88 C14.4466667,14.08 14.4766667,14.27 14.59,14.45 Z" id="形状"></path>
<path d="M0.77,9 C0.77,10.6666667 1.12,12.2466667 1.82,13.74 C2.52666667,15.2333333 3.51333333,16.5166667 4.78,17.59 C4.94,17.7166667 5.12,17.7733333 5.32,17.76 C5.52,17.7466667 5.69,17.6666667 5.83,17.52 C5.95666667,17.36 6.01333333,17.1766667 6,16.97 C5.98666667,16.7633333 5.9,16.5866667 5.74,16.44 C4.63333333,15.5133333 3.77666667,14.4 3.17,13.1 C2.56333333,11.8066667 2.26,10.44 2.26,9 C2.26,7.56 2.56333333,6.18666667 3.17,4.88 C3.77666667,3.58 4.64,2.46666667 5.76,1.54 C5.90666667,1.39333333 5.99,1.21666667 6.01,1.01 C6.03666667,0.803333333 5.97666667,0.626666667 5.83,0.48 C5.70333333,0.32 5.53666667,0.233333333 5.33,0.22 C5.12333333,0.2 4.94,0.253333333 4.78,0.38 C3.51333333,1.45333333 2.52666667,2.74333333 1.82,4.25 C1.12,5.75 0.77,7.33333333 0.77,9 Z M18.17,17.5 C18.2966667,17.66 18.4633333,17.7466667 18.67,17.76 C18.8766667,17.7733333 19.06,17.7166667 19.22,17.59 C20.0733333,16.89 20.8,16.0833333 21.4,15.17 C22,14.2566667 22.4533333,13.2766667 22.76,12.23 C23.0733333,11.1833333 23.23,10.1066667 23.23,9 C23.23,7.89333333 23.0733333,6.81666667 22.76,5.77 C22.4533333,4.72333333 22,3.74 21.4,2.82 C20.8,1.9 20.0733333,1.08666667 19.22,0.38 C19.06,0.253333333 18.8766667,0.2 18.67,0.22 C18.4633333,0.233333333 18.2966667,0.32 18.17,0.48 C18.0233333,0.64 17.96,0.823333333 17.98,1.03 C17.9933333,1.23666667 18.08,1.40666667 18.24,1.54 C18.9733333,2.14666667 19.6,2.85 20.12,3.65 C20.64,4.45 21.0366667,5.3 21.31,6.2 C21.5833333,7.10666667 21.72,8.04 21.72,9 C21.72,9.96 21.5833333,10.8933333 21.31,11.8 C21.0366667,12.7 20.6466667,13.5466667 20.14,14.34 C19.6266667,15.1333333 19,15.8333333 18.26,16.44 C18.1,16.5666667 18.0133333,16.7333333 18,16.94 C17.9866667,17.1533333 18.0433333,17.34 18.17,17.5 Z" id="形状"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 KiB

Binary file not shown.

View File

@ -22,6 +22,22 @@
"pages/TestCommonImage", "pages/TestCommonImage",
"pages/ImageAnimatorPage", "pages/ImageAnimatorPage",
"pages/TestSetCustomImagePage", "pages/TestSetCustomImagePage",
"pages/TestErrorHolderPage" "pages/TestErrorHolderPage",
"pages/TestTaskResourcePage",
"pages/ImageKnifeReload",
"pages/LazyForEachCount",
"pages/LazyForEachCache",
"pages/PrefetchAndCacheCount",
"pages/PrefetchAndPreload",
"pages/TestCacheDataPage",
"pages/TestChangeColorPage",
"pages/TestLoadCancelListenerPage",
"pages/CustomNetImagePage",
"pages/SetMaxRequestPage",
"pages/MaxRequest1",
"pages/MaxRequest2",
"pages/MaxRequest3",
"pages/TestImageKnifeCallbackPage",
"pages/TestListImageKnifeCallbackPage"
] ]
} }

View File

@ -19,6 +19,362 @@
{ {
"name": "app_permission_READ_IMAGEVIDEO", "name": "app_permission_READ_IMAGEVIDEO",
"value": "获取读媒体资源权限" "value": "获取读媒体资源权限"
},
{
"name": "Test_ImageAnimator",
"value": "Test ImageAnimator component"
},
{
"name": "Test_multiple_images",
"value": "Test loading multiple identical images"
},
{
"name": "Test_Task_error",
"value": "Test placeholder map Task error"
},
{
"name": "Test_HSP",
"value": "Test HSP scene preloading"
},
{
"name": "Test_SingleImage",
"value": "SingleImage"
},
{
"name": "Test_custom_download",
"value": "Global custom download"
},
{
"name": "Multiple_images",
"value": "Multiple images"
},
{
"name": "Display_long_image",
"value": "Display long image"
},
{
"name": "Image_scaling",
"value": "Image scaling"
},
{
"name": "Message_list",
"value": "Message list"
},
{
"name": "Custom_cache_key",
"value": "Custom cache key"
},
{
"name": "Preloading_images_to_cache",
"value": "Preloading images to file cache"
},
{
"name": "Retrieve_image_display_from_cache",
"value": "Retrieve image display from cache"
},
{
"name": "Test_single_request_header",
"value": "Test a single request header"
},
{
"name": "Test_write_cache_strategy",
"value": "Test write cache strategy"
},
{
"name": "Image_Transformation",
"value": "Image Transformation"
},
{
"name": "Different_ObjectFit",
"value": "Different ObjectFit"
},
{
"name": "Test_image_loading_success_or_failure_events",
"value": "Test image loading success/failure events"
},
{
"name": "Test_removing_image_cache_interface",
"value": "Test removing image cache interface"
},
{
"name": "Test_error_image_display",
"value": "Test error image display"
},
{
"name": "Test_media_URL",
"value": "Test media URL"
},
{
"name": "Display_the_first_frame",
"value": "Display the first frame of the animation"
},
{
"name": "Display_the_last_frame",
"value": "Display the last frame of the animation"
},
{
"name": "Play",
"value": "Play"
},
{
"name": "Pause",
"value": "Pause"
},
{
"name": "Stop",
"value": "Stop"
},
{
"name": "Infinite_loop",
"value": "Infinite loop"
},
{
"name": "Play_once",
"value": "Play once"
},
{
"name": "Play_twice",
"value": "Play twice"
},
{
"name": "Local_SVG",
"value": "Local SVG image"
},
{
"name": "Under_context_file",
"value": "Files under context file"
},
{
"name": "Network_images",
"value": "Network images"
},
{
"name": "Custom_network_download",
"value": "Custom network download"
},
{
"name": "PixelMap_loads_images",
"value": "PixelMap loads images"
},
{
"name": "Enlarge",
"value": "Enlarge"
},
{
"name": "Reduce",
"value": "Reduce"
},
{
"name": "Click_on_add",
"value": "Click on the size to add 50"
},
{
"name": "Click_on_reduce",
"value": "Click to reduce size by 50"
},
{
"name": "The_key_fixed_1",
"value": "The key is fixed at 1"
},
{
"name": "The_key_changes_timestamp",
"value": "Key changes every time: timestamp"
},
{
"name": "Load",
"value": "Load"
},
{
"name": "Preloading_images_to_file_cache_using_URL",
"value": "Preloading images to file cache using URL"
},
{
"name": "Preloading_images_to_file_cache_using_option",
"value": "Preloading images to file cache using option"
},
{
"name": "Load_image_offline_after_preloading",
"value": "Load image (can be loaded offline after preloading)"
},
{
"name": "Preloading_GIF",
"value": "Preloading GIF"
},
{
"name": "Retrieve_GIF_from_memory",
"value": "Retrieve GIF from memory cache"
},
{
"name": "Retrieve_GIF_from_disk",
"value": "Retrieve GIF from disk cache"
},
{
"name": "Preloading_static_images",
"value": "Preloading static images"
},
{
"name": "Retrieve_images_from_memory",
"value": "Retrieve images from memory cache"
},
{
"name": "Retrieve_images_from_disk",
"value": "Retrieve images from memory disk"
},
{
"name": "Write_memory_and_file",
"value": "Write to memory and file cache"
},
{
"name": "Write_memory",
"value": "Write to memory cache"
},
{
"name": "Write_file",
"value": "Write to file cache"
},
{
"name": "Main_image_Fill",
"value": "Main image Fill Stretch Fill"
},
{
"name": "Maintain_proportion_filling",
"value": "Maintain proportion filling in the placeholder map 'Include'"
},
{
"name": "Error_graph_None",
"value": "Error graph None remains unchanged"
},
{
"name": "Test_failure_success",
"value": "Test failure/success"
},
{
"name": "Custom_download_failed",
"value": "Custom download failed"
},
{
"name": "Retrieve_media_gallery",
"value": "Retrieve the URI of the media gallery and display it using ImageKnife"
},
{
"name": "Click_load_Uri",
"value": "Click to load Uri and display"
},
{
"name": "Delete_all_caches",
"value": "Delete all caches"
},
{
"name": "Delete_all_memory_caches",
"value": "Delete all memory caches"
},
{
"name": "Delete_all_file_caches",
"value": "Delete all file caches"
},
{
"name": "Delete_all_custom_memory_caches",
"value": "Delete all custom memory caches"
},
{
"name": "Delete_all_custom_file_caches",
"value": "Delete all custom file caches"
},
{
"name": "Blur_effect",
"value": "Blur effect"
},
{
"name": "Highlighting_effect",
"value": "Highlighting effect"
},
{
"name": "Ashing_effect",
"value": "Ashing effect"
},
{
"name": "Inverse_effect",
"value": "Inverse effect"
},
{
"name": "Animation_filter_effect",
"value": "Animation filter effect"
},
{
"name": "Crop_circular_effect",
"value": "Crop circular effect"
},
{
"name": "Crop_circular_with_border_effect",
"value": "Crop circular with border effect"
},
{
"name": "Contrast_effect",
"value": "Contrast effect"
},
{
"name": "Black_ink_filtering_effect",
"value": "Black ink filtering effect"
},
{
"name": "Rotate",
"value": "Rotate"
},
{
"name": "Corners",
"value": "Corners"
},
{
"name": "Kuwahara_Filter_effect",
"value": "Kuwahara filter effect"
},
{
"name": "Pixelated_Filter_effect",
"value": "Pixelated filtering effect"
},
{
"name": "Sketch_Filter_effect",
"value": "Sketch Filter effect"
},
{
"name": "Distortion_Filter_effect",
"value": "Distortion Filter effect"
},
{
"name": "Decorative_Filter_effect",
"value": "Decorative Filter effect"
},
{
"name": "Square_cutting_effect",
"value": "Square cutting effect"
},
{
"name": "Top_cutting_effect",
"value": "Top cutting effect"
},
{
"name": "Middle_cutting_effect",
"value": "Middle cutting effect"
},
{
"name": "Bottom_cutting_effect",
"value": "Bottom cutting effect"
},
{
"name": "Mask_effect",
"value": "Mask effect"
},
{
"name": "TIPS",
"value": "Please shut down the network first and ensure that there is no cache of images from this network in the test failure scenario locally"
},
{
"name": "Network_reload",
"value": "Network recovery reload"
},
{
"name": "preloading_prefetch",
"value": "Dynamic preloading prefetch"
} }
] ]
} }

View File

@ -19,6 +19,614 @@
{ {
"name": "app_permission_READ_IMAGEVIDEO", "name": "app_permission_READ_IMAGEVIDEO",
"value": "获取读媒体资源权限" "value": "获取读媒体资源权限"
},
{
"name": "Test_ImageAnimator",
"value": "测试ImageAnimator组件"
},
{
"name": "Test_multiple_images",
"value": "测试加载多张相同图片"
},
{
"name": "Test_Task_error",
"value": "测试占位图Task报错"
},
{
"name": "Test_HSP",
"value": "测试HSP场景预加载"
},
{
"name": "Test_SingleImage",
"value": "单个图片使用"
},
{
"name": "Test_custom_download",
"value": "全局自定义下载"
},
{
"name": "Multiple_images",
"value": "多图"
},
{
"name": "Display_long_image",
"value": "长图显示"
},
{
"name": "Image_scaling",
"value": "缩放图片"
},
{
"name": "Message_list",
"value": "消息列表"
},
{
"name": "Custom_cache_key",
"value": "自定义缓存key"
},
{
"name": "Preloading_images_to_cache",
"value": "预加载图片到文件缓存"
},
{
"name": "Retrieve_image_display_from_cache",
"value": "从缓存获取图片显示"
},
{
"name": "Test_single_request_header",
"value": "测试单个请求头"
},
{
"name": "Test_write_cache_strategy",
"value": "测试写入缓存策略"
},
{
"name": "Image_Transformation",
"value": "图片变换"
},
{
"name": "Different_ObjectFit",
"value": "不同的ObjectFit"
},
{
"name": "Test_image_loading_success_or_failure_events",
"value": "测试图片加载成功/失败事件"
},
{
"name": "Test_removing_image_cache_interface",
"value": "测试移除图片缓存接口"
},
{
"name": "Test_error_image_display",
"value": "测试错误图显示"
},
{
"name": "Display_the_first_frame",
"value": "动画显示第一帧"
},
{
"name": "Display_the_last_frame",
"value": "动画显示最后一帧"
},
{
"name": "Play",
"value": "播放"
},
{
"name": "Pause",
"value": "暂停"
},
{
"name": "Stop",
"value": "停止"
},
{
"name": "Infinite_loop",
"value": "无限循环"
},
{
"name": "Play_once",
"value": "播放一次"
},
{
"name": "Play_twice",
"value": "播放两次"
},
{
"name": "Local_SVG",
"value": "本地资源SVG图片"
},
{
"name": "Under_context_file",
"value": "本地context files下文件"
},
{
"name": "Network_images",
"value": "网络图片"
},
{
"name": "Custom_network_download",
"value": "自定义下载"
},
{
"name": "PixelMap_loads_images",
"value": "PixelMap加载图片"
},
{
"name": "Enlarge",
"value": "放大"
},
{
"name": "Reduce",
"value": "缩小"
},
{
"name": "Click_on_add",
"value": "点击尺寸加50"
},
{
"name": "Click_on_reduce",
"value": "点击尺寸减50"
},
{
"name": "The_key_fixed_1",
"value": "key固定为 1"
},
{
"name": "The_key_changes_timestamp",
"value": "key每次变化时间戳"
},
{
"name": "Load",
"value": "加载"
},
{
"name": "Preloading_images_to_file_cache_using_URL",
"value": "url预加载图片到文件缓存"
},
{
"name": "Preloading_images_to_file_cache_using_option",
"value": "option预加载图片到文件缓存"
},
{
"name": "Load_image_offline_after_preloading",
"value": "加载图片(预加载后可断网加载)"
},
{
"name": "Preloading_GIF",
"value": "预加载gif图"
},
{
"name": "Retrieve_GIF_from_memory",
"value": "内存缓存获取gif"
},
{
"name": "Retrieve_GIF_from_disk",
"value": "文件缓存获取gif"
},
{
"name": "Preloading_static_images",
"value": "预加载静态图"
},
{
"name": "Retrieve_images_from_memory",
"value": "内存缓存获取"
},
{
"name": "Retrieve_images_from_disk",
"value": "文件缓存获取"
},
{
"name": "Write_memory_and_file",
"value": "写入内存文件缓存"
},
{
"name": "Write_memory",
"value": "写入内存缓存"
},
{
"name": "Write_file",
"value": "写入文件缓存"
},
{
"name": "Main_image_Fill",
"value": "主图Fill拉伸填充"
},
{
"name": "Maintain_proportion_filling",
"value": "占位图Contain保持比例填充"
},
{
"name": "Error_graph_None",
"value": "错误图None不变化"
},
{
"name": "Test_failure_success",
"value": "测试失败/成功场景"
},
{
"name": "Custom_download_failed",
"value": "自定义下载失败"
},
{
"name": "Retrieve_media_gallery",
"value": "获取媒体图库的uri用ImageKnife展示"
},
{
"name": "Click_load_Uri",
"value": "点击加载Uri并展示"
},
{
"name": "Delete_all_caches",
"value": "删除全部缓存"
},
{
"name": "Delete_all_memory_caches",
"value": "删除全部内存缓存"
},
{
"name": "Delete_all_file_caches",
"value": "删除全部文件缓存"
},
{
"name": "Delete_all_custom_memory_caches",
"value": "删除自定义内存缓存"
},
{
"name": "Delete_all_custom_file_caches",
"value": "删除自定义文件缓存"
},
{
"name": "Blur_effect",
"value": "模糊效果"
},
{
"name": "Highlighting_effect",
"value": "高亮效果"
},
{
"name": "Ashing_effect",
"value": "灰化效果"
},
{
"name": "Inverse_effect",
"value": "反转效果"
},
{
"name": "Animation_filter_effect",
"value": "动画滤镜效果"
},
{
"name": "Crop_circular_effect",
"value": "裁剪圆形效果"
},
{
"name": "Crop_circular_with_border_effect",
"value": "裁剪圆形带边框效果"
},
{
"name": "Contrast_effect",
"value": "对比度效果"
},
{
"name": "Black_ink_filtering_effect",
"value": "乌墨色滤波效果"
},
{
"name": "Rotate",
"value": "旋转效果"
},
{
"name": "Corners",
"value": "圆角效果"
},
{
"name": "Kuwahara_Filter_effect",
"value": "桑原滤波效果"
},
{
"name": "Pixelated_Filter_effect",
"value": "像素化滤波效果"
},
{
"name": "Sketch_Filter_effect",
"value": "素描滤波效果"
},
{
"name": "Distortion_Filter_effect",
"value": "扭曲滤波效果"
},
{
"name": "Decorative_Filter_effect",
"value": "装饰滤波效果"
},
{
"name": "Square_cutting_effect",
"value": "正方形裁剪效果"
},
{
"name": "Top_cutting_effect",
"value": "上方裁剪效果"
},
{
"name": "Middle_cutting_effect",
"value": "中间裁剪效果"
},
{
"name": "Bottom_cutting_effect",
"value": "底下裁剪效果"
},
{
"name": "Mask_effect",
"value": "遮罩效果"
},
{
"name": "TIPS",
"value": "测试失败场景请先关闭网络,并保证本地没有此网络图片的缓存"
},
{
"name": "Network_reload",
"value": "网络恢复reload"
},
{
"name": "preloading_prefetch",
"value": "动态预加载prefetch"
},
{
"name": "image_format",
"value": "图片格式:%s"
},
{
"name": "image_width",
"value": "图片宽度:%d"
},
{
"name": "image_height",
"value": "图片高度:%d"
},
{
"name": "cur_cache_limit",
"value": "%s:当前缓存上限:%fM"
},
{
"name": "cur_cache_image_num",
"value": "%s:当前缓存图片数量:%d"
},
{
"name": "cur_cache_size",
"value": "%s:当前缓存的大小:%fM"
},
{
"name": "load_memory",
"value": "内存加载图片"
},
{
"name": "load_disk",
"value": "磁盘缓存加载图片"
},
{
"name": "get_cur_memory_limit",
"value": "获取当前内存缓存上限"
},
{
"name": "get_img_number_of_cache",
"value": "获取当前内存缓存图片数量"
},
{
"name": "get_cur_memory_size",
"value": "获取当前缓存的大小"
},
{
"name": "get_cur_disk_limit",
"value": "获取当前磁盘缓存上限"
},
{
"name": "get_img_number_of_disk",
"value": "获取当前磁盘缓存图片数量"
},
{
"name": "get_cur_disk_size",
"value": "获取当前磁盘的大小"
},
{
"name": "select_color_btn",
"value": "点击选择要更改的颜色"
},
{
"name": "click_img_to_change_color",
"value": "点击图片更改图片颜色"
},
{
"name": "test_non_svg_color",
"value": "测试非svg图片变色"
},
{
"name": "test_svg_color",
"value": "测试svg图片变色"
},
{
"name": "red",
"value": "红色"
},
{
"name": "yellow",
"value": "黄色"
},
{
"name": "green",
"value": "绿色"
},
{
"name": "blue",
"value": "蓝色"
},
{
"name": "master_image",
"value": "原图:"
},
{
"name": "rm_component_of_net",
"value": "移除组件-网络加载图片"
},
{
"name": "rm_component_of_local",
"value": "移除组件-本地资源图片"
},
{
"name": "component_display",
"value": "恢复组件显示"
},
{
"name": "onLoadCancel_reason",
"value": "onLoadCancel回调原因:%s"
},
{
"name": "test_cache_btn",
"value": "测试缓存数据"
},
{
"name": "test_change_color_btn",
"value": "测试颜色变换"
},
{
"name": "test_cancel_callback_btn",
"value": "测试加载取消回调接口"
},
{
"name": "memory",
"value": "内存"
},
{
"name": "disk",
"value": "磁盘"
},
{
"name": "Customize_RCP_network",
"value": "自定义rcp网络请求"
},
{
"name": "request_concurrency",
"value": "设置请求并发度"
},
{
"name": "test_callback",
"value": "测试图片加载回调数据"
},
{
"name": "gif",
"value": "gif"
},
{
"name": "local_pic",
"value": "本地图片"
},
{
"name": "share_pic",
"value": "共享图片"
},
{
"name": "net_load_failed",
"value": "网络加载失败"
},
{
"name": "local_load_failed",
"value": "本地加载失败"
},
{
"name": "share_load_failed",
"value": "共享图片加载失败"
},
{
"name": "list_pic",
"value": "加载图片列表"
},
{
"name": "img_url",
"value": "业务设置的url:%s"
},
{
"name": "img_format",
"value": "图片的格式:%s"
},
{
"name": "img_master_size",
"value": "图片的原始宽高大小-宽:%d ,高:%d, 大小:%d"
},
{
"name": "componentWH",
"value": "component的宽高-宽:%d ,高:%d "
},
{
"name": "img_frame",
"value": "图片的帧数:%d "
},
{
"name": "img_content_size",
"value": "图片解码后宽高大小:%s "
},
{
"name": "err_msg",
"value": "错误信息:%s "
},
{
"name": "err_phase",
"value": "发生错误阶段:%s "
},
{
"name": "err_code",
"value": "错误code:%d "
},
{
"name": "http_code",
"value": "网络请求code:%d "
},
{
"name": "req_start_time",
"value": "图片的请求开始时间点:%s "
},
{
"name": "req_end_time",
"value": "图片请求结束的时间点:%s "
},
{
"name": "req_cancel_time",
"value": "图片请求取消的时间点:%s "
},
{
"name": "memory_start_time",
"value": "开始检查内存缓存时间点:%s "
},
{
"name": "memory_end_time",
"value": "结束检查内存缓存时间点:%s "
},
{
"name": "disk_start_time",
"value": "开始检查磁盘缓存时间点:%s "
},
{
"name": "disk_end_time",
"value": "结束检查磁盘缓存时间点:%s "
},
{
"name": "net_start_time",
"value": "网络请求开始时间点:%s "
},
{
"name": "net_end_time",
"value": "网络请求结束时间点:%s "
},
{
"name": "decode_start_time",
"value": "解码开始时间点:%s "
},
{
"name": "decode_end_time",
"value": "解码结束时间点:%s "
},
{
"name": "render_time",
"value": "渲染成功的时间:%s "
} }
] ]
} }

View File

@ -14,8 +14,8 @@
*/ */
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
import { ImageKnifeOption, ImageKnifeRequest } from '@ohos/imageknife/Index'; import { ImageKnifeOption, ImageKnifeRequest } from '@ohos/imageknife/Index';
import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/utils/DefaultJobQueue'; import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/queue/DefaultJobQueue';
import { IJobQueue } from '@ohos/imageknife/src/main/ets/utils/IJobQueue'; import { IJobQueue } from '@ohos/imageknife/src/main/ets/queue/IJobQueue';
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
@ -55,12 +55,12 @@ export default function DefaultJobQueueTest() {
expect(job.getQueueLength()).assertEqual(7) expect(job.getQueueLength()).assertEqual(7)
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("high1") expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("high1")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium4")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium3")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium2")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium1") expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium1")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low2") expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium2")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium3")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("medium4")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low1") expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low1")
expect(job.pop()!.imageKnifeOption.loadSrc).assertEqual("low2")
expect(job.pop()).assertEqual(undefined) expect(job.pop()).assertEqual(undefined)
expect(job.getQueueLength()).assertEqual(0) expect(job.getQueueLength()).assertEqual(0)

View File

@ -17,7 +17,7 @@ import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from
import Constants from '../../../main/ets/common/Constants'; import Constants from '../../../main/ets/common/Constants';
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
import { GlobalContext } from '../../../main/ets/common/GlobalContext'; import { GlobalContext } from '../../../main/ets/common/GlobalContext';
import { FileCache } from '@ohos/imageknife/src/main/ets/utils/FileCache'; import { FileCache } from '@ohos/imageknife/src/main/ets/cache/FileCache';
import { IEngineKey, ImageKnifeOption } from '@ohos/imageknife'; import { IEngineKey, ImageKnifeOption } from '@ohos/imageknife';
import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey'; import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey';

View File

@ -18,6 +18,8 @@ import ImageKnifeOptionTest from './ImageKnifeOption.test';
import MemoryLruCacheTest from './MemoryLruCache.test'; import MemoryLruCacheTest from './MemoryLruCache.test';
import ImageKnifeTest from './ImageKnife.test'; import ImageKnifeTest from './ImageKnife.test';
import Transform from './transform.test'; import Transform from './transform.test';
import imageFormatAndSize from './imageFormatAndSize.test'
import loadCallBackData from './loadCallBackData.test'
export default function testsuite() { export default function testsuite() {
MemoryLruCacheTest(); MemoryLruCacheTest();
@ -26,4 +28,6 @@ export default function testsuite() {
ImageKnifeOptionTest(); ImageKnifeOptionTest();
ImageKnifeTest(); ImageKnifeTest();
Transform(); Transform();
imageFormatAndSize();
loadCallBackData();
} }

View File

@ -17,7 +17,7 @@ import image from '@ohos.multimedia.image';
import Constants from '../../../main/ets/common/Constants'; import Constants from '../../../main/ets/common/Constants';
import { MemoryLruCache } from '@ohos/imageknife/src/main/ets/utils/MemoryLruCache'; import { MemoryLruCache } from '@ohos/imageknife/src/main/ets/cache/MemoryLruCache';
import { ImageKnifeData } from '@ohos/imageknife/src/main/ets/model/ImageKnifeData'; import { ImageKnifeData } from '@ohos/imageknife/src/main/ets/model/ImageKnifeData';
import { IEngineKey, ImageKnifeOption,ImageKnifeRequestSource } from '@ohos/imageknife'; import { IEngineKey, ImageKnifeOption,ImageKnifeRequestSource } from '@ohos/imageknife';
import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey'; import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey';

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
import {
ImageKnifeOption,
ImageKnife,
ImageKnifeRequest,
ImageKnifeRequestSource,
CacheStrategy
} from "@ohos/imageknife"
import { common } from '@kit.AbilityKit';
export default function imageFormatAndSize() {
describe('imageFormatAndSize', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('getImageSizeInCache', 0, async () => {
let width = 0;
let height = 0;
let imageFormat: string = "";
let url: string =
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/ed/v3/KMO4D6D2QGuVOCLX4AhOFA/ef51xAaLQuK7BsnuD9abog.jpg"
let imageKnifeOption: ImageKnifeOption = {
loadSrc: url,
}
await new Promise<string>((resolve, reject) => {
imageKnifeOption.onLoadListener = {
onLoadSuccess: (data, imageknifeData) => {
resolve("")
},
onLoadFailed(err) {
reject(err)
}
}
let request = new ImageKnifeRequest(
imageKnifeOption,
imageKnifeOption.context !== undefined ? imageKnifeOption.context : getContext() as common.UIAbilityContext,
0,
0,
0,
{
showPixelMap(version: number, pixelMap: PixelMap | string) {
}
}
)
ImageKnife.getInstance().execute(request);
})
let data = await ImageKnife.getInstance()
.getCacheImage(url, CacheStrategy.Memory);
if (data) {
width = data.imageWidth
height = data.imageHeight
imageFormat = data.type!
}
expect(width != 0).assertTrue();
expect(height != 0).assertTrue();
expect(imageFormat != "").assertTrue();
});
});
}

View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
import {
ImageKnifeOption,
ImageKnife,
ImageKnifeRequest,
ImageKnifeRequestSource,
CacheStrategy
} from "@ohos/imageknife"
import { common } from '@kit.AbilityKit';
export default function loadCallBackData() {
describe('loadCallBackData', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('startAndSuccess-CallBack', 0, async () => {
let startCallBack: ESObject = undefined;
let successCallBack: ESObject = undefined;
let url: string =
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/63/v3/qbe6NZkCQyGcITvdWoZBgg/Y-5U1z3GT_yaK8CBD3jkwg.jpg"
let imageKnifeOption: ImageKnifeOption = {
loadSrc: url,
}
await new Promise<string>((resolve, reject) => {
imageKnifeOption.onLoadListener = {
onLoadStart: (data) => {
startCallBack = data?.getImageKnifeData();
},
onLoadSuccess: (data, imageknifeData,req) => {
successCallBack = req?.getImageKnifeData();
resolve("")
},
onLoadFailed(err) {
reject(err)
}
}
let request = new ImageKnifeRequest(
imageKnifeOption,
imageKnifeOption.context !== undefined ? imageKnifeOption.context : getContext() as common.UIAbilityContext,
0,
0,
0,
{
showPixelMap(version: number, pixelMap: PixelMap | string) {
}
}
)
ImageKnife.getInstance().execute(request);
})
expect(startCallBack != undefined).assertTrue();
expect(successCallBack != undefined).assertTrue();
});
it('failed-CallBack', 0, async () => {
let failedCallBack: ESObject = undefined;
let url: string =
"https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/163/v3/qbe6NZkCQyGcITvdWoZBgg/Y-5U1z3GT_yaK8CBD3jkwg.jpg"
let imageKnifeOption: ImageKnifeOption = {
loadSrc: url,
}
await new Promise<string>((resolve, reject) => {
imageKnifeOption.onLoadListener = {
onLoadStart: (data) => {
},
onLoadSuccess: (data, imageknifeData) => {
},
onLoadFailed(res,req) {
failedCallBack = req?.getImageKnifeData();
resolve(res)
}
}
let request = new ImageKnifeRequest(
imageKnifeOption,
imageKnifeOption.context !== undefined ? imageKnifeOption.context : getContext() as common.UIAbilityContext,
0,
0,
0,
{
showPixelMap(version: number, pixelMap: PixelMap | string) {
}
}
)
ImageKnife.getInstance().execute(request);
})
expect(failedCallBack != undefined).assertTrue();
});
});
}

View File

@ -18,9 +18,9 @@ export { ImageKnifeAnimatorComponent } from './src/main/ets/components/ImageKnif
export { ImageKnife } from './src/main/ets/ImageKnife' export { ImageKnife } from './src/main/ets/ImageKnife'
export { ImageKnifeOption , AnimatorOption } from './src/main/ets/ImageKnifeOption' export { ImageKnifeOption , AnimatorOption } from './src/main/ets/model/ImageKnifeOption'
export { ImageKnifeRequest } from './src/main/ets/ImageKnifeRequest' export { ImageKnifeRequest } from './src/main/ets/model/ImageKnifeRequest'
export { FileUtils } from './src/main/ets/utils/FileUtils' export { FileUtils } from './src/main/ets/utils/FileUtils'

View File

@ -14,7 +14,7 @@
"main": "index.ets", "main": "index.ets",
"repository": "https://gitee.com/openharmony-tpc/ImageKnife", "repository": "https://gitee.com/openharmony-tpc/ImageKnife",
"type": "module", "type": "module",
"version": "3.0.1-rc.2", "version": "3.2.0-rc.1",
"dependencies": { "dependencies": {
"@ohos/gpu_transform": "^1.0.2" "@ohos/gpu_transform": "^1.0.2"
}, },

View File

@ -12,14 +12,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeRequest } from './ImageKnifeRequest'; import { ImageKnifeRequest, ImageKnifeRequestState } from './model/ImageKnifeRequest';
import { CacheStrategy, ImageKnifeData, ImageKnifeRequestSource } from './model/ImageKnifeData'; import { CacheStrategy, ImageKnifeData, ImageKnifeRequestSource } from './model/ImageKnifeData';
import { MemoryLruCache } from './utils/MemoryLruCache'; import { MemoryLruCache } from './cache/MemoryLruCache';
import { IMemoryCache } from './utils/IMemoryCache' import { IMemoryCache } from './cache/IMemoryCache'
import { FileCache } from './utils/FileCache'; import { FileCache } from './cache/FileCache';
import { ImageKnifeDispatcher } from './ImageKnifeDispatcher'; import { ImageKnifeDispatcher } from './ImageKnifeDispatcher';
import { IEngineKey } from './key/IEngineKey'; import { IEngineKey } from './key/IEngineKey';
import { HeaderOptions, ImageKnifeOption } from './ImageKnifeOption'; import { HeaderOptions, ImageKnifeOption } from './model/ImageKnifeOption';
import { FileTypeUtil } from './utils/FileTypeUtil'; import { FileTypeUtil } from './utils/FileTypeUtil';
import { util } from '@kit.ArkTS'; import { util } from '@kit.ArkTS';
import { image } from '@kit.ImageKit'; import { image } from '@kit.ImageKit';
@ -38,7 +38,7 @@ export class ImageKnife {
private _isRequestInSubThread: boolean = true; private _isRequestInSubThread: boolean = true;
//定义全局网络请求header map //定义全局网络请求header map
headerMap: Map<string, Object> = new Map<string, Object>(); headerMap: Map<string, Object> = new Map<string, Object>();
customGetImage: ((context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>) | undefined = undefined customGetImage: ((context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>) | undefined = undefined
public static getInstance(): ImageKnife { public static getInstance(): ImageKnife {
if (!ImageKnife.instance) { if (!ImageKnife.instance) {
ImageKnife.instance = new ImageKnife(); ImageKnife.instance = new ImageKnife();
@ -80,7 +80,15 @@ export class ImageKnife {
public isFileCacheInit(): boolean { public isFileCacheInit(): boolean {
return this.fileCache === undefined ? false : this.fileCache.isFileCacheInit() return this.fileCache === undefined ? false : this.fileCache.isFileCacheInit()
} }
/**
* 重新加载
*/
reload(request: ImageKnifeRequest) {
if (request.requestState == ImageKnifeRequestState.ERROR) {
request.requestState = ImageKnifeRequestState.PROGRESS
ImageKnife.getInstance().execute(request)
}
}
/** /**
* 全局添加单个请求头header * 全局添加单个请求头header
* @param key 请求头属性 * @param key 请求头属性
@ -137,8 +145,39 @@ export class ImageKnife {
let key = this.getEngineKeyImpl().generateMemoryKey(imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, imageKnifeOption); let key = this.getEngineKeyImpl().generateMemoryKey(imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC, imageKnifeOption);
this.memoryCache.remove(key); this.memoryCache.remove(key);
} }
/**
* 预加载
* @param loadSrc 图片地址url
* @returns 图片请求request
*/
preload(loadSrc:string | ImageKnifeOption):ImageKnifeRequest{
let imageKnifeOption = new ImageKnifeOption()
if (typeof loadSrc == "string") {
imageKnifeOption.loadSrc = loadSrc
} else {
imageKnifeOption = loadSrc;
}
let request = new ImageKnifeRequest(
imageKnifeOption,
imageKnifeOption.context !== undefined ? imageKnifeOption.context : getContext(this) as common.UIAbilityContext,
0,
0,
0,
{
showPixelMap(version: number, pixelMap: PixelMap | string) {
}
}
)
this.execute(request)
return request
}
/**
* 取消图片请求
* @param request 图片请求request
*/
cancel(request:ImageKnifeRequest) {
request.requestState = ImageKnifeRequestState.DESTROY
}
/** /**
* 预加载图片到文件缓存 * 预加载图片到文件缓存
* @param loadSrc 图片地址url * @param loadSrc 图片地址url
@ -302,6 +341,65 @@ export class ImageKnife {
return this.fileCache as FileCache return this.fileCache as FileCache
} }
/**
* get cache upper limit
* @param cacheType
* @returns
*/
getCacheLimitSize(cacheType?: CacheStrategy): number | undefined {
if (cacheType == undefined || cacheType == CacheStrategy.Default) {
cacheType = CacheStrategy.Memory;
}
if (cacheType == CacheStrategy.Memory) {
return (this.memoryCache as MemoryLruCache).maxMemory;
} else {
if (this.isFileCacheInit()) {
return this.fileCache?.maxMemory;
} else {
throw new Error("the disk cache not init");
}
}
}
/**
* gets the number of images currently cached
* @param cacheType
* @returns
*/
getCurrentCacheNum(cacheType: CacheStrategy): number | undefined {
if (cacheType == undefined || cacheType == CacheStrategy.Default) {
cacheType = CacheStrategy.Memory;
}
if (cacheType == CacheStrategy.Memory) {
return (this.memoryCache as MemoryLruCache).size();
} else {
if (this.isFileCacheInit()) {
return this.fileCache?.size();
} else {
throw new Error("the disk cache not init");
}
}
}
/**
* gets the current cache size
* @param cacheType
* @returns
*/
getCurrentCacheSize(cacheType: CacheStrategy): number | undefined {
if (cacheType == undefined || cacheType == CacheStrategy.Default) {
cacheType = CacheStrategy.Memory;
}
if (cacheType == CacheStrategy.Memory) {
return (this.memoryCache as MemoryLruCache).currentMemory;
} else {
if (this.isFileCacheInit()) {
return this.fileCache?.currentMemory;
} else {
throw new Error("the disk cache not init");
}
}
}
private pixelMapToArrayBuffer(pixelMap: PixelMap): ArrayBuffer { private pixelMapToArrayBuffer(pixelMap: PixelMap): ArrayBuffer {
let imageInfo = pixelMap.getImageInfoSync(); let imageInfo = pixelMap.getImageInfoSync();
@ -384,10 +482,10 @@ export class ImageKnife {
* 全局设置自定义下载 * 全局设置自定义下载
* @param customGetImage 自定义请求函数 * @param customGetImage 自定义请求函数
*/ */
setCustomGetImage(customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>) { setCustomGetImage(customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>) {
this.customGetImage = customGetImage this.customGetImage = customGetImage
} }
getCustomGetImage(): undefined | ((context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>){ getCustomGetImage(): undefined | ((context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>){
return this.customGetImage return this.customGetImage
} }
} }

View File

@ -12,24 +12,19 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeRequest, ImageKnifeRequestState } from './ImageKnifeRequest' import { ImageKnifeRequest, ImageKnifeRequestState } from './model/ImageKnifeRequest'
import { DefaultJobQueue } from './utils/DefaultJobQueue' import { DefaultJobQueue } from './queue/DefaultJobQueue'
import { IJobQueue } from './utils/IJobQueue' import { IJobQueue } from './queue/IJobQueue'
import List from '@ohos.util.List'; import List from '@ohos.util.List';
import LightWeightMap from '@ohos.util.LightWeightMap'; import LightWeightMap from '@ohos.util.LightWeightMap';
import { LogUtil } from './utils/LogUtil'; import { LogUtil } from './utils/LogUtil';
import buffer from '@ohos.buffer';
import { FileCache } from './utils/FileCache';
import fs from '@ohos.file.fs';
import { ImageKnife } from './ImageKnife'; import { ImageKnife } from './ImageKnife';
import { ImageKnifeData, CacheStrategy } from './model/ImageKnifeData'; import { ImageKnifeData, CacheStrategy, TimeInfo, ErrorInfo } from './model/ImageKnifeData';
import http from '@ohos.net.http';
import image from '@ohos.multimedia.image'; import image from '@ohos.multimedia.image';
import emitter from '@ohos.events.emitter'; import emitter from '@ohos.events.emitter';
import { Constants } from './utils/Constants'; import { Constants, LoadPhase, LoadPixelMapCode } from './utils/Constants';
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
import { FileTypeUtil } from './utils/FileTypeUtil'; import { FileTypeUtil } from './utils/FileTypeUtil';
import util from '@ohos.util';
import { IEngineKey } from './key/IEngineKey'; import { IEngineKey } from './key/IEngineKey';
import { DefaultEngineKey } from './key/DefaultEngineKey'; import { DefaultEngineKey } from './key/DefaultEngineKey';
import { import {
@ -38,8 +33,9 @@ import {
RequestJobResult, RequestJobResult,
RequestJobRequest RequestJobRequest
} from './model/ImageKnifeData' } from './model/ImageKnifeData'
import { combineArrayBuffers } from './model/utils';
import { BusinessError } from '@kit.BasicServicesKit'; import { BusinessError } from '@kit.BasicServicesKit';
import { ImageKnifeLoader } from './ImageKnifeLoader'
export class ImageKnifeDispatcher { export class ImageKnifeDispatcher {
// 最大并发 // 最大并发
@ -52,8 +48,9 @@ export class ImageKnifeDispatcher {
private engineKey: IEngineKey = new DefaultEngineKey(); private engineKey: IEngineKey = new DefaultEngineKey();
showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): boolean { showFromMemomry(request: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): boolean {
LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_showFromMemomry.start:" + request.imageKnifeOption.loadSrc + "requestSource=" + requestSource + " isAnimator=" + isAnimator)
let memoryCache: ImageKnifeData | undefined; let memoryCache: ImageKnifeData | undefined;
let memoryCheckStartTime = Date.now();
if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') { if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') {
memoryCache = { memoryCache = {
source: request.imageKnifeOption.loadSrc as image.PixelMap, source: request.imageKnifeOption.loadSrc as image.PixelMap,
@ -65,40 +62,100 @@ export class ImageKnifeDispatcher {
.loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator)); .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator));
} }
//记录ImageKnifeRequestSource.SRC 开始内存检查的时间点
if (requestSource == ImageKnifeRequestSource.SRC && request.getImageKnifeData()) {
let timeInfo = request.getImageKnifeData()?.timeInfo
if (timeInfo) {
timeInfo.memoryCheckStartTime = memoryCheckStartTime;
timeInfo.memoryCheckEndTime = Date.now();
//设置请求结束的时间点
if (memoryCache !== undefined) {
timeInfo.requestEndTime = Date.now();
}
}
}
if (memoryCache !== undefined) { if (memoryCache !== undefined) {
// 画主图 // 画主图
if (request.requestState === ImageKnifeRequestState.PROGRESS) { if (request.requestState === ImageKnifeRequestState.PROGRESS) {
// 回调请求开始 // 回调请求开始
if (requestSource === ImageKnifeRequestSource.SRC && request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { if (requestSource === ImageKnifeRequestSource.SRC && request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
request.imageKnifeOption.onLoadListener?.onLoadStart() request.imageKnifeOption.onLoadListener.onLoadStart(request)
LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadStart:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadStart:" + request.imageKnifeOption.loadSrc)
} }
LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.start:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.start:" + request.imageKnifeOption.loadSrc)
request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource,memoryCache.imageAnimator) request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source,
{ width: memoryCache.imageWidth, height: memoryCache.imageHeight }, requestSource, memoryCache.imageAnimator)
LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.end:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_showPixelMap.end:" + request.imageKnifeOption.loadSrc)
if (requestSource == ImageKnifeRequestSource.SRC) { if (requestSource == ImageKnifeRequestSource.SRC) {
request.requestState = ImageKnifeRequestState.COMPLETE request.requestState = ImageKnifeRequestState.COMPLETE
// 回调请求开结束 // 回调请求开结束
if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) { if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) {
request.imageKnifeOption.onLoadListener?.onLoadSuccess(memoryCache.source,memoryCache) this.copyMemoryCacheInfo(memoryCache, request.getImageKnifeData());
request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source, memoryCache, request)
LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadSuccess:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadSuccess:" + request.imageKnifeOption.loadSrc)
} }
} else if (requestSource == ImageKnifeRequestSource.ERROR_HOLDER) { } else if (requestSource == ImageKnifeRequestSource.ERROR_HOLDER) {
request.requestState = ImageKnifeRequestState.ERROR request.requestState = ImageKnifeRequestState.ERROR
} }
} }
LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_true:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_hasmemory:" + request.imageKnifeOption.loadSrc)
return true return true
} }
LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_false:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_nomemory:" + request.imageKnifeOption.loadSrc)
return false return false
} }
private copyMemoryCacheInfo(memoryCache: ImageKnifeData | undefined, target: ImageKnifeData | undefined) {
if (!memoryCache || !target) {
return;
}
target.source = memoryCache.source;
target.imageWidth = memoryCache.imageWidth;
target.imageHeight = memoryCache.imageHeight;
target.type = memoryCache.type;
target.imageAnimator = memoryCache.imageAnimator;
}
private assembleImageKnifeData(beforeCallData: ImageKnifeData | undefined, afterCallData: ImageKnifeData | undefined, req: ImageKnifeRequest) {
if (!beforeCallData || !afterCallData || !req) {
return;
}
//设置图片开始加载时间及其缓存检查时间点
if (beforeCallData.timeInfo) {
if (afterCallData.timeInfo) {
afterCallData.timeInfo.requestStartTime = beforeCallData.timeInfo.requestStartTime;
afterCallData.timeInfo.memoryCheckStartTime = beforeCallData.timeInfo.memoryCheckStartTime;
afterCallData.timeInfo.memoryCheckEndTime = beforeCallData.timeInfo.memoryCheckEndTime;
}
}
req.setImageKnifeData(afterCallData);
}
private initCallData(request: ImageKnifeRequest) {
if (!request) {
return
}
//图片加载信息回调数据
let callBackData: ImageKnifeData = {
source: "",
imageWidth: 0,
imageHeight: 0,
};
//图片加载信息回调数据时间点
let callBackTimeInfo: TimeInfo = {};
callBackTimeInfo.requestStartTime = Date.now();
callBackData.timeInfo = callBackTimeInfo;
//跟隨請求保存回調信息點
request.setImageKnifeData(callBackData);
}
enqueue(request: ImageKnifeRequest,isAnimator?: boolean): void { enqueue(request: ImageKnifeRequest,isAnimator?: boolean): void {
//初始化加载回调信息
this.initCallData(request);
//1.内存有的话直接渲染 //1.内存有的话直接渲染
if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator)) { if (this.showFromMemomry(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator)) {
return return
@ -110,7 +167,7 @@ export class ImageKnifeDispatcher {
} }
} }
//3.判断是否要排队 //3.判断是否要排队
if (this.executingJobMap.length > this.maxRequests) { if (this.executingJobMap.length >= this.maxRequests) {
this.jobQueue.add(request) this.jobQueue.add(request)
return return
} }
@ -134,6 +191,11 @@ export class ImageKnifeDispatcher {
*/ */
getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): void { getAndShowImage(currentRequest: ImageKnifeRequest, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean): void {
LogUtil.log("ImageKnife_DataTime_getAndShowImage.start:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage.start:" + currentRequest.imageKnifeOption.loadSrc)
if (requestSource === ImageKnifeRequestSource.SRC && currentRequest.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
currentRequest.imageKnifeOption.onLoadListener?.onLoadStart(currentRequest)
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc)
}
let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator) let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator)
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey) let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey)
if (requestList == undefined) { if (requestList == undefined) {
@ -146,21 +208,35 @@ export class ImageKnifeDispatcher {
} }
let isWatchProgress : boolean = false let isWatchProgress : boolean = false
if (currentRequest.imageKnifeOption.progressListener !== undefined && requestSource === ImageKnifeRequestSource.SRC) {
isWatchProgress = true
}
// 回调请求开始 // 回调请求开始
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart() requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart(requestWithSource.request)
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc)
} }
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) { if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
isWatchProgress = true isWatchProgress = true
} }
}); });
let src: string | number = ""
let moduleName: string = ""
let resName: string = ""
if((imageSrc as Resource).id != undefined) {
moduleName = (imageSrc as Resource).moduleName
src = (imageSrc as Resource).id
if(src == -1) {
resName = (imageSrc as Resource).params![0]
}
} else if(typeof imageSrc == "string") {
src = imageSrc
}
let request: RequestJobRequest = { let request: RequestJobRequest = {
context: currentRequest.context, context: currentRequest.context,
src: imageSrc, src: src,
headers: currentRequest.imageKnifeOption.headerOption, headers: currentRequest.imageKnifeOption.headerOption,
allHeaders: currentRequest.headers, allHeaders: currentRequest.headers,
componentWidth:currentRequest.componentWidth, componentWidth:currentRequest.componentWidth,
@ -175,13 +251,25 @@ export class ImageKnifeDispatcher {
requestSource: requestSource, requestSource: requestSource,
isWatchProgress: isWatchProgress, isWatchProgress: isWatchProgress,
memoryKey: memoryKey, memoryKey: memoryKey,
fileCacheFolder: ImageKnife.getInstance().getFileCache().getCacheFolder(), fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(),
isAnimator:isAnimator isAnimator:isAnimator,
moduleName: moduleName == "" ? undefined : moduleName,
resName: resName == "" ? undefined : resName
} }
if(request.customGetImage == undefined) { if(request.customGetImage == undefined) {
request.customGetImage = ImageKnife.getInstance().getCustomGetImage() request.customGetImage = ImageKnife.getInstance().getCustomGetImage()
} }
emitter.on(Constants.CALLBACK_EMITTER + memoryKey,(data)=>{
emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
let res = data?.data?.value as RequestJobResult | undefined
this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
if (isWatchProgress){
emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
}
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
})
if (ImageKnife.getInstance().isRequestInSubThread){ if (ImageKnife.getInstance().isRequestInSubThread){
// 启动线程下载和解码主图 // 启动线程下载和解码主图
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc)
@ -193,16 +281,18 @@ export class ImageKnifeDispatcher {
}); });
} }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" + currentRequest.imageKnifeOption.loadSrc)
taskpool.execute(task).then((res: Object) => { taskpool.execute(task).then((res: Object) => {
this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); // this.doTaskCallback(res as RequestJobResult | undefined, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
if (isWatchProgress){ // if (isWatchProgress){
emitter.off(Constants.PROGRESS_EMITTER + memoryKey) // emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
} // }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) // LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) // LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
}).catch((err: BusinessError) => { }).catch((err: BusinessError) => {
LogUtil.error("Fail to execute in sub thread src=" + imageSrc + " err=" + err) emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
LogUtil.error("Fail to requestJob in sub thread src=" + imageSrc + " err=" + err)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
if (isWatchProgress){ if (isWatchProgress){
emitter.off(Constants.PROGRESS_EMITTER + memoryKey) emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
} }
@ -210,12 +300,15 @@ export class ImageKnifeDispatcher {
this.dispatchNextJob(); this.dispatchNextJob();
}) })
} else { //主线程请求 } else { //主线程请求
requestJob(request, requestList).then((res: RequestJobResult | undefined) => { LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" + currentRequest.imageKnifeOption.loadSrc)
this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator); requestJob(request, requestList).then(() => {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc) // this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc) // LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.end:"+currentRequest.imageKnifeOption.loadSrc)
// LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:"+currentRequest.imageKnifeOption.loadSrc)
}).catch((err: BusinessError) => { }).catch((err: BusinessError) => {
LogUtil.error("Fail to execute in main thread src=" + imageSrc + " err=" + err) emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
LogUtil.error("Fail to requestJob in main thread src=" + imageSrc + " err=" + err)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc)
this.executingJobMap.remove(memoryKey); this.executingJobMap.remove(memoryKey);
this.dispatchNextJob(); this.dispatchNextJob();
}) })
@ -242,14 +335,22 @@ export class ImageKnifeDispatcher {
if (requestJobResult === undefined){ if (requestJobResult === undefined){
return return
} }
//设置请求结束的时间
if (requestJobResult.imageKnifeData && requestJobResult.imageKnifeData.timeInfo) {
requestJobResult.imageKnifeData.timeInfo.requestEndTime = Date.now();
}
let pixelmap = requestJobResult.pixelMap; let pixelmap = requestJobResult.pixelMap;
if (pixelmap === undefined) { if (pixelmap === undefined) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.pixelmap undefined:"+currentRequest.imageKnifeOption.loadSrc)
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
// 回调请求失败 // 回调请求失败
if (requestWithSource.source === ImageKnifeRequestSource.SRC && if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadFailed !== undefined && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadFailed !== undefined &&
requestJobResult.loadFail) { requestJobResult.loadFail) {
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail); this.assembleImageKnifeData(requestWithSource.request.getImageKnifeData(), requestJobResult.imageKnifeData, requestWithSource.request)
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail,requestWithSource.request);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:"+currentRequest.imageKnifeOption.loadSrc)
} }
if (requestWithSource.source === ImageKnifeRequestSource.SRC && if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
@ -263,6 +364,7 @@ export class ImageKnifeDispatcher {
} }
}); });
this.executingJobMap.remove(memoryKey); this.executingJobMap.remove(memoryKey);
this.dispatchNextJob();
return; return;
} }
// 保存文件缓存 // 保存文件缓存
@ -272,12 +374,19 @@ export class ImageKnifeDispatcher {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:"+currentRequest.imageKnifeOption.loadSrc)
} }
let ImageKnifeData: ImageKnifeData = { let imageKnifeData: ImageKnifeData;
if (!requestJobResult.imageKnifeData) {
imageKnifeData = {
source: pixelmap!, source: pixelmap!,
imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width, imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height, imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
type:requestJobResult.type type: requestJobResult.type,
}; };
} else {
imageKnifeData = requestJobResult.imageKnifeData;
imageKnifeData.source = pixelmap!;
}
if(requestJobResult.pixelMapList != undefined) { if(requestJobResult.pixelMapList != undefined) {
let imageAnimator: Array<ImageFrameInfo> = [] let imageAnimator: Array<ImageFrameInfo> = []
requestJobResult.pixelMapList.forEach((item,index)=>{ requestJobResult.pixelMapList.forEach((item,index)=>{
@ -286,19 +395,27 @@ export class ImageKnifeDispatcher {
duration:requestJobResult.delayList![index] duration:requestJobResult.delayList![index]
}) })
}) })
ImageKnifeData.imageAnimator = imageAnimator imageKnifeData.imageAnimator = imageAnimator
} }
//构建缓存保存的ImageKnifeData
let saveCacheImageData: ImageKnifeData = {
source: pixelmap!,
imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
type: requestJobResult.type,
imageAnimator: imageKnifeData.imageAnimator
}
// 保存内存缓存 // 保存内存缓存
if (currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.File) { if (currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.File) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.start:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.start:"+currentRequest.imageKnifeOption.loadSrc)
ImageKnife.getInstance() ImageKnife.getInstance()
.saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator), .saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator),
ImageKnifeData); saveCacheImageData);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:"+currentRequest.imageKnifeOption.loadSrc)
} }
if (requestList !== undefined) { if (requestList !== undefined) {
// todo 判断request生命周期已销毁的不需要再绘制
// key相同的request一起绘制 // key相同的request一起绘制
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.request.requestState !== ImageKnifeRequestState.DESTROY) { if (requestWithSource.request.requestState !== ImageKnifeRequestState.DESTROY) {
@ -309,7 +426,8 @@ export class ImageKnifeDispatcher {
requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) { requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:"+currentRequest.imageKnifeOption.loadSrc)
requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion, requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion,
ImageKnifeData.source, requestWithSource.source,ImageKnifeData.imageAnimator); imageKnifeData.source, { width: imageKnifeData.imageWidth, height: imageKnifeData.imageHeight },
requestWithSource.source, imageKnifeData.imageAnimator);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:"+currentRequest.imageKnifeOption.loadSrc)
} }
@ -318,7 +436,9 @@ export class ImageKnifeDispatcher {
if (requestWithSource.request.imageKnifeOption.onLoadListener && if (requestWithSource.request.imageKnifeOption.onLoadListener &&
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) { requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) {
// 回调请求成功 // 回调请求成功
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(ImageKnifeData.source,ImageKnifeData); this.assembleImageKnifeData(requestWithSource.request.getImageKnifeData(), imageKnifeData,requestWithSource.request);
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(imageKnifeData.source,
saveCacheImageData, requestWithSource.request);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:"+currentRequest.imageKnifeOption.loadSrc)
} }
} else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) { } else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) {
@ -327,7 +447,19 @@ export class ImageKnifeDispatcher {
} else { } else {
if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) { if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
// 回调请求成功 // 回调请求成功
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") // 回调请求成功
//设置失败回调的时间点
let callBackData = requestWithSource.request.getImageKnifeData();
if (requestJobResult.imageKnifeData && requestJobResult.imageKnifeData.timeInfo) {
requestJobResult.imageKnifeData.timeInfo.requestCancelTime = Date.now();
if (requestJobResult.imageKnifeData.errorInfo) {
requestJobResult.imageKnifeData.errorInfo.phase = LoadPhase.PHASE_WILL_SHOW;
requestJobResult.imageKnifeData.errorInfo.code = LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE;
}
}
this.assembleImageKnifeData(callBackData,requestJobResult.imageKnifeData,requestWithSource.request)
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed", requestWithSource.request)
} }
} }
}); });
@ -346,14 +478,28 @@ export class ImageKnifeDispatcher {
while (true) { while (true) {
let request = this.jobQueue.pop() let request = this.jobQueue.pop()
if (request === undefined) { if (request === undefined) {
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:no any job")
break // 队列已无任务 break // 队列已无任务
} }
else if (request.requestState === ImageKnifeRequestState.PROGRESS) { else if (request.requestState === ImageKnifeRequestState.PROGRESS) {
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.start executeJob:" + request.imageKnifeOption.loadSrc)
this.executeJob(request) this.executeJob(request)
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end:" + request.imageKnifeOption.loadSrc) LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end executeJob:" + request.imageKnifeOption.loadSrc)
break break
}else if (request.requestState == ImageKnifeRequestState.DESTROY && request.imageKnifeOption.onLoadListener?.onLoadCancel) { }else if (request.requestState == ImageKnifeRequestState.DESTROY && request.imageKnifeOption.onLoadListener?.onLoadCancel) {
request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") //构建回调错误信息
let callBackData = request.getImageKnifeData();
if (callBackData) {
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData)
timeInfo.requestCancelTime = Date.now();
timeInfo.requestEndTime = Date.now()
let errorInfo: ErrorInfo = {
phase: LoadPhase.PHASE_THREAD_QUEUE,
code: LoadPixelMapCode.IMAGE_LOAD_CANCEL_FAILED_CODE,
};
callBackData.errorInfo = errorInfo;
}
request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed", request)
} }
} }
} }
@ -380,289 +526,16 @@ export class ImageKnifeDispatcher {
* @returns * @returns
*/ */
@Concurrent @Concurrent
async function requestJob(request: RequestJobRequest, requestList?: List<ImageKnifeRequestWithSource>): Promise<RequestJobResult | undefined> { async function requestJob(request: RequestJobRequest, requestList?: List<ImageKnifeRequestWithSource>) {
LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src) LogUtil.log("ImageKnife_DataTime_requestJob.start:" + request.src + " requestSource=" + request.requestSource)
let resBuf: ArrayBuffer | undefined let src = typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src
let bufferSize: number = 0 // 生成文件缓存key
let loadError: string = ''; let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator)
class RequestData { //获取图片资源
receiveSize: number = 2000 ImageKnifeLoader.execute(request,requestList,fileKey)
totalSize: number = 2000
}
// 生成文件key
let fileKey = request.engineKey.generateFileKey(request.src, request.signature,request.isAnimator)
// 判断自定义下载
if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC) {
// 先从文件缓存获取
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
if (resBuf === undefined) {
LogUtil.log("customGetImage customGetImage");
resBuf = await request.customGetImage(request.context, request.src)
loadError = resBuf == undefined ? "customGetImage loadFile" : loadError
// 保存文件缓存
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
let copyBuf = buffer.concat([buffer.from(resBuf)]).buffer; // IDE有bug不能直接获取resBuf.byteLength
bufferSize = copyBuf.byteLength
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder)
}
}
}
else {
if (typeof request.src === 'string') {
if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载
// 先从文件缓存获取
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
if (resBuf === undefined && request.onlyRetrieveFromCache != true) {
LogUtil.log("ImageKnife_DataTime_requestJob_httpRequest.start:"+request.src)
let httpRequest = http.createHttp();
let progress: number = 0
let arrayBuffers = new Array<ArrayBuffer>()
const headerObj: Record<string, object> = {}
if (request.headers != undefined) {
request.headers.forEach((value) => {
headerObj[value.key] = value.value
})
} else if (request.allHeaders.size > 0) {
request.allHeaders.forEach((value, key) => {
headerObj[key] = value
})
}
httpRequest.on("dataReceive", (data: ArrayBuffer) => {
arrayBuffers.push(data)
});
if (request.isWatchProgress) {
httpRequest.on('dataReceiveProgress', (data: RequestData) => {
// 下载进度
if (data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number')) {
let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100)
if (progress !== percent) {
progress = percent
if (requestList === undefined) {
// 子线程
emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { "value": progress } })
}else {
// 主线程请求
requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
requestWithSource.request.imageKnifeOption.progressListener(progress)
}
})
}
}
}
})
}
let promise = httpRequest.requestInStream(request.src, {
header: headerObj,
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
connectTimeout: 6000,
readTimeout: 6000,
// usingProtocol:http.HttpProtocol.HTTP1_1
// header: new Header('application/json')
});
await promise.then((data: number) => {
if (data == 200) {
resBuf = combineArrayBuffers(arrayBuffers)
} else {
loadError = "HttpDownloadClient has error, http code =" + JSON.stringify(data)
}
}).catch((err: Error) => {
loadError = err.message;
LogUtil.error("requestInStream ERROR : err = " + JSON.stringify(err));
});
LogUtil.log("ImageKnife_DataTime_requestJob_httpRequest.end:"+request.src)
// 保存文件缓存
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src)
let copyBuf = combineArrayBuffers(arrayBuffers); // IDE有bug不能直接获取resBuf.byteLength
bufferSize = copyBuf.byteLength
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder)
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src)
}
}
else {
LogUtil.log("success get image from filecache for key = " + fileKey);
loadError = "success get image from filecache for key = " + fileKey;
}
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
await fs.stat(file.fd).then(async (stat) =>{
let buf = new ArrayBuffer(stat.size);
await fs.read(file.fd, buf).then((readLen) => {
resBuf = buf;
fs.close(file.fd);
}).catch((err:BusinessError) => {
loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
})
}).catch((err:BusinessError) => {
loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
})
}).catch((err:BusinessError) => {
loadError ='LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code;
})
} else { //从本地文件获取
try {
let stat = fs.statSync(request.src);
if (stat.size > 0) {
let file = fs.openSync(request.src, fs.OpenMode.READ_ONLY);
resBuf = new ArrayBuffer(stat.size);
fs.readSync(file.fd, resBuf);
fs.closeSync(file);
}
} catch (err) {
if (typeof err == 'string') {
loadError = err;
} else {
loadError = err.message;
}
}
}
} else if ((request.src as Resource).id !== undefined) { //从资源文件获取
let res = request.src as Resource;
let manager = request.context.createModuleContext(res.moduleName).resourceManager
if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == ImageKnifeRequestSource.SRC) {
if(res.id == -1) {
let resName = (res.params![0] as string)
resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer
} else {
resBuf = manager.getMediaContentSync(res.id).buffer as ArrayBuffer
}
} else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) {
if(res.id == -1) {
let resName = (res.params![0] as string)
resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer
} else {
resBuf = manager.getMediaContentSync(res.id).buffer as ArrayBuffer
}
}
}
} }
if (resBuf == undefined) {
LogUtil.log("ImageKnife_DataTime_requestJob.end_undefined:"+request.src)
return {
pixelMap: undefined,
bufferSize: 0,
fileKey: '',
loadFail: loadError,
}
}
LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.start:"+request.src)
let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(resBuf);
if(typeValue == null) {
return {
pixelMap: undefined,
bufferSize: 0,
fileKey: '',
loadFail: "request is not a valid image source",
}
}
let imageSource: image.ImageSource = image.createImageSource(resBuf);
let decodingOptions: image.DecodingOptions = {
editable: true,
}
if(request.isAnimator) {
if (typeValue === 'gif' || typeValue === 'webp') {
let pixelMapList: Array<PixelMap> = []
let delayList: Array<number> = []
await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => {
//sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList()
await imageSource.getDelayTimeList().then(delayTimes => {
if (pixelList.length > 0) {
for (let i = 0; i < pixelList.length; i++) {
pixelMapList.push(pixelList[i]);
if (i < delayTimes.length) {
delayList.push(delayTimes[i]);
} else {
delayList.push(delayTimes[delayTimes.length - 1])
}
}
imageSource.release();
}
})
})
return {
pixelMap: "",
bufferSize: bufferSize,
fileKey: fileKey,
type: typeValue,
pixelMapList,
delayList
}
} else {
return {
pixelMap: undefined,
bufferSize: 0,
fileKey: '',
loadFail: "ImageKnifeAnimatorComponent组件仅支持动态图",
}
}
}
let resPixelmap: PixelMap | undefined = undefined
if (typeValue === 'gif' || typeValue === 'webp') {
let size = (await imageSource.getImageInfo()).size
let base64Help = new util.Base64Helper()
let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(resBuf))
LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.end_GIF:"+request.src)
LogUtil.log("ImageKnife_DataTime_requestJob.end_GIF:"+request.src)
return {
pixelMap: base64str,
bufferSize: bufferSize,
fileKey: fileKey,
size:size,
type:typeValue
};
} else if(typeValue == "svg") {
let hValue = Math.round(request.componentHeight);
let wValue = Math.round(request.componentWidth);
let defaultSize: image.Size = {
height: vp2px(hValue),
width: vp2px(wValue)
};
let opts: image.DecodingOptions = {
editable: true,
desiredSize: defaultSize
};
await imageSource.createPixelMap(opts)
.then((pixelmap: PixelMap) => {
resPixelmap = pixelmap
imageSource.release()
})
return {
pixelMap: resPixelmap,
bufferSize: bufferSize,
fileKey: fileKey,
type:typeValue
};
}
let size = (await imageSource.getImageInfo()).size
await imageSource.createPixelMap(decodingOptions)
.then((pixelmap: PixelMap) => {
resPixelmap = pixelmap
imageSource.release()
})
// 图形变化
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined) {
resPixelmap = await request.transformation?.transform(request.context, resPixelmap!, request.componentWidth, request.componentHeight);
}
LogUtil.log("ImageKnife_DataTime_requestJob_createPixelMap.end:"+request.src)
LogUtil.log("ImageKnife_DataTime_requestJob.end:"+request.src)
return {
pixelMap: resPixelmap,
bufferSize: bufferSize,
fileKey: fileKey,
size:size,
type:typeValue
};
}

View File

@ -0,0 +1,543 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
CacheStrategy,
DecodeImageInfo,
ErrorInfo,
ImageKnifeData,
ImageKnifeRequestSource,
ImageKnifeRequestWithSource, RequestJobRequest,
TimeInfo } from './model/ImageKnifeData';
import List from '@ohos.util.List'
import { FileCache } from './cache/FileCache';
import { LogUtil } from './utils/LogUtil';
import { Constants, LoadPhase, LoadPixelMapCode } from './utils/Constants';
import http from '@ohos.net.http';
import { combineArrayBuffers } from './utils/ArrayBufferUtils';
import { BusinessError } from '@kit.BasicServicesKit';
import fs from '@ohos.file.fs';
import emitter from '@ohos.events.emitter';
import image from '@ohos.multimedia.image';
import { RequestJobResult } from './model/ImageKnifeData'
import util from '@ohos.util';
import { FileTypeUtil } from './utils/FileTypeUtil';
class RequestData {
receiveSize: number = 2000
totalSize: number = 2000
}
/**
* ImageKnifeDispatcher 抽取出来的方法,因@Concurrent只能import方法故抽取到另一个类
*/
export class ImageKnifeLoader {
static execute(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined, fileKey: string){
ImageKnifeLoader.getImageArrayBuffer(request,requestList,fileKey)
}
static async parseImage(resBuf: ArrayBuffer, fileKey: string,
request: RequestJobRequest, callBackData: ImageKnifeData) {
callBackData.bufSize = resBuf.byteLength;
let typeValue = new FileTypeUtil().getFileType(resBuf);
if(typeValue == null) {
LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src)
ImageKnifeLoader.makeEmptyResult(request,"request is not a valid image source", ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_GET_FORMAT, LoadPixelMapCode.IMAGE_PARSE_FORMAT_FAILED_CODE))
return
}
callBackData.type = typeValue;
if(request.isAnimator) {
ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request, callBackData)
return
}
if (typeValue === 'gif' || typeValue === 'webp') {
ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request, callBackData)
return
} else if(typeValue == "svg") {
ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request, callBackData)
return
}
ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData)
}
static makeEmptyResult(request:RequestJobRequest,error: string, data?: ImageKnifeData){
let res: RequestJobResult = {
pixelMap: undefined,
bufferSize: 0,
fileKey: '',
loadFail: error,
imageKnifeData: data
}
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
}
static assembleError(data: ImageKnifeData | undefined, phase: string, code?: number,
httpCode?: number): ImageKnifeData | undefined {
let errorCallBackData = data?.errorInfo;
if (!errorCallBackData) {
return data;
}
errorCallBackData.phase = phase;
errorCallBackData.code = code? code: 0;
if (httpCode && httpCode != 0) {
errorCallBackData.httpCode = httpCode;
}
return data
}
static getTimeInfo(callBackData: ImageKnifeData): TimeInfo {
let timeInfo: TimeInfo;
if (callBackData.timeInfo) {
timeInfo = callBackData.timeInfo;
}else {
timeInfo = {};
callBackData.timeInfo = timeInfo;
}
return timeInfo;
}
static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest, callBackData: ImageKnifeData) {
let resPixelmap: PixelMap | undefined = undefined
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
let decodingOptions: image.DecodingOptions = {
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
}
let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed", ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_SOURCE, LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
return
}
let size = (await imageSource.getImageInfo()).size
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
timeInfo.decodeStartTime = Date.now();
await imageSource.createPixelMap(decodingOptions)
.then((pixelmap: PixelMap) => {
timeInfo.decodeEndTime = Date.now();
resPixelmap = pixelmap
imageSource.release()
}).catch((error: BusinessError) => {
timeInfo.decodeEndTime = Date.now();
imageSource.release()
ImageKnifeLoader.makeEmptyResult(request,JSON.stringify(error), ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_PIXEL_MAP, LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
return
})
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && resPixelmap !== undefined) {
LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src)
resPixelmap = await request.transformation?.transform(request.context, resPixelmap, request.componentWidth, request.componentHeight);
LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src)
}
try {
resPixelmap?.setTransferDetached(true)
} catch (e) {
LogUtil.error("PixelMap setTransferDetached err:"+JSON.stringify(e))
}
//获取各个pixelMap的大小
if (resPixelmap && typeof resPixelmap !== "string") {
let decodeImages: Array<DecodeImageInfo> = [];
let size = (resPixelmap as PixelMap).getImageInfoSync().size;
let decodeImage: DecodeImageInfo = {
contentWidth: size.width,
contentHeight: size.height,
contentSize: (resPixelmap as PixelMap).getPixelBytesNumber()
}
decodeImages.push(decodeImage);
callBackData.decodeImages = decodeImages;
}
let res: RequestJobResult = {
pixelMap: resPixelmap,
bufferSize: resBuf.byteLength,
fileKey: fileKey,
size:size,
type:typeValue,
imageKnifeData:callBackData
}
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
}
static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
request: RequestJobRequest, callBackData: ImageKnifeData) {
let resPixelmap: PixelMap | undefined = undefined
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed", ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_SOURCE, LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
return
}
let size = (await imageSource.getImageInfo()).size
let scale = size.height / size.width
let hValue = Math.round(request.componentHeight);
let wValue = Math.round(request.componentWidth);
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
timeInfo.decodeStartTime = Date.now();
let defaultSize: image.Size = {
height: vp2px(wValue) * scale,
width: vp2px(wValue)
};
let opts: image.DecodingOptions = {
editable: true,
desiredSize: defaultSize
};
await imageSource.createPixelMap(opts)
.then((pixelmap: PixelMap) => {
timeInfo.decodeEndTime = Date.now();
resPixelmap = pixelmap
imageSource.release()
try {
resPixelmap.setTransferDetached(true)
} catch (e) {
LogUtil.error("PixelMap setTransferDetached err:"+JSON.stringify(e))
}
}).catch((error: BusinessError) => {
timeInfo.decodeEndTime = Date.now();
imageSource.release()
ImageKnifeLoader.makeEmptyResult(request,JSON.stringify(error), ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_PIXEL_MAP, LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
return
})
//获取各个pixelMap的大小
if (resPixelmap && typeof resPixelmap !== "string") {
let decodeImages: Array<DecodeImageInfo> = [];
let decodeImage: DecodeImageInfo = {
contentWidth: defaultSize.width,
contentHeight: defaultSize.height,
contentSize: (resPixelmap as PixelMap).getPixelBytesNumber()
}
decodeImages.push(decodeImage);
}
let res: RequestJobResult = {
pixelMap: resPixelmap,
bufferSize: resBuf.byteLength,
fileKey: fileKey,
type:typeValue,
imageKnifeData:callBackData
}
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
}
static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string,
fileKey: string,request: RequestJobRequest, callBackData: ImageKnifeData) {
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed", ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_CREATE_SOURCE,LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
return
}
let frameCount = await imageSource.getFrameCount()
let size = (await imageSource.getImageInfo()).size
callBackData.frameCount = frameCount;
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
imageSource.release()
if(frameCount == undefined || frameCount == 1) {
} else {
timeInfo.decodeStartTime = Date.now()
let base64str = "data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf))
timeInfo.diskCheckEndTime = Date.now()
let res: RequestJobResult = {
pixelMap: base64str,
bufferSize: resBuf.byteLength,
fileKey: fileKey,
size:size,
type:typeValue,
imageKnifeData:callBackData
}
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
return
}
ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData)
}
// 为AnimatorComponent解析动图
static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest, callBackData: ImageKnifeData) {
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
if (typeValue === 'gif' || typeValue === 'webp') {
let imageSource: image.ImageSource = image.createImageSource(resBuf);
if (imageSource === undefined){
ImageKnifeLoader.makeEmptyResult(request,"image.createImageSource failed", ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_SOURCE, LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
return
}
let decodingOptions: image.DecodingOptions = {
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
}
callBackData.imageWidth = imageSource.getImageInfoSync().size.width;
callBackData.imageHeight = imageSource.getImageInfoSync().size.height;
let pixelMapList: Array<PixelMap> = []
let delayList: Array<number> = []
timeInfo.decodeStartTime = Date.now();
let decodeImages: Array<DecodeImageInfo> = [];
await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => {
timeInfo.decodeEndTime = Date.now();
//sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList()
await imageSource.getDelayTimeList().then(delayTimes => {
if (pixelList.length > 0) {
for (let i = 0; i < pixelList.length; i++) {
pixelMapList.push(pixelList[i]);
if (i < delayTimes.length) {
delayList.push(delayTimes[i]);
} else {
delayList.push(delayTimes[delayTimes.length - 1])
}
//获取各个pixelMap的大小
let size = pixelList[i].getImageInfoSync().size
let decodeImage: DecodeImageInfo = {
contentWidth: size.width,
contentHeight: size.height,
contentSize: pixelList[i].getPixelBytesNumber()
}
decodeImages.push(decodeImage);
}
imageSource.release();
}
})
}).catch((error: BusinessError) => {
imageSource.release()
timeInfo.decodeEndTime = Date.now();
ImageKnifeLoader.makeEmptyResult(request,JSON.stringify(error), ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_CREATE_PIXEL_MAP,LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
return
})
callBackData.decodeImages = decodeImages;
let res: RequestJobResult = {
pixelMap: "",
bufferSize: resBuf.byteLength,
fileKey: fileKey,
type: typeValue,
imageKnifeData:callBackData,
pixelMapList,
delayList
}
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { "value": res } })
} else {
ImageKnifeLoader.makeEmptyResult(request,"ImageKnifeAnimatorComponent组件仅支持动态图", ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_PARSE_IAMGE,LoadPixelMapCode.IMAGE_FORMAT_ERROR_CODE))
}
}
static getHeaderObj(request:RequestJobRequest){
const headerObj: Record<string, Object> = {}
if (request.headers != undefined) {
request.headers.forEach((value) => {
headerObj[value.key] = value.value
})
} else if (request.allHeaders.size > 0) {
request.allHeaders.forEach((value, key) => {
headerObj[key] = value
})
}
return headerObj
}
static FileCacheParseImage(request:RequestJobRequest,resBuf:ArrayBuffer,fileKey:string, callBackData: ImageKnifeData){
// 保存文件缓存
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:"+request.src)
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder)
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:"+request.src)
}
ImageKnifeLoader.parseImage(resBuf,fileKey,request, callBackData)
}
// 获取图片资源
static async getImageArrayBuffer(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined,fileKey:string) {
let resBuf: ArrayBuffer | undefined
let loadError: string = ""
//定义图片各个阶段错误信息
let error: ErrorInfo = { code: 0, phase: LoadPhase.PHASE_LOAD }
//定义加载时间点
let callBackTimeInfo: TimeInfo = {};
//定义加载信息回调数据
let callBackData: ImageKnifeData = {
source: "",
imageWidth: 0,
imageHeight: 0,
timeInfo: callBackTimeInfo,
errorInfo: error
};
// 判断自定义下载
if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == "string") {
// 先从文件缓存获取
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_CUSTOM_LOAD)
callBackTimeInfo.diskCheckStartTime = Date.now();
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
callBackTimeInfo.diskCheckEndTime = Date.now();
if (resBuf === undefined) {
LogUtil.log("start customGetImage src=" + request.src)
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request)
try {
request.customGetImage(request.context, request.src, headerObj)
.then((buffer)=>{
if(buffer != undefined) {
ImageKnifeLoader.FileCacheParseImage(request,buffer,fileKey,callBackData)
} else {
loadError = "customGetImage loadFail undefined"
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE))
}
}).catch((err:string)=>{
ImageKnifeLoader.makeEmptyResult(request,err, ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE))
})
} catch (e) {
loadError = "customGetImage loadFail failed"
ImageKnifeLoader.makeEmptyResult(request,loadError + e, ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CUSTOM_LOAD, LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE))
}
LogUtil.log("end customGetImage src=" + request.src)
return
}
}
else {
if (typeof request.src === 'string') {
if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载
// 先从文件缓存获取
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET)
callBackTimeInfo.diskCheckStartTime = Date.now()
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
callBackTimeInfo.diskCheckEndTime = Date.now()
if (resBuf !== undefined){
LogUtil.log("success get image from filecache for key = " + fileKey + " src = " + request.src)
}
else if (request.onlyRetrieveFromCache != true) {
LogUtil.log("HttpDownloadClient.start:" + request.src)
callBackTimeInfo.netRequestStartTime = Date.now();
let httpRequest = http.createHttp();
let progress: number = 0
let arrayBuffers = new Array<ArrayBuffer>()
const headerObj: Record<string, Object> = ImageKnifeLoader.getHeaderObj(request)
httpRequest.on("dataReceive", (data: ArrayBuffer) => {
arrayBuffers.push(data)
});
if (request.isWatchProgress) {
httpRequest.on('dataReceiveProgress', (data: RequestData) => {
// 下载进度
if (data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number')) {
let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100)
if (progress !== percent) {
progress = percent
if (requestList === undefined) {
// 子线程
emitter.emit(Constants.PROGRESS_EMITTER + request.memoryKey, { data: { "value": progress } })
}else {
// 主线程请求
requestList!.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
requestWithSource.request.imageKnifeOption.progressListener(progress)
}
})
}
}
}
})
}
let promise = httpRequest.requestInStream(request.src, {
header: headerObj,
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
connectTimeout: 60000,
readTimeout: 0,
// usingProtocol:http.HttpProtocol.HTTP1_1
// header: new Header('application/json')
});
promise.then((data: number) => {
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, undefined, data)
callBackTimeInfo.netRequestEndTime = Date.now();
if (data == 200 || data == 206 || data == 204) {
resBuf = combineArrayBuffers(arrayBuffers)
ImageKnifeLoader.FileCacheParseImage(request,resBuf,fileKey, callBackData)
} else {
loadError = "HttpDownloadClient has error, http code =" + JSON.stringify(data)
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE, data))
}
}).catch((err: Error) => {
loadError = "HttpDownloadClient download ERROR : err = " + JSON.stringify(err)
callBackTimeInfo.netRequestEndTime = Date.now();
ImageKnifeLoader.makeEmptyResult(request,loadError, ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_NET, LoadPixelMapCode.IMAGE_HTTPS_LOAD_FAILED_CODE, undefined))
});
LogUtil.log("HttpDownloadClient.end:" + request.src)
return
}
else {
callBackTimeInfo.netRequestEndTime = Date.now();
loadError = 'onlyRetrieveFromCache,do not fetch image src = ' + request.src
}
} else if (request.src.startsWith('datashare://') || request.src.startsWith('file://')) {
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE)
await fs.open(request.src, fs.OpenMode.READ_ONLY).then(async (file) => {
await fs.stat(file.fd).then(async (stat) =>{
let buf = new ArrayBuffer(stat.size);
await fs.read(file.fd, buf).then((readLen) => {
resBuf = buf;
fs.closeSync(file.fd);
}).catch((err:BusinessError) => {
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
loadError = 'LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code
})
}).catch((err:BusinessError) => {
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
loadError = 'LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code
})
}).catch((err:BusinessError) => {
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_SHARE_FILE, LoadPixelMapCode.IMAGE_LOAD_SHARE_FILE_FAILED_CODE)
loadError = 'LoadDataShareFileClient fs.open err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code
})
} else { //从本地文件获取
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_LOCAL_FILE)
try {
let stat = fs.statSync(request.src);
if (stat.size > 0) {
let file = fs.openSync(request.src, fs.OpenMode.READ_ONLY);
resBuf = new ArrayBuffer(stat.size);
fs.readSync(file.fd, resBuf);
fs.closeSync(file);
}
} catch (err) {
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_LOCAL_FILE, LoadPixelMapCode.IMAGE_LOAD_LOCAL_FILE_FAILED_CODE)
loadError = err
}
}
} else if (typeof request.src == "number") { //从资源文件获取
let manager = request.context.createModuleContext(request.moduleName).resourceManager
if (resBuf == undefined && request.onlyRetrieveFromCache != true && request.requestSource == ImageKnifeRequestSource.SRC) {
if(request.src == -1) {
let resName = request.resName as string
resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer
} else {
resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer
}
} else if (resBuf == undefined && request.requestSource != ImageKnifeRequestSource.SRC) {
if(request.src == -1) {
let resName = request.resName as string
resBuf = (await manager.getMediaByName(resName.substring(10))).buffer as ArrayBuffer
} else {
resBuf = manager.getMediaContentSync(request.src).buffer as ArrayBuffer
}
}
}
}
if (resBuf === undefined){
callBackTimeInfo.requestEndTime = Date.now();
ImageKnifeLoader.makeEmptyResult(request,loadError ,callBackData)
return
}
ImageKnifeLoader.parseImage(resBuf,fileKey,request, callBackData)
}
}

View File

@ -13,12 +13,12 @@
* limitations under the License. * limitations under the License.
*/ */
import util from '@ohos.util'; import util from '@ohos.util';
import { FileUtils } from './FileUtils'; import { FileUtils } from '../utils/FileUtils';
import fs from '@ohos.file.fs'; import fs from '@ohos.file.fs';
import { LogUtil } from './LogUtil'; import { LogUtil } from '../utils/LogUtil';
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'; import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5';
const INT_MAX = 2147483647
/** /**
* 二级文件缓存 * 二级文件缓存
* 主线程通过lruCache管理缓存大小 * 主线程通过lruCache管理缓存大小
@ -34,12 +34,12 @@ export class FileCache {
private isInited: boolean = false private isInited: boolean = false
private context?: Context private context?: Context
readonly defaultMaxSize: number = 512; readonly defaultMaxSize: number = 512;
readonly defaultSize: number = 128; readonly defaultSize: number = INT_MAX;
readonly defaultMaxMemorySize: number = 512 * 1024 * 1024; readonly defaultMaxMemorySize: number = 512 * 1024 * 1024;
readonly defaultMemorySize: number = 128 * 1024 * 1024; readonly defaultMemorySize: number = 128 * 1024 * 1024;
constructor(context: Context, size: number, memory: number) { constructor(context: Context, size: number, memory: number) {
if (size <= 0) { if (size <= 0 || size > INT_MAX) {
size = this.defaultSize size = this.defaultSize
} }
if (memory <= 0 || memory > this.defaultMaxMemorySize) { if (memory <= 0 || memory > this.defaultMaxMemorySize) {
@ -232,18 +232,18 @@ export class FileCache {
} }
else if (value != undefined) { else if (value != undefined) {
this.currentMemory -= value.byteLength this.currentMemory -= value.byteLength
LogUtil.info("FileCache removeMemorySize: " + value.byteLength + " currentMemory" + this.currentMemory) LogUtil.debug("FileCache removeMemorySize: " + value.byteLength + " currentMemory" + this.currentMemory)
} }
} }
private addMemorySize(value: ArrayBuffer | number): void { private addMemorySize(value: ArrayBuffer | number): void {
if (typeof value == "number") { if (typeof value == "number") {
this.currentMemory += value this.currentMemory += value
LogUtil.info("FileCache addMemorySize: " + value + " currentMemory" + this.currentMemory) LogUtil.debug("FileCache addMemorySize: " + value + " currentMemory" + this.currentMemory)
} }
else if (value != undefined) { else if (value != undefined) {
this.currentMemory += value.byteLength this.currentMemory += value.byteLength
LogUtil.info("FileCache addMemorySize: " + value.byteLength + " currentMemory" + this.currentMemory) LogUtil.debug("FileCache addMemorySize: " + value.byteLength + " currentMemory" + this.currentMemory)
} }
} }

View File

@ -12,8 +12,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { AnimatorOption, ImageKnifeOption } from '../ImageKnifeOption'; import { AnimatorOption, ImageKnifeOption } from '../model/ImageKnifeOption';
import { ImageKnifeRequest, ImageKnifeRequestState } from '../ImageKnifeRequest'; import { ImageKnifeRequest, ImageKnifeRequestState } from '../model/ImageKnifeRequest';
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
import { ImageKnife } from '../ImageKnife'; import { ImageKnife } from '../ImageKnife';
import { LogUtil } from '../utils/LogUtil'; import { LogUtil } from '../utils/LogUtil';
@ -22,12 +22,9 @@ import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
@Component @Component
export struct ImageKnifeAnimatorComponent { export struct ImageKnifeAnimatorComponent {
@Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption; @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
@Watch('watchAnimatorOption') @State animatorOption: AnimatorOption = new AnimatorOption(); @State animatorOption: AnimatorOption = new AnimatorOption();
@State pixelMap: PixelMap | string | undefined = undefined @State pixelMap: PixelMap | string | undefined = undefined
@State imageAnimator: Array<ImageFrameInfo> | undefined = undefined @State imageAnimator: Array<ImageFrameInfo> | undefined = undefined
@State state: AnimationStatus = AnimationStatus.Running
@State iterations: number = -1
@State reverse: boolean = false
@State adaptiveWidth: Length = '100%' @State adaptiveWidth: Length = '100%'
@State adaptiveHeight: Length = '100%' @State adaptiveHeight: Length = '100%'
@State objectFit: ImageFit = ImageFit.Contain @State objectFit: ImageFit = ImageFit.Contain
@ -64,9 +61,9 @@ export struct ImageKnifeAnimatorComponent {
.width(this.adaptiveWidth) .width(this.adaptiveWidth)
.height(this.adaptiveHeight) .height(this.adaptiveHeight)
.border(this.imageKnifeOption.border) .border(this.imageKnifeOption.border)
.state(this.state) .state(this.animatorOption.state == undefined ? AnimationStatus.Running : this.animatorOption.state)
.iterations(this.iterations) .iterations(this.animatorOption.iterations == undefined ? -1 : this.animatorOption.iterations)
.reverse(this.reverse) .reverse(this.animatorOption.reverse == undefined ? false : this.animatorOption.reverse)
.onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => { .onSizeChange((oldValue:SizeOptions, newValue:SizeOptions) => {
this.currentWidth = newValue.width as number this.currentWidth = newValue.width as number
this.currentHeight = newValue.height as number this.currentHeight = newValue.height as number
@ -82,18 +79,11 @@ export struct ImageKnifeAnimatorComponent {
} }
} }
}) })
} .onStart(this.animatorOption.onStart)
.onFinish(this.animatorOption.onFinish)
watchAnimatorOption(){ .onPause(this.animatorOption.onPause)
if(this.animatorOption.state != undefined) { .onCancel(this.animatorOption.onCancel)
this.state = this.animatorOption.state .onRepeat(this.animatorOption.onRepeat)
}
if(this.animatorOption.iterations != undefined) {
this.iterations = this.animatorOption.iterations
}
if(this.animatorOption.reverse != undefined) {
this.reverse = this.animatorOption.reverse
}
} }
watchImageKnifeOption() { watchImageKnifeOption() {
@ -121,7 +111,7 @@ export struct ImageKnifeAnimatorComponent {
height, height,
this.componentVersion, this.componentVersion,
{ {
showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => { showPixelMap: (version: number, pixelMap: PixelMap | string,size: Size, requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => {
if (version !== this.componentVersion) { if (version !== this.componentVersion) {
return //针对reuse场景不显示历史图片 return //针对reuse场景不显示历史图片
} }

View File

@ -12,8 +12,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeOption } from '../ImageKnifeOption'; import { ImageKnifeOption } from '../model/ImageKnifeOption';
import { ImageKnifeRequest, ImageKnifeRequestState } from '../ImageKnifeRequest'; import { ImageKnifeRequest, ImageKnifeRequestState } from '../model/ImageKnifeRequest';
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
import { ImageKnife } from '../ImageKnife'; import { ImageKnife } from '../ImageKnife';
import { LogUtil } from '../utils/LogUtil'; import { LogUtil } from '../utils/LogUtil';
@ -24,7 +24,7 @@ import { DefaultEngineKey } from '../key/DefaultEngineKey';
@Component @Component
export struct ImageKnifeComponent { export struct ImageKnifeComponent {
@Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption; @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
@State pixelMap: PixelMap | string | undefined = undefined @State pixelMap: PixelMap | string | ImageContent | undefined = undefined
@State syncLoad: boolean = false @State syncLoad: boolean = false
@State adaptiveWidth: Length = '100%' @State adaptiveWidth: Length = '100%'
@State adaptiveHeight: Length = '100%' @State adaptiveHeight: Length = '100%'
@ -38,43 +38,48 @@ export struct ImageKnifeComponent {
private currentContext: common.UIAbilityContext | undefined = undefined private currentContext: common.UIAbilityContext | undefined = undefined
aboutToAppear(): void { aboutToAppear(): void {
//闪动问题失效,注释相应代码后续修复 this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
if(this.syncLoad) {
if(this.syncLoad) { //针对部分消息列表最新消息的图片闪动问题建议使用同步方式在aboutToAppear时加载图片
let engineKey: IEngineKey = new DefaultEngineKey(); let engineKey: IEngineKey = new DefaultEngineKey();
let memoryCacheSrc: ImageKnifeData | undefined = ImageKnife.getInstance() let memoryCacheSrc: ImageKnifeData | undefined = ImageKnife.getInstance()
.loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption))
if (memoryCacheSrc !== undefined){ if (memoryCacheSrc !== undefined){
LogUtil.log("aboutToAppear load from memory cache for key = "+ engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) LogUtil.log("aboutToAppear success load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc)
//画主图
this.pixelMap = memoryCacheSrc.source; this.pixelMap = memoryCacheSrc.source;
}else{ }else{
LogUtil.log("aboutToAppear fail load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc)
if (this.imageKnifeOption.placeholderSrc !== undefined){
let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance() let memoryCachePlace: ImageKnifeData | undefined = ImageKnife.getInstance()
.loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,ImageKnifeRequestSource.PLACE_HOLDER,this.imageKnifeOption)) .loadFromMemoryCache(engineKey.generateMemoryKey(this.imageKnifeOption.placeholderSrc!,ImageKnifeRequestSource.PLACE_HOLDER,this.imageKnifeOption))
if (memoryCachePlace !== undefined){ if (memoryCachePlace !== undefined){
LogUtil.log("aboutToAppear load from memory cache for key = "+ engineKey.generateMemoryKey(this.imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,this.imageKnifeOption)) LogUtil.log("aboutToAppear success load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc)
//画主图
this.pixelMap = memoryCachePlace.source; this.pixelMap = memoryCachePlace.source;
}else{
LogUtil.log("aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc)
}
} }
} }
} }
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
} }
aboutToDisappear(): void { aboutToDisappear(): void {
if (this.request !== undefined) { this.clearLastRequest()
this.request.requestState = ImageKnifeRequestState.DESTROY
this.request = undefined
}
} }
aboutToRecycle() { aboutToRecycle() {
this.pixelMap = ImageContent.EMPTY
this.clearLastRequest()
}
/**
* 对已DESTROY的组件不再发起请求
*/
private clearLastRequest(){
if (this.request !== undefined) { if (this.request !== undefined) {
this.request.requestState = ImageKnifeRequestState.DESTROY this.request.requestState = ImageKnifeRequestState.DESTROY
this.request = undefined this.request = undefined
} }
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
} }
build() { build() {
Image(this.pixelMap) Image(this.pixelMap)
.colorFilter(this.imageKnifeOption.drawingColorFilter) .colorFilter(this.imageKnifeOption.drawingColorFilter)
@ -103,11 +108,13 @@ export struct ImageKnifeComponent {
} }
watchImageKnifeOption() { watchImageKnifeOption() {
if (this.request !== undefined) { this.clearLastRequest()
this.request.requestState = ImageKnifeRequestState.DESTROY
}
this.request = undefined
this.componentVersion++ this.componentVersion++
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
LogUtil.log("watchImageKnifeOption execute request:width=" + this.currentWidth + " height= " + this.currentHeight
+ " loadSrc = " + this.request?.imageKnifeOption.loadSrc
+ " placeholderSrc = " + this.request?.imageKnifeOption.placeholderSrc
+ " errorholderSrc = " + this.request?.imageKnifeOption.errorholderSrc)
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight)) ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight))
} }
@ -127,17 +134,16 @@ export struct ImageKnifeComponent {
height, height,
this.componentVersion, this.componentVersion,
{ {
showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource) => { showPixelMap: (version: number, pixelMap: PixelMap | string,size:Size, requestSource: ImageKnifeRequestSource) => {
if (version !== this.componentVersion) { if (version !== this.componentVersion) {
return //针对reuse场景不显示历史图片 return //针对reuse场景不显示历史图片
} }
this.pixelMap = pixelMap this.pixelMap = pixelMap
if (typeof this.pixelMap !== 'string') { if (typeof this.pixelMap !== 'string') {
if (this.imageKnifeOption.objectFit === ImageFit.Auto) { if (this.imageKnifeOption.objectFit === ImageFit.Auto) {
let info = await this.pixelMap.getImageInfo()
this.adaptiveWidth = this.currentWidth this.adaptiveWidth = this.currentWidth
this.adaptiveHeight = info.size.height * this.currentWidth / info.size.width this.adaptiveHeight = size.height * this.currentWidth / size.width
// if (this.currentWidth / this.currentHeight > info.size.width / info.size.height) { // if (this.currentWidth / this.currentHeight > info.size.width / info.size.height) {
// this.adaptiveWidth = this.currentWidth // this.adaptiveWidth = this.currentWidth

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'; import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5';
import { ImageKnifeOption } from '../ImageKnifeOption'; import { ImageKnifeOption } from '../model/ImageKnifeOption';
import { IEngineKey } from './IEngineKey'; import { IEngineKey } from './IEngineKey';
import { PixelMapTransformation } from '../transform/PixelMapTransformation'; import { PixelMapTransformation } from '../transform/PixelMapTransformation';
import { ImageKnifeRequestSource } from '../model/ImageKnifeData'; import { ImageKnifeRequestSource } from '../model/ImageKnifeData';

View File

@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeOption } from '../ImageKnifeOption' import { ImageKnifeOption } from '../model/ImageKnifeOption'
import { ImageKnifeRequestSource } from '../model/ImageKnifeData' import { ImageKnifeRequestSource } from '../model/ImageKnifeData'
export interface IEngineKey { export interface IEngineKey {

View File

@ -12,20 +12,61 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { HeaderOptions } from '../ImageKnifeOption' import { HeaderOptions } from './ImageKnifeOption'
import { ImageKnifeRequest } from '../ImageKnifeRequest' import { ImageKnifeRequest } from './ImageKnifeRequest'
import { IEngineKey } from '../key/IEngineKey' import { IEngineKey } from '../key/IEngineKey'
import { PixelMapTransformation } from '../transform/PixelMapTransformation' import { PixelMapTransformation } from '../transform/PixelMapTransformation'
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
import { Size } from '@kit.ArkUI' import { Size } from '@kit.ArkUI'
export interface ImageKnifeData { export interface ImageKnifeData {
source: PixelMap | string, source: PixelMap | string, // url
imageWidth: number, imageWidth: number, // 原始宽高大小
imageHeight: number, imageHeight: number,
bufSize?: number, // 图片的字节数
type?:string, type?:string,
imageAnimator?: Array<ImageFrameInfo> imageAnimator?: Array<ImageFrameInfo>
frameCount ?: number // 帧
decodeImages?: Array<DecodeImageInfo> //Image组件或者ImageAnimator组件可以加载一张或者多张
timeInfo?: TimeInfo // 加载图片的各个时间点
errorInfo?: ErrorInfo // 错误
} }
/**
* 解码后的图片的size
*/
export interface DecodeImageInfo {
contentWidth ?: number // 解码后宽高
contentHeight?: number
contentSize ?: number // 大小
}
/**
* 加载的错误信息
*/
export interface ErrorInfo {
phase: string, //图片加载阶段信息,如:网络加载阶段,缓存获取阶段及其解码阶段等
code: number,
httpCode?: number
}
/**
* load检查时间点
*/
export interface TimeInfo {
requestStartTime?: number,
requestEndTime?: number,
requestCancelTime?: number,
memoryCheckStartTime?: number,
memoryCheckEndTime?: number,
diskCheckStartTime?: number,
diskCheckEndTime?: number,
netRequestStartTime?: number,
netRequestEndTime?: number,
decodeStartTime?: number,
decodeEndTime?: number,
}
/** /**
* onComplete成功回调 * onComplete成功回调
*/ */
@ -78,7 +119,8 @@ export interface RequestJobResult {
size?:Size, size?:Size,
type?: string, type?: string,
pixelMapList?:Array<PixelMap>, pixelMapList?:Array<PixelMap>,
delayList?: Array<number> delayList?: Array<number>,
imageKnifeData?: ImageKnifeData,
} }
/** /**
@ -86,12 +128,12 @@ export interface RequestJobResult {
*/ */
export interface RequestJobRequest { export interface RequestJobRequest {
context: common.UIAbilityContext, context: common.UIAbilityContext,
src: string | PixelMap | Resource, src: string | number,
headers?: Array<HeaderOptions>, headers?: Array<HeaderOptions>,
allHeaders: Map<string, Object>, allHeaders: Map<string, Object>,
componentWidth: number, componentWidth: number,
componentHeight: number, componentHeight: number,
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined>, customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>,
onlyRetrieveFromCache?: boolean onlyRetrieveFromCache?: boolean
requestSource: ImageKnifeRequestSource requestSource: ImageKnifeRequestSource
transformation?: PixelMapTransformation transformation?: PixelMapTransformation
@ -101,6 +143,8 @@ export interface RequestJobRequest {
isWatchProgress: boolean isWatchProgress: boolean
memoryKey: string memoryKey: string
fileCacheFolder: string, fileCacheFolder: string,
isAnimator?: boolean isAnimator?: boolean,
moduleName?:string,
resName?: string
} }

View File

@ -14,9 +14,10 @@
*/ */
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { CacheStrategy, ImageKnifeData,EventImage } from './model/ImageKnifeData'; import { CacheStrategy, ImageKnifeData,EventImage } from './ImageKnifeData';
import { PixelMapTransformation } from './transform/PixelMapTransformation'; import { PixelMapTransformation } from '../transform/PixelMapTransformation';
import { drawing } from '@kit.ArkGraphics2D'; import { drawing } from '@kit.ArkGraphics2D';
import { ImageKnifeRequest } from './ImageKnifeRequest';
export interface HeaderOptions { export interface HeaderOptions {
key: string; key: string;
@ -31,6 +32,16 @@ export class AnimatorOption {
iterations?: number = -1 iterations?: number = -1
@Track @Track
reverse?: boolean = false reverse?: boolean = false
@Track
onStart?:()=>void
@Track
onFinish?:()=>void
@Track
onPause?:()=>void
@Track
onCancel?:()=>void
@Track
onRepeat?:()=>void
} }
@Observed @Observed
@ -50,7 +61,7 @@ export class ImageKnifeOption {
placeholderObjectFit?: ImageFit placeholderObjectFit?: ImageFit
// 错误图填充效果 // 错误图填充效果
errorholderObjectFit?: ImageFit errorholderObjectFit?: ImageFit
customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined> customGetImage?: (context: Context, src: string | PixelMap | Resource,headers?: Record<string,Object>) => Promise<ArrayBuffer | undefined>
border?: BorderOptions border?: BorderOptions
// 缓存策略 // 缓存策略
writeCacheStrategy?: CacheStrategy writeCacheStrategy?: CacheStrategy
@ -73,13 +84,13 @@ export class ImageKnifeOption {
*/ */
export interface OnLoadCallBack { export interface OnLoadCallBack {
// 请求开始 // 请求开始
onLoadStart?: () => void; onLoadStart?: (request?: ImageKnifeRequest) => void;
// 请求成功 // 请求成功
onLoadSuccess?: (data: string | PixelMap | undefined, imageKnifeData: ImageKnifeData) => void; onLoadSuccess?: (data: string | PixelMap | undefined, imageKnifeData: ImageKnifeData, request?: ImageKnifeRequest) => void;
// 请求结束 // 请求结束
onLoadFailed?: (err: string) => void; onLoadFailed?: (err: string, request?: ImageKnifeRequest) => void;
// 请求取消 // 请求取消
onLoadCancel?: (reason: string) => void; onLoadCancel?: (reason: string, request?: ImageKnifeRequest) => void;
} }

View File

@ -14,7 +14,7 @@
*/ */
import { ImageKnifeOption } from './ImageKnifeOption'; import { ImageKnifeOption } from './ImageKnifeOption';
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
import { ImageKnifeRequestSource } from './model/ImageKnifeData'; import { ImageKnifeData, ImageKnifeRequestSource } from './ImageKnifeData';
export class ImageKnifeRequest { export class ImageKnifeRequest {
@ -27,6 +27,7 @@ export class ImageKnifeRequest {
ImageKnifeRequestCallback: ImageKnifeRequestCallback ImageKnifeRequestCallback: ImageKnifeRequestCallback
componentVersion: number = 0 componentVersion: number = 0
headers: Map<string,Object> = new Map<string,Object>() headers: Map<string,Object> = new Map<string,Object>()
private imageCallBackData: ImageKnifeData | undefined = undefined;
constructor(option: ImageKnifeOption, constructor(option: ImageKnifeOption,
uIAbilityContext: common.UIAbilityContext, uIAbilityContext: common.UIAbilityContext,
width: number, width: number,
@ -53,6 +54,14 @@ export class ImageKnifeRequest {
} }
}) })
} }
setImageKnifeData(data: ImageKnifeData) {
this.imageCallBackData = data;
}
getImageKnifeData(): ImageKnifeData | undefined {
return this.imageCallBackData
}
} }
export enum ImageKnifeRequestState { export enum ImageKnifeRequestState {
@ -64,5 +73,5 @@ export enum ImageKnifeRequestState {
export interface ImageKnifeRequestCallback { export interface ImageKnifeRequestCallback {
showPixelMap: (version: number, pixelMap: PixelMap | string , requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => void; showPixelMap: (version: number, pixelMap: PixelMap | string ,size: Size, requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => void;
} }

View File

@ -12,15 +12,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeRequest } from '../ImageKnifeRequest'; import { ImageKnifeRequest } from '../model/ImageKnifeRequest';
import { IJobQueue } from './IJobQueue' import { IJobQueue } from './IJobQueue'
import Queue from '@ohos.util.Queue'; import Queue from '@ohos.util.Queue';
import { taskpool,Stack } from '@kit.ArkTS'; import { taskpool,Stack } from '@kit.ArkTS';
export class DefaultJobQueue implements IJobQueue { export class DefaultJobQueue implements IJobQueue {
highQueue: Stack<ImageKnifeRequest> = new Stack(); highQueue: Queue<ImageKnifeRequest> = new Queue();
normalQueue: Stack<ImageKnifeRequest> = new Stack(); normalQueue: Queue<ImageKnifeRequest> = new Queue();
lowQueue: Stack<ImageKnifeRequest> = new Stack(); lowQueue: Queue<ImageKnifeRequest> = new Queue();
getQueueLength(): number { getQueueLength(): number {
return this.highQueue.length + this.normalQueue.length + this.lowQueue.length return this.highQueue.length + this.normalQueue.length + this.lowQueue.length
@ -28,11 +28,11 @@ export class DefaultJobQueue implements IJobQueue {
add(request: ImageKnifeRequest): void { add(request: ImageKnifeRequest): void {
if (request.imageKnifeOption.priority === undefined || request.imageKnifeOption.priority === taskpool.Priority.MEDIUM) { if (request.imageKnifeOption.priority === undefined || request.imageKnifeOption.priority === taskpool.Priority.MEDIUM) {
this.normalQueue.push(request) this.normalQueue.add(request)
} else if (request.imageKnifeOption.priority === taskpool.Priority.HIGH) { } else if (request.imageKnifeOption.priority === taskpool.Priority.HIGH) {
this.highQueue.push(request) this.highQueue.add(request)
} else { } else {
this.lowQueue.push(request) this.lowQueue.add(request)
} }
} }

View File

@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { ImageKnifeRequest } from '../ImageKnifeRequest' import { ImageKnifeRequest } from '../model/ImageKnifeRequest'
export interface IJobQueue { export interface IJobQueue {

View File

@ -14,4 +14,61 @@
*/ */
export class Constants { export class Constants {
public static PROGRESS_EMITTER: string = "progressEmitter" public static PROGRESS_EMITTER: string = "progressEmitter"
public static CALLBACK_EMITTER: string = "callBackEmitter"
}
/**
* 图片加载的code
*/
export enum LoadPixelMapCode {
// createImageSource error code
IMAGE_SOURCE_ERROR_CODE = 100001,
// createPixelMap error code
IMAGE_DECODE_ERROR_CODE = 100002,
//ImageKnifeAnimatorComponent组件仅支持动态图 code
IMAGE_FORMAT_ERROR_CODE = 100003,
//load failed code
IMAGE_LOAD_FAILED_CODE = 100004,
//自定义下载失败 code
IMAGE_CUSTOM_LOAD_FAILED_CODE = 100005,
// http请求失败 code
IMAGE_HTTPS_LOAD_FAILED_CODE = 100006,
//设置onlyRetrieveFromCache 导致的加载失败的code
IMAGE_RETRIEVE_CACHE_CODE = 100007,
//加载共享图片失败code
IMAGE_LOAD_SHARE_FILE_FAILED_CODE = 100008,
//加载本地文件图片失败code
IMAGE_LOAD_LOCAL_FILE_FAILED_CODE = 100009,
// 取消请求加载code
IMAGE_LOAD_CANCEL_FAILED_CODE = 1000010,
// 解析图片格式阶段
IMAGE_PARSE_FORMAT_FAILED_CODE = 1000011
}
/**
* 图片加载的各个阶段
*/
export enum LoadPhase {
// 图片加载阶段
PHASE_LOAD = "load",
// 网络请求下载阶段
PHASE_NET = "net",
//获取图片格式阶段
PHASE_GET_FORMAT = "parse_format",
//自定义下载阶段 customGetImage
PHASE_CUSTOM_LOAD = "customGetImage",
// createPixelMap 阶段
PHASE_CREATE_SOURCE = "createImageSource",
//createPixelMap 阶段
PHASE_CREATE_PIXEL_MAP = "createPixelMap",
//请求队列排队阶段
PHASE_THREAD_QUEUE = "thread_queue",
//图片解析阶段
PHASE_PARSE_IAMGE = "parseImage",
//加载解析datashare:// 或者file:// 阶段
PHASE_SHARE_FILE = "datashare_or_file",
//加载解析本地文件阶段
PHASE_LOCAL_FILE = "load_local_file",
//图片加载解析完成,即将显示的阶段
PHASE_WILL_SHOW = "will_show",
} }

View File

@ -176,6 +176,7 @@ export class FileUtils {
let length = stat.size; let length = stat.size;
let buf = new ArrayBuffer(length); let buf = new ArrayBuffer(length);
await fs.read(fd, buf); await fs.read(fd, buf);
await fs.close(fd)
return buf return buf
} catch (error) { } catch (error) {
let err: BusinessError = error as BusinessError; let err: BusinessError = error as BusinessError;

View File

@ -12,44 +12,29 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { hilog } from '@kit.PerformanceAnalysisKit';
export class LogUtil { export class LogUtil {
public static OFF: number = 1 public static readonly DOMAIN: number = 0xD002220;
public static LOG: number = 2 public static readonly TAG: string = "ImageKnife::";
public static DEBUG: number = 3
public static INFO: number = 4
public static WARN: number = 5
public static ERROR: number = 6
public static ALL: number = 7
public static mLogLevel: number = LogUtil.OFF;
public static TAG: string = "ImageKnife:: ";
public static debug(message: string, ...args: Object[]) { public static debug(message: string, ...args: Object[]) {
if (LogUtil.mLogLevel >= LogUtil.DEBUG) { hilog.debug(LogUtil.DOMAIN, LogUtil.TAG, message, args)
console.debug(LogUtil.TAG + message, args)
}
} }
public static info(message: string, ...args: Object[]) { public static info(message: string, ...args: Object[]) {
if (LogUtil.mLogLevel >= LogUtil.INFO) { hilog.info(LogUtil.DOMAIN, LogUtil.TAG, message, args)
console.info(LogUtil.TAG + message, args)
}
} }
public static log(message: string, ...args: Object[]) { public static log(message: string, ...args: Object[]) {
if (LogUtil.mLogLevel >= LogUtil.LOG) { hilog.debug(LogUtil.DOMAIN, LogUtil.TAG, message, args)
console.log(LogUtil.TAG + message, args)
}
} }
public static warn(message: string, ...args: Object[]) { public static warn(message: string, ...args: Object[]) {
if (LogUtil.mLogLevel >= LogUtil.WARN) { hilog.warn(LogUtil.DOMAIN, LogUtil.TAG, message, args)
console.warn(LogUtil.TAG + message, args)
}
} }
public static error(message: string, ...args: Object[]) { public static error(message: string, ...args: Object[]) {
if (LogUtil.mLogLevel >= LogUtil.ERROR) { hilog.error(LogUtil.DOMAIN, LogUtil.TAG, message, args)
console.error(LogUtil.TAG + message, args)
}
} }
} }

View File

@ -1,35 +0,0 @@
/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'
import util from '@ohos.util'
export class Tools {
private static keyCache: util.LRUCache<string,string> = new util.LRUCache(1024)
public static generateMemoryKey(key: string | PixelMap | Resource): string{
return typeof key == "string"? key : JSON.stringify(key)
}
// 生成唯一的key
public static generateKey(key: string | PixelMap | Resource): string{
let keyCache = typeof key == "string"? key : JSON.stringify(key)
let result = Tools.keyCache.get(keyCache)
if(result != undefined) {
return result
} else {
result = SparkMD5.hashBinary(keyCache)
Tools.keyCache.put(keyCache,result)
return result
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -21,7 +21,7 @@ export struct IndexComponent {
} }
build() { build() {
Column() { Column() {
Button("预加载").onClick((event: ClickEvent) => { Button("preload").onClick((event: ClickEvent) => {
ImageKnife.getInstance() ImageKnife.getInstance()
.preLoadCache('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp') .preLoadCache('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp')
.then((data) => { .then((data) => {