Compare commits

..

112 Commits

Author SHA1 Message Date
landwind bc55de9e2e Modify the README file
Signed-off-by: landwind <mamingshuai1@huawei.com>
2025-04-28 10:56:30 +08:00
openharmony_ci c1426cd35a
!463 项目配置文件新增设备类型,样例设置混淆
Merge pull request !463 from zgf/master
2025-02-20 03:00:15 +00:00
zgf adb78853af 项目配置文件新增设备类型,样例设置混淆
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-02-19 17:39:29 +08:00
openharmony_ci 9e387602f6
!461 支持图片携带的EXIF元数据作为显示方向
Merge pull request !461 from yang/master
2025-02-19 09:24:27 +00:00
yang 115118e238 支持图片携带的EXIF元数据作为显示方向
Signed-off-by: yang <yangweiping7@h-partners.com>
2025-02-19 14:46:37 +08:00
openharmony_ci acb45a66bc
!460 修改版本号3.2.2-rc.0
Merge pull request !460 from zgf/master
2025-02-18 07:51:13 +00:00
zgf 25b7899746 修改版本号3.2.2-rc.0
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-02-18 15:03:11 +08:00
openharmony_ci e41fce46bf
!459 增加ImageKnifeComponent组件销毁网络请求中断
Merge pull request !459 from zgf/master
2025-02-18 03:56:03 +00:00
zgf 8601f87865 增加ImageKnifeComponent组件销毁网络请求中断
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-02-13 16:15:49 +08:00
openharmony_ci 933cc284ec
!458 优化ImageKnifeLoader类的getImageArrayBuffer方法
Merge pull request !458 from 刘海康/master
2025-02-07 09:12:11 +00:00
openharmony_ci fbf4cc88bd
!456 增加图片下载失败各种错误信息样例
Merge pull request !456 from zgf/master
2025-02-07 02:48:13 +00:00
liuhaikang a21a8f025f 优化ImageKnifeLoader类的getImageArrayBuffer方法
Signed-off-by: liuhaikang <liuhaikang1@h-partners.com>
2025-02-06 20:09:06 +08:00
zgf 996fc5c909
增加图片下载失败各种错误信息样例
增加图片下载失败各种错误信息样例

Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-02-06 08:16:36 +00:00
zgf 677ea73337 增加图片下载失败各种错误信息样例
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-02-06 15:56:37 +08:00
openharmony_ci 5c22496b96
!455 发布正式版本3.2.1
Merge pull request !455 from 刘海康/master
2025-01-23 03:38:42 +00:00
liuhaikang 425aa3a5bc 发布正式版本3.2.1
Signed-off-by: liuhaikang <liuhaikang1@h-partners.com>
2025-01-23 11:04:36 +08:00
openharmony_ci 226d9939be
!454 判断loadSrc传入pixelmap类型处增加保护
Merge pull request !454 from zgf/master
2025-01-21 08:04:35 +00:00
zgf 2c7473f422 判断loadSrc传入pixelmap类型处增加保护
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-01-21 15:25:12 +08:00
openharmony_ci 17e3787cfa
!453 优化文件缓存初始化效率
Merge pull request !453 from 刘海康/master
2025-01-21 02:29:39 +00:00
liuhaikang 915eded1ab 优化文件缓存初始化效率
Signed-off-by: liuhaikang <liuhaikang1@h-partners.com>
2025-01-20 15:34:07 +08:00
openharmony_ci a1e8e0b15f
!452 修复自定义矩形裁剪异常、清除文件缓存接口导致文件缓存失效
Merge pull request !452 from zgf/master
2025-01-13 07:40:45 +00:00
zgf 1615da7b7c 修复自定义矩形裁剪异常、清除文件缓存接口导致文件缓存失效
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-01-13 14:49:46 +08:00
madixin 3378d36046 优化ImageFit.Auto的demo,使用滚动条调整宽度,体现高度的自适应
Signed-off-by: madixin <42690727@qq.com>
2025-01-12 11:57:05 +08:00
openharmony_ci f709bd3f01
!450 修改版本号和OAT配置
Merge pull request !450 from zgf/master
2025-01-03 06:02:22 +00:00
zgf a844860bae 修改版本号和OAT配置
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-01-03 12:07:39 +08:00
zgf 60ec83850a 删除重复debug日志(showpixelmap)
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-01-02 07:36:20 +00:00
openharmony_ci 9939c748a8
!448 修改样例resource泄露、heic格式补充、降采样优化、增加解码和文件读取debug日志
Merge pull request !448 from zgf/master
2025-01-02 02:23:11 +00:00
zgf 1efe55db1e 修改样例resource泄露、heic格式补充、降采样优化、增加解码和文件读取debug日志
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2025-01-02 10:15:25 +08:00
openharmony_ci 990a9a363f
!446 修正decodeEndTime记录错误
Merge pull request !446 from Madi/master
2024-12-24 03:05:09 +00:00
madixin 618320843f 1.修正decodeEndTime记录错误
2.内存缓存记录图片buffersize
3.测试加载回调demo里展示图片来源于网络,文件缓存,还是内存缓存。 去除renderTime的记录
4.调整动图的测试页面,不涉及逻辑修改

Signed-off-by: madixin <madixin@huawei.com>
2024-12-24 10:40:17 +08:00
openharmony_ci db56763a50
!445 扩大内存和文件缓存的限制和默认值
Merge pull request !445 from Madi/master
2024-12-23 02:48:35 +00:00
madixin 2f2e562aed 扩大内存和文件缓存的限制和默认值
Signed-off-by: madixin <madixin@huawei.com>
2024-12-21 18:25:32 +08:00
zgf fc6668cb0d 高度自适应方案修改、成功回调返回httpCode以及修复错误码httpCode无数据
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-12-19 17:04:22 +08:00
openharmony_ci ba48f233a7
!443 增加页面展示和测试local本地图片的显示
Merge pull request !443 from Madi/master
2024-12-16 03:58:54 +00:00
madixin 549d9edf48 1.增加页面展示和测试local本地图片的显示,目前发现rawfile下的文件无法显示
2.httpRequestOption --》 HttpRequestOption

Signed-off-by: madixin <madixin@huawei.com>
2024-12-14 17:22:05 +08:00
openharmony_ci db78e56e9a
!442 增加日志开关和网络请求超时参数
Merge pull request !442 from zgf/master
2024-12-09 02:56:01 +00:00
zgf 68672e1dc7 增加日志开关和网络请求超时参数
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-12-09 10:43:33 +08:00
zgf 6719e8ab19 修改网络请求readTimeout和日志修改
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-12-05 19:35:18 +08:00
zgf 7b025a7415 错误日志和回调增加信息
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-12-04 06:44:32 +00:00
openharmony_ci 912c23f34b
!439 调整closeSync方法,紧接着writeSync,readSync,防止打开的文件没有正确关闭
Merge pull request !439 from Madi/master
2024-12-03 10:43:13 +00:00
madixin 5f548d1090 调整closeSync方法,紧接着writeSync,readSync,防止打开的文件没有正确关闭
Signed-off-by: madixin <madixin@huawei.com>
2024-12-03 17:21:18 +08:00
madixin 303ff79be1 更新issue bug的模版版本和PR模版
Signed-off-by: madixin <madixin@huawei.com>
2024-12-01 19:58:19 +08:00
openharmony_ci 51e4675957
!437 增加仓库默认issue模板,填写正确imageknife版本
Merge pull request !437 from Madi/master
2024-11-30 13:02:57 +00:00
madixin 47edcfed3e 提交imageknife issue模版,选定版本
Signed-off-by: madixin <madixin@huawei.com>
2024-11-30 20:37:36 +08:00
zgf e475dcd30a 修改ImageKnifeComponent组件pixel Map初始值以及修复多张错误图不显示
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-29 18:26:46 +08:00
openharmony_ci e98984c56a
!435 主图和错误图并发加载时,以及主图加载失败后立即加载错误图,可能会导致短时间内并发数超过maxRequests,及时减少并发
Merge pull request !435 from Madi/master
2024-11-27 11:32:27 +00:00
madixin fba280904e 主图和错误图并发加载时,以及主图加载失败后立即加载错误图,可能会导致短时间内并发数超过maxRequests,故在dispatchNextJob减少响应的并发
Signed-off-by: madixin <madixin@huawei.com>
2024-11-27 15:39:04 +08:00
Madixin 8aebc58a53 更新默认OpenHarmony工程
Signed-off-by: Madixin <madixin@huawei.com>
2024-11-27 06:00:00 +00:00
openharmony_ci 9ff70d9c78
!433 ImageFit.Auto 组件宽度更改后自动支持自适应高度
Merge pull request !433 from Madi/master
2024-11-27 01:13:11 +00:00
madixin e29c659e89 1. ImageFit.Auto 组件宽度更改后自动支持自适应高度,并补充样例。
2.修复onLoadStart会调用2次的bug

Signed-off-by: madixin <madixin@huawei.com>
2024-11-25 17:45:55 +08:00
openharmony_ci 83b42f36b0
!432 完善日志,补充组件id信息
Merge pull request !432 from Madi/master
2024-11-25 02:40:14 +00:00
madixin 74bc24d61d 完善日志,补充组件id信息
Signed-off-by: madixin <madixin@huawei.com>
2024-11-25 09:54:50 +08:00
zgf dac7731794 支持ico格式图片、修复错误回调无法执行reload和新增降采样默认值
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-22 16:51:22 +08:00
zgf 1ae2ce8d92 ImageKnifeAnimatorComponent补充圆角功能
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-15 15:37:10 +08:00
openharmony_ci 65c39faf8a
!429 taskpool执行异常时,回调onLoadFailed
Merge pull request !429 from Madi/master
2024-11-15 06:03:32 +00:00
madixin 328257bb96 1.taskpool执行异常时,回调onLoadFailed
2.调整imageKnifeData为public作用域,以及命名

Signed-off-by: madixin <madixin@huawei.com>
2024-11-15 12:17:52 +08:00
openharmony_ci a45fb6af7d
!428 完善错误日志的打印
Merge pull request !428 from Madi/master
2024-11-15 03:03:58 +00:00
madixin 5296bf7a1d 1.完善错误日志
2.修复部分imagesource没有release的问题

Signed-off-by: madixin <madixin@huawei.com>
2024-11-15 10:05:23 +08:00
openharmony_ci 30c327747b
!427 修复无法解析其他module的Resource格式图片
Merge pull request !427 from zgf/master
2024-11-12 09:44:47 +00:00
zgf 73bc96e524 修复无法解析其他module的Resource格式图片
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-12 17:05:05 +08:00
openharmony_ci 32da743bcc
!426 判断和处理imageSource.getImageInfo为空的场景,返回错误信息
Merge pull request !426 from Madi/master
2024-11-12 01:45:34 +00:00
madixin 630b0df448 判断和处理imageSource.getImageInfo为空的场景,返回错误信息
Signed-off-by: madixin <madixin@huawei.com>
2024-11-10 08:06:57 +08:00
zgf f552f57713 修改CHANGELOG版本号
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-08 15:12:39 +08:00
openharmony_ci 3dd622e4e2
!424 3.x分支代码合并master分支
Merge pull request !424 from zgf/master
2024-11-08 06:10:07 +00:00
zgf 3423f4cd5d 3.x分支代码合并到master分支
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-08 11:02:58 +08:00
zgf 0e0f1a96c2 Merge remote-tracking branch 'origin/3.x'
# Conflicts:
#	CHANGELOG.md
#	README.md
#	README_zh.md
#	entry/src/main/ets/common/CustomEngineKeyImpl.ets
#	entry/src/main/ets/pages/DownSamplePage.ets
#	entry/src/main/ets/pages/ImageAnimatorPage.ets
#	entry/src/main/ets/pages/Index.ets
#	entry/src/main/ets/pages/LoadStatePage.ets
#	entry/src/main/ets/pages/ObjectFitPage.ets
#	entry/src/main/ets/pages/SingleImage.ets
#	entry/src/main/ets/pages/TestCacheDataPage.ets
#	entry/src/main/ets/pages/TestChangeColorPage.ets
#	entry/src/main/ets/pages/TestLoadCancelListenerPage.ets
#	entry/src/main/ets/pages/TestSetCustomImagePage.ets
#	entry/src/main/ets/pages/TestTaskResourcePage.ets
#	entry/src/main/ets/pages/TestWriteCacheStage.ets
#	entry/src/main/ets/pages/UserPage.ets
#	entry/src/main/resources/base/element/string.json
#	entry/src/main/resources/base/profile/main_pages.json
#	entry/src/main/resources/zh_CN/element/string.json
#	entry/src/ohosTest/ets/test/List.test.ets
#	entry/src/ohosTest/ets/test/SamplingTest.test.ets
#	entry/src/ohosTest/ets/test/imageFormatAndSize.test.ets
#	library/oh-package.json5
#	library/src/main/ets/ImageKnife.ets
#	library/src/main/ets/ImageKnifeDispatcher.ets
#	library/src/main/ets/ImageKnifeLoader.ets
#	library/src/main/ets/components/ImageKnifeAnimatorComponent.ets
#	library/src/main/ets/components/ImageKnifeComponent.ets
#	library/src/main/ets/downsampling/BaseDownsampling.ets
#	library/src/main/ets/downsampling/DownsampleStartegy.ets
#	library/src/main/ets/downsampling/Downsampler.ets
#	library/src/main/ets/key/DefaultEngineKey.ets
#	library/src/main/ets/model/ImageKnifeData.ets
#	library/src/main/ets/model/ImageKnifeOption.ets
#	library/src/main/ets/model/ImageKnifeRequest.ets
#	sharedlibrary/src/main/ets/pages/Index.ets
2024-11-06 18:40:38 +08:00
madixin 8adc342444 补充:解决单个图片解码后内存占用超过内存缓存最大值,导致无法显示图片的问题
Signed-off-by: madixin <madixin@huawei.com>
2024-11-06 16:52:09 +08:00
madixin 95ffcb9e74 解决单个图片解码后内存占用超过内存缓存最大值,导致无法显示图片的问题
Signed-off-by: madixin <madixin@huawei.com>
2024-11-06 15:50:15 +08:00
zgf b0661e83ac 3.x分支新增降采样功能
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-04 16:18:47 +08:00
zgf 04e2d430f2 修改CHANGELOG版本号
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-11-01 16:38:49 +08:00
jinzhao 80ba246aeb 删除对constructor的修改
Signed-off-by: jinzhao <jinzhao@kaihong.com>
2024-11-01 07:44:21 +00:00
jinzhao c75bb9226a 新增https自定义证书功能
Signed-off-by: jinzhao <jinzhao@kaihong.com>
2024-11-01 07:44:21 +00:00
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
openharmony_ci a7fa5de2de
!405 ImageKnife降采样适配3.x
Merge pull request !405 from 田双明/master
2024-10-23 01:53:00 +00:00
田双明 346c704193
update entry/src/main/ets/pages/Index.ets.
Signed-off-by: 田双明 <tianshuangming@h-partners.com>
2024-10-23 01:12:36 +00:00
田双明 e857a41129 Merge branch 'master' of gitee.com:openharmony-tpc/ImageKnife into master
Signed-off-by: 田双明 <tianshuangming@h-partners.com>
2024-10-22 10:43:49 +00: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
openharmony_ci da4c159d44
!404 增加onLoadCancel回调的demo、增加设置图片颜色变换demo、增加从缓存获取图片格式大小的xts等
Merge pull request !404 from tyBrave/master
2024-10-21 01:28:42 +00:00
tsm 29e0df8d2b 降采样功demo文字国际化
Signed-off-by: tsm <tianshuangming@h-partners.com>
2024-10-18 18:16:42 +08:00
tsm 5fa004afc0 降采样功能
Signed-off-by: tsm <tianshuangming@h-partners.com>
2024-10-18 15:31:38 +08:00
tyBrave d82d85ea19 去掉多余的日志信息
Signed-off-by: tyBrave <tianyong21@h-partners.com>

TestCacheDataPage 文件添加版权头

Signed-off-by: tyBrave <tianyong21@h-partners.com>

资源国际化

Signed-off-by: tyBrave <tianyong21@h-partners.com>

add TIPS text dec

Signed-off-by: tyBrave <tianyong21@h-partners.com>

update code because of checkcode

Signed-off-by: tyBrave <tianyong21@h-partners.com>

update code because of use image url

Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-17 17:39:50 +08:00
tyBrave 8e55d336f9 修改获取缓存中的图片格式大小的单元测试
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-16 17:17:02 +08:00
tyBrave e31c592ee4 修改onLoadCancel回调demo及其缓存中获取图片的格式大小信息
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-16 15:56:42 +08:00
tyBrave 1027fc0304 add xts test get size and format in image of callback
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-16 10:57:36 +08:00
tyBrave ec651e91df add test cancel callback demo
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-16 10:56:06 +08:00
tyBrave 7b9da8d9fa add change color of image in lib
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-16 10:40:22 +08:00
tyBrave 2a81312ed5 add get cache data
Signed-off-by: tyBrave <tianyong21@h-partners.com>
2024-10-12 09:57:11 +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
openharmony_ci 78770a430c
!398 中文图片链接替换
Merge pull request !398 from zgf/master
2024-10-10 01:24:31 +00:00
zgf 2201fec90c 中文图片链接替换
Signed-off-by: zgf <zenggaofeng2@h-partners.com>
2024-10-09 15:36:07 +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
145 changed files with 6742 additions and 4491 deletions

View File

@ -0,0 +1,13 @@
### 该问题是怎么引起的?
### 重现步骤
### 报错信息

View File

@ -0,0 +1,47 @@
name: 缺陷反馈|Bug
description: 当您发现了一个缺陷,需要向社区反馈时,请使用此模板。
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
感谢对OpenHarmony社区的支持与关注欢迎反馈缺陷。
- type: textarea
attributes:
label: 发生了什么问题?
description: 提供尽可能多的信息描述产生了什么问题。
placeholder: ""
validations:
required: true
- type: textarea
attributes:
label: 期望行为是什么?
description: 描述期望的行为应该是什么样子的。
placeholder: ""
validations:
required: true
- type: textarea
attributes:
label: 如何复现该缺陷
description: 提供尽可能多的信息描述如何复现该缺陷。
validations:
required: true
- type: textarea
attributes:
label: 其他补充信息
description: 补充下其他您认为需要提供的信息。
validations:
required: false
- type: checkboxes
attributes:
label: 版本或分支信息
description: 在哪些版本、分支存在该缺陷的?
options:
- label: master
- label: Release 3.2
- label: Release 3.1
- label: Release 3.0
- label: Release 2.x
validations:
required: true

View File

@ -0,0 +1 @@
blank_issues_enabled: false

View File

@ -0,0 +1,21 @@
name: 新需求|Feature
description: 您需要反馈或实现一个新需求时,使用此模板。
title: "[新需求]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
感谢提出新需求。
- type: textarea
attributes:
label: 新需求提供了什么功能?
description: 请描述下新需求的功能是什么,解决了什么问题
validations:
required: true
- type: textarea
attributes:
label: 该需求带来的价值、应用场景?
description: 请描述下该需求的价值,应用场景等。
validations:
required: false

View File

@ -0,0 +1,15 @@
name: 问题咨询|Question
description: 如果您对OpenHarmony社区有疑问欢迎反馈咨询。
title: "[问题咨询]: "
labels: ["question"]
body:
- type: markdown
attributes:
value: |
感谢提出问题,我们将安排人答复!
- type: textarea
attributes:
label: 问题描述
description: 请描述下您的问题
validations:
required: true

View File

@ -0,0 +1,72 @@
name: 安全问题|Security Issue
description: 当您发现安全问题时,使用此模板反馈。
title: "[安全问题]: "
labels: ["SIG_Security"]
body:
- type: markdown
attributes:
value: |
感谢对OpenHarmony社区的支持与关注欢迎反馈安全问题。
- type: input
attributes:
label: 漏洞编号:
description: 请描述下漏洞编号。
placeholder: ""
validations:
required: false
- type: input
attributes:
label: 漏洞归属组件
description: 请描述下漏洞归属组件。
placeholder: ""
validations:
required: false
- type: input
attributes:
label: 漏洞归属版本
description: 请描述下漏洞归属版本。
placeholder: ""
validations:
required: false
- type: input
attributes:
label: CVSS V3.0分值
description: 请描述下CVSS V3.0分值。
placeholder: ""
validations:
required: false
- type: textarea
attributes:
label: 漏洞简述
description: 请提供下漏洞的描述信息。
placeholder: ""
validations:
required: true
- type: textarea
attributes:
label: 影响性分析说明
description: 请描述下该漏洞的影响。
placeholder: ""
validations:
required: false
- type: textarea
attributes:
label: 原理分析
description: 请分析下该漏洞的原理。
placeholder: ""
validations:
required: false
- type: input
attributes:
label: 受影响版本
description: 请描述下该漏洞的影响版本。
placeholder: ""
validations:
required: false
- type: textarea
attributes:
label: 规避方案或消减措施
description: 请描述下该漏洞的规避方案或消减措施。
placeholder: ""
validations:
required: false

View File

@ -0,0 +1,8 @@
### 一、修改说明
### 二、变更内容
### 三、测试建议

View File

@ -1,3 +1,74 @@
## 3.2.2-rc.1
- Support EXIF metadata carried by images as display orientation
## 3.2.2-rc.0
- Add ImageKnifeComponent to destroy network request interruption
- Code refactoring during the download of image resources stage
## 3.2.1
- Release official version
## 3.2.1-rc.0
- Fix bug: CropTransformation is used to crop the original image
- Fix bug: After calling the clear all file cache interfaces, the file cache becomes invalid
- Optimize the efficiency of file cache initialization.
- Add protection at the location where loadSrc is passed in the pixelmap type
## 3.2.0
- When successfully requesting the network, return the httpcode as well
- Fix bug: Network error code httpCode returns no data
- Modify implementation of ImageFit.Auto: do not modify image height
- Modify memory cache limit and file cache limit
- Fix record decodeEndTime in imageKinfaData
- Add image buffersize in memory cache
- Optimize the magic number of heif format image files
- Fix bug: The width and height of the downsampling component are inconsistent with the image resolution unit
## 3.2.0-rc.6
- Support LogUtil to turn off log
- Support set network request readTimeout and connectTimeout through ImageKnifeOption
## 3.2.0-rc.5
- Enhance: ImageFit.Auto support adaptive height after component width change
- Fix bug: call onLoadStart 2 times(import from 3.2.0-rc.0)
- Change the initial value of the PixelMap component of ImageKnife to ImageContent EMPTY
- Clear memory cache, cancel pixel map release
- Loading process log modification
- Change the network request readTimeout to 30s
## 3.2.0-rc.4
- Support ICO format images
- Fix bug: call reload problem in onLoadFailed
- Provide default downsampling strategy to prevent slow loading for large images
## 3.2.0-rc.3
- Fix bug: PixelMap size exceeds the maximum value of memory cache and is not cached
- Dealing with exception scenarios where imageSource.getImageInfo return undefined
- Fix inability to parse Resource format images of other modules
- Improve the error logs
- Fix callback onLoadFailed when taskpool exception occurs
- ImageKnife AnimatorComponent component adds rounded corner function
## 3.2.0-rc.2
- 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
- HTTPS custom certificate verification
- Add downsampling function to reduces memory cache consumption
## 3.2.0-rc.1
- 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.1.1-rc.1
- Photo reduction sampling
## 3.1.1-rc.0 ## 3.1.1-rc.0
- 重构代码抽取ImageKnifeDispatcher子线程requestJob相关代码到ImageKnifeLoader中降低函数复杂度 - 重构代码抽取ImageKnifeDispatcher子线程requestJob相关代码到ImageKnifeLoader中降低函数复杂度
@ -23,6 +94,35 @@
- imageKnifeOption={...}用法改为new ImageKnifeOption({...}) - imageKnifeOption={...}用法改为new ImageKnifeOption({...})
- animatorOption={...}用法改为new AnimatorOption({...}) - animatorOption={...}用法改为new AnimatorOption({...})
## 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 ## 3.0.1
- 修复animatorOption属性设置初始化值失效 - 修复animatorOption属性设置初始化值失效
- 网络请求code为206、204时返回arraybuffer - 网络请求code为206、204时返回arraybuffer

View File

@ -27,6 +27,7 @@
<filteritem type="filename" name="hvigorw" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/> <filteritem type="filename" name="hvigorw" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/>
<filteritem type="filename" name="hvigorw.bat" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/> <filteritem type="filename" name="hvigorw.bat" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/>
<filteritem type="filename" name="hvigor-wrapper.js" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/> <filteritem type="filename" name="hvigor-wrapper.js" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/>
<filteritem type="filename" name=".gitmodules" desc="git配置文件不添加版权头"/>
<filteritem type="filepath" name="library/src/main/ets/3rd_party/.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> <filteritem type="filepath" name="library/src/main/ets/3rd_party/.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/>
</filefilter> </filefilter>
<filefilter name="defaultPolicyFilter" desc="Filters for compatibilitylicense header policies"> <filefilter name="defaultPolicyFilter" desc="Filters for compatibilitylicense header policies">
@ -37,6 +38,7 @@
<filteritem type="filename" name="hvigorw" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/> <filteritem type="filename" name="hvigorw" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/>
<filteritem type="filename" name="hvigorw.bat" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/> <filteritem type="filename" name="hvigorw.bat" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/>
<filteritem type="filename" name="hvigor-wrapper.js" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/> <filteritem type="filename" name="hvigor-wrapper.js" desc="hvigorw配置文件DevEco Studio自动生成不手动修改"/>
<filteritem type="filename" name=".gitmodules" desc="git配置文件不添加版权头"/>
<filteritem type="filepath" name="library/src/main/ets/3rd_party/.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> <filteritem type="filepath" name="library/src/main/ets/3rd_party/.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/>
</filefilter> </filefilter>
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies"> <filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies">
@ -48,6 +50,7 @@
<filteritem type="filename" name="*.gif" desc="gif图片格式文件,用于展示示例"/> <filteritem type="filename" name="*.gif" desc="gif图片格式文件,用于展示示例"/>
<filteritem type="filename" name="*.jpg" desc="jpg图片格式文件,用于展示示例"/> <filteritem type="filename" name="*.jpg" desc="jpg图片格式文件,用于展示示例"/>
<filteritem type="filename" name="*.jpeg" desc="jpeg图片格式文件,用于展示示例"/> <filteritem type="filename" name="*.jpeg" desc="jpeg图片格式文件,用于展示示例"/>
<filteritem type="filename" name="*.heic" desc="heic图片格式文件,用于展示示例"/>
<filteritem type="filename" name="*.json5" desc="hvigor配置文件"/> <filteritem type="filename" name="*.json5" desc="hvigor配置文件"/>
</filefilter> </filefilter>
<filefilter name="defaultFilter" desc="Files not to check"> <filefilter name="defaultFilter" desc="Files not to check">

View File

@ -1,3 +1,9 @@
## 🚨 **重要提示 | IMPORTANT**
>
> **⚠️ 此代码仓已归档。新地址请访问 [ImageKnife](https://gitcode.com/openharmony-tpc/ImageKnife)。| ⚠️ This repository has been archived. For the new address, please visit [ImageKnife](https://gitcode.com/openharmony-tpc/ImageKnife).**
>
---
>
# ImageKnife # ImageKnife
ImageKnife is a specially crafted image loading and caching library for OpenHarmony, optimized for efficiency, lightness, and simplicity. ImageKnife is a specially crafted image loading and caching library for OpenHarmony, optimized for efficiency, lightness, and simplicity.
@ -56,12 +62,12 @@ await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption:{
loadSrc: $r("app.media.app_icon"), loadSrc: $r("app.media.app_icon"),
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto objectFit: ImageFit.Auto
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
@ -69,12 +75,12 @@ ImageKnifeComponent({
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc: this.localFile, loadSrc: this.localFile,
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto objectFit: ImageFit.Auto
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
@ -82,12 +88,12 @@ ImageKnifeComponent({
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto objectFit: ImageFit.Auto
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
@ -95,13 +101,13 @@ ImageKnifeComponent({
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg", loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto, objectFit: ImageFit.Auto,
customGetImage: custom customGetImage: custom
}) }
}).width(100).height(100) }).width(100).height(100)
// Custom implementation of the image acquisition method, such as custom network download。 // Custom implementation of the image acquisition method, such as custom network download。
@ -117,33 +123,33 @@ async function custom(context: Context, src: string | PixelMap | Resource): Prom
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)} progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)}
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 6. Setting Border Options #### 6. Setting Border Options
``` ```
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
border: {radius:50} border: {radius:50}
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 7. Setting Image Transformation Options #### 7. Setting Image Transformation Options
``` ```
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
border: {radius:50}, border: {radius:50},
transformation: new BlurTransformation(3) transformation: new BlurTransformation(3)
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
Multiple combined transformation usages: Multiple combined transformation usages:
@ -153,14 +159,14 @@ let transformations: collections.Array<PixelMapTransformation> = new collections
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: new ImageKnifeOption({ 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 } }, // Rounded corner settings border: { radius: { topLeft: 50, bottomRight: 50 } }, // Rounded corner settings
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // Graphic transformation group transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // Graphic transformation group
}) }
}).width(300) }).width(300)
.height(300) .height(300)
.rotate ({angle: 90}) // Rotate by 90 degrees. .rotate ({angle: 90}) // Rotate by 90 degrees.
@ -171,12 +177,12 @@ Other transformation-related properties can be stacked to achieve combined trans
Example of circular cropping transformation: Example of circular cropping transformation:
``` ```
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r('app.media.pngSample'), loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Cover, objectFit: ImageFit.Cover,
border: { radius: 150 } border: { radius: 150 }
}) }
}).width(300) }).width(300)
.height(300) .height(300)
``` ```
@ -184,12 +190,12 @@ ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
Example of Circular cropping with border transformation: Example of Circular cropping with border transformation:
``` ```
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r('app.media.pngSample'), loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Cover, objectFit: ImageFit.Cover,
border: { radius: 150, color: Color.Red, width: 5 } border: { radius: 150, color: Color.Red, width: 5 }
}) }
}).width(300) }).width(300)
.height(300) .height(300)
``` ```
@ -198,9 +204,9 @@ Example of contrast filtering transformation:
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: $r('app.media.pngSample') loadSrc: $r('app.media.pngSample')
}) }
}).width(300) }).width(300)
.height(300) .height(300)
.contrast(12) .contrast(12)
@ -210,9 +216,9 @@ Example of rotation transformation:
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption:({
loadSrc: $r('app.media.pngSample') loadSrc: $r('app.media.pngSample')
}) }
}).width(300) }).width(300)
.height(300) .height(300)
.rotate({angle:90}) .rotate({angle:90})
@ -222,7 +228,7 @@ ImageKnifeComponent({
#### 8. Listening for Image Loading Success and Failure #### 8. Listening for Image Loading Success and Failure
``` ```
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
onLoadListener:{ onLoadListener:{
@ -241,27 +247,27 @@ ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
console.info(err) console.info(err)
} }
} }
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 9. Use of syncLoad #### 9. Use of syncLoad
**syncLoad** sets whether to load the image synchronously. By default, the image is loaded asynchronously. When loading a small image, you are advised to set **syncLoad** to **true** so that the image loading can be quickly completed on the main thread. **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:new ImageKnifeOption({ imageKnifeOption:{
loadSrc:$r("app.media.pngSample"), loadSrc:$r("app.media.pngSample"),
placeholderSrc:$r("app.media.loading") placeholderSrc:$r("app.media.loading")
}),syncLoad:true },syncLoad:true
}) })
``` ```
#### 10. Use of ImageKnifeAnimatorComponent #### 10. Use of ImageKnifeAnimatorComponent
``` ```
ImageKnifeAnimatorComponent({ ImageKnifeAnimatorComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption:{
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
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})
``` ```
#### Reuse Scenario #### Reuse Scenario
@ -359,7 +365,15 @@ Method 2: Set the third-party HAR as a dependency in the **oh-package.json5** fi
This project has been verified in the following version: This project has been verified in the following version:
DevEco Studio: 5.0 Canary3 (5.0.3.502), SDK: API 12 (5.0.0.31) DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66)
## About obfuscation
- Code obfuscation, please see[Code Obfuscation](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/arkts-utils/source-obfuscation.md)
- If you want the imageknife library not to be obfuscated during code obfuscation, you need to add corresponding exclusion rules in the obfuscation rule configuration file obfuscation-rules.txt
```
-keep
./oh_modules/@ohos/imageknife
```
## How to Contribute ## How to Contribute
@ -372,4 +386,4 @@ This project is licensed under [Apache License 2.0](https://gitee.com/openharmon
## Known Issues ## Known Issues
- The **ImageFit** attribute cannot be set for the **ImageKnifeAnimator** component. - The **ImageFit** attribute cannot be set for the **ImageKnifeAnimator** component.
- The **border** attribute of the **ImageKnifeAnimator** component cannot make the image rounded corners. - The **border** attribute of the **ImageKnifeAnimator** component cannot make the image rounded corners.

View File

@ -1,3 +1,9 @@
## 🚨 **重要提示 | IMPORTANT**
>
> **⚠️ 此代码仓已归档。新地址请访问 [ImageKnife](https://gitcode.com/openharmony-tpc/ImageKnife)。| ⚠️ This repository has been archived. For the new address, please visit [ImageKnife](https://gitcode.com/openharmony-tpc/ImageKnife).**
>
---
>
# ImageKnife # ImageKnife
**专门为OpenHarmony打造的一款图像加载缓存库致力于更高效、更轻便、更简单。** **专门为OpenHarmony打造的一款图像加载缓存库致力于更高效、更轻便、更简单。**
@ -56,12 +62,12 @@ await ImageKnife.getInstance().initFileCache(context, 256, 256 * 1024 * 1024)
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc: $r("app.media.app_icon"), loadSrc: $r("app.media.app_icon"),
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto objectFit: ImageFit.Auto
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
@ -69,12 +75,12 @@ ImageKnifeComponent({
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc: this.localFile, loadSrc: this.localFile,
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto objectFit: ImageFit.Auto
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
@ -82,12 +88,12 @@ ImageKnifeComponent({
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto objectFit: ImageFit.Auto
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
@ -95,13 +101,13 @@ ImageKnifeComponent({
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg", loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg",
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r("app.media.loading"),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r("app.media.app_icon"),
objectFit: ImageFit.Auto, objectFit: ImageFit.Auto,
customGetImage: custom customGetImage: custom
}) }
}).width(100).height(100) }).width(100).height(100)
// 自定义实现图片获取方法,如自定义网络下载 // 自定义实现图片获取方法,如自定义网络下载
@ -117,33 +123,33 @@ async function custom(context: Context, src: string | PixelMap | Resource): Prom
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
ImageKnifeOption: new ImageKnifeOption({ ImageKnifeOption: {
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png",
progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)} progressListener:(progress:number)=>{console.info("ImageKinfe:: call back progress = " + progress)}
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 6.支持option传入border设置边框圆角 #### 6.支持option传入border设置边框圆角
``` ```
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
border: {radius:50} border: {radius:50}
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 7.支持option图片变换 #### 7.支持option图片变换
``` ```
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
border: {radius:50}, border: {radius:50},
transformation: new BlurTransformation(3) transformation: new BlurTransformation(3)
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
多种组合变换用法 多种组合变换用法
@ -153,14 +159,14 @@ let transformations: collections.Array<PixelMapTransformation> = new collections
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: new ImageKnifeOption({ 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 } }, // 圆角设置
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组 transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined // 图形变换组
}) }
}).width(300) }).width(300)
.height(300) .height(300)
.rotate({ angle: 90 }) // 旋转90度 .rotate({ angle: 90 }) // 旋转90度
@ -171,12 +177,12 @@ ImageKnifeComponent({
圆形裁剪变换示例 圆形裁剪变换示例
``` ```
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r('app.media.pngSample'), loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Cover, objectFit: ImageFit.Cover,
border: { radius: 150 } border: { radius: 150 }
}) }
}).width(300) }).width(300)
.height(300) .height(300)
``` ```
@ -184,12 +190,12 @@ ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
圆形裁剪带边框变换示例 圆形裁剪带边框变换示例
``` ```
ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r('app.media.pngSample'), loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Cover, objectFit: ImageFit.Cover,
border: { radius: 150, color: Color.Red, width: 5 } border: { radius: 150, color: Color.Red, width: 5 }
}) }
}).width(300) }).width(300)
.height(300) .height(300)
``` ```
@ -198,9 +204,9 @@ ImageKnifeComponent({ ImageKnifeOption:new ImageKnifeOption(
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: $r('app.media.pngSample') loadSrc: $r('app.media.pngSample')
}) }
}).width(300) }).width(300)
.height(300) .height(300)
.contrast(12) .contrast(12)
@ -210,9 +216,9 @@ ImageKnifeComponent({
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: $r('app.media.pngSample') loadSrc: $r('app.media.pngSample')
}) }
}).width(300) }).width(300)
.height(300) .height(300)
.rotate({angle:90}) .rotate({angle:90})
@ -222,7 +228,7 @@ ImageKnifeComponent({
#### 8.监听图片加载成功与失败 #### 8.监听图片加载成功与失败
``` ```
ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption( ImageKnifeComponent({ ImageKnifeOption:
{ {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
onLoadListener:{ onLoadListener:{
@ -241,29 +247,97 @@ ImageKnifeComponent({ ImageKnifeOption: new ImageKnifeOption(
console.info(err) console.info(err)
} }
} }
}) }
}).width(100).height(100) }).width(100).height(100)
``` ```
#### 9.ImageKnifeComponent - syncLoad #### 9.ImageKnifeComponent - syncLoad
设置是否同步加载图片默认是异步加载。建议加载尺寸较小的Resource图片时将syncLoad设为true因为耗时较短在主线程上执行即可 设置是否同步加载图片默认是异步加载。建议加载尺寸较小的Resource图片时将syncLoad设为true因为耗时较短在主线程上执行即可
``` ```
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption:{
loadSrc:$r("app.media.pngSample"), loadSrc:$r("app.media.pngSample"),
placeholderSrc:$r("app.media.loading") placeholderSrc:$r("app.media.loading")
}),syncLoad:true },syncLoad:true
}) })
``` ```
#### 10.ImageKnifeAnimatorComponent 示例 #### 10.ImageKnifeAnimatorComponent 示例
``` ```
ImageKnifeAnimatorComponent({ ImageKnifeAnimatorComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption: {
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
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})
``` ```
#### 11.加载图片回调信息数据 示例
```
ImageKnifeComponent({ ImageKnifeOption: = {
loadSrc: $r('app.media.pngSample'),
objectFit: ImageFit.Contain,
onLoadListener: {
onLoadStart: (req) => {
let startCallBackData = JSON.stringify(req?.imageKnifeData);
},
onLoadFailed: (res, req) => {
let failedBackData = res + ";" + JSON.stringify(req?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
let successBackData = JSON.stringify(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
let cancelBackData = res + ";" + JSON.stringify(req?.imageKnifeData);
}
},
border: { radius: 50 },
onComplete: (event) => {
if (event && event.loadingStatus == 0) {
let render_success = JSON.stringify(Date.now())
}
}
}
}).width(100).height(100)
```
#### 12.图片降采样 示例
```
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:$r("app.media.pngSample"),
placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed'),
downsampleOf: DownsampleStrategy.NONE
}
}).width(300).height(300)
```
#### 13.rcp自定义网络请求
```
ImageKnifeComponent({
loadSrc:"http//xx.xx",
customGetImage:custom
})
// 自定义下载方法
@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))
})
}
})
}
```
#### 复用场景 #### 复用场景
在aboutToRecycle生命周期清空组件内容通过watch监听触发图片的加载。 在aboutToRecycle生命周期清空组件内容通过watch监听触发图片的加载。
## 接口说明 ## 接口说明
@ -287,44 +361,73 @@ ImageKnifeAnimatorComponent({
### ImageKnifeOption参数列表 ### ImageKnifeOption参数列表
| 参数名称 | 入参内容 | 功能简介 | | 参数名称 | 入参内容 | 功能简介 |
|-----------------------|-------------------------------------------------------|-----------------| |-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
| loadSrc | string、PixelMap、Resource | 主图展示 | | loadSrc | string、PixelMap、Resource | 主图展示 |
| placeholderSrc | PixelMap、Resource | 占位图图展示(可选) | | placeholderSrc | PixelMap、Resource | 占位图图展示(可选) |
| errorholderSrc | PixelMap、Resource | 错误图展示(可选) | | errorholderSrc | PixelMap、Resource | 错误图展示(可选) |
| objectFit | ImageFit | 主图填充效果(可选) | | objectFit | ImageFit | 主图填充效果(可选) |
| placeholderObjectFit | ImageFit | 占位图填充效果(可选) | | placeholderObjectFit | ImageFit | 占位图填充效果(可选) |
| errorholderObjectFit | ImageFit | 错误图填充效果(可选) | | errorholderObjectFit | ImageFit | 错误图填充效果(可选) |
| writeCacheStrategy | CacheStrategyType | 写入缓存策略(可选) | | writeCacheStrategy | CacheStrategyType | 写入缓存策略(可选) |
| onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) | | onlyRetrieveFromCache | boolean | 是否跳过网络和本地请求(可选) |
| customGetImage | (context: Context, src: string | 自定义下载图片(可选) | | Resource | 错误占位图数据源 | | customGetImage | customGetImage?:(context: Context, src: string、PixelMap、Resource ,headers?: Record<string, Object>) => Promise<ArrayBufferundefined> | 自定义下载图片(可选) | | Resource | 错误占位图数据源 |
| border | BorderOptions | 边框圆角(可选) | | border | BorderOptions | 边框圆角(可选) |
| priority | taskpool.Priority | 加载优先级(可选) | | priority | taskpool.Priority | 加载优先级(可选) |
| context | common.UIAbilityContext | 上下文(可选) | | context | common.UIAbilityContext | 上下文(可选) |
| progressListener | (progress: number)=>void | 进度(可选) | | progressListener | (progress: number)=>void | 进度(可选) |
| signature | String | 自定义缓存关键字(可选) | | signature | String | 自定义缓存关键字(可选) |
| headerOption | Array<HeaderOptions> | 设置请求头(可选) | | headerOption | Array<HeaderOptions> | 设置请求头(可选) |
| transformation | PixelMapTransformation | 图片变换(可选) | | transformation | PixelMapTransformation | 图片变换(可选) |
| drawingColorFilter | ColorFilter | drawing.ColorFilter | 图片变换(可选) | | drawingColorFilter | ColorFilter、drawing.ColorFilter | 颜色滤镜效果(可选) |
| onComplete | (event:EventImage | undefined) => voi | 颜色滤镜效果(可选) | | onComplete | (event:EventImage、undefined) => void | 图片成功回调事件(可选) |
| onLoadListener | onLoadStart: () => void、onLoadSuccess: (data: string | PixelMap | undefined) => void、onLoadFailed: (err: string) => void| 监听图片加载成功与失败 | | 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 | 监听图片加载成功与失败 |
| downsampleOf | DownsampleStrategy | 降采样(可选) |
| httpOption | HttpRequestOption | 网络请求配置(可选) |
### 降采样类型
| 类型 | 相关描述 |
|------------------------|-------------------|
| NONE | 不进行降采样 |
| AT_MOST | 请求尺寸大于实际尺寸不进行放大 |
| FIT_CENTER_MEMORY | 两边自适应内存优先 |
| FIT_CENTER_QUALITY | 两边自适应质量优先 |
| CENTER_INSIDE_MEMORY | 宽高缩放比最大的比例,进行缩放适配内存优先 |
| CENTER_INSIDE_QUALITY | 宽高缩放比最大的比例,进行缩放适配质量优先 |
| AT_LEAST | 根据宽高的最小的比例,进行适配 |
### ImageKnife接口 ### ImageKnife接口
| 参数名称 | 入参内容 | 功能简介 | | 参数名称 | 入参内容 | 功能简介 |
|------------------|-------------------------------------------------------------------------------------------------------|---------------| |-------------------|---------------------------------------------------------------------------------------------------------------------------------------|------------------|
| initMemoryCache | newMemoryCache: IMemoryCache | 自定义内存缓存策略 | | initMemoryCache | newMemoryCache: IMemoryCache | 自定义内存缓存策略 |
| initFileCache | context: Context, size: number, memory: number | 初始化文件缓存数量和大小 | | initFileCache | context: Context, size: number, memory: number | 初始化文件缓存数量和大小 |
| preLoadCache | loadSrc: string I ImageKnifeOption | 预加载并返回文件缓存路径 | | reload | request: ImageKnifeRequest | 图片重新加载 |
| getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 从内存或文件缓存中获取资源 | | preLoad | loadSrc: string I ImageKnifeOption | 预加载返回图片请求request |
| addHeader | key: string, value: Object | 全局添加http请求头 | | cancel | request: ImageKnifeRequest | 取消图片请求 |
| setHeaderOptions | Array<HeaderOptions> | 全局设置http请求头 | | preLoadCache | loadSrc: string I ImageKnifeOption | 预加载并返回文件缓存路径 |
| deleteHeader | key: string | 全局删除http请求头 | | getCacheImage | loadSrc: string, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) | 从内存或文件缓存中获取资源 |
| setCustomGetImage | customGetImage?: (context: Context, src: string | PixelMap | Resource) => Promise<ArrayBuffer | undefined> | 全局设置自定义下载 | | addHeader | key: string, value: Object | 全局添加http请求头 |
| setEngineKeyImpl | IEngineKey | 全局配置缓存key生成策略 | | setHeaderOptions | Array<HeaderOptions> | 全局设置http请求头 |
| putCacheImage | url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string | 写入内存磁盘缓存 | | deleteHeader | key: string | 全局删除http请求头 |
| removeMemoryCache| url: string | ImageKnifeOption | 清理指定内存缓存 | | setCustomGetImage | customGetImage?: (context: Context, src: string、PixelMap、Resource ,headers?: Record<string, Object>) => Promise<ArrayBufferundefined>| 全局设置自定义下载 |
| removeFileCache | url: string | ImageKnifeOption | 清理指定磁盘缓存 | | 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添加依赖项 ### 图形变换类型需要为GPUImage添加依赖项
| 类型 | 相关描述 | | 类型 | 相关描述 |
@ -358,8 +461,16 @@ ImageKnifeAnimatorComponent({
## 约束与限制 ## 约束与限制
在下述版本验证通过: 在下述版本验证通过:
DevEco Studio 5.0 Canary35.0.3.502--SDK:API12 (5.0.0.31) DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66)
## 关于混淆
- 代码混淆,请查看[代码混淆简介](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/arkts-utils/source-obfuscation.md)
- 如果希望imageknife库在代码混淆过程中不会被混淆需要在混淆规则配置文件obfuscation-rules.txt中添加相应的排除规则
```
-keep
./oh_modules/@ohos/imageknife
```
## 贡献代码 ## 贡献代码
使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues) 使用过程中发现任何问题都可以提 [issue](https://gitee.com/openharmony-tpc/ImageKnife/issues)
@ -371,5 +482,4 @@ DevEco Studio 5.0 Canary35.0.3.502--SDK:API12 (5.0.0.31)
## 遗留问题 ## 遗留问题
- ImageKnifeAnimator组件无法设置ImageFit属性 - ImageKnifeAnimator组件无法设置ImageFit属性
- ImageKnifeAnimator组件设置border属性无法将图片变为圆角

View File

@ -8,7 +8,8 @@
"name": "default", "name": "default",
"signingConfig": "default", "signingConfig": "default",
"compileSdkVersion": 12, "compileSdkVersion": 12,
"compatibleSdkVersion": 12 "compatibleSdkVersion": 12,
"runtimeOS": "OpenHarmony"
} }
], ],
"buildModeSet": [ "buildModeSet": [

View File

@ -15,4 +15,7 @@
# Keep options: # Keep options:
# -keep-property-name: specifies property names that you want to keep # -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope # -keep-global-name: specifies names that you want to keep in the global scope
-keep
./oh_modules/@ohos/imageknife

View File

@ -12,7 +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 { IEngineKey, ImageKnifeOption, PixelMapTransformation,SparkMD5 ,ImageKnifeRequestSource} from '@ohos/libraryimageknife'; import { IEngineKey, ImageKnifeOption, PixelMapTransformation,SparkMD5 ,ImageKnifeRequestSource,
DownsampleStrategy} from '@ohos/libraryimageknife';
//全局自定义key demo //全局自定义key demo
@Sendable @Sendable
@ -35,6 +36,9 @@ export class CustomEngineKeyImpl implements IEngineKey {
if (imageKnifeOption.transformation) { if (imageKnifeOption.transformation) {
key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";" key += "transformation=" + this.getTransformation(imageKnifeOption.transformation) + ";"
} }
if ((imageKnifeOption.downsampleOf !== DownsampleStrategy.NONE && imageKnifeOption.downsampleOf !== undefined)) {
key += "downsampleOf" + imageKnifeOption.downsampleOf + "width=" + width + "height=" + height
}
} }
return key return key
} }

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'

View File

@ -0,0 +1,58 @@
/*
* 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';
import { display } from '@kit.ArkUI';
@Entry
@Component
struct AutoImageFit {
@State imageWidth: number = 200;
private maxWidth: number = px2vp(display.getDefaultDisplaySync().width);
build() {
Column() {
this.Slider()
Column() {
Text('Image')
Image('https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg')
.width('100%')
.objectFit(ImageFit.Auto)
Text('ImageKnife')
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: 'https://contentcenter-drcn.dbankcdn.cn/pub_1/DevEcoSpace_1_900_9/56/v3/8MdhfSsCSMKj4sA6okUWrg/5uBx56tLTUO3RYQl-E5JiQ.jpg',
objectFit: ImageFit.Auto,
}
}).width('100%')
}.width(this.imageWidth).border({ width: 1 })
}
}
@Builder
Slider() {
Slider({
value: this.imageWidth,
min: 100,
max: this.maxWidth,
style: SliderStyle.OutSet
})
.blockColor(Color.White)
.width('100%')
.onChange((value: number) => {
this.imageWidth = value;
})
}
}

View File

@ -0,0 +1,220 @@
/*
* 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 { DownsampleStrategy, ImageKnifeOption, } from '@ohos/imageknife';
import { ImageKnifeComponent } from '@ohos/libraryimageknife';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { Downsampler } from '@ohos/imageknife/src/main/ets/downsampling/Downsampler';
import { FileTypeUtil } from '@ohos/imageknife/src/main/ets/utils/FileTypeUtil';
@Entry
@Component
struct DownSamplePage {
@State imageKnifeOption: ImageKnifeOption = {
loadSrc: $r('app.media.startIcon'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain
}
isBrightness: boolean = false
@State beforeSampling: number = 0
@State afterSampling: number = 0
@State SamplingList: SamplingType[] = [
new SamplingType(7, 'AT_LEAST'),
new SamplingType(1, 'AT_MOST'),
new SamplingType(2, 'FIT_CENTER_MEMORY'),
new SamplingType(4, 'FIT_CENTER_QUALITY'),
new SamplingType(5, 'CENTER_INSIDE_MEMORY'),
new SamplingType(6, 'CENTER_INSIDE_QUALITY'),
new SamplingType(0, 'NONE'),
]
@State checked: boolean = false
updateImageKnifeOption(value: string) {
if (value === 'NONE') {
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain,
downsampleOf: DownsampleStrategy.NONE
}
this.originalPixMap($r('app.media.pngSample'))
this.afterSamplingFunc($r('app.media.pngSample'))
} else if (value === 'AT_MOST') {
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain,
downsampleOf: DownsampleStrategy.AT_MOST
}
this.originalPixMap($r('app.media.pngSample'))
this.afterSamplingFunc($r('app.media.pngSample'))
} else if (value === 'FIT_CENTER_MEMORY') {
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain,
downsampleOf: DownsampleStrategy.FIT_CENTER_MEMORY
}
this.originalPixMap($r('app.media.pngSample'))
this.afterSamplingFunc($r('app.media.pngSample'))
} else if (value === 'FIT_CENTER_QUALITY') {
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain,
downsampleOf: DownsampleStrategy.FIT_CENTER_QUALITY
}
this.originalPixMap($r('app.media.pngSample'))
this.afterSamplingFunc($r('app.media.pngSample'))
} else if (value === 'CENTER_INSIDE_MEMORY') {
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain,
downsampleOf: DownsampleStrategy.CENTER_INSIDE_MEMORY
}
this.originalPixMap($r('app.media.pngSample'))
this.afterSamplingFunc($r('app.media.pngSample'))
} else if (value === 'CENTER_INSIDE_QUALITY') {
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain,
downsampleOf: DownsampleStrategy.CENTER_INSIDE_QUALITY
}
this.originalPixMap($r('app.media.pngSample'))
this.afterSamplingFunc($r('app.media.pngSample'))
} else {
this.imageKnifeOption = {
loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Contain,
downsampleOf: DownsampleStrategy.AT_LEAST
}
this.originalPixMap($r('app.media.pngSample'))
this.afterSamplingFunc($r('app.media.pngSample'))
}
}
async afterSamplingFunc(imgs: Resource) {
let img: Uint8Array = await getContext(this).resourceManager.getMediaContent(imgs);
let imageSource: image.ImageSource = image.createImageSource(img.buffer.slice(0));
let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(img.buffer.slice(0)) as string;
let decodingOptions: image.DecodingOptions = {
editable: true,
desiredPixelFormat: 3,
}
let imageInfo = await imageSource.getImageInfo()
if (this.imageKnifeOption.downsampleOf !== DownsampleStrategy.NONE && this.imageKnifeOption.downsampleOf != undefined ) {
let reqSize =
new Downsampler().calculateScaling(typeValue, imageInfo.size.width, imageInfo.size.height, 300,
300, this.imageKnifeOption.downsampleOf)
decodingOptions = {
editable: true,
desiredSize: {
width: reqSize.width,
height: reqSize.height
}
}
}
// 创建pixelMap
imageSource.createPixelMap(decodingOptions).then((pixelMap: image.PixelMap) => {
imageSource.release()
this.afterSampling = pixelMap.getPixelBytesNumber()
pixelMap.release()
}).catch((err: BusinessError) => {
imageSource.release()
console.error('Failed to create PixelMap')
});
}
async originalPixMap(imgs: Resource,) {
let img: Uint8Array = await getContext(this).resourceManager.getMediaContent(imgs);
let imageSource: image.ImageSource = image.createImageSource(img.buffer.slice(0));
let decodingOptions: image.DecodingOptions = {
editable: true,
desiredPixelFormat: 3,
}
// 创建pixelMap
imageSource.createPixelMap(decodingOptions).then((pixelMap: image.PixelMap) => {
imageSource.release()
this.beforeSampling = pixelMap.getPixelBytesNumber()
pixelMap.release()
}).catch((err: BusinessError) => {
imageSource.release()
console.error('Failed to create PixelMap')
});
}
getResourceString(res:Resource){
return getContext().resourceManager.getStringSync(res.id)
}
build() {
Scroll() {
Column() {
ForEach(this.SamplingList, (item: SamplingType, index) => {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Radio({ value: item.value + 'radio', group: 'radioGroup' })
.height(50)
.width(50)
.checked(this.checked)
.onClick(() => {
this.updateImageKnifeOption(item.value)
})
Text(this.getResourceString($r('app.string.Sampling_pecification'))+ item.value).fontSize(20)
}
}, (item: SamplingType) => JSON.stringify(item))
Column() {
Text(`${this.getResourceString($r('app.string.Unreal_samples'))}${this.beforeSampling}`).fontSize(20)
Text(`${ this.getResourceString($r('app.string.After_the_sampling'))}${this.afterSampling}`).fontSize(20)
}
ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption
})
.height(px2vp(300))
.width(px2vp(300))
.borderWidth(1)
.borderColor(Color.Pink)
}
}
.height('100%')
.width('100%')
}
}
class SamplingType {
key: number
value: string
constructor(key: number, value: string) {
this.key = key
this.value = value
}
}

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 { ImageKnifeComponent } from '@ohos/libraryimageknife'
@Entry
@Component
struct ErrorMessageDownload {
@State httpCode: string = ''
@State httpError: string = ''
@State storageError: string = ''
@State fileError: string = ''
@State notPic: string = ''
build() {
Column() {
Text(this.httpCode)
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:'https://gitee.com/openharmony-tpc/ImageKnife/issues/1111111',
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed:(err)=>{
this.httpCode = err
}
}
}
}).width(100).height(100).margin({bottom:10})
Text(this.httpError)
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:'https://xx.xx.xx',
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed:(err)=>{
this.httpError = err
}
}
}
}).width(100).height(100).margin({bottom:10})
Text(this.storageError)
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:'/data/storage/el2/base/haps/entry/cache/a/b',
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed:(err)=>{
this.storageError = err
}
}
}
}).width(100).height(100).margin({bottom:10})
Text(this.fileError)
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:'file://xx.xx.xx',
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed:(err)=>{
this.fileError = err
}
}
}
}).width(100).height(100).margin({bottom:10})
Text(this.notPic)
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:'xx.xx.xx',
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed:(err)=>{
this.notPic = err
}
}
}
}).width(100).height(100).margin({bottom:10})
}
}
}

View File

@ -12,82 +12,91 @@
* 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, ImageKnifeAnimatorComponent,ImageKnifeOption } from "@ohos/libraryimageknife" import { AnimatorOption, ImageKnifeAnimatorComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct ImageAnimatorPage { struct ImageAnimatorPage {
@Local animatorOption: AnimatorOption = new AnimatorOption({ @State animatorOption: AnimatorOption = {
state: AnimationStatus.Running, state: AnimationStatus.Running,
iterations: -1, iterations: -1,
onFinish:()=>{ onFinish: () => {
console.log("ImageKnifeAnimatorComponent animatorOption onFinish") console.log('ImageKnifeAnimatorComponent animatorOption onFinish')
}, },
onStart:()=>{ onStart: () => {
console.log("ImageKnifeAnimatorComponent animatorOption onStart") console.log('ImageKnifeAnimatorComponent animatorOption onStart')
}, },
onPause:()=>{ onPause: () => {
console.log("ImageKnifeAnimatorComponent animatorOption onPause") console.log('ImageKnifeAnimatorComponent animatorOption onPause')
}, },
onCancel:()=>{ onCancel: () => {
console.log("ImageKnifeAnimatorComponent animatorOption onCancel") console.log('ImageKnifeAnimatorComponent animatorOption onCancel')
}, },
onRepeat:()=>{ onRepeat: () => {
console.log("ImageKnifeAnimatorComponent animatorOption onRepeat") console.log('ImageKnifeAnimatorComponent animatorOption onRepeat')
} }
}) }
@Local animatorOption1: AnimatorOption = new AnimatorOption({ @State animatorOptionFirstFrame: AnimatorOption = {
state: AnimationStatus.Initial state: AnimationStatus.Initial
}) }
@Local animatorOption2: AnimatorOption = new AnimatorOption({ @State animatorOptionLastFrame: AnimatorOption = {
state: AnimationStatus.Initial, state: AnimationStatus.Initial,
reverse: true reverse: true
}) }
@State imageKnifeOption: ImageKnifeOption = {
loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658',
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.failed')
}
build() { build() {
Column(){ Column() {
Flex(){ Row() {
Button($r('app.string.Play')).onClick(()=>{ Button($r('app.string.Play')).onClick(() => {
this.animatorOption.state = AnimationStatus.Running this.animatorOption.state = AnimationStatus.Running
}) })
Button($r('app.string.Pause')).onClick(()=>{ Button($r('app.string.Pause')).onClick(() => {
this.animatorOption.state = AnimationStatus.Paused this.animatorOption.state = AnimationStatus.Paused
}) })
Button($r('app.string.Stop')).onClick(()=>{ Button($r('app.string.Stop')).onClick(() => {
this.animatorOption.state = AnimationStatus.Stopped this.animatorOption.state = AnimationStatus.Stopped
}) })
Button($r('app.string.Infinite_loop')).onClick(()=>{ }
Row() {
Button($r('app.string.Infinite_loop')).onClick(() => {
this.animatorOption.iterations = -1 this.animatorOption.iterations = -1
}) })
Button($r('app.string.Play_once')).onClick(()=>{ Button($r('app.string.Play_once')).onClick(() => {
this.animatorOption.iterations = 1 this.animatorOption.iterations = 1
}) })
Button($r('app.string.Play_twice')).onClick(()=>{ Button($r('app.string.Play_twice')).onClick(() => {
this.animatorOption.iterations = 2 this.animatorOption.iterations = 2
}) })
} }
ImageKnifeAnimatorComponent({ ImageKnifeAnimatorComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption: this.imageKnifeOption,
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", animatorOption: this.animatorOption
placeholderSrc:$r('app.media.loading'), }).width(300).height(300).backgroundColor(Color.Orange).margin({ top: 30 })
errorholderSrc:$r('app.media.failed')
}),animatorOption:this.animatorOption Row({ space: 10 }) {
}).width(200).height(200).backgroundColor(Color.Orange).margin({top:30}) Column() {
Text($r('app.string.Display_the_first_frame')).fontSize(20) Text($r('app.string.Display_the_first_frame')).fontSize(20)
ImageKnifeAnimatorComponent({ ImageKnifeAnimatorComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption: this.imageKnifeOption,
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", animatorOption: this.animatorOptionFirstFrame
placeholderSrc:$r('app.media.loading'), }).width(120).height(120).backgroundColor(Color.Orange)
errorholderSrc:$r('app.media.failed') }
}),animatorOption:this.animatorOption1
}).width(200).height(200).backgroundColor(Color.Orange).margin({top:30}) Column() {
Text($r('app.string.Display_the_last_frame')).fontSize(20) Text($r('app.string.Display_the_last_frame')).fontSize(20)
ImageKnifeAnimatorComponent({ ImageKnifeAnimatorComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption: this.imageKnifeOption,
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", animatorOption: this.animatorOptionLastFrame
placeholderSrc:$r('app.media.loading'), }).width(120).height(120).backgroundColor(Color.Orange)
errorholderSrc:$r('app.media.failed') }
}),animatorOption:this.animatorOption2 }.margin({ top: 50 }).padding(10)
}).width(200).height(200).backgroundColor(Color.Orange).margin({top:30}) }.width('100%').height('100%')
}.width("100%").height("100%")
} }
} }

View File

@ -0,0 +1,99 @@
/*
* 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 {
@State index: number = 0
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})
Text("重试5次" + this.index)
ImageKnifeComponent({
imageKnifeOption:{
loadSrc:'https://img-blog.csdn.net/20140514114029140',
placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed'),
onLoadListener:{
onLoadFailed:(err,request) => {
this.index++
if(request != undefined && this.index < 5) {
ImageKnife.getInstance().reload(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

@ -35,17 +35,17 @@ import {
import { collections } from '@kit.ArkTS' import { collections } from '@kit.ArkTS'
@Entry @Entry
@ComponentV2 @Component
struct ImageTransformation { struct ImageTransformation {
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption: 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
}) }
@Local isRound: boolean = false; @State isRound: boolean = false;
@Local isContrast: boolean = false; @State isContrast: boolean = false;
@Local isRotate: boolean = false; @State isRotate: boolean = false;
isBlur: boolean = false isBlur: boolean = false
isBrightness: boolean = false isBrightness: boolean = false
isGrayScale: boolean = false; isGrayScale: boolean = false;
@ -398,13 +398,13 @@ struct ImageTransformation {
transformations.push(new CropSquareTransformation()); transformations.push(new CropSquareTransformation());
} }
if (this.isCropTop) { if (this.isCropTop) {
transformations.push(new CropTransformation(25, 25, 0)); transformations.push(new CropTransformation(100, 100, 0));
} }
if (this.isCropCenter) { if (this.isCropCenter) {
transformations.push(new CropTransformation(25, 25, 1)); transformations.push(new CropTransformation(100, 100, 1));
} }
if (this.isCropBottom) { if (this.isCropBottom) {
transformations.push(new CropTransformation(25, 25, 2)); transformations.push(new CropTransformation(100, 100, 2));
} }
if (this.isSepia) { if (this.isSepia) {
transformations.push(new SepiaTransformation()); transformations.push(new SepiaTransformation());
@ -412,14 +412,14 @@ struct ImageTransformation {
if (this.isMask) { if (this.isMask) {
transformations.push(new MaskTransformation($r('app.media.mask_starfish'))); transformations.push(new MaskTransformation($r('app.media.mask_starfish')));
} }
this.imageKnifeOption = new ImageKnifeOption({ this.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: this.isRound ? { topLeft: 50, bottomRight: 50 } : 0 }, border: { radius: this.isRound ? { topLeft: 50, bottomRight: 50 } : 0 },
transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined transformation: transformations.length > 0 ? new MultiTransTransformation(transformations) : undefined
}) }
if (this.isCropCircle) { if (this.isCropCircle) {
this.imageKnifeOption.objectFit = ImageFit.Cover; this.imageKnifeOption.objectFit = ImageFit.Cover;
this.imageKnifeOption.border = { radius: 150 }; this.imageKnifeOption.border = { radius: 150 };

View File

@ -15,7 +15,7 @@
import router from '@system.router'; import router from '@system.router';
@Entry @Entry
@ComponentV2 @Component
struct Index { struct Index {
getResourceString(res:Resource){ getResourceString(res:Resource){
@ -35,6 +35,31 @@ struct Index {
uri: 'pages/ImageAnimatorPage', uri: 'pages/ImageAnimatorPage',
}); });
}) })
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.Single_CallBack')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/SingleImageCallBack',
});
})
Button($r('app.string.Multiple_CallBack')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/MultipleImageCallBack',
});
})
Button($r('app.string.Test_multiple_images')).margin({top:10}).onClick(()=>{ Button($r('app.string.Test_multiple_images')).margin({top:10}).onClick(()=>{
router.push({ router.push({
uri: 'pages/TestCommonImage', uri: 'pages/TestCommonImage',
@ -57,37 +82,53 @@ struct Index {
}); });
}) })
Button($r('app.string.Test_LocalImageShow')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/LocalImage',
});
})
Button($r('app.string.Error_Message')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/ErrorMessageDownload',
});
})
Button($r('app.string.Test_custom_download')).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(this.getResourceString($r('app.string.Multiple_images')) + " + LazyForEach").margin({top:10}).onClick(()=>{ Button(this.getResourceString($r('app.string.Multiple_images')) + ' + reuse + LazyForeach').margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/ManyPhotoShowPage',
});
})
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($r('app.string.Image_Downsampling_Functionality')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/DownSamplePage',
});
})
Button($r('app.string.Display_long_image')).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($r('app.string.Auto_ImageFit')).margin({top:10}).onClick(()=>{
router.push({
uri: 'pages/AutoImageFit',
});
})
Button($r('app.string.Image_scaling')).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(this.getResourceString($r('app.string.Message_list')) + " + 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',
@ -162,7 +203,32 @@ struct Index {
}); });
}) })
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',
});
})
Button($r('app.string.test_exif')).margin({ top: 10 }).onClick(() => {
router.push({
uri: 'pages/TestImageExif',
});
})
} }
} .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

@ -15,11 +15,11 @@
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'; import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
@Entry @Entry
@ComponentV2 @Component
struct ListPage { struct ListPage {
private data: string[] = [] private data: string[] = []
@Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ loadSrc: $r('app.media.startIcon')}) @State ImageKnifeOption: ImageKnifeOption = { loadSrc: $r('app.media.startIcon')}
aboutToAppear(): void { aboutToAppear(): void {

View File

@ -12,37 +12,37 @@
* 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 { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife" import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
import matrix4 from '@ohos.matrix4' import matrix4 from '@ohos.matrix4'
@Entry @Entry
@ComponentV2 @Component
struct LoadStatePage { struct LoadStatePage {
starTime:number = new Date().getTime() starTime:number = new Date().getTime()
@Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State ImageKnifeOption: ImageKnifeOption = {
loadSrc: $r("app.media.rabbit"), loadSrc: $r('app.media.rabbit'),
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,
onLoadListener: { onLoadListener: {
onLoadFailed: (err) => { onLoadFailed: (err) => {
console.error("Load Failed Reason: " + err); console.error('Load Failed Reason: ' + err);
}, },
onLoadSuccess: (data) => { onLoadSuccess: (data) => {
return data; return data;
}, },
}, },
border: { radius: 50 } border: { radius: 50 }
}) }
@Local imageKnifeOption1: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption1: ImageKnifeOption = {
loadSrc: $r('app.media.startIcon') loadSrc: $r('app.media.startIcon')
}) }
@Local message: string = "" @State message: string = ''
@Local currentWidth: number = 200 @State currentWidth: number = 200
@Local currentHeight: number = 200 @State currentHeight: number = 200
@Local typeValue: string = "" @State typeValue: string = ''
build() { build() {
Column() { Column() {
Text($r('app.string.TIPS')) Text($r('app.string.TIPS'))
@ -50,21 +50,21 @@ struct LoadStatePage {
Row() { Row() {
Button($r('app.string.Test_failure_success')) Button($r('app.string.Test_failure_success'))
.onClick(() => { .onClick(() => {
this.ImageKnifeOption = new ImageKnifeOption({ this.ImageKnifeOption = {
loadSrc: "https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", loadSrc: 'https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png',
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,
onLoadListener: { onLoadListener: {
onLoadStart:()=>{ onLoadStart:()=>{
this.starTime = new Date().getTime() this.starTime = new Date().getTime()
console.info("Load start: "); console.info('Load start: ');
}, },
onLoadFailed: (err) => { onLoadFailed: (err) => {
console.error("Load Failed Reason: " + err + " cost " + (new Date().getTime() - this.starTime) + " milliseconds"); console.error('Load Failed Reason: ' + err + ' cost ' + (new Date().getTime() - this.starTime) + ' milliseconds');
}, },
onLoadSuccess: (data,imageData) => { onLoadSuccess: (data,imageData) => {
console.info("Load Successful: cost " + (new Date().getTime() - this.starTime) + " milliseconds"); console.info('Load Successful: cost ' + (new Date().getTime() - this.starTime) + ' milliseconds');
this.currentWidth = imageData.imageWidth! this.currentWidth = imageData.imageWidth!
this.currentHeight = imageData.imageHeight! this.currentHeight = imageData.imageHeight!
this.typeValue = imageData.type! this.typeValue = imageData.type!
@ -73,27 +73,29 @@ struct LoadStatePage {
}, },
border: { radius: 50 }, border: { radius: 50 },
onComplete:(event)=>{ onComplete:(event)=>{
console.error("Load onComplete width:"+event?.width , " height:"+event?.height , " componentWidth:"+event?.componentWidth," componentHeight:" + event?.componentHeight); console.error('Load onComplete width:'+event?.width , ' height:'+event?.height , ' componentWidth:'+event?.componentWidth,' componentHeight:' + event?.componentHeight);
} }
}) }
}) })
} }
.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($r('app.string.Custom_download_failed')).onClick(()=>{ Button($r('app.string.Custom_download_failed')).onClick(()=>{
this.imageKnifeOption1 = new ImageKnifeOption({ this.imageKnifeOption1 = {
loadSrc: "abc", loadSrc: 'abc',
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed'), errorholderSrc:$r('app.media.failed'),
customGetImage:custom, customGetImage:custom,
onLoadListener: { onLoadListener: {
onLoadFailed:(err)=>{ onLoadFailed:(err)=>{
this.message = "err:" + err this.message = 'err:' + err
} }
} }
}) }
}).margin({ top: 20 }) }).margin({ top: 20 })
Text(this.message).fontSize(20).margin({ top: 20 }) Text(this.message).fontSize(20).margin({ top: 20 })
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).height(this.currentHeight).width(this.currentWidth) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).height(this.currentHeight).width(this.currentWidth)
@ -107,8 +109,8 @@ 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,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 { ImageKnifeComponent } from '@ohos/libraryimageknife';
import fs from '@ohos.file.fs';
@Entry
@Component
struct LocalImage {
scroller: Scroller = new Scroller;
localFile: string = getContext(this).filesDir + '/icon.png'
aboutToAppear(): void {
// 拷贝本地文件
let icon: Uint8Array = getContext(this).resourceManager.getMediaContentSync($r('app.media.startIcon'));
let file = fs.openSync(this.localFile, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
fs.writeSync(file.fd, icon.buffer);
fs.fsyncSync(file.fd);
fs.closeSync(file);
}
build() {
Scroll(this.scroller) {
Column() {
Text($r('app.string.local_r_file'))
.fontSize(30)
.fontWeight(FontWeight.Bold)
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $r('app.media.startIcon'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
Text($r('app.string.local_rawfile'))
.fontSize(30)
.fontWeight(FontWeight.Bold)
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $rawfile('image/startIcon.png'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
Text($r('app.string.Under_context_file'))
.fontSize(30)
.fontWeight(FontWeight.Bold)
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.localFile,
objectFit: ImageFit.Contain
}
}).width(100).height(100)
Text($r('app.string.local_other_module'))
.fontSize(30)
.fontWeight(FontWeight.Bold)
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $r('[sharedlibrary].media.startIcon'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
}
.width('100%')
}
.height('100%')
}
}

View File

@ -12,26 +12,30 @@
* 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 { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct LongImagePage { struct LongImagePage {
build() { build() {
Scroll() { Scroll() {
// Image("https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg").objectFit(ImageFit.Auto).height(300) // Image('https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg').objectFit(ImageFit.Auto).height(300)
// Image($r("app.media.aaa")).objectFit(ImageFit.Auto).width(200) // Image($r('app.media.aaa')).objectFit(ImageFit.Auto).width(200)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc:"https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg", loadSrc:'https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg',
//src:$r("app.media.aaa"), //src:$r('app.media.aaa'),
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r("app.media.failed"), errorholderSrc: $r('app.media.failed'),
httpOption: {
connectTimeout: 60000,
readTimeout: 60000
},
objectFit: ImageFit.Auto objectFit: ImageFit.Auto
}) }
}) })
} }
.height('100%') .width('100%') .height('100%') .width('100%')

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,151 @@
/*
* 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';
import { CommonDataSource } from './model/CommonDataSource'
@Entry
@Component
struct MultipleImageCallBack {
@State hotCommendList: CommonDataSource<string> = new CommonDataSource<string>([])
@State componentIndex: number = 0
@State startIndex: number = 0
@State successIndex: number = 0
@State failIndex: number = 0
@State cancelJobIndex: number = 0
@State cancelLoadIndex: number = 0
@State memoryIndex: number = 0
@State fileCacheIndex: number = 0
@State netIndex: number = 0
@State checkText: string = ''
private data: Array<string> = []
aboutToAppear(): void {
for (let index = 0; index < 100; index++) {
this.data.push(`https://img-blog.csdn.net/20140514114029140?${index}`)
}
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.data)
}
build() {
Column() {
Row() {
Column() {
Text('图片总数:' + this.componentIndex)
Text('开始回调:' + this.startIndex)
Text('成功回调:' + this.successIndex)
Text('失败回调:' + this.failIndex)
Text('队列取消回调:' + this.cancelJobIndex)
Text('加载取消回调:' + this.cancelLoadIndex)
Text('内存数量:' + this.memoryIndex)
Text('文件数量:' + this.fileCacheIndex)
Text('网络数量:' + this.netIndex)
}.width('50%')
Column() {
Button('check')
.onClick(()=>{
this.checkText = ''
if (this.componentIndex !== this.startIndex + this.cancelJobIndex) {
this.checkText = this.checkText + '图片总数!=开始+队列取消,'
}
if(this.startIndex !== this.successIndex + this.failIndex + this.cancelLoadIndex) {
this.checkText = this.checkText + '开始回调!=成功+失败+加载取消,'
}
if(this.successIndex !== this.memoryIndex + this.fileCacheIndex + this.netIndex) {
this.checkText = this.checkText + '成功回调!=内存+文件+网络,'
}
if(this.componentIndex !== this.successIndex + this.failIndex + this.cancelJobIndex + this.cancelLoadIndex) {
this.checkText = this.checkText + '图片总数!=成功+失败+加载取消+队列取消,'
}
if(this.checkText == '') {
this.checkText = 'check正确'
}
})
Text(this.checkText)
}.width('50%')
}.width('100%')
Column() {
WaterFlow() {
LazyForEach(this.hotCommendList, (item: string,index: number) => {
FlowItem() {
Column() {
Text(index + '')
ImageComponent({
imageKnifeOption: {
loadSrc: item,
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.failed'),
onLoadListener: {
onLoadStart:()=>{
this.startIndex++
console.log('image load multiple loadStart:' + this.startIndex)
},
onLoadSuccess:(pixelmap,imageData,request)=>{
this.successIndex++
let memory = request?.imageKnifeData?.timeInfo?.memoryCheckEndTime ? 1 : 0
let fileCache = request?.imageKnifeData?.timeInfo?.diskCheckEndTime ? 1 : 0
let net = request?.imageKnifeData?.timeInfo?.netRequestEndTime ? 1 : 0
memory = memory - fileCache
fileCache = fileCache - net
this.memoryIndex = this.memoryIndex + memory
this.fileCacheIndex = this.fileCacheIndex + fileCache
this.netIndex = this.netIndex + net
console.log('image load multiple loadSuccess:' + this.successIndex)
},
onLoadFailed:()=>{
this.failIndex++
console.log('image load multiple loadFail:' + this.failIndex)
},
onLoadCancel:(message,request)=>{
let flag = request?.imageKnifeData?.timeInfo?.netRequestStartTime ? true : false
if (flag) {
this.cancelLoadIndex++
} else {
this.cancelJobIndex++
}
console.log('image load multiple cancelJobIndex:' + this.cancelJobIndex,'cancelLoadIndex' + this.cancelLoadIndex)
}
}
},index:this.componentIndex
}).width('50%').height(160)
}
}.height(200)
.backgroundColor('#95efd2')
}, (item: string) => item)
}
.cachedCount(0)
.columnsTemplate('1fr 1fr')
.columnsGap(10)
.rowsGap(5)
.backgroundColor(0xFAEEE0)
.width('100%')
}
.height('80%')
}.width('100%')
.height('100%')
}
}
@Component
struct ImageComponent {
@State imageKnifeOption: ImageKnifeOption = new ImageKnifeOption()
@Link index: number
aboutToAppear(): void {
this.index++
}
build() {
ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption
})
}
}

View File

@ -15,49 +15,49 @@
import { ImageKnife, ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnife, ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct ObjectFitPage { struct ObjectFitPage {
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption: ImageKnifeOption = {
loadSrc: $r("app.media.app_icon"), loadSrc: $r('app.media.app_icon'),
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Fill objectFit: ImageFit.Fill
}) }
build() { build() {
Column() { Column() {
Button($r('app.string.Main_image_Fill')).onClick(()=>{ Button($r('app.string.Main_image_Fill')).onClick(()=>{
this.imageKnifeOption = new 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'),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Fill objectFit: ImageFit.Fill
}) }
}) })
Button($r('app.string.Maintain_proportion_filling')).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()
this.imageKnifeOption = new ImageKnifeOption({ this.imageKnifeOption = {
loadSrc: "https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg", loadSrc: 'https://wx2.sinaimg.cn/mw690/006HyQKGgy1hnqp08dw09j30u04twu0x.jpg',
placeholderSrc: $r("app.media.app_icon"), placeholderSrc: $r('app.media.app_icon'),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Fill, objectFit: ImageFit.Fill,
placeholderObjectFit: ImageFit.Contain placeholderObjectFit: ImageFit.Contain
}) }
}) })
Button($r('app.string.Error_graph_None')).margin({top:10}).onClick(() => { Button($r('app.string.Error_graph_None')).margin({top:10}).onClick(() => {
this.imageKnifeOption = new ImageKnifeOption({ this.imageKnifeOption = {
loadSrc: "http://xxxxx", loadSrc: 'http://xxxxx',
placeholderSrc: $r("app.media.loading"), placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r("app.media.app_icon"), errorholderSrc: $r('app.media.app_icon'),
objectFit: ImageFit.Fill, objectFit: ImageFit.Fill,
errorholderObjectFit: ImageFit.None errorholderObjectFit: ImageFit.None
}) }
}) })
ImageKnifeComponent({ ImageKnifeComponent({

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,37 @@
/*
* 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 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

@ -1,13 +1,13 @@
/* /*
* Copyright (C) 2024 Huawei Device Co., Ltd. * Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* 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.
@ -16,18 +16,18 @@ import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife';
@Entry @Entry
@ComponentV2 @Component
struct SignatureTestPage { struct SignatureTestPage {
@Local imageKnifeOption1: ImageKnifeOption =new ImageKnifeOption( @State imageKnifeOption1: ImageKnifeOption =
{ {
loadSrc: $r('app.media.icon'), loadSrc: $r('app.media.icon'),
placeholderSrc:$r("app.media.loading"), placeholderSrc:$r('app.media.loading'),
}); };
@Local imageKnifeOption2: ImageKnifeOption =new ImageKnifeOption( @State imageKnifeOption2: ImageKnifeOption =
{ {
loadSrc: $r('app.media.icon'), loadSrc: $r('app.media.icon'),
placeholderSrc:$r("app.media.loading"), placeholderSrc:$r('app.media.loading'),
}); };
build() { build() {
Scroll() { Scroll() {
@ -37,11 +37,11 @@ struct SignatureTestPage {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button($r('app.string.Load')) Button($r('app.string.Load'))
.onClick(() => { .onClick(() => {
this.imageKnifeOption1 = new ImageKnifeOption({ this.imageKnifeOption1 = {
loadSrc: 'https://img-blog.csdn.net/20140514114029140', loadSrc: 'https://img-blog.csdn.net/20140514114029140',
placeholderSrc:$r("app.media.loading"), placeholderSrc:$r('app.media.loading'),
signature: "1" signature: '1'
}) }
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
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)
@ -50,11 +50,11 @@ struct SignatureTestPage {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button($r('app.string.Load')) Button($r('app.string.Load'))
.onClick(() => { .onClick(() => {
this.imageKnifeOption2 = new ImageKnifeOption({ this.imageKnifeOption2 = {
loadSrc: 'https://img-blog.csdn.net/20140514114029140', loadSrc: 'https://img-blog.csdn.net/20140514114029140',
placeholderSrc:$r("app.media.loading"), placeholderSrc:$r('app.media.loading'),
signature: new Date().getTime().toString() signature: new Date().getTime().toString()
}) }
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300) ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300)
}.width('100%').backgroundColor(Color.Pink) }.width('100%').backgroundColor(Color.Pink)
@ -66,7 +66,7 @@ struct SignatureTestPage {
} }
aboutToAppear() { aboutToAppear() {
console.log("唯一标识页面:" + new Date().getTime().toString()) console.log('唯一标识页面:' + new Date().getTime().toString())
} }
} }

View File

@ -12,28 +12,28 @@
* 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 { ImageKnifeComponent,BlurTransformation,ImageKnifeOption } from '@ohos/libraryimageknife'; import { ImageKnifeComponent,BlurTransformation } from '@ohos/libraryimageknife';
import fs from '@ohos.file.fs'; import fs from '@ohos.file.fs';
import image from '@ohos.multimedia.image'; import image from '@ohos.multimedia.image';
import { common2D, drawing } from '@kit.ArkGraphics2D'; import { common2D, drawing } from '@kit.ArkGraphics2D';
@Entry @Entry
@ComponentV2 @Component
struct SingleImage { struct SingleImage {
resource: string = "app.media.svgSample" resource: string = 'app.media.svgSample'
scroller: Scroller = new Scroller; scroller: Scroller = new Scroller;
localFile: string = getContext(this).filesDir + "/icon.png" localFile: string = getContext(this).filesDir + '/icon.png'
@Local pixelMap:PixelMap | undefined = undefined; @State pixelMap:PixelMap | undefined = undefined;
@Local DrawingColorFilter: ColorFilter | undefined = undefined @State DrawingColorFilter: ColorFilter | undefined = undefined
private color: common2D.Color = { alpha: 255, red: 255, green: 0, blue: 0 }; private color: common2D.Color = { alpha: 255, red: 255, green: 0, blue: 0 };
aboutToAppear(): void { aboutToAppear(): void {
// 拷贝本地文件 // 拷贝本地文件
let icon: Uint8Array = getContext(this).resourceManager.getMediaContentSync($r("app.media.startIcon")); let icon: Uint8Array = getContext(this).resourceManager.getMediaContentSync($r('app.media.startIcon'));
let file = fs.openSync(this.localFile, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE); let file = fs.openSync(this.localFile, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
fs.writeSync(file.fd, icon.buffer); fs.writeSync(file.fd, icon.buffer);
fs.fsyncSync(file.fd); fs.fsyncSync(file.fd);
fs.closeSync(file); fs.closeSync(file);
this.changePic(getContext().resourceManager.getMediaContentSync( $r("app.media.aaa")) this.changePic(getContext().resourceManager.getMediaContentSync( $r('app.media.aaa'))
.buffer as ArrayBuffer); .buffer as ArrayBuffer);
@ -46,62 +46,76 @@ struct SingleImage {
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: $r("app.media.svgSample"), loadSrc: $r(this.resource),
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
}) }
}).width(100).height(100) }).width(100).height(100)
.onClick(()=>{ .onClick(()=>{
this.DrawingColorFilter = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN); this.DrawingColorFilter = drawing.ColorFilter.createBlendModeColorFilter(this.color, drawing.BlendMode.SRC_IN);
}) })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $r('[sharedlibrary].media.pngSample'),
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.failed'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
Text($r('app.string.Under_context_file')) Text($r('app.string.Under_context_file'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: this.localFile, loadSrc: this.localFile,
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
}) }
}).width(100).height(100) }).width(100).height(100)
Text($r('app.string.Network_images')) Text($r('app.string.Network_images'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc:"https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png", loadSrc:'https://www.openharmony.cn/_nuxt/img/logo.dcf95b3.png',
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,
progressListener:(progress:number)=>{console.info("ImageKnife:: call back progress = " + progress)} progressListener:(progress:number)=>{console.info('ImageKnife:: call back progress = ' + progress)},
}) // 通过https协议进行连接时默认使用系统预设CA证书。若希望使用自定义证书进行https连接则需要将自定义证书上传至应用沙箱目录中并在caPath中指定该证书所在的应用沙箱路径
// caPath: '/data/storage/el1/bundle/ca.pem',
}
}).width(100).height(100) }).width(100).height(100)
Text($r('app.string.Custom_network_download')) Text($r('app.string.Custom_network_download'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: "https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg", loadSrc: 'https://file.atomgit.com/uploads/user/1704857786989_8994.jpeg',
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($r('app.string.PixelMap_loads_images')) Text($r('app.string.PixelMap_loads_images'))
.fontSize(30) .fontSize(30)
.fontWeight(FontWeight.Bold) .fontWeight(FontWeight.Bold)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: this.pixelMap!, loadSrc: this.pixelMap!,
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,
}) }
}).width(100).height(100) }).width(100).height(100)
} }
.width('100%') .width('100%')
@ -116,6 +130,7 @@ struct SingleImage {
editable: true, editable: true,
} }
imageSource.createPixelMap(decodingOptions,(err,pixelMap)=>{ imageSource.createPixelMap(decodingOptions,(err,pixelMap)=>{
imageSource.release()
this.pixelMap = pixelMap; this.pixelMap = pixelMap;
}) })
} }
@ -124,9 +139,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,126 @@
/*
* 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';
import { CommonDataSource } from './model/CommonDataSource'
@Entry
@Component
struct SingleImageCallBack {
@State hotCommendList: CommonDataSource<string> = new CommonDataSource<string>([])
@State componentIndex: number = 0
@State startIndex: number = 0
@State successIndex: number = 0
@State failIndex: number = 0
@State cancelJobIndex: number = 0
@State cancelLoadIndex: number = 0
@State memoryIndex: number = 0
@State fileCacheIndex: number = 0
@State netIndex: number = 0
@State checkText: string = ''
build() {
Column() {
Row() {
Column() {
Text('图片总数:' + this.componentIndex)
Text('开始回调:' + this.startIndex)
Text('成功回调:' + this.successIndex)
Text('失败回调:' + this.failIndex)
Text('队列取消回调:' + this.cancelJobIndex)
Text('加载取消回调:' + this.cancelLoadIndex)
Text('内存数量:' + this.memoryIndex)
Text('文件数量:' + this.fileCacheIndex)
Text('网络数量:' + this.netIndex)
}.width('50%')
Column() {
Button('check')
.onClick(()=>{
this.checkText = ''
if (this.componentIndex !== this.startIndex + this.cancelJobIndex) {
this.checkText = this.checkText + '图片总数!=开始+队列取消,'
}
if(this.startIndex !== this.successIndex + this.failIndex + this.cancelLoadIndex) {
this.checkText = this.checkText + '开始回调!=成功+失败+加载取消,'
}
if(this.successIndex !== this.memoryIndex + this.fileCacheIndex + this.netIndex) {
this.checkText = this.checkText + '成功回调!=内存+文件+网络,'
}
if(this.componentIndex !== this.successIndex + this.failIndex + this.cancelJobIndex + this.cancelLoadIndex) {
this.checkText = this.checkText + '图片总数!=成功+失败+加载取消+队列取消,'
}
if(this.checkText == '') {
this.checkText = 'check正确'
}
})
Text(this.checkText)
}.width('50%')
}.width('100%')
Column() {
ImageComponent({
imageKnifeOption: {
loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.failed'),
onLoadListener: {
onLoadStart: () => {
this.startIndex++
console.log('image load multiple loadStart:' + this.startIndex)
},
onLoadSuccess: (pixelmap, imageData, request) => {
this.successIndex++
let memory = request?.imageKnifeData?.timeInfo?.memoryCheckEndTime ? 1 : 0
let fileCache = request?.imageKnifeData?.timeInfo?.diskCheckEndTime ? 1 : 0
let net = request?.imageKnifeData?.timeInfo?.netRequestEndTime ? 1 : 0
memory = memory - fileCache
fileCache = fileCache - net
this.memoryIndex = this.memoryIndex + memory
this.fileCacheIndex = this.fileCacheIndex + fileCache
this.netIndex = this.netIndex + net
console.log('image load multiple loadSuccess:' + this.successIndex)
},
onLoadFailed: () => {
this.failIndex++
console.log('image load multiple loadFail:' + this.failIndex)
},
onLoadCancel: (message,request) => {
let flag = request?.imageKnifeData?.type ? true : false
if (flag) {
this.cancelLoadIndex++
} else {
this.cancelJobIndex++
}
console.log('image load multiple cancelJobIndex:' + this.cancelJobIndex,'cancelLoadIndex' + this.cancelLoadIndex)
}
}
},index:this.componentIndex
}).width(300).height(300)
}
.height('80%')
}.width('100%')
.height('100%')
}
}
@Component
struct ImageComponent {
@State imageKnifeOption: ImageKnifeOption = new ImageKnifeOption()
@Link index: number
aboutToAppear(): void {
this.index++
}
build() {
ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption
})
}
}

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

@ -12,10 +12,10 @@
* 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 { ImageKnifeComponent ,ImageKnifeOption} from '@ohos/libraryimageknife'; import { ImageKnifeComponent } from '@ohos/libraryimageknife';
@Entry @Entry
@ComponentV2 @Component
struct TestCommonImage { struct TestCommonImage {
private data: Array<string> = [] private data: Array<string> = []
aboutToAppear(): void { aboutToAppear(): void {
@ -30,23 +30,23 @@ struct TestCommonImage {
FlowItem() { FlowItem() {
Column(){ Column(){
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: item, loadSrc: item,
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,
signature: "aaa" signature: 'aaa'
}) }
}).width("50%").height(200) }).width('50%').height(200)
} }
}.height(200) }.height(200)
.backgroundColor("#95efd2") .backgroundColor('#95efd2')
},(item: string) => item) },(item: string) => item)
}.columnsTemplate("1fr 1fr") }.columnsTemplate('1fr 1fr')
.columnsGap(10) .columnsGap(10)
.rowsGap(5) .rowsGap(5)
.backgroundColor(0xFAEEE0) .backgroundColor(0xFAEEE0)
.width("100%").height("100%") .width('100%').height('100%')
} }
} }
} }

View File

@ -12,34 +12,34 @@
* 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 { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestErrorHolderPage { struct TestErrorHolderPage {
build() { build() {
Column() { Column() {
Text("ImageKnifeComponent1").fontSize(20) Text('ImageKnifeComponent1').fontSize(20)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: "abc", loadSrc: 'abc',
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
}) }
}).width(200).height(200) }).width(200).height(200)
Text("ImageKnifeComponent2").fontSize(20) Text('ImageKnifeComponent2').fontSize(20)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: "abc", loadSrc: 'abc',
errorholderSrc:$r('app.media.startIcon') errorholderSrc:$r('app.media.startIcon')
}) }
}).width(200).height(200) }).width(200).height(200)
Text("ImageKnifeComponent2").fontSize(20) Text('ImageKnifeComponent2').fontSize(20)
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: "abc", loadSrc: 'abc',
errorholderSrc:$r('app.media.mask_starfish') errorholderSrc:$r('app.media.mask_starfish')
}) }
}).width(200).height(200) }).width(200).height(200)
} }
.height('100%') .width('100%') .height('100%') .width('100%')

View File

@ -15,18 +15,18 @@
import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestPrefetchToFileCachePage { struct TestPrefetchToFileCachePage {
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption: ImageKnifeOption = {
loadSrc:"https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658", loadSrc:'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658',
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
headerOption:[ headerOption:[
{ {
key:"abc", key:'abc',
value:"单个" value:'单个'
} }
] ]
}) }
build() { build() {
Column() { Column() {

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 { IndexComponent } from "@ohos/libraryimageknife" import { IndexComponent } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestHspPreLoadImage { struct TestHspPreLoadImage {
build() { build() {
Column() { Column() {
IndexComponent() IndexComponent()
}.width("100%").height('100%') }.width('100%').height('100%')
} }
} }

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2025 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';
import fs from '@ohos.file.fs';
@Entry
@Component
struct LocalImage {
scroller: Scroller = new Scroller;
build() {
Scroll(this.scroller) {
Column() {
Column() {
Text($r('app.string.base_image'))
.fontSize(20)
.fontWeight(FontWeight.Bold)
Row() {
Image($rawfile('rotate/rotate.jpg')).width(100).height(100).margin({ right: 10 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $rawfile('rotate/rotate.jpg'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
}
}
.margin({ bottom: 20 })
Column() {
Text($r('app.string.rotate_mirror'))
.fontSize(20)
.fontWeight(FontWeight.Bold)
Row() {
Image($rawfile('rotate/rotate_mirror.jpg')).width(100).height(100).margin({ right: 10 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $rawfile('rotate/rotate_mirror.jpg'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
}
}.margin({ bottom: 20 })
Column() {
Text($r('app.string.rotate_rotate90'))
.fontSize(20)
.fontWeight(FontWeight.Bold)
Row() {
Image($rawfile('rotate/rotate_rotate90.jpg')).width(100).height(100).margin({ right: 10 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $rawfile('rotate/rotate_rotate90.jpg'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
}
}.margin({ bottom: 20 })
Column() {
Text($r('app.string.rotate_mirror_rotate270'))
.fontSize(20)
.fontWeight(FontWeight.Bold)
Row() {
Image($rawfile('rotate/rotate_mirror_rotate270.jpg')).width(100).height(100).margin({ right: 10 })
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: $rawfile('rotate/rotate_mirror_rotate270.jpg'),
objectFit: ImageFit.Contain
}
}).width(100).height(100)
}
}
}
.width('100%')
}
.height('100%')
}
}

View File

@ -12,9 +12,9 @@
* 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 { ImageKnifeComponent,ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent } from '@ohos/libraryimageknife'
@ObservedV2 @Observed
export class MsgModel { export class MsgModel {
id: string id: string
cId: string cId: string
@ -30,66 +30,66 @@ export class MsgModel {
} }
// @Reusable @Reusable
@ComponentV2 @Component
export struct MsgItem { export struct MsgItem {
@Param count: number = 0 count: number = 0
private data: Array<string> = [ private data: Array<string> = [
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg", 'http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg',
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg", 'http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg',
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg", 'http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg',
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg", 'http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg',
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg", 'http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg',
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg", 'http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg',
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg", 'http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg',
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg", 'http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg',
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg", 'http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg',
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg", 'http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg',
"http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg", 'http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg',
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg", 'http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg',
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg", 'http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg',
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg", 'http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg',
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg", 'http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg',
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg", 'http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg',
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg", 'http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg',
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg", 'http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg',
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg", 'http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg',
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg", 'http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg',
] ]
build(){ build(){
if (this.count % 2 == 0 && this.count <6){ if (this.count % 2 == 0 && this.count <6){
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption:{
loadSrc:$r("app.media.startIcon"), loadSrc:$r('app.media.startIcon'),
placeholderSrc:$r("app.media.loading") placeholderSrc:$r('app.media.loading')
}),syncLoad:true },syncLoad:true
}) })
}else if (this.count > 6 && this.count - 6 < this.data.length){ }else if (this.count > 6 && this.count - 6 < this.data.length){
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption:{
loadSrc:this.data[this.count - 6], loadSrc:this.data[this.count - 6],
placeholderSrc:$r("app.media.loading") placeholderSrc:$r('app.media.loading')
}),syncLoad:true },syncLoad:true
}) })
}else { }else {
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption:new ImageKnifeOption({ imageKnifeOption:{
loadSrc:$r("app.media.pngSample"), loadSrc:$r('app.media.pngSample'),
placeholderSrc:$r("app.media.loading") placeholderSrc:$r('app.media.loading')
}),syncLoad:true },syncLoad:true
}) })
} }
} }
} }
@Entry @Entry
@ComponentV2 @Component
struct ImageTestPage { struct ImageTestPage {
count : number = 0 count : number = 0
rCount: number = 0 rCount: number = 0
scroller: Scroller = new Scroller() scroller: Scroller = new Scroller()
@Local list: MsgModel[] = [] @State list: MsgModel[] = []
@Local imageSize: number =100 @State imageSize: number =100
handAdd(){ handAdd(){
this.count++ this.count++
const msgItem = new MsgModel('add_id'+this.count, 'addBody'+this.count,'cId'+ this.count) const msgItem = new MsgModel('add_id'+this.count, 'addBody'+this.count,'cId'+ this.count)
@ -103,10 +103,10 @@ struct ImageTestPage {
build(){ build(){
Column(){ Column(){
Row(){ Row(){
Button("addItem").onClick(()=> { Button('addItem').onClick(()=> {
this.handAdd() this.handAdd()
}) })
Button("remove").onClick(()=> { Button('remove').onClick(()=> {
this.list.splice(0,1) this.list.splice(0,1)
}) })
} }

View File

@ -0,0 +1,387 @@
/*
* 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 errMsg: string | undefined = ''
@State errPhase: string | undefined = ''
@State errCode: number | undefined = 0
@State httpCode: 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 showChild: boolean = true;
@State requestFrom: string = '';
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.errMsg)).fontSize(14)
Text($r('app.string.err_phase', this.errPhase)).fontSize(14)
Text($r('app.string.err_code', this.errCode)).fontSize(14)
Text($r('app.string.http_code', this.httpCode)).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.request_data_from', this.requestFrom)).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?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.imageKnifeData);
}
},
border: { radius: 50 },
}
})
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?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.imageKnifeData);
}
},
border: { radius: 50 },
}
})
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?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.imageKnifeData);
}
},
border: { radius: 50 },
}
})
}
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?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.imageKnifeData);
}
},
border: { radius: 50 },
}
})
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?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.imageKnifeData);
}
},
border: { radius: 50 },
}
})
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?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.imageKnifeData);
}
},
border: { radius: 50 },
}
})
}
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?.imageKnifeData);
},
onLoadSuccess: (data, imageData, req) => {
this.analyzeSuccessCallBackData(req?.imageKnifeData);
},
onLoadCancel: (res, req) => {
this.analyzeFailedBackData(res, req?.imageKnifeData);
}
},
border: { radius: 50 },
}
})
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?.imageKnifeData;
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);
this.requestFrom = '';
}
}
analyzeSuccessCallBackData(data: ImageKnifeData | undefined) {
if (data) {
this.imageWidth = data.imageWidth;
this.imageHeight = data.imageHeight;
this.imageSize = data.bufSize;
this.frameNum = data.frameCount;
this.httpCode = data.httpCode
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);
if (data.timeInfo?.netRequestEndTime !== undefined) {
this.requestFrom = 'Http request';
} else if (data.timeInfo?.diskCheckEndTime !== undefined) {
this.requestFrom = 'File Cache';
} else {
this.requestFrom = 'Memory Cache';
}
}
}
analyzeFailedBackData(res: string, data: ImageKnifeData | undefined) {
if (data) {
this.errMsg = res;
this.errPhase = data.errorInfo?.phase;
this.errCode = data.errorInfo?.code;
this.httpCode = data.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)
this.requestFrom = '';
}
}
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.errMsg = ''
this.errPhase = ''
this.errCode = 0
this.httpCode = 0
this.reqStartTime = ''
this.reqEndTime = ''
this.reqCancelTime = ''
this.memoryStartTime = ''
this.memoryEndTime = ''
this.diskStartTime = ''
this.diskEndTime = ''
this.netStartTime = ''
this.netEndTime = ''
this.decodeStartTime = ''
this.decodeEndTime = ''
this.showChild = true;
}
}

View File

@ -15,37 +15,37 @@
import { ImageKnifeComponent, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife' import { ImageKnifeComponent, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestIsUrlExist { struct TestIsUrlExist {
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption: ImageKnifeOption = {
loadSrc: $r('app.media.startIcon'), loadSrc: $r('app.media.startIcon'),
placeholderSrc: $r('app.media.loading'), placeholderSrc: $r('app.media.loading'),
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
}) }
@Local source: PixelMap | string | Resource = $r("app.media.startIcon") @State source: PixelMap | string | Resource = $r('app.media.startIcon')
@Local source1: PixelMap | string | Resource = $r("app.media.startIcon") @State source1: PixelMap | string | Resource = $r('app.media.startIcon')
build() { build() {
Column() { Column() {
Flex() { Flex() {
Button($r('app.string.Preloading_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($r('app.string.Retrieve_GIF_from_memory')).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)
.then((data) => { .then((data) => {
this.source = data !== undefined ? data.source : $r("app.media.startIcon") this.source = data !== undefined ? data.source : $r('app.media.startIcon')
}) })
}) })
Button($r('app.string.Retrieve_GIF_from_disk')).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)
.then((data) => { .then((data) => {
this.source1 = data !== undefined ? data.source : $r("app.media.startIcon") this.source1 = data !== undefined ? data.source : $r('app.media.startIcon')
}) })
}) })
} }

View File

@ -0,0 +1,103 @@
/*
* 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 {
public src: string = '';
public w: number = 0;
public 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?.imageKnifeData))
},
onLoadFailed: (res, req) => {
console.log('listCache onLoadFailed:res:' + res + ';' + JSON.stringify(req?.imageKnifeData))
},
onLoadSuccess: (data, imageData,req) => {
console.log('listCache onLoadSuccess:' + JSON.stringify(req?.imageKnifeData))
},
onLoadCancel: (res, req) => {
console.log('listCache onLoadCancel:res:' + res + ';' + JSON.stringify(req?.imageKnifeData))
}
},
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

@ -15,31 +15,31 @@
import { ImageKnifeComponent,ImageKnife,ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent,ImageKnife,ImageKnifeOption } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestPrefetchToFileCachePage { struct TestPrefetchToFileCachePage {
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption: ImageKnifeOption = {
loadSrc:$r('app.media.startIcon'), loadSrc:$r('app.media.startIcon'),
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
}) }
async preload(url:string) { async preload(url:string) {
let fileCachePath = await ImageKnife.getInstance().preLoadCache(url) let fileCachePath = await ImageKnife.getInstance().preLoadCache(url)
console.log("preload-fileCachePath=="+ fileCachePath) console.log('preload-fileCachePath=='+ fileCachePath)
} }
async preload1(url:string) { async preload1(url:string) {
let fileCachePath = await ImageKnife.getInstance().preLoadCache(new ImageKnifeOption({ loadSrc: url })) let fileCachePath = await ImageKnife.getInstance().preLoadCache({ loadSrc: url })
console.log("preload-fileCachePath1=="+ fileCachePath) console.log('preload-fileCachePath1=='+ fileCachePath)
} }
build() { build() {
Column() { Column() {
Button($r('app.string.Preloading_images_to_file_cache_using_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($r('app.string.Preloading_images_to_file_cache_using_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($r('app.string.Load_image_offline_after_preloading')).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({
imageKnifeOption: this.imageKnifeOption imageKnifeOption: this.imageKnifeOption

View File

@ -15,40 +15,40 @@
import { ImageKnifeComponent, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife' import { ImageKnifeComponent, ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestRemoveCache { struct TestRemoveCache {
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption: ImageKnifeOption = {
loadSrc: $r('app.media.startIcon'), loadSrc: $r('app.media.startIcon'),
placeholderSrc: $r('app.media.loading'), placeholderSrc: $r('app.media.loading'),
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
}) }
@Local source: PixelMap | string | Resource = $r("app.media.startIcon"); @State source: PixelMap | string | Resource = $r('app.media.startIcon');
@Local source1: PixelMap | string | Resource = $r("app.media.startIcon"); @State source1: PixelMap | string | Resource = $r('app.media.startIcon');
@Local url: string = ''; @State url: string = '';
build() { build() {
Column() { Column() {
Flex() { Flex() {
Button($r('app.string.Preloading_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($r('app.string.Retrieve_GIF_from_memory')).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)
.then((data) => { .then((data) => {
this.source = data !== undefined ? data.source : $r("app.media.startIcon"); this.source = data !== undefined ? data.source : $r('app.media.startIcon');
}) })
}) })
.margin({left:10}) .margin({left:10})
Button($r('app.string.Retrieve_GIF_from_disk')).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)
.then((data) => { .then((data) => {
this.source1 = data !== undefined ? data.source : $r("app.media.startIcon"); this.source1 = data !== undefined ? data.source : $r('app.media.startIcon');
}) })
}) })
.margin({left:10}) .margin({left:10})

View File

@ -15,55 +15,54 @@
import { ImageKnifeComponent, ImageKnife, ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent, ImageKnife, ImageKnifeOption } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestSetCustomImagePage { struct TestSetCustomImagePage {
@State imageKnifeOption: ImageKnifeOption = {
getResourceString(res:Resource){
return getContext().resourceManager.getStringSync(res.id)
}
@Local imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({
loadSrc: $r('app.media.startIcon'), loadSrc: $r('app.media.startIcon'),
placeholderSrc: $r('app.media.loading') placeholderSrc: $r('app.media.loading')
}) }
aboutToAppear(): void { aboutToAppear(): void {
ImageKnife.getInstance().setCustomGetImage(custom) ImageKnife.getInstance().setCustomGetImage(custom)
} }
aboutToDisappear(): void { aboutToDisappear(): void {
ImageKnife.getInstance().setCustomGetImage() ImageKnife.getInstance().setCustomGetImage()
} }
getResourceString(res:Resource){
return getContext().resourceManager.getStringSync(res.id)
}
build() { build() {
Column() { Column() {
Button(this.getResourceString($r('app.string.Custom_network_download')) + " a").onClick(()=>{ Button(this.getResourceString($r('app.string.Custom_network_download')) + ' a').onClick(()=>{
this.imageKnifeOption = new ImageKnifeOption({ this.imageKnifeOption ={
loadSrc: "aaa", loadSrc: 'aaa',
placeholderSrc: $r('app.media.loading') placeholderSrc: $r('app.media.loading')
}) }
}) })
Button(this.getResourceString($r('app.string.Custom_network_download')) + " b").onClick(()=>{ Button(this.getResourceString($r('app.string.Custom_network_download')) + ' b').onClick(()=>{
this.imageKnifeOption = new ImageKnifeOption({ this.imageKnifeOption = {
loadSrc: "bbb", loadSrc: 'bbb',
placeholderSrc: $r('app.media.loading') placeholderSrc: $r('app.media.loading')
}) }
}) })
Button(this.getResourceString($r('app.string.Custom_network_download')) + " c").onClick(()=>{ Button(this.getResourceString($r('app.string.Custom_network_download')) + ' c').onClick(()=>{
this.imageKnifeOption = new ImageKnifeOption({ this.imageKnifeOption = {
loadSrc: "ccc", loadSrc: 'ccc',
placeholderSrc: $r('app.media.loading') placeholderSrc: $r('app.media.loading')
}) }
}) })
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption imageKnifeOption: this.imageKnifeOption
}).width(300) }).width(300)
.height(300) .height(300)
} }
.width("100%") .width('100%')
.height("100%") .height('100%')
} }
} }
@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

@ -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 { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife" import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
@ComponentV2 @ComponentV2
export struct ZuImage { export struct ZuImage {
@ -24,12 +24,12 @@ export struct ZuImage {
if (this.src) { if (this.src) {
//当前版本存在bug //当前版本存在bug
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: new ImageKnifeOption({ imageKnifeOption: {
loadSrc: this.src, loadSrc: this.src,
placeholderSrc: this.placeholderSrc, placeholderSrc: this.placeholderSrc,
errorholderSrc: this.errorholderSrc ?? this.placeholderSrc, errorholderSrc: this.errorholderSrc ?? this.placeholderSrc,
objectFit: ImageFit.Cover objectFit: ImageFit.Cover
}) }
}) })
} else { } else {
Image(this.placeholderSrc) Image(this.placeholderSrc)
@ -43,8 +43,8 @@ export struct ZuImage {
@ComponentV2 @ComponentV2
struct TestTaskResourcePage { struct TestTaskResourcePage {
@Local stateMenus: Array<string> = [ @Local stateMenus: Array<string> = [
"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',
] ]
@ -53,7 +53,7 @@ struct TestTaskResourcePage {
Column({ space: 8 }) { Column({ space: 8 }) {
ZuImage({ ZuImage({
src: item, src: item,
placeholderSrc: $r("app.media.loading") placeholderSrc: $r('app.media.loading')
}).width(44) }).width(44)
.height(44) .height(44)
} }
@ -66,7 +66,7 @@ struct TestTaskResourcePage {
this._buildItem(item) this._buildItem(item)
} }
}) })
}.width("100%") }.width('100%')
.columnsTemplate('1fr 1fr 1fr 1fr 1fr') .columnsTemplate('1fr 1fr 1fr 1fr 1fr')
.rowsGap(24) .rowsGap(24)
.padding({ .padding({

View File

@ -15,55 +15,55 @@
import { ImageKnifeComponent,CacheStrategy,ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent,CacheStrategy,ImageKnifeOption } from '@ohos/libraryimageknife'
@Entry @Entry
@ComponentV2 @Component
struct TestWriteCacheStage { struct TestWriteCacheStage {
@Local imageKnifeOption1: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption1: ImageKnifeOption = {
loadSrc:$r('app.media.startIcon'), loadSrc:$r('app.media.startIcon'),
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
}) }
@Local imageKnifeOption2: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption2: ImageKnifeOption = {
loadSrc:$r('app.media.startIcon'), loadSrc:$r('app.media.startIcon'),
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
}) }
@Local imageKnifeOption3: ImageKnifeOption = new ImageKnifeOption({ @State imageKnifeOption3: ImageKnifeOption = {
loadSrc:$r('app.media.startIcon'), loadSrc:$r('app.media.startIcon'),
placeholderSrc:$r('app.media.loading'), placeholderSrc:$r('app.media.loading'),
errorholderSrc:$r('app.media.failed') errorholderSrc:$r('app.media.failed')
}) }
build() { build() {
Column() { Column() {
Button($r('app.string.Write_memory_and_file')).margin({top:10}).onClick(async ()=>{ Button($r('app.string.Write_memory_and_file')).margin({top:10}).onClick(async ()=>{
this.imageKnifeOption1 = new ImageKnifeOption({ 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'),
errorholderSrc:$r('app.media.failed'), errorholderSrc:$r('app.media.failed'),
writeCacheStrategy:CacheStrategy.Default writeCacheStrategy:CacheStrategy.Default
}) }
}) })
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption1 imageKnifeOption: this.imageKnifeOption1
}).width(200).height(200).margin({top:10}) }).width(200).height(200).margin({top:10})
Button($r('app.string.Write_memory')).margin({top:10}).onClick(async ()=>{ Button($r('app.string.Write_memory')).margin({top:10}).onClick(async ()=>{
this.imageKnifeOption2 = new ImageKnifeOption({ 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'),
errorholderSrc:$r('app.media.failed'), errorholderSrc:$r('app.media.failed'),
writeCacheStrategy:CacheStrategy.Memory writeCacheStrategy:CacheStrategy.Memory
}) }
}) })
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption2 imageKnifeOption: this.imageKnifeOption2
}).width(200).height(200).margin({top:10}) }).width(200).height(200).margin({top:10})
Button($r('app.string.Write_file')).margin({top:10}).onClick(async ()=>{ Button($r('app.string.Write_file')).margin({top:10}).onClick(async ()=>{
this.imageKnifeOption3 = new ImageKnifeOption({ 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'),
errorholderSrc:$r('app.media.failed'), errorholderSrc:$r('app.media.failed'),
writeCacheStrategy:CacheStrategy.File writeCacheStrategy:CacheStrategy.File
}) }
}) })
ImageKnifeComponent({ ImageKnifeComponent({
imageKnifeOption: this.imageKnifeOption3 imageKnifeOption: this.imageKnifeOption3

View File

@ -12,22 +12,22 @@
* 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 { ImageKnifeComponent, ImageKnifeOption } from "@ohos/libraryimageknife" import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
import matrix4 from '@ohos.matrix4' import matrix4 from '@ohos.matrix4'
@Entry @Entry
@ComponentV2 @Component
struct TransformPage { struct TransformPage {
private custom_scale:number = 1 private custom_scale:number = 1
@Local matrix1:object = matrix4.identity().scale({ x: 1, y: 1 }) @State matrix1:object = matrix4.identity().scale({ x: 1, y: 1 })
@Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ @State ImageKnifeOption: ImageKnifeOption = {
loadSrc: $r("app.media.rabbit"), loadSrc: $r('app.media.rabbit'),
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: 50 } border: { radius: 50 }
}) }
build() { build() {
Column() { Column() {

View File

@ -15,50 +15,24 @@
import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife' import { ImageKnifeComponent, ImageKnifeOption } from '@ohos/libraryimageknife'
// const logger = new imUtils.logger.IMLogger('Avatar') // const logger = new imUtils.logger.IMLogger('Avatar')
@ObservedV2
export class MyStorage { class MyImageOption extends ImageKnifeOption {
static instance:MyStorage | undefined = undefined account?: string
static getInstance(){
if(MyStorage.instance == undefined) {
MyStorage.instance = new MyStorage()
}
return MyStorage.instance
}
@Trace WeLink_Mob_fontSize_multiple: number = 1
} }
@ComponentV2 @Component
export struct UserAvatar { export struct UserAvatar {
// @Prop userInfo: string = "" @Prop @Watch('userInfoUpdate') userInfo: string = ''
// @Prop userInfo: string = ''
imgSize: number = 100 imgSize: number = 100
radius: number = 12 radius: number = 12
borderSize: number = 0 borderSize: number = 0
imgSizes: number = 1 imgSizes: number = 1
@Local ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption() @State ImageKnifeOption: ImageKnifeOption = new ImageKnifeOption()
@StorageProp('WeLink_Mob_fontSize_multiple') @Watch('updateImgSize') WeLink_Mob_fontSize_multiple: number = 0
scalable: boolean = true; scalable: boolean = true;
@Local calcImgSize: number = 100 @State calcImgSize: number = 100
@Param userInfo: string = ""
@Monitor('userInfo')
userInfoUpdate() {
// if (uri === 'userInfo' && this.imageKnifeOption.account !== this.userInfo.contactId) return;
// // logger.info(`userInfoUpdate uri=${uri} oldAcc=${this.imageKnifeOption.loadSrc} nowAcc=${this.userInfo.externalHeadUrl}`)
// if (this.userInfo.externalHeadUrl === this.imageKnifeOption.loadSrc && this.userInfo.infoUpdateTime.getTime()
// .toString() === this.imageKnifeOption?.signature?.getKey()) return;
this.ImageKnifeOption = new ImageKnifeOption({
//TODO:写死loadSRC场景变更组件大小所有图片不显示
loadSrc: this.userInfo,
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.failed'),
border: { radius:20,width:5,color:$r('app.color.start_window_background') },
objectFit:ImageFit.Contain
// signature: new ObjectKey(this.userInfo.infoUpdateTime.getTime().toString())
})
}
@Local storage: MyStorage = MyStorage.getInstance()
@Monitor('storage.WeLink_Mob_fontSize_multiple')
updateImgSize() {
this.setImageSize()
}
aboutToAppear(): void { aboutToAppear(): void {
this.userInfoUpdate() this.userInfoUpdate()
this.setImageSize() this.setImageSize()
@ -67,19 +41,39 @@ export struct UserAvatar {
setImageSize() { setImageSize() {
if (!this.scalable) { if (!this.scalable) {
this.calcImgSize = this.imgSize this.calcImgSize = this.imgSize
} else if (this.storage.WeLink_Mob_fontSize_multiple < 0.9) { } else if (this.WeLink_Mob_fontSize_multiple < 0.9) {
this.calcImgSize = this.imgSize * 0.9 this.calcImgSize = this.imgSize * 0.9
} else if (this.storage.WeLink_Mob_fontSize_multiple > 1.6) { } else if (this.WeLink_Mob_fontSize_multiple > 1.6) {
this.calcImgSize = this.imgSize * 1.6 this.calcImgSize = this.imgSize * 1.6
} else { } else {
this.calcImgSize = this.imgSize * this.storage.WeLink_Mob_fontSize_multiple this.calcImgSize = this.imgSize * this.WeLink_Mob_fontSize_multiple
} }
} }
updateImgSize() {
this.setImageSize()
}
aboutToReuse(param: ESObject) { aboutToReuse(param: ESObject) {
this.userInfoUpdate() this.userInfoUpdate()
} }
userInfoUpdate() {
// if (uri === 'userInfo' && this.imageKnifeOption.account !== this.userInfo.contactId) return;
// // logger.info(`userInfoUpdate uri=${uri} oldAcc=${this.imageKnifeOption.loadSrc} nowAcc=${this.userInfo.externalHeadUrl}`)
// if (this.userInfo.externalHeadUrl === this.imageKnifeOption.loadSrc && this.userInfo.infoUpdateTime.getTime()
// .toString() === this.imageKnifeOption?.signature?.getKey()) return;
this.ImageKnifeOption = {
//TODO:写死loadSRC场景变更组件大小所有图片不显示
loadSrc: this.userInfo,
placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.failed'),
border: { radius:20,width:5,color:$r('app.color.start_window_background') },
objectFit:ImageFit.Contain
// signature: new ObjectKey(this.userInfo.infoUpdateTime.getTime().toString())
}
}
build() { build() {
Row() { Row() {
// Image(this.imageKnifeOption.loadSrc) // Image(this.imageKnifeOption.loadSrc)
@ -93,12 +87,12 @@ export struct UserAvatar {
// Image(this.userInfo) // Image(this.userInfo)
// Text((this.imageKnifeOption.loadSrc as string).split('/')[8]) // Text((this.imageKnifeOption.loadSrc as string).split('/')[8])
// .position({ x: 0, y: 0 }) // .position({ x: 0, y: 0 })
// .zIndex(9) // .zIndex(9)
// .fontSize(12) // .fontSize(12)
// .fontColor('#ff0000') // .fontColor('#ff0000')
} }
} }
} }

View File

@ -12,138 +12,83 @@
* 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 { MyStorage, UserAvatar } from './User' import { CommonDataSource } from './model/CommonDataSource'
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
@ComponentV2 @Component
struct Index { struct Index {
@Local 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',
] ]
aboutToAppear(): void { aboutToAppear(): void {
MyStorage.getInstance().WeLink_Mob_fontSize_multiple = 1 this.hotCommendList.addData(this.hotCommendList.totalCount(),this.data)
AppStorage.set('WeLink_Mob_fontSize_multiple',1)
} }
build() { build() {
Column() { Column() {
Button("bigger").onClick(()=>{ Button('bigger').onClick(()=>{
MyStorage.getInstance().WeLink_Mob_fontSize_multiple = 1.6 AppStorage.set('WeLink_Mob_fontSize_multiple',1.6)
}) })
Button("small").onClick(()=>{ Button('small').onClick(()=>{
MyStorage.getInstance().WeLink_Mob_fontSize_multiple = 0.8 AppStorage.set('WeLink_Mob_fontSize_multiple',0.8)
}) })
List(){ List(){
// LazyForEach(this.hotCommendList,(item:string)=>{ LazyForEach(this.hotCommendList,(item:string)=>{
// ListItem(){ ListItem(){
// ReuseImage({ ReuseImage({
// userInfo:item userInfo:item
// }).width("100%").height("100%").backgroundColor(Color.Yellow) }).width('100%').height('100%').backgroundColor(Color.Yellow)
// }.width(200).height(200).margin({bottom:5}) }.width(200).height(200).margin({bottom:5})
// }) })
Repeat(this.data)
.each((repeatItem)=>{
ListItem(){
ReuseImage({
userInfo:repeatItem.item
}).width("100%").height("100%").backgroundColor(Color.Yellow)
}.width(200).height(200).margin({bottom:5}).key("reuse")
})
.key(item => item+"reuse")
.virtualScroll()
.template("1",(repeatItem)=>{
ListItem(){
ReuseImage({
userInfo:repeatItem.item
}).width("100%").height("100%").backgroundColor(Color.Yellow)
}.width(200).height(200).margin({bottom:5}).key("reuse")
})
} }
// .cachedCount(20) // .cachedCount(20)
.width("100%") .width('100%')
.height("100%") .height('100%')
.backgroundColor(0xFAEEE0) .backgroundColor(0xFAEEE0)
}.width('100%').height("100%") }.width('100%').height('100%')
} }
} }
// @Reusable @Reusable
@ComponentV2 @Component
struct ReuseImage { struct ReuseImage {
@Param userInfo:string = "" @State userInfo:string = ''
// aboutToReuse(params: ESObject): void { aboutToReuse(params: ESObject): void {
// this.userInfo = params.userInfo this.userInfo = params.userInfo
// } }
build() { build() {
Column(){ Column(){
UserAvatar({ UserAvatar({
userInfo:this.userInfo userInfo:this.userInfo
}) })
}.width("100%").height("100%") }.width('100%').height('100%')
} }
} }

View File

@ -1,13 +1,13 @@
/* /*
* Copyright (C) 2024 Huawei Device Co., Ltd. * Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* 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.
@ -18,15 +18,15 @@ import { photoAccessHelper } from '@kit.MediaLibraryKit';
@Entry @Entry
@ComponentV2 @Component
struct DataShareUriLoadPage { struct DataShareUriLoadPage {
@Local imageKnifeOption1: ImageKnifeOption = @State imageKnifeOption1: ImageKnifeOption =
new ImageKnifeOption({ {
loadSrc: $r('app.media.icon'), loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.loading'), placeholderSrc: $r('app.media.loading'),
errorholderSrc: $r('app.media.failed') errorholderSrc: $r('app.media.failed')
}); };
build() { build() {
@ -43,10 +43,10 @@ struct DataShareUriLoadPage {
let photoViewPicker = new photoAccessHelper.PhotoViewPicker(); let photoViewPicker = new photoAccessHelper.PhotoViewPicker();
let photoSelectResult: photoAccessHelper.PhotoSelectResult = await photoViewPicker.select(photoSelectOptions); let photoSelectResult: photoAccessHelper.PhotoSelectResult = await photoViewPicker.select(photoSelectOptions);
uris = photoSelectResult.photoUris; uris = photoSelectResult.photoUris;
this.imageKnifeOption1 = new ImageKnifeOption({ this.imageKnifeOption1 = {
loadSrc: uris[0], loadSrc: uris[0],
placeholderSrc:$r('app.media.loading') placeholderSrc:$r('app.media.loading')
}) }
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
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)

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.
*/
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)
})
}
}

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

@ -6,7 +6,11 @@
"mainElement": "EntryAbility", "mainElement": "EntryAbility",
"deviceTypes": [ "deviceTypes": [
"default", "default",
"tablet" "tablet",
"tv",
"wearable",
"car",
"2in1"
], ],
"deliveryWithInstall": true, "deliveryWithInstall": true,
"installationFree": false, "installationFree": false,
@ -42,6 +46,15 @@
], ],
"when": "always" "when": "always"
} }
},
{
"name": "ohos.permission.GET_NETWORK_INFO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "always"
}
} }
] ]
} }

View File

@ -40,6 +40,10 @@
"name": "Test_SingleImage", "name": "Test_SingleImage",
"value": "SingleImage" "value": "SingleImage"
}, },
{
"name": "Test_LocalImageShow",
"value": "LocalImageShow"
},
{ {
"name": "Test_custom_download", "name": "Test_custom_download",
"value": "Global custom download" "value": "Global custom download"
@ -106,11 +110,11 @@
}, },
{ {
"name": "Display_the_first_frame", "name": "Display_the_first_frame",
"value": "Display the first frame of the animation" "value": "first frame"
}, },
{ {
"name": "Display_the_last_frame", "name": "Display_the_last_frame",
"value": "Display the last frame of the animation" "value": "last frame"
}, },
{ {
"name": "Play", "name": "Play",
@ -140,10 +144,26 @@
"name": "Local_SVG", "name": "Local_SVG",
"value": "Local SVG image" "value": "Local SVG image"
}, },
{
"name": "local_r_file",
"value": "Local $r file"
},
{
"name": "local_rawfile",
"value": "Local rawfile"
},
{ {
"name": "Under_context_file", "name": "Under_context_file",
"value": "Files under context file" "value": "Files under context file"
}, },
{
"name": "local_other_module",
"value": "Local other module"
},
{
"name": "in_other_module",
"value": "in other module"
},
{ {
"name": "Network_images", "name": "Network_images",
"value": "Network images" "value": "Network images"
@ -367,6 +387,326 @@
{ {
"name": "TIPS", "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" "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 frames of the animator:%d "
},
{
"name": "img_content_size",
"value": "decoded width and height size of image:%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": "request start time:%s "
},
{
"name": "req_end_time",
"value": "request end time:%s "
},
{
"name": "req_cancel_time",
"value": "request cancel time:%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": "request_data_from",
"value": "request from:%s "
},
{
"name": "Image_Downsampling_Functionality",
"value": "Downsampling function"
},
{
"name": "Sampling_pecification",
"value": "Downsampling specification"
},
{
"name": "Unreal_samples",
"value": "Unsampled size"
},
{
"name": "After_the_sampling",
"value": "Size after downsampling"
},
{
"name": "adjust_size",
"value": "Adjust size"
},
{
"name": "Auto_ImageFit",
"value": "ImageFit.Auto:Auto ImageFit Height"
},
{
"name": "Single_CallBack",
"value": "Single image callback"
},
{
"name": "Multiple_CallBack",
"value": "Multiple image callback"
},
{
"name": "Error_Message",
"value": "error message"
},
{
"name": "test_exif",
"value": "Test display orientation base on the EXIF metadata "
},
{
"name": "base_image",
"value": "The image don't carry rotation information"
},
{
"name": "rotate_mirror",
"value": "Mirror horizontal"
},
{
"name": "rotate_rotate90",
"value": "Rotate 90°"
},
{
"name": "rotate_mirror_rotate270",
"value": "Mirror horizontal and rotate 270°"
} }
] ]
} }

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

View File

@ -3,7 +3,6 @@
"pages/Index", "pages/Index",
"pages/ListPage", "pages/ListPage",
"pages/SingleImage", "pages/SingleImage",
"pages/ManyPhotoShowPage",
"pages/LongImagePage", "pages/LongImagePage",
"pages/TransformPage", "pages/TransformPage",
"pages/UserPage", "pages/UserPage",
@ -23,6 +22,27 @@
"pages/ImageAnimatorPage", "pages/ImageAnimatorPage",
"pages/TestSetCustomImagePage", "pages/TestSetCustomImagePage",
"pages/TestErrorHolderPage", "pages/TestErrorHolderPage",
"pages/TestTaskResourcePage" "pages/TestTaskResourcePage",
"pages/ImageKnifeReload",
"pages/LazyForEachCount",
"pages/LazyForEachCache",
"pages/PrefetchAndCacheCount",
"pages/PrefetchAndPreload",
"pages/TestCacheDataPage",
"pages/TestChangeColorPage",
"pages/TestLoadCancelListenerPage",
"pages/SetMaxRequestPage",
"pages/MaxRequest1",
"pages/MaxRequest2",
"pages/MaxRequest3",
"pages/TestImageKnifeCallbackPage",
"pages/TestListImageKnifeCallbackPage",
"pages/DownSamplePage",
"pages/AutoImageFit",
"pages/SingleImageCallBack",
"pages/MultipleImageCallBack",
"pages/LocalImage",
"pages/ErrorMessageDownload",
"pages/TestImageExif"
] ]
} }

View File

@ -1,24 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
},
{
"name": "app_permission_WRITE_IMAGEVIDEO",
"value": "获取写入媒体资源权限"
},
{
"name": "app_permission_READ_IMAGEVIDEO",
"value": "获取读媒体资源权限"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -40,6 +40,10 @@
"name": "Test_SingleImage", "name": "Test_SingleImage",
"value": "单个图片使用" "value": "单个图片使用"
}, },
{
"name": "Test_LocalImageShow",
"value": "本地图片显示"
},
{ {
"name": "Test_custom_download", "name": "Test_custom_download",
"value": "全局自定义下载" "value": "全局自定义下载"
@ -102,11 +106,11 @@
}, },
{ {
"name": "Display_the_first_frame", "name": "Display_the_first_frame",
"value": "动画显示第一帧" "value": "第一帧"
}, },
{ {
"name": "Display_the_last_frame", "name": "Display_the_last_frame",
"value": "动画显示最后一帧" "value": "最后一帧"
}, },
{ {
"name": "Play", "name": "Play",
@ -136,9 +140,21 @@
"name": "Local_SVG", "name": "Local_SVG",
"value": "本地资源SVG图片" "value": "本地资源SVG图片"
}, },
{
"name": "local_r_file",
"value": "本地$r文件"
},
{
"name": "local_rawfile",
"value": "本地rawfile文件"
},
{ {
"name": "Under_context_file", "name": "Under_context_file",
"value": "本地context files下文件" "value": "本地沙箱路径文件"
},
{
"name": "local_other_module",
"value": "本地其他模块文件"
}, },
{ {
"name": "Network_images", "name": "Network_images",
@ -363,6 +379,326 @@
{ {
"name": "TIPS", "name": "TIPS",
"value": "测试失败场景请先关闭网络,并保证本地没有此网络图片的缓存" "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": "request_data_from",
"value": "请求数据来自于:%s "
},
{
"name": "Image_Downsampling_Functionality",
"value": "降采样功能"
},
{
"name": "Sampling_pecification",
"value": "降采样规格"
},
{
"name": "Unreal_samples",
"value": "未降采样大小"
},
{
"name": "After_the_sampling",
"value": "降采样后大小"
},
{
"name": "adjust_size",
"value": "调整大小"
},
{
"name": "Auto_ImageFit",
"value": "ImageFit.Auto:自适用图片高度"
},
{
"name": "Single_CallBack",
"value": "单个图片回调"
},
{
"name": "Multiple_CallBack",
"value": "多张图片回调"
},
{
"name": "Error_Message",
"value": "错误信息"
},
{
"name": "base_image",
"value": "图片不携带旋转信息"
},
{
"name": "test_exif",
"value": "测试图片携带的EXIF元数据作为显示方向"
},
{
"name": "rotate_mirror",
"value": "水平翻转"
},
{
"name": "rotate_rotate90",
"value": "顺时针90°"
},
{
"name": "rotate_mirror_rotate270",
"value": "水平翻转后再顺时针270°"
} }
] ]
} }

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
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';
import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/queue/DefaultJobQueue'; import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/queue/DefaultJobQueue';
import { IJobQueue } from '@ohos/imageknife/src/main/ets/queue/IJobQueue'; import { IJobQueue } from '@ohos/imageknife/src/main/ets/queue/IJobQueue';
import taskpool from '@ohos.taskpool'; import taskpool from '@ohos.taskpool';
@ -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)
@ -70,10 +70,10 @@ export default function DefaultJobQueueTest() {
} }
function makeRequest(src: string, context: common.UIAbilityContext, priority?: taskpool.Priority): ImageKnifeRequest { function makeRequest(src: string, context: common.UIAbilityContext, priority?: taskpool.Priority): ImageKnifeRequest {
let option: ImageKnifeOption = new ImageKnifeOption({ let option: ImageKnifeOption = {
loadSrc: src, loadSrc: src,
priority: priority priority: priority
}) }
return new ImageKnifeRequest( return new ImageKnifeRequest(
option, option,
context, context,

View File

@ -153,9 +153,9 @@ export default function FileLruCacheTest() {
}); });
it('fileCacheEngineKey', 0, () => { it('fileCacheEngineKey', 0, () => {
let engineKey: IEngineKey = new DefaultEngineKey() let engineKey: IEngineKey = new DefaultEngineKey()
let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ let imageKnifeOption: ImageKnifeOption = {
loadSrc:"abc" loadSrc:"abc"
}) }
let imageKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"") let imageKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"")
let imageAnimatorKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"",true) let imageAnimatorKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"",true)
expect(imageKey == imageAnimatorKey).assertFalse() expect(imageKey == imageAnimatorKey).assertFalse()

View File

@ -40,10 +40,10 @@ export default function ImageKnifeTest() {
it('removeMemoryCache', 0, async () => { it('removeMemoryCache', 0, async () => {
let a = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'; let a = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp';
let option: ImageKnifeOption = new ImageKnifeOption({ let option: ImageKnifeOption = {
loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
signature: '' signature: ''
}) }
let key = ImageKnife.getInstance() let key = ImageKnife.getInstance()
.getEngineKeyImpl() .getEngineKeyImpl()
.generateMemoryKey('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', ImageKnifeRequestSource.SRC, option) .generateMemoryKey('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', ImageKnifeRequestSource.SRC, option)

View File

@ -44,7 +44,7 @@ export default function ImageKnifeOptionTest() {
imageWidth: 0, imageWidth: 0,
imageHeight: 0, imageHeight: 0,
} }
let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ let imageKnifeOption: ImageKnifeOption = {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
onLoadListener: { onLoadListener: {
onLoadFailed: (err) => { onLoadFailed: (err) => {
@ -58,7 +58,7 @@ export default function ImageKnifeOptionTest() {
return data; return data;
}, },
}, },
}) }
if (imageKnifeOption.onLoadListener && imageKnifeOption.onLoadListener.onLoadSuccess && imageKnifeOption.onLoadListener.onLoadFailed) { if (imageKnifeOption.onLoadListener && imageKnifeOption.onLoadListener.onLoadSuccess && imageKnifeOption.onLoadListener.onLoadFailed) {
imageKnifeOption.onLoadListener.onLoadSuccess(a,imageData); imageKnifeOption.onLoadListener.onLoadSuccess(a,imageData);
imageKnifeOption.onLoadListener.onLoadFailed(a); imageKnifeOption.onLoadListener.onLoadFailed(a);

View File

@ -44,7 +44,7 @@ export default function ImageKnifeOptionTest() {
imageWidth: 0, imageWidth: 0,
imageHeight: 0, imageHeight: 0,
} }
let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ let imageKnifeOption: ImageKnifeOption = {
loadSrc: $r("app.media.rabbit"), loadSrc: $r("app.media.rabbit"),
onLoadListener: { onLoadListener: {
onLoadFailed: (err) => { onLoadFailed: (err) => {
@ -58,7 +58,7 @@ export default function ImageKnifeOptionTest() {
return data; return data;
}, },
}, },
}) }
if (imageKnifeOption.onLoadListener && imageKnifeOption.onLoadListener.onLoadSuccess && imageKnifeOption.onLoadListener.onLoadFailed) { if (imageKnifeOption.onLoadListener && imageKnifeOption.onLoadListener.onLoadSuccess && imageKnifeOption.onLoadListener.onLoadFailed) {
imageKnifeOption.onLoadListener.onLoadSuccess(a,imageData); imageKnifeOption.onLoadListener.onLoadSuccess(a,imageData);
imageKnifeOption.onLoadListener.onLoadFailed(a); imageKnifeOption.onLoadListener.onLoadFailed(a);

View File

@ -14,10 +14,13 @@
*/ */
import DefaultJobQueueTest from './DefaultJobQueueTest.test'; import DefaultJobQueueTest from './DefaultJobQueueTest.test';
import FileLruCacheTest from './FileLruCache.test'; import FileLruCacheTest from './FileLruCache.test';
import ImageKnifeOptionTest from './ImageKnifeOption.test'; 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'
import SamplingTest from './SamplingTest.test';
export default function testsuite() { export default function testsuite() {
MemoryLruCacheTest(); MemoryLruCacheTest();
@ -26,4 +29,7 @@ export default function testsuite() {
ImageKnifeOptionTest(); ImageKnifeOptionTest();
ImageKnifeTest(); ImageKnifeTest();
Transform(); Transform();
SamplingTest()
imageFormatAndSize();
loadCallBackData();
} }

View File

@ -122,9 +122,9 @@ export default function MemoryLruCacheTest() {
it('memoryCacheEngineKey', 0, () => { it('memoryCacheEngineKey', 0, () => {
let engineKey: IEngineKey = new DefaultEngineKey() let engineKey: IEngineKey = new DefaultEngineKey()
let imageKnifeOption: ImageKnifeOption = new ImageKnifeOption({ let imageKnifeOption: ImageKnifeOption = {
loadSrc:"abc" loadSrc:"abc"
}) }
let imageKey = engineKey.generateMemoryKey(imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,imageKnifeOption) let imageKey = engineKey.generateMemoryKey(imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,imageKnifeOption)
let imageAnimatorKey = engineKey.generateMemoryKey(imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,imageKnifeOption,true) let imageAnimatorKey = engineKey.generateMemoryKey(imageKnifeOption.loadSrc,ImageKnifeRequestSource.SRC,imageKnifeOption,true)
expect(imageKey == imageAnimatorKey).assertFalse() expect(imageKey == imageAnimatorKey).assertFalse()

View File

@ -0,0 +1,84 @@
/*
* 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 { Downsampler } from '@ohos/imageknife/src/main/ets/downsampling/Downsampler'
import { DownsampleStrategy } from '@ohos/imageknife'
export default function SamplingTest() {
describe('SamplingTest', () => {
// 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('AT_MOST', 0, () => {
let reqSize: Size =
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
200, DownsampleStrategy.AT_MOST)
let req = (reqSize.width < 1024 && reqSize.height < 1024)
expect(req).assertEqual(true);
})
it('FIT_CENTER_MEMORY', 1, () => {
let reqSize: Size =
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
200, DownsampleStrategy.FIT_CENTER_MEMORY)
let req = (reqSize.width < 1024 && reqSize.height < 1024)
expect(req).assertEqual(true);
})
it('FIT_CENTER_QUALITY', 2, () => {
let reqSize: Size =
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
200, DownsampleStrategy.FIT_CENTER_QUALITY)
let req = (reqSize.width < 1024 && reqSize.height < 1024)
expect(req).assertEqual(true);
})
it('CENTER_OUTSIDE_MEMORY', 3, () => {
let reqSize: Size =
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
200, DownsampleStrategy.CENTER_INSIDE_MEMORY)
let req = (reqSize.width < 1024 && reqSize.height < 1024)
expect(req).assertEqual(true);
})
it('CENTER_OUTSIDE_QUALITY', 4, () => {
let reqSize: Size =
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
200, DownsampleStrategy.CENTER_INSIDE_QUALITY)
let req = (reqSize.width < 1024 && reqSize.height < 1024)
expect(req).assertEqual(true);
})
it('AT_LEAST', 5, () => {
let reqSize: Size =
new Downsampler().calculateScaling('jpg', 1024, 1024, 200,
200, DownsampleStrategy.AT_LEAST)
let req = (reqSize.width < 1024 && reqSize.height < 1024)
expect(req).assertEqual(true);
})
})
}

View File

@ -1,52 +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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
import { SendableData } from '@ohos/imageknife/src/main/ets/components/imageknife/SendableData'
export default function SendableDataTest() {
describe('SendableDataTest', ()=> {
// 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('TestPlaceHolderCacheKey', 0, () => {
let value: string = "placeholderRegisterCacheKey";
let data: SendableData = new SendableData();
data.setPlaceHolderRegisterCacheKey(value);
expect(data.getPlaceHolderRegisterCacheKey()).assertEqual(value);
})
it('TestPlaceHolderMemoryCacheKey', 1, () => {
let value: string = "placeholderRegisterMemoryCacheKey";
let data: SendableData = new SendableData();
data.setPlaceHolderRegisterMemoryCacheKey(value);
expect(data.getPlaceHolderRegisterMemoryCacheKey()).assertEqual(value);
})
})
}

View File

@ -1,106 +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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
import { DownloadClient } from '@ohos/imageknife/src/main/ets/components/imageknife/networkmanage/DownloadClient';
import common from '@ohos.app.ability.common';
import { GlobalContext } from '../testability/GlobalContext';
import { CustomDataFetchClient, DataFetchResult, ImageKnifeGlobal, RequestOption } from '@ohos/imageknife';
const BASE_COUNT: number = 2000;
export default function CustomDataFetchClientTest() {
describe('CustomDataFetchClientTest', () => {
// 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('TestIsLocalLoadSrc', 0, () => {
let path = 'invalid path';
let client = new DownloadClient()
expect(client.isLocalLoadSrc(undefined, path)).assertFalse();
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
if (context != undefined) {
let loadSrc1 = (context as common.UIAbilityContext).filesDir + 'a.jpg';
let loadSrc2 = (context as common.UIAbilityContext).cacheDir + 'b.jpg';
expect(client.isLocalLoadSrc(context, loadSrc1)).assertTrue();
expect(client.isLocalLoadSrc(context, loadSrc2)).assertTrue();
}
})
it('TestLoadData', 1, async () => {
let client = new CustomDataFetchClient();
let request = new RequestOption();
request.loadSrc = $r('app.media.icon');
let error = (await client.loadData(request) as DataFetchResult).error as String;
expect(error).assertEqual('CustomDataFetchClient request or loadSrc error.');
})
it('TestLoadData_customGetImage', 2, async () => {
let client = new CustomDataFetchClient();
let request = new RequestOption();
request.loadSrc = 'http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg';
request.customGetImage = (context: Context, src: string) => {
// 这里是模拟的customGetImage逻辑
return Promise.resolve(new DataFetchResult());
}
console.log('LXH', 'TestLoadData 2 --1 customGetImage is undefined ?' + (request.customGetImage == undefined));
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let result = await client.loadData(request);
if (context != undefined) {
console.log('LXH', 'TestLoadData 2 --2');
expect(typeof result)
.assertEqual(typeof (await request?.customGetImage(context as common.UIAbilityContext, request.loadSrc)));
}
})
it('TestLoadData_combineArrayBuffers', 3, () => {
// 创建几个ArrayBuffer作为测试数据
const arrayBuffer1 = new ArrayBuffer(4);
const uint8Array1 = new Uint8Array(arrayBuffer1);
uint8Array1[0] = 1;
uint8Array1[1] = 2;
uint8Array1[2] = 3;
uint8Array1[3] = 4;
const arrayBuffer2 = new ArrayBuffer(2);
const uint8Array2 = new Uint8Array(arrayBuffer2);
uint8Array2[0] = 5;
uint8Array2[1] = 6;
let client = new CustomDataFetchClient();
const combinedArrayBuffer = client.combineArrayBuffers([arrayBuffer1, arrayBuffer2]);
expect(combinedArrayBuffer.byteLength).assertEqual(6);
const combinedUint8Array = new Uint8Array(combinedArrayBuffer);
for (let i = 0; i < 4; i++) {
expect(combinedUint8Array[i]).assertEqual(uint8Array1[i]);
}
for (let i = 0; i < 2; i++) {
expect(combinedUint8Array[i + 4]).assertEqual(uint8Array2[i]);
}
});
})
}

View File

@ -0,0 +1,88 @@
/*
* 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,
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,116 @@
/*
* 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,
ImageKnifeData
} 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: ImageKnifeData | undefined = undefined;
let successCallBack: ImageKnifeData | undefined = 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?.imageKnifeData;
},
onLoadSuccess: (data, imageknifeData,req) => {
successCallBack = req?.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);
})
expect(startCallBack != undefined).assertTrue();
expect(successCallBack != undefined).assertTrue();
});
it('failed-CallBack', 0, async () => {
let failedCallBack: ImageKnifeData | undefined = 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?.imageKnifeData;
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

@ -6,7 +6,11 @@
"mainElement": "TestAbility", "mainElement": "TestAbility",
"deviceTypes": [ "deviceTypes": [
"default", "default",
"tablet" "tablet",
"tv",
"wearable",
"car",
"2in1"
], ],
"deliveryWithInstall": true, "deliveryWithInstall": true,
"installationFree": false, "installationFree": false,

View File

@ -18,7 +18,10 @@ 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/model/ImageKnifeOption' export { ImageKnifeOption,
AnimatorOption,
HttpRequestOption,
HeaderOptions } from './src/main/ets/model/ImageKnifeOption'
export { ImageKnifeRequest } from './src/main/ets/model/ImageKnifeRequest' export { ImageKnifeRequest } from './src/main/ets/model/ImageKnifeRequest'
@ -30,6 +33,8 @@ export { IEngineKey } from './src/main/ets/key/IEngineKey'
export { ImageKnifeData , CacheStrategy , ImageKnifeRequestSource} from "./src/main/ets/model/ImageKnifeData" export { ImageKnifeData , CacheStrategy , ImageKnifeRequestSource} from "./src/main/ets/model/ImageKnifeData"
export { DownsampleStrategy } from './src/main/ets/downsampling/DownsampleStartegy'
export { PixelMapTransformation } from './src/main/ets/transform/PixelMapTransformation' export { PixelMapTransformation } from './src/main/ets/transform/PixelMapTransformation'
export { MultiTransTransformation } from './src/main/ets/transform/MultiTransTransformation' export { MultiTransTransformation } from './src/main/ets/transform/MultiTransTransformation'
@ -66,4 +71,4 @@ export { CropTransformation } from './src/main/ets/transform/CropTransformation'
export { MaskTransformation } from './src/main/ets/transform/MaskTransformation' export { MaskTransformation } from './src/main/ets/transform/MaskTransformation'
export { SepiaTransformation } from './src/main/ets/transform/SepiaTransformation' export { SepiaTransformation } from './src/main/ets/transform/SepiaTransformation'

View File

@ -1,6 +1,19 @@
{ {
"meta": {
"stableOrder": false
},
"lockfileVersion": 3, "lockfileVersion": 3,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {}, "specifiers": {
"packages": {} "@ohos/gpu_transform@^1.0.2": "@ohos/gpu_transform@1.0.4"
},
"packages": {
"@ohos/gpu_transform@1.0.4": {
"name": "@ohos/gpu_transform",
"version": "1.0.4",
"integrity": "sha512-PrKlOK66kzObw/ANIzt55YMrOLLmtrhmAZIE2c/60GBoTl7+NLxONeHA2NsDZuiW+A0KnD4QylDYWH4/yo8T0w==",
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/gpu_transform/-/gpu_transform-1.0.4.har",
"registryType": "ohpm"
}
}
} }

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.1.1-rc.0", "version": "3.2.2-rc.1",
"dependencies": { "dependencies": {
"@ohos/gpu_transform": "^1.0.2" "@ohos/gpu_transform": "^1.0.2"
}, },

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 './model/ImageKnifeRequest'; import { ImageKnifeRequest, ImageKnifeRequestState } from './model/ImageKnifeRequest';
import { CacheStrategy, ImageKnifeData, ImageKnifeRequestSource } from './model/ImageKnifeData'; import { CacheStrategy, ImageKnifeData, ImageKnifeRequestSource } from './model/ImageKnifeData';
import { MemoryLruCache } from './cache/MemoryLruCache'; import { MemoryLruCache } from './cache/MemoryLruCache';
import { IMemoryCache } from './cache/IMemoryCache' import { IMemoryCache } from './cache/IMemoryCache'
@ -25,6 +25,7 @@ import { util } from '@kit.ArkTS';
import { image } from '@kit.ImageKit'; import { image } from '@kit.ImageKit';
import { common } from '@kit.AbilityKit'; import { common } from '@kit.AbilityKit';
import { LogUtil } from './utils/LogUtil'; import { LogUtil } from './utils/LogUtil';
import { emitter } from '@kit.BasicServicesKit';
export class ImageKnife { export class ImageKnife {
@ -38,7 +39,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 +81,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 +146,42 @@ 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) {
if (typeof request?.imageKnifeOption.loadSrc === 'string' && !request?.drawMainSuccess) {
emitter.emit(request.imageKnifeOption.loadSrc + request.componentId)
}
request.requestState = ImageKnifeRequestState.DESTROY
}
/** /**
* 预加载图片到文件缓存 * 预加载图片到文件缓存
* @param loadSrc 图片地址url * @param loadSrc 图片地址url
@ -147,15 +190,15 @@ export class ImageKnife {
preLoadCache(loadSrc: string | ImageKnifeOption): Promise<string> { preLoadCache(loadSrc: string | ImageKnifeOption): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let imageKnifeOption = new ImageKnifeOption() let imageKnifeOption = new ImageKnifeOption()
if (typeof loadSrc == "string") { if (typeof loadSrc == 'string') {
imageKnifeOption.loadSrc = loadSrc imageKnifeOption.loadSrc = loadSrc
} else { } else {
imageKnifeOption = loadSrc; imageKnifeOption = loadSrc;
} }
LogUtil.log("ImageKnife_DataTime_preLoadCache-imageKnifeOption:"+loadSrc) LogUtil.log('ImageKnife_DataTime_preLoadCache-imageKnifeOption:'+loadSrc)
let fileKey = this.getEngineKeyImpl().generateFileKey(imageKnifeOption.loadSrc, imageKnifeOption.signature) let fileKey = this.getEngineKeyImpl().generateFileKey(imageKnifeOption.loadSrc, imageKnifeOption.signature)
let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(fileKey) let cachePath = ImageKnife.getInstance().getFileCache().getFileToPath(fileKey)
if (cachePath == null || cachePath == "" || cachePath == undefined) { if (cachePath == null || cachePath == '' || cachePath == undefined) {
imageKnifeOption.onLoadListener = { imageKnifeOption.onLoadListener = {
onLoadSuccess(){ onLoadSuccess(){
resolve(ImageKnife.getInstance().getFileCache().getFileToPath(fileKey)) resolve(ImageKnife.getInstance().getFileCache().getFileToPath(fileKey))
@ -191,10 +234,10 @@ export class ImageKnife {
*/ */
getCacheImage(loadSrc: string, getCacheImage(loadSrc: string,
cacheType: CacheStrategy = CacheStrategy.Default, signature?: string): Promise<ImageKnifeData | undefined> { cacheType: CacheStrategy = CacheStrategy.Default, signature?: string): Promise<ImageKnifeData | undefined> {
let option: ImageKnifeOption = new ImageKnifeOption({ let option: ImageKnifeOption = {
loadSrc: loadSrc, loadSrc: loadSrc,
signature:signature signature:signature
}) }
let engineKeyImpl: IEngineKey = this.getEngineKeyImpl(); let engineKeyImpl: IEngineKey = this.getEngineKeyImpl();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -218,7 +261,7 @@ export class ImageKnife {
*/ */
putCacheImage(url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) { putCacheImage(url: string, pixelMap: PixelMap, cacheType: CacheStrategy = CacheStrategy.Default, signature?: string) {
let memoryKey = this.getEngineKeyImpl() let memoryKey = this.getEngineKeyImpl()
.generateMemoryKey(url, ImageKnifeRequestSource.SRC, new ImageKnifeOption({ loadSrc: url, signature: signature })); .generateMemoryKey(url, ImageKnifeRequestSource.SRC, { loadSrc: url, signature: signature });
let fileKey = this.getEngineKeyImpl().generateFileKey(url, signature); let fileKey = this.getEngineKeyImpl().generateFileKey(url, signature);
let imageKnifeData: ImageKnifeData = { source: pixelMap, imageWidth: 0, imageHeight: 0 }; let imageKnifeData: ImageKnifeData = { source: pixelMap, imageWidth: 0, imageHeight: 0 };
switch (cacheType) { switch (cacheType) {
@ -252,9 +295,9 @@ export class ImageKnife {
if (url instanceof ImageKnifeOption) { if (url instanceof ImageKnifeOption) {
imageKnifeOption = url; imageKnifeOption = url;
} else { } else {
imageKnifeOption = new ImageKnifeOption({ imageKnifeOption = {
loadSrc: url loadSrc: url
}); };
} }
let key = this.getEngineKeyImpl().generateFileKey(imageKnifeOption.loadSrc, imageKnifeOption.signature); let key = this.getEngineKeyImpl().generateFileKey(imageKnifeOption.loadSrc, imageKnifeOption.signature);
if (this.fileCache !== undefined) { if (this.fileCache !== undefined) {
@ -278,14 +321,14 @@ export class ImageKnife {
} }
loadFromMemoryCache(key: string): ImageKnifeData | undefined { loadFromMemoryCache(key: string): ImageKnifeData | undefined {
if (key !== "") { if (key !== '') {
return this.memoryCache.get(key) return this.memoryCache.get(key)
} }
return undefined return undefined
} }
saveMemoryCache(key: string, data: ImageKnifeData): void { saveMemoryCache(key: string, data: ImageKnifeData): void {
if (key !== "") { if (key !== '') {
this.memoryCache.put(key, data) this.memoryCache.put(key, data)
} }
} }
@ -302,6 +345,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();
@ -326,7 +428,7 @@ export class ImageKnife {
if (typeValue === 'gif' || typeValue === 'webp') { if (typeValue === 'gif' || typeValue === 'webp') {
let base64Help = new util.Base64Helper() let base64Help = new util.Base64Helper()
let base64str = "data:image/" + typeValue + ";base64," + base64Help.encodeToStringSync(new Uint8Array(buffer)) let base64str = 'data:image/' + typeValue + ';base64,' + base64Help.encodeToStringSync(new Uint8Array(buffer))
onComplete({ onComplete({
source: base64str, source: base64str,
imageWidth: 0, imageWidth: 0,
@ -364,13 +466,13 @@ export class ImageKnife {
return false return false
} }
async execute(request: ImageKnifeRequest,isAnimator?: boolean): Promise<void> { async execute(request: ImageKnifeRequest): Promise<void> {
LogUtil.log("ImageKnife_DataTime_execute.start:"+request.imageKnifeOption.loadSrc) LogUtil.log('ImageKnife_DataTime_execute.start:'+request.imageKnifeOption.loadSrc)
if (this.headerMap.size > 0) { if (this.headerMap.size > 0) {
request.addHeaderMap(this.headerMap) request.addHeaderMap(this.headerMap)
} }
this.dispatcher.enqueue(request,isAnimator) this.dispatcher.enqueue(request)
LogUtil.log("ImageKnife_DataTime_execute.end:"+request.imageKnifeOption.loadSrc) LogUtil.log('ImageKnife_DataTime_execute.end:'+request.imageKnifeOption.loadSrc)
} }
setEngineKeyImpl(impl: IEngineKey): void { setEngineKeyImpl(impl: IEngineKey): void {
@ -384,10 +486,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

@ -19,12 +19,11 @@ 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 { ImageKnife } from './ImageKnife'; import { ImageKnife } from './ImageKnife';
import { ImageKnifeData, CacheStrategy } from './model/ImageKnifeData'; import { ImageKnifeData, CacheStrategy, TimeInfo, ErrorInfo } from './model/ImageKnifeData';
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 { IEngineKey } from './key/IEngineKey'; import { IEngineKey } from './key/IEngineKey';
import { DefaultEngineKey } from './key/DefaultEngineKey'; import { DefaultEngineKey } from './key/DefaultEngineKey';
import { import {
@ -35,6 +34,7 @@ import {
} from './model/ImageKnifeData' } from './model/ImageKnifeData'
import { BusinessError } from '@kit.BasicServicesKit'; import { BusinessError } from '@kit.BasicServicesKit';
import { ImageKnifeLoader } from './ImageKnifeLoader' import { ImageKnifeLoader } from './ImageKnifeLoader'
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
export class ImageKnifeDispatcher { export class ImageKnifeDispatcher {
@ -48,9 +48,10 @@ 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 + "requestSource=" + requestSource + " isAnimator=" + isAnimator) LogUtil.log('showFromMemomry.start:' + request.componentId + ',srcType:' + requestSource + ',version:' + request.componentVersion + ' isAnimator=' + isAnimator)
let memoryCache: ImageKnifeData | undefined; let memoryCache: ImageKnifeData | undefined;
if ((typeof (request.imageKnifeOption.loadSrc as image.PixelMap).isEditable) == 'boolean') { let memoryCheckStartTime = Date.now();
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,
imageWidth: 0, imageWidth: 0,
@ -58,7 +59,20 @@ export class ImageKnifeDispatcher {
} }
} else { } else {
memoryCache = ImageKnife.getInstance() memoryCache = ImageKnife.getInstance()
.loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator)); .loadFromMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, request.imageKnifeOption,isAnimator, request.componentWidth, request.componentHeight));
}
//记录ImageKnifeRequestSource.SRC 开始内存检查的时间点
if (requestSource == ImageKnifeRequestSource.SRC && request.imageKnifeData) {
let timeInfo = request.imageKnifeData?.timeInfo
if (timeInfo) {
timeInfo.memoryCheckStartTime = memoryCheckStartTime;
timeInfo.memoryCheckEndTime = Date.now();
//设置请求结束的时间点
if (memoryCache !== undefined) {
timeInfo.requestEndTime = Date.now();
}
}
} }
if (memoryCache !== undefined) { if (memoryCache !== undefined) {
@ -66,35 +80,82 @@ export class ImageKnifeDispatcher {
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_showPixelMap.start:" + request.imageKnifeOption.loadSrc) request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source,
request.ImageKnifeRequestCallback?.showPixelMap(request.componentVersion, memoryCache.source, requestSource,memoryCache.imageAnimator) { width: memoryCache.imageWidth, height: memoryCache.imageHeight }, requestSource, memoryCache.imageAnimator)
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
request.drawMainSuccess = true
// 回调请求开结束 // 回调请求开结束
if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) { if (request.imageKnifeOption.onLoadListener?.onLoadSuccess !== undefined) {
request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source,memoryCache) this.copyMemoryCacheInfo(memoryCache, request.imageKnifeData);
LogUtil.log("ImageKnife_DataTime_MemoryCache_onLoadSuccess:" + request.imageKnifeOption.loadSrc) request.imageKnifeOption.onLoadListener.onLoadSuccess(memoryCache.source, memoryCache, request)
} }
} 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_hasmemory:" + request.imageKnifeOption.loadSrc) LogUtil.log('showFromMemomry.end_hasmemory:' + request.componentId + ',srcType:' + requestSource + ',version:' + request.componentVersion)
return true return true
} }
LogUtil.log("ImageKnife_DataTime_showFromMemomry.end_nomemory:" + request.imageKnifeOption.loadSrc) LogUtil.log('showFromMemomry.end_nomemory:' + request.componentId + ',srcType:' + requestSource + ',version:' + request.componentVersion)
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.bufSize = memoryCache.bufSize
target.imageAnimator = memoryCache.imageAnimator;
}
enqueue(request: ImageKnifeRequest,isAnimator?: boolean): void { 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.imageKnifeData = 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.imageKnifeData = callBackData;
}
enqueue(request: ImageKnifeRequest,): 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,request.animator)) {
return return
} }
// 2.内存获取占位图 // 2.内存获取占位图
@ -104,31 +165,34 @@ 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
} }
this.executeJob(request,isAnimator) this.executeJob(request)
} }
executeJob(request: ImageKnifeRequest,isAnimator?: boolean): void { executeJob(request: ImageKnifeRequest): void {
LogUtil.log("ImageKnife_DataTime_executeJob.start:" + request.imageKnifeOption.loadSrc) LogUtil.log('executeJob.start:' + request.componentId + ',version:' + request.componentVersion)
// 加载占位符 // 加载占位符
if (request.imageKnifeOption.placeholderSrc !== undefined && request.drawPlayHolderSuccess == false) { if (request.imageKnifeOption.placeholderSrc !== undefined && request.drawPlayHolderSuccess == false) {
this.getAndShowImage(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER) this.getAndShowImage(request, request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)
} }
if (request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) {
request.imageKnifeOption.onLoadListener?.onLoadStart(request)
}
// 加载主图 // 加载主图
this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,isAnimator) this.getAndShowImage(request, request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,request.animator)
LogUtil.log("ImageKnife_DataTime_executeJob.end:" + request.imageKnifeOption.loadSrc) LogUtil.log('executeJob.end:' + request.componentId + ',version:' + request.componentVersion)
} }
/** /**
* 获取和显示图片 * 获取和显示图片
*/ */
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('getAndShowImage.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator)
let memoryKey: string = this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator, currentRequest.componentWidth, currentRequest.componentHeight)
let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey) let requestList: List<ImageKnifeRequestWithSource> | undefined = this.executingJobMap.get(memoryKey)
if (requestList == undefined) { if (requestList == undefined) {
requestList = new List() requestList = new List()
@ -138,29 +202,20 @@ export class ImageKnifeDispatcher {
requestList.add({ request: currentRequest, source: requestSource }) requestList.add({ request: currentRequest, source: requestSource })
return return
} }
LogUtil.info('image load getAndShowImage start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
let isWatchProgress : boolean = false let isWatchProgress : boolean = false
if (currentRequest.imageKnifeOption.progressListener !== undefined && requestSource === ImageKnifeRequestSource.SRC) {
isWatchProgress = true
}
// 回调请求开始 let src: string | number = ''
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { let moduleName: string = ''
if (requestWithSource.source === ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart !== undefined) { let resName: string = ''
requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadStart()
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadStart:" + currentRequest.imageKnifeOption.loadSrc)
}
if (requestWithSource.request.imageKnifeOption.progressListener !== undefined && requestWithSource.source === ImageKnifeRequestSource.SRC) {
isWatchProgress = true
}
});
let src: string | number = ""
let moduleName: string = ""
let resName: string = ""
if((imageSrc as Resource).id != undefined) { if((imageSrc as Resource).id != undefined) {
moduleName = (imageSrc as Resource).moduleName moduleName = (imageSrc as Resource).moduleName
src = (imageSrc as Resource).id src = (imageSrc as Resource).id
if(src == -1) { resName = (imageSrc as Resource).params![0]
resName = (imageSrc as Resource).params![0] } else if(typeof imageSrc == 'string') {
}
} else if(typeof imageSrc == "string") {
src = imageSrc src = imageSrc
} }
let request: RequestJobRequest = { let request: RequestJobRequest = {
@ -182,52 +237,91 @@ export class ImageKnifeDispatcher {
memoryKey: memoryKey, memoryKey: memoryKey,
fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(), fileCacheFolder: ImageKnife.getInstance().getFileCache()?.getCacheFolder(),
isAnimator:isAnimator, isAnimator:isAnimator,
moduleName: moduleName == "" ? undefined : moduleName, moduleName: moduleName == '' ? undefined : moduleName,
resName: resName == "" ? undefined : resName resName: resName == '' ? undefined : resName,
caPath: currentRequest.imageKnifeOption.httpOption?.caPath,
targetWidth: currentRequest.componentWidth,
targetHeight: currentRequest.componentHeight,
downsampType: currentRequest.imageKnifeOption.downsampleOf == undefined ? DownsampleStrategy.DEFAULT : currentRequest.imageKnifeOption.downsampleOf,
isAutoImageFit: currentRequest.imageKnifeOption.objectFit == ImageFit.Auto,
componentId: currentRequest.componentId,
componentVersion: currentRequest.componentVersion,
connectTimeout: currentRequest.imageKnifeOption.httpOption?.connectTimeout,
readTimeout: currentRequest.imageKnifeOption.httpOption?.readTimeout
} }
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('getAndShowImage.end:'+ currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
})
if (ImageKnife.getInstance().isRequestInSubThread){ if (ImageKnife.getInstance().isRequestInSubThread){
// 启动线程下载和解码主图 // 启动线程下载和解码主图
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.start:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log('etAndShowImage_Task.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
let task = new taskpool.Task(requestJob, request) let task = new taskpool.Task(requestJob, request)
LogUtil.log("ImageKnife_DataTime_getAndShowImage_Task.end:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_Task.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
if (isWatchProgress){ if (isWatchProgress){
emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => { emitter.on(Constants.PROGRESS_EMITTER + memoryKey, (data) => {
this.progressCallBack(requestList! , data?.data?.value as number) this.progressCallBack(requestList! , data?.data?.value as number)
}); });
} }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(subthread):" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_execute.start(subthread):' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
taskpool.execute(task).then((res: Object) => { taskpool.execute(task).then((res: Object) => {
this.doTaskCallback(res as RequestJobResult | undefined, 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)
}).catch((err: BusinessError) => { }).catch((err: BusinessError) => {
LogUtil.error("Fail to requestJob in sub thread src=" + imageSrc + " err=" + err) emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.error('Fail to requestJob in sub thread src=' + imageSrc + ' err=' + err)
if (isWatchProgress){ if (isWatchProgress){
emitter.off(Constants.PROGRESS_EMITTER + memoryKey) emitter.off(Constants.PROGRESS_EMITTER + memoryKey)
} }
this.executingJobMap.remove(memoryKey);
this.dispatchNextJob(); this.doTaskCallback({
pixelMap: undefined,
bufferSize: 0,
fileKey: '',
loadFail: 'Fail to requestJob in sub thread src=' + imageSrc + ' err=' + err,
imageKnifeData: {
source: '',
imageWidth: 0,
imageHeight: 0,
timeInfo: { requestEndTime: Date.now() },
errorInfo: {
phase: LoadPhase.PHASE_LOAD,
code: LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE,
}
}
}, requestList!, currentRequest, memoryKey, imageSrc, requestSource, isAnimator)
}) })
} else { //主线程请求 } else { //主线程请求
LogUtil.log("ImageKnife_DataTime_getAndShowImage_execute.start(mainthread):" + currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_execute.start(mainthread):' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
requestJob(request, requestList).then((res: RequestJobResult | undefined) => { requestJob(request, requestList).then(() => {
this.doTaskCallback(res, requestList!, currentRequest, memoryKey, imageSrc, requestSource,isAnimator);
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 requestJob in main thread src=" + imageSrc + " err=" + err) emitter.off(Constants.CALLBACK_EMITTER + memoryKey)
LogUtil.log("ImageKnife_DataTime_getAndShowImage.end:" + currentRequest.imageKnifeOption.loadSrc) LogUtil.error('Fail to requestJob in main thread src=' + imageSrc + ' err=' + err)
this.executingJobMap.remove(memoryKey);
this.dispatchNextJob(); this.doTaskCallback({
pixelMap: undefined,
bufferSize: 0,
fileKey: '',
loadFail: 'Fail to requestJob in main thread src=' + imageSrc + ' err=' + err,
imageKnifeData: {
source: '',
imageWidth: 0,
imageHeight: 0,
timeInfo: { requestEndTime: Date.now() },
errorInfo: {
phase: LoadPhase.PHASE_LOAD,
code: LoadPixelMapCode.IMAGE_CUSTOM_LOAD_FAILED_CODE,
}
}
}, requestList!, currentRequest, memoryKey, imageSrc, requestSource, isAnimator)
}) })
} }
} }
@ -248,24 +342,79 @@ export class ImageKnifeDispatcher {
private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List<ImageKnifeRequestWithSource> , private doTaskCallback(requestJobResult: RequestJobResult | undefined, requestList: List<ImageKnifeRequestWithSource> ,
currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean):void { currentRequest: ImageKnifeRequest, memoryKey: string, imageSrc: string | PixelMap | Resource, requestSource: ImageKnifeRequestSource,isAnimator?: boolean):void {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.start:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_CallBack.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
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) { // 请求取消
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.pixelmap undefined:"+currentRequest.imageKnifeOption.loadSrc) if (currentRequest.requestState === ImageKnifeRequestState.DESTROY) {
this.executingJobMap.remove(memoryKey);
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (currentRequest.componentId !== requestWithSource.request.componentId && requestWithSource.request.requestState !== ImageKnifeRequestState.DESTROY) {
// 加载占位符
if (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER &&
requestWithSource.request.imageKnifeOption.placeholderSrc !== undefined &&
requestWithSource.request.drawPlayHolderSuccess == false) {
this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.placeholderSrc, ImageKnifeRequestSource.PLACE_HOLDER)
} else if (requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER &&
requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) {
this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc, ImageKnifeRequestSource.ERROR_HOLDER)
} else if (requestWithSource.source === ImageKnifeRequestSource.SRC) {
// 加载主图
this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.loadSrc, ImageKnifeRequestSource.SRC,requestWithSource.request.animator)
}
} else {
if (pixelmap !== undefined && typeof pixelmap !== 'string') {
(pixelmap as PixelMap).release()
}
if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
// 回调请求成功
// 回调请求成功
//设置失败回调的时间点
let callBackData = requestWithSource.request.imageKnifeData;
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)
LogUtil.log('getAndShowImage cancel:' + requestWithSource.request.componentId + ',srcType:' + requestSource + ',version:' + requestWithSource.request.componentVersion)
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel(requestJobResult.loadFail ?? 'component has destroyed from load', requestWithSource.request)
}
}
})
this.dispatchNextJob()
return
}
// 请求失败
if (pixelmap === undefined) {
this.executingJobMap.remove(memoryKey);
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
requestWithSource.request.requestState = ImageKnifeRequestState.ERROR
LogUtil.error('getAndShowImage_CallBack.pixelmap failed:' + currentRequest.componentId + ',srcType:' +
requestSource + ',version:' + currentRequest.componentVersion + " error: " + requestJobResult.loadFail)
// 回调请求失败 // 回调请求失败
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.imageKnifeData, requestJobResult.imageKnifeData,
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadFailed:"+currentRequest.imageKnifeOption.loadSrc) requestWithSource.request)
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadFailed(requestJobResult.loadFail,
requestWithSource.request);
} }
if (requestWithSource.source === ImageKnifeRequestSource.SRC && if (requestWithSource.source === ImageKnifeRequestSource.SRC &&
requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) { requestWithSource.request.imageKnifeOption.errorholderSrc !== undefined) {
requestWithSource.request.requestState = ImageKnifeRequestState.PROGRESS
if (this.showFromMemomry(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc, if (this.showFromMemomry(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc,
ImageKnifeRequestSource.ERROR_HOLDER) === false) { ImageKnifeRequestSource.ERROR_HOLDER) === false) {
this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc, this.getAndShowImage(requestWithSource.request, requestWithSource.request.imageKnifeOption.errorholderSrc,
@ -273,23 +422,29 @@ export class ImageKnifeDispatcher {
} }
} }
}); });
this.executingJobMap.remove(memoryKey);
this.dispatchNextJob(); this.dispatchNextJob();
return; return;
} }
// 保存文件缓存 // 保存文件缓存
if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) { if (requestJobResult.bufferSize > 0 && currentRequest.imageKnifeOption.writeCacheStrategy !== CacheStrategy.Memory) {
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.start:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_saveWithoutWriteFile.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize); ImageKnife.getInstance().saveWithoutWriteFile(requestJobResult.fileKey, requestJobResult.bufferSize);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveWithoutWriteFile.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_saveWithoutWriteFile.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
}
let imageKnifeData: ImageKnifeData;
if (!requestJobResult.imageKnifeData) {
imageKnifeData = {
source: pixelmap!,
imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
type: requestJobResult.type,
};
} else {
imageKnifeData = requestJobResult.imageKnifeData;
imageKnifeData.source = pixelmap!;
} }
let ImageKnifeData: ImageKnifeData = {
source: pixelmap!,
imageWidth: requestJobResult.size == undefined ? 0 : requestJobResult.size.width,
imageHeight: requestJobResult.size == undefined ? 0 : requestJobResult.size.height,
type:requestJobResult.type
};
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)=>{
@ -298,74 +453,98 @@ 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?.width ?? 0,
imageHeight: requestJobResult.size?.height ?? 0,
type: requestJobResult.type,
bufSize: requestJobResult.bufferSize,
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('getAndShowImage_saveMemoryCache.start:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
ImageKnife.getInstance() ImageKnife.getInstance()
.saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator), .saveMemoryCache(this.engineKey.generateMemoryKey(imageSrc, requestSource, currentRequest.imageKnifeOption,isAnimator, currentRequest.componentWidth, currentRequest.componentHeight),
ImageKnifeData); saveCacheImageData);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_saveMemoryCache.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_saveMemoryCache.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
} }
if (requestList !== undefined) { if (requestList !== undefined) {
// key相同的request一起绘制 // key相同的request一起绘制
requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => { requestList.forEach((requestWithSource: ImageKnifeRequestWithSource) => {
if (requestWithSource.request.requestState !== ImageKnifeRequestState.DESTROY) { // 画主图
// 画主图 if (requestWithSource.source === ImageKnifeRequestSource.SRC ||
if (requestWithSource.source === ImageKnifeRequestSource.SRC || requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER
requestWithSource.source === ImageKnifeRequestSource.ERROR_HOLDER || (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER &&
|| (requestWithSource.source === ImageKnifeRequestSource.PLACE_HOLDER && requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) {
requestWithSource.request.requestState === ImageKnifeRequestState.PROGRESS)) { requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion,
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.start:"+currentRequest.imageKnifeOption.loadSrc) imageKnifeData.source, { width: imageKnifeData.imageWidth, height: imageKnifeData.imageHeight },
requestWithSource.request.ImageKnifeRequestCallback.showPixelMap(requestWithSource.request.componentVersion, requestWithSource.source, imageKnifeData.imageAnimator);
ImageKnifeData.source, requestWithSource.source,ImageKnifeData.imageAnimator); }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_showPixelMap.end:"+currentRequest.imageKnifeOption.loadSrc)
}
if (requestWithSource.source == ImageKnifeRequestSource.SRC) { if (requestWithSource.source == ImageKnifeRequestSource.SRC) {
requestWithSource.request.requestState = ImageKnifeRequestState.COMPLETE; requestWithSource.request.requestState = ImageKnifeRequestState.COMPLETE;
if (requestWithSource.request.imageKnifeOption.onLoadListener && requestWithSource.request.drawMainSuccess = true
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) { if (requestWithSource.request.imageKnifeOption.onLoadListener &&
// 回调请求成功 requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess) {
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(ImageKnifeData.source,ImageKnifeData);
LogUtil.log("ImageKnife_DataTime_getAndShowImage_onLoadSuccess:"+currentRequest.imageKnifeOption.loadSrc)
}
} else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) {
requestWithSource.request.requestState = ImageKnifeRequestState.ERROR;
}
} else {
if (requestWithSource.source == ImageKnifeRequestSource.SRC && requestWithSource.request.imageKnifeOption.onLoadListener?.onLoadCancel) {
// 回调请求成功 // 回调请求成功
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadCancel("component has destroyed") this.assembleImageKnifeData(requestWithSource.request.imageKnifeData, imageKnifeData,
requestWithSource.request);
requestWithSource.request.imageKnifeOption.onLoadListener.onLoadSuccess(imageKnifeData.source,
saveCacheImageData, requestWithSource.request);
} }
} else if (requestWithSource.source == ImageKnifeRequestSource.ERROR_HOLDER) {
requestWithSource.request.requestState = ImageKnifeRequestState.ERROR;
} }
}); });
this.executingJobMap.remove(memoryKey); this.executingJobMap.remove(memoryKey);
this.dispatchNextJob(); this.dispatchNextJob();
} else { } else {
LogUtil.log("error: no requestlist need to draw for key = " + memoryKey); LogUtil.log('error: no requestlist need to draw for key = ' + memoryKey);
} }
LogUtil.log("ImageKnife_DataTime_getAndShowImage_CallBack.end:"+currentRequest.imageKnifeOption.loadSrc) LogUtil.log('getAndShowImage_CallBack.end:' + currentRequest.componentId + ',srcType:' + requestSource + ',version:' + currentRequest.componentVersion)
} }
dispatchNextJob() { dispatchNextJob() {
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.start") LogUtil.log('dispatchNextJob.start')
// 主图和错误图并发加载时以及主图加载失败后立即加载错误图可能会导致短时间内并发数超过maxRequests故此处减少响应的并发
if (this.executingJobMap.length >= this.maxRequests) {
return
}
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") LogUtil.log('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) LogUtil.log('dispatchNextJob.start executeJob:' + request.componentId + ',version:' + request.componentVersion)
this.executeJob(request) this.executeJob(request)
LogUtil.log("ImageKnife_DataTime_dispatchNextJob.end executeJob:" + request.imageKnifeOption.loadSrc) LogUtil.log('dispatchNextJob.end executeJob:' + request.componentId + ',version:' + request.componentVersion)
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.imageKnifeData;
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;
}
LogUtil.log('dispatchNextJob cancel:' + request.componentId + ',version:' + request.componentVersion)
request.imageKnifeOption.onLoadListener.onLoadCancel('component has destroyed from queue', request)
} }
} }
} }
@ -392,44 +571,15 @@ 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 + " requestSource=" + request.requestSource) LogUtil.log('requestJob.start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
let src = typeof request.src == "number" ? request.resName != undefined ? request.resName : request.src + "" : request.src let src = typeof request.src == 'number' ? request.resName != undefined ? request.resName : request.src + '' : request.src
// 生成文件缓存key // 生成文件缓存key
let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator) let fileKey = request.engineKey.generateFileKey(src, request.signature, request.isAnimator)
//获取图片资源 //获取图片资源
let resBuf: ArrayBuffer ImageKnifeLoader.execute(request,requestList,fileKey)
try {
LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.start:" + request.src)
resBuf = await ImageKnifeLoader.getImageArrayBuffer(request, requestList, fileKey)
LogUtil.log("ImageKnife_DataTime_requestJob.getImageArrayBuffer.end:" + request.src)
} catch (error) {
LogUtil.error("ImageKnife_DataTime_requestJob.end: getImageArrayBuffer error " + request.src + " err=" + error)
return ImageKnifeLoader.makeEmptyResult(error)
}
// 获取图片类型
let typeValue = new FileTypeUtil().getFileType(resBuf);
if(typeValue == null) {
LogUtil.log("ImageKnife_DataTime_requestJob.end: getFileType is null " + request.src)
return ImageKnifeLoader.makeEmptyResult("request is not a valid image source")
}
// 解析图片
LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.start:" + request.src)
let result: RequestJobResult = await ImageKnifeLoader.parseImage(resBuf, typeValue, fileKey, request)
LogUtil.log("ImageKnife_DataTime_requestJob.parseImage.end:" + request.src)
// 图形变化
if (request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined && result?.pixelMap !== undefined && typeof result.pixelMap !== 'string') {
LogUtil.log("ImageKnife_DataTime_requestJob.transform.start:" + request.src)
result.pixelMap = await request.transformation?.transform(request.context, result.pixelMap, request.componentWidth, request.componentHeight);
LogUtil.log("ImageKnife_DataTime_requestJob.transform.end:" + request.src)
}
LogUtil.log("ImageKnife_DataTime_requestJob.end:" + request.src)
return result
} }

View File

@ -14,12 +14,17 @@
*/ */
import { import {
CacheStrategy, CacheStrategy,
DecodeImageInfo,
ErrorInfo,
FlipRotate,
ImageKnifeData,
ImageKnifeRequestSource, ImageKnifeRequestSource,
ImageKnifeRequestWithSource, RequestJobRequest } from './model/ImageKnifeData'; ImageKnifeRequestWithSource, RequestJobRequest,
TimeInfo } from './model/ImageKnifeData';
import List from '@ohos.util.List' import List from '@ohos.util.List'
import { FileCache } from './cache/FileCache'; import { FileCache } from './cache/FileCache';
import { LogUtil } from './utils/LogUtil'; import { LogUtil } from './utils/LogUtil';
import { Constants } from './utils/Constants'; import { Constants, LoadPhase, LoadPixelMapCode } from './utils/Constants';
import http from '@ohos.net.http'; import http from '@ohos.net.http';
import { combineArrayBuffers } from './utils/ArrayBufferUtils'; import { combineArrayBuffers } from './utils/ArrayBufferUtils';
import { BusinessError } from '@kit.BasicServicesKit'; import { BusinessError } from '@kit.BasicServicesKit';
@ -28,6 +33,11 @@ import emitter from '@ohos.events.emitter';
import image from '@ohos.multimedia.image'; import image from '@ohos.multimedia.image';
import { RequestJobResult } from './model/ImageKnifeData' import { RequestJobResult } from './model/ImageKnifeData'
import util from '@ohos.util'; import util from '@ohos.util';
import { FileTypeUtil } from './utils/FileTypeUtil';
import { DownsampleStrategy } from './downsampling/DownsampleStartegy';
import { Downsampler } from './downsampling/Downsampler';
import { common } from '@kit.AbilityKit';
import { ImageLoaderFactory } from './loaderStrategy/ImageLoaderFactory';
class RequestData { class RequestData {
receiveSize: number = 2000 receiveSize: number = 2000
@ -38,67 +48,207 @@ class RequestData {
* ImageKnifeDispatcher 抽取出来的方法,因@Concurrent只能import方法故抽取到另一个类 * ImageKnifeDispatcher 抽取出来的方法,因@Concurrent只能import方法故抽取到另一个类
*/ */
export class ImageKnifeLoader { export class ImageKnifeLoader {
static async parseImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, static execute(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined, fileKey: string){
request: RequestJobRequest): Promise<RequestJobResult> { ImageKnifeLoader.getImageArrayBuffer(request,requestList,fileKey)
}
static getUnit8Array (resBuf: ArrayBuffer) {
let unit8 = new Uint8Array(resBuf)
let unitString = ''
if (unit8.length >= 3) {
unitString = unit8[0] + ',' + unit8[1] + ',' + unit8[2]
} else if (unit8.length > 0 && unit8.length < 3) {
unitString = unit8.length + ''
}
return unitString
}
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('requestJob.end: getFileType is null: ' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
ImageKnifeLoader.makeEmptyResult(request,
'request is not a valid image source:' + request.src + ',componentId' + request.componentId + ',srcType:' +
request.requestSource + ',' +
request.componentVersion + ',buffer:' + resBuf.byteLength + ',unit8:' + ImageKnifeLoader.getUnit8Array(resBuf),
ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_GET_FORMAT,
LoadPixelMapCode.IMAGE_PARSE_FORMAT_FAILED_CODE))
return
}
callBackData.type = typeValue;
if(request.isAnimator) { if(request.isAnimator) {
return ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request) ImageKnifeLoader.parseForAnimatorComponent(resBuf ,typeValue ,fileKey, request, callBackData)
return
} }
if (typeValue === 'gif' || typeValue === 'webp') { if (typeValue === 'gif' || typeValue === 'webp') {
return ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request) ImageKnifeLoader.parseAnimatorImage(resBuf ,typeValue ,fileKey , request, callBackData)
} else if(typeValue == "svg") { return
return ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request) } else if(typeValue == 'svg') {
ImageKnifeLoader.parseSvgImage(resBuf ,typeValue ,fileKey , request, callBackData)
return
} }
return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData)
} }
static makeEmptyResult(error: string): RequestJobResult{ static makeEmptyResult(request:RequestJobRequest,error: string, data?: ImageKnifeData){
return { let res: RequestJobResult = {
pixelMap: undefined, pixelMap: undefined,
bufferSize: 0, bufferSize: 0,
fileKey: '', fileKey: '',
loadFail: error, loadFail: error,
imageKnifeData: data
} }
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
} }
static async parseNormalImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, request: RequestJobRequest):Promise<RequestJobResult> { static assembleError(data: ImageKnifeData | undefined, phase: string, code?: number): ImageKnifeData | undefined {
let errorCallBackData = data?.errorInfo;
if (!errorCallBackData) {
return data;
}
errorCallBackData.phase = phase;
errorCallBackData.code = code? code: 0;
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) {
LogUtil.log('image parse pixelmap start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
let resPixelmap: PixelMap | undefined = undefined let resPixelmap: PixelMap | undefined = undefined
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
let decodingOptions: image.DecodingOptions = { let decodingOptions: image.DecodingOptions = {
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
} }
let imageSource: image.ImageSource = image.createImageSource(resBuf) let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){ if (imageSource === undefined){
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") 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 imageInfoSync = imageSource.getImageInfoSync()
if (imageInfoSync == undefined){
imageSource.release()
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
return
}
let size = imageInfoSync.size
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
if (request.isAutoImageFit && request.requestSource == ImageKnifeRequestSource.SRC){
request.componentHeight = request.componentWidth * size.height / size.width
}
try {
if ((request.downsampType !== DownsampleStrategy.NONE) &&
request.requestSource == ImageKnifeRequestSource.SRC) {
decodingOptions =
ImageKnifeLoader.getDownsamplerDecodingOptions(typeValue, request, size, ImageKnifeRequestSource.SRC)
}
} catch (err) {
imageSource.release()
ImageKnifeLoader.makeEmptyResult(request, 'getDownsamplerDecodingOptions failed:' + err)
return
}
timeInfo.decodeStartTime = Date.now();
// 获取旋转信息
let exif: string | undefined = undefined;
await imageSource.getImageProperty(image.PropertyKey.ORIENTATION).then((res)=>{
exif = res;
}).catch((error: BusinessError)=>{
LogUtil.info("The normal image don't have rotation information, " + error.message);
})
await imageSource.createPixelMap(decodingOptions) await imageSource.createPixelMap(decodingOptions)
.then((pixelmap: PixelMap) => { .then((pixelmap: PixelMap) => {
timeInfo.decodeEndTime = Date.now();
resPixelmap = pixelmap resPixelmap = pixelmap
imageSource.release() imageSource.release()
}).catch((error: BusinessError) => { }).catch((error: BusinessError) => {
timeInfo.decodeEndTime = Date.now();
imageSource.release() imageSource.release()
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) ImageKnifeLoader.makeEmptyResult(request, 'createPixelMap failed:' + 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('requestJob.transform.start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
resPixelmap = await request.transformation?.transform(request.context, resPixelmap, request.componentWidth, request.componentHeight);
LogUtil.log('requestJob.transform.end:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
}
try {
resPixelmap?.setTransferDetached(true)
} catch (e) {
LogUtil.error('PixelMap setTransferDetached failed:' + JSON.stringify(e))
}
// 设置翻转和旋转角度
if(exif && exif !== 'Top-left'){
let result = ImageKnifeLoader.getOrientation(exif);
if(result.horizontal || result.vertical) {
resPixelmap?.flipSync(result.horizontal, result.vertical);
}
if(result.rotate > 0) {
resPixelmap?.rotateSync(result.rotate);
}
LogUtil.log('The normal image set flip , horizontal=' + result.horizontal + ', vertical=' +result.vertical + ', rotate=' + result.rotate);
}
return { //获取各个pixelMap的大小
if (resPixelmap !== undefined) {
let decodeImages: 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, pixelMap: resPixelmap,
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
fileKey: fileKey, fileKey: fileKey,
size:size, size:size,
type:typeValue type:typeValue,
}; imageKnifeData:callBackData
}
LogUtil.log('image parse pixelmap end:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
} }
static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string, static async parseSvgImage(resBuf: ArrayBuffer, typeValue: string, fileKey: string,
request: RequestJobRequest): Promise<RequestJobResult> { request: RequestJobRequest, callBackData: ImageKnifeData) {
let resPixelmap: PixelMap | undefined = undefined let resPixelmap: PixelMap | undefined = undefined
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
let imageSource: image.ImageSource = image.createImageSource(resBuf) let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){ if (imageSource === undefined){
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") 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 imageInfoSync = imageSource.getImageInfoSync()
if (imageInfoSync == undefined){
imageSource.release()
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
return
}
let size = imageInfoSync.size
let scale = size.height / size.width let scale = size.height / size.width
let hValue = Math.round(request.componentHeight); let hValue = Math.round(request.componentHeight);
let wValue = Math.round(request.componentWidth); let wValue = Math.round(request.componentWidth);
@ -110,59 +260,143 @@ export class ImageKnifeLoader {
editable: true, editable: true,
desiredSize: defaultSize desiredSize: defaultSize
}; };
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
try {
if ((request.downsampType !== DownsampleStrategy.NONE) &&
request.requestSource == ImageKnifeRequestSource.SRC) {
opts = ImageKnifeLoader.getDownsamplerDecodingOptions(typeValue, request, size)
}
} catch (err) {
imageSource.release()
ImageKnifeLoader.makeEmptyResult(request,'getDownsamplerDecodingOptions failed:' + err)
return
}
timeInfo.decodeStartTime = Date.now();
// 获取旋转信息
let exif: string | undefined = undefined;
await imageSource.getImageProperty(image.PropertyKey.ORIENTATION).then((res)=>{
exif = res;
}).catch((error: BusinessError)=>{
LogUtil.info("Svg image don't have rotation information, " + error.message);
})
await imageSource.createPixelMap(opts) await imageSource.createPixelMap(opts)
.then((pixelmap: PixelMap) => { .then((pixelmap: PixelMap) => {
timeInfo.decodeEndTime = Date.now();
resPixelmap = pixelmap resPixelmap = pixelmap
imageSource.release() imageSource.release()
try {
resPixelmap.setTransferDetached(true)
// 设置翻转和旋转角度
if(exif && exif !== 'Top-left'){
let result = ImageKnifeLoader.getOrientation(exif);
if(result.horizontal || result.vertical) {
resPixelmap?.flipSync(result.horizontal, result.vertical);
}
if(result.rotate > 0) {
resPixelmap?.rotateSync(result.rotate);
}
LogUtil.log('Svg image set flip , horizontal=' + result.horizontal + ', vertical=' +result.vertical + ', rotate=' + result.rotate);
}
} catch (e) {
LogUtil.error('PixelMap setTransferDetached failed:' + JSON.stringify(e))
}
}).catch((error: BusinessError) => { }).catch((error: BusinessError) => {
timeInfo.decodeEndTime = Date.now();
imageSource.release() imageSource.release()
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) ImageKnifeLoader.makeEmptyResult(request,'getImageInfoSync failed:' + JSON.stringify(error), ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_PIXEL_MAP, LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
return
}) })
return { //获取各个pixelMap的大小
if (resPixelmap && typeof resPixelmap !== 'string') {
let decodeImages: DecodeImageInfo[] = [];
let decodeImage: DecodeImageInfo = {
contentWidth: defaultSize.width,
contentHeight: defaultSize.height,
contentSize: (resPixelmap as PixelMap).getPixelBytesNumber()
}
decodeImages.push(decodeImage);
}
let res: RequestJobResult = {
pixelMap: resPixelmap, pixelMap: resPixelmap,
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
fileKey: fileKey, fileKey: fileKey,
type:typeValue type:typeValue,
}; imageKnifeData:callBackData
}
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
} }
static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string, static async parseAnimatorImage(resBuf: ArrayBuffer, typeValue: string,
fileKey: string,request: RequestJobRequest): Promise<RequestJobResult> { fileKey: string,request: RequestJobRequest, callBackData: ImageKnifeData) {
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
let imageSource: image.ImageSource = image.createImageSource(resBuf) let imageSource: image.ImageSource = image.createImageSource(resBuf)
if (imageSource === undefined){ if (imageSource === undefined){
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") 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 frameCount = await imageSource.getFrameCount()
let size = (await imageSource.getImageInfo()).size let imageInfoSync = imageSource.getImageInfoSync()
imageSource.release() imageSource.release()
if (imageInfoSync == undefined){
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
return
}
let size = imageInfoSync.size
callBackData.frameCount = frameCount;
callBackData.imageWidth = size.width;
callBackData.imageHeight = size.height;
if(frameCount == undefined || frameCount == 1) { if(frameCount == undefined || frameCount == 1) {
} else { } else {
let base64str = "data:image/" + typeValue + ";base64," + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf)) timeInfo.decodeStartTime = Date.now()
return { let base64str = 'data:image/' + typeValue + ';base64,' + new util.Base64Helper().encodeToStringSync(new Uint8Array(resBuf))
timeInfo.decodeEndTime = Date.now()
let res: RequestJobResult = {
pixelMap: base64str, pixelMap: base64str,
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
fileKey: fileKey, fileKey: fileKey,
size:size, size:size,
type:typeValue type:typeValue,
}; imageKnifeData:callBackData
}
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
return
} }
return ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request) ImageKnifeLoader.parseNormalImage(resBuf, typeValue, fileKey, request, callBackData)
} }
// 为AnimatorComponent解析动图 // 为AnimatorComponent解析动图
static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest): Promise<RequestJobResult> { static async parseForAnimatorComponent(resBuf: ArrayBuffer, typeValue: string, fileKey: string,request: RequestJobRequest, callBackData: ImageKnifeData) {
let timeInfo: TimeInfo = ImageKnifeLoader.getTimeInfo(callBackData);
if (typeValue === 'gif' || typeValue === 'webp') { if (typeValue === 'gif' || typeValue === 'webp') {
let imageSource: image.ImageSource = image.createImageSource(resBuf); let imageSource: image.ImageSource = image.createImageSource(resBuf);
if (imageSource === undefined){ if (imageSource === undefined){
return ImageKnifeLoader.makeEmptyResult("image.createImageSource failed") ImageKnifeLoader.makeEmptyResult(request,'image.createImageSource failed', ImageKnifeLoader.assembleError(callBackData, LoadPhase.PHASE_CREATE_SOURCE, LoadPixelMapCode.IMAGE_SOURCE_ERROR_CODE))
return
} }
let decodingOptions: image.DecodingOptions = { let decodingOptions: image.DecodingOptions = {
editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false, editable: request.requestSource === ImageKnifeRequestSource.SRC && request.transformation !== undefined ? true : false,
} }
let imageInfoSync = imageSource.getImageInfoSync()
if (imageInfoSync == undefined){
imageSource.release()
ImageKnifeLoader.makeEmptyResult(request, 'getImageInfoSync failed')
return
}
callBackData.imageWidth = imageInfoSync.size.width;
callBackData.imageHeight = imageInfoSync.size.height;
let pixelMapList: Array<PixelMap> = [] let pixelMapList: Array<PixelMap> = []
let delayList: Array<number> = [] let delayList: Array<number> = []
timeInfo.decodeStartTime = Date.now();
let decodeImages: Array<DecodeImageInfo> = [];
await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => { await imageSource.createPixelMapList(decodingOptions).then(async (pixelList: Array<PixelMap>) => {
timeInfo.decodeEndTime = Date.now();
//sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList() //sdk的api接口发生变更从.getDelayTime() 变为.getDelayTimeList()
await imageSource.getDelayTimeList().then(delayTimes => { await imageSource.getDelayTimeList().then(delayTimes => {
if (pixelList.length > 0) { if (pixelList.length > 0) {
@ -173,185 +407,161 @@ export class ImageKnifeLoader {
} else { } else {
delayList.push(delayTimes[delayTimes.length - 1]) 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(); imageSource.release();
} }
}) })
}).catch((error: BusinessError) => { }).catch((error: BusinessError) => {
imageSource.release() imageSource.release()
return ImageKnifeLoader.makeEmptyResult(JSON.stringify(error)) timeInfo.decodeEndTime = Date.now();
ImageKnifeLoader.makeEmptyResult(request,'createPixelMapList failed:' + JSON.stringify(error),
ImageKnifeLoader.assembleError(callBackData,LoadPhase.PHASE_CREATE_PIXEL_MAP,LoadPixelMapCode.IMAGE_DECODE_ERROR_CODE))
return
}) })
return { callBackData.decodeImages = decodeImages;
pixelMap: "", let res: RequestJobResult = {
pixelMap: '',
bufferSize: resBuf.byteLength, bufferSize: resBuf.byteLength,
fileKey: fileKey, fileKey: fileKey,
type: typeValue, type: typeValue,
imageKnifeData:callBackData,
pixelMapList, pixelMapList,
delayList delayList
} }
emitter.emit(Constants.CALLBACK_EMITTER + request.memoryKey, { data: { 'value': res } })
} else { } else {
return ImageKnifeLoader.makeEmptyResult("ImageKnifeAnimatorComponent组件仅支持动态图") ImageKnifeLoader.makeEmptyResult(request,'ImageKnifeAnimatorComponent not support format', 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){
try {
// 保存文件缓存
if (resBuf !== undefined && request.writeCacheStrategy !== CacheStrategy.Memory) {
LogUtil.log('requestJob_saveFileCacheOnlyFile.start:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf , request.fileCacheFolder)
LogUtil.log('requestJob_saveFileCacheOnlyFile.end:' + request.componentId + ',srcType:' + request.requestSource + ',' + request.componentVersion)
}
ImageKnifeLoader.parseImage(resBuf,fileKey,request, callBackData)
} catch (e) {
ImageKnifeLoader.makeEmptyResult(request,
'image load FileCacheParseImage error:' + e + ',componentId' + request.componentId + ',srcType:' +
request.requestSource + ',' + request.componentVersion)
}
}
// 获取图片资源
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
};
const loaderStrategy = ImageLoaderFactory.getLoaderStrategy(request);
if (loaderStrategy) {
await loaderStrategy.loadImage(request, requestList, fileKey, callBackData, callBackTimeInfo);
} else {
loadError = `Unsupported request type: ${request.src}`;
callBackTimeInfo.requestEndTime = Date.now();
ImageKnifeLoader.makeEmptyResult(request, loadError, callBackData);
}
}
static isLocalLoadSrc(context: Object | undefined, loadSrc: string): boolean {
if (context != undefined) {
let fileDir: string = (context as common.UIAbilityContext).filesDir as string;
let cacheDir: string = (context as common.UIAbilityContext).cacheDir as string
if (loadSrc.startsWith(fileDir) || loadSrc.startsWith(cacheDir)) {
return true;
}
}
return false;
}
static getDownsamplerDecodingOptions(typeValue: string, request: RequestJobRequest, size: Size,
SRC?: ImageKnifeRequestSource):image.DecodingOptions {
let reqSize =
new Downsampler().calculateScaling(typeValue, size.width, size.height,
vp2px(request.targetWidth), vp2px(request.targetHeight), request.downsampType)
if (typeValue == 'svg') {
return {
editable: true,
desiredSize: {
height: vp2px(reqSize.height),
width: vp2px(reqSize.width)
}
}
} else {
return {
editable: request.requestSource === SRC && request.transformation !== undefined ? true : false,
desiredSize:{
width: reqSize.width,
height: reqSize.height
}
}
} }
} }
// 获取图片资源 static getOrientation(orientation: string | undefined){
static async getImageArrayBuffer(request: RequestJobRequest, requestList: List<ImageKnifeRequestWithSource> | undefined,fileKey:string): Promise<ArrayBuffer> { let horizontal: boolean = false;
let resBuf: ArrayBuffer | undefined let vertical: boolean = false;
let rotate: number= 0;
// 判断自定义下载 switch (orientation){
if (request.customGetImage !== undefined && request.requestSource == ImageKnifeRequestSource.SRC && typeof request.src == "string") { case 'Top-left': break
// 先从文件缓存获取 case 'Top-right':
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder) horizontal = true;
if (resBuf === undefined) { break;
LogUtil.log("start customGetImage src=" + request.src) case 'Bottom-left':
try { vertical = true;
resBuf = await request.customGetImage(request.context, request.src) break
LogUtil.log("end customGetImage src=" + request.src) case 'Bottom-right':
} catch (err) { rotate = 180;
throw new Error('customGetImage loadFile failed! err = ' + err) break;
} case 'Left-top':
if (resBuf === undefined) { horizontal = true;
throw new Error('customGetImage loadFile failed!') rotate = 270;
} break
// 保存文件缓存 case 'Right-top':
if (request.writeCacheStrategy !== CacheStrategy.Memory) { rotate = 90;
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.start:" + request.src) break;
FileCache.saveFileCacheOnlyFile(request.context, fileKey, resBuf, request.fileCacheFolder) case 'Left-bottom':
LogUtil.log("ImageKnife_DataTime_requestJob_saveFileCacheOnlyFile.end:" + request.src) rotate = 270;
} break
} case 'Right-bottom':
} horizontal = true;
else { rotate = 90;
if (typeof request.src === 'string') { break;
if (request.src.indexOf("http://") == 0 || request.src.indexOf("https://") == 0) { //从网络下载
// 先从文件缓存获取
resBuf = FileCache.getFileCacheByFile(request.context, fileKey , request.fileCacheFolder)
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)
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: 60000,
readTimeout: 0,
// usingProtocol:http.HttpProtocol.HTTP1_1
// header: new Header('application/json')
});
await promise.then((data: number) => {
if (data == 200 || data == 206 || data == 204) {
resBuf = combineArrayBuffers(arrayBuffers)
} else {
throw new Error("HttpDownloadClient has error, http code =" + JSON.stringify(data))
}
}).catch((err: Error) => {
throw new Error("HttpDownloadClient download ERROR : err = " + JSON.stringify(err))
});
LogUtil.log("HttpDownloadClient.end:" + request.src)
// 保存文件缓存
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)
}
}
else {
throw new Error('onlyRetrieveFromCache,do not fetch image src = ' + request.src)
}
} 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.closeSync(file.fd);
}).catch((err:BusinessError) => {
throw new Error('LoadDataShareFileClient fs.read err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code)
})
}).catch((err:BusinessError) => {
throw new Error('LoadDataShareFileClient fs.stat err happened uri=' + request.src + " err.msg=" + err?.message + " err.code=" + err?.code)
})
}).catch((err:BusinessError) => {
throw new Error('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) {
throw new Error(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){ let data: FlipRotate = { horizontal: horizontal, vertical: vertical, rotate:rotate };
throw new Error('getImageArrayBuffer undefined') return data
}
return resBuf
} }
} }

View File

@ -16,7 +16,6 @@ import util from '@ohos.util';
import { FileUtils } from '../utils/FileUtils'; import { FileUtils } from '../utils/FileUtils';
import fs from '@ohos.file.fs'; import fs from '@ohos.file.fs';
import { LogUtil } from '../utils/LogUtil'; import { LogUtil } from '../utils/LogUtil';
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5';
const INT_MAX = 2147483647 const INT_MAX = 2147483647
/** /**
@ -25,32 +24,29 @@ const INT_MAX = 2147483647
* 子线程直接读写文件 * 子线程直接读写文件
*/ */
export class FileCache { export class FileCache {
static CACHE_FOLDER: string = "ImageKnife" // context cacheDir 的缓存文件目录 static CACHE_FOLDER: string = 'ImageKnife' // context cacheDir 的缓存文件目录
maxMemory: number = 0 maxMemory: number = 0
currentMemory: number = 0 currentMemory: number = 0
maxSize: number = 0 maxSize: number = 0
path: string = "" path: string = ''
private lruCache: util.LRUCache<string, number> private lruCache: util.LRUCache<string, number>
private isInited: boolean = false private isInited: boolean = false
private context?: Context private context?: Context
readonly defaultMaxSize: number = 512; readonly defaultMaxMemorySize: number = 10 * 1024 * 1024 * 1024;
readonly defaultSize: number = INT_MAX; readonly defaultMemorySize: number = 1024 * 1024 * 1024;
readonly defaultMaxMemorySize: number = 512 * 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 || size > INT_MAX) { if (size <= 0 || size > INT_MAX) {
size = this.defaultSize size = INT_MAX;
} }
if (memory <= 0 || memory > this.defaultMaxMemorySize) { if (memory <= 0 || memory > this.defaultMaxMemorySize) {
memory = this.defaultMemorySize memory = this.defaultMemorySize;
} }
this.lruCache = new util.LRUCache(size); this.lruCache = new util.LRUCache(size);
this.maxMemory = memory this.maxMemory = memory;
this.currentMemory = 0; this.currentMemory = 0;
this.maxSize = size this.maxSize = size;
this.context = context this.context = context;
} }
/** /**
@ -60,6 +56,7 @@ export class FileCache {
if (this.isInited) { if (this.isInited) {
return return
} }
let startTime = Date.now()
if (this.context && path.startsWith(this.context.cacheDir) === true) { if (this.context && path.startsWith(this.context.cacheDir) === true) {
this.path = path this.path = path
} else { } else {
@ -73,6 +70,7 @@ export class FileCache {
interface CacheFileInfo { interface CacheFileInfo {
file: string; file: string;
ctime: number; ctime: number;
size: number;
} }
// 按照上次访问该文件的时间排序 // 按照上次访问该文件的时间排序
@ -81,29 +79,29 @@ export class FileCache {
let stat: fs.Stat | undefined = await FileUtils.getInstance().Stat(this.path + filenames[i]) let stat: fs.Stat | undefined = await FileUtils.getInstance().Stat(this.path + filenames[i])
cachefiles.push({ cachefiles.push({
file: filenames[i], file: filenames[i],
ctime: stat === undefined ? 0 : stat.ctime ctime: stat === undefined ? 0 : stat.ctime,
size: stat?.size ?? 0
}) })
} }
let sortedCachefiles: CacheFileInfo[] = cachefiles.sort((a, b) => a.ctime - b.ctime) let sortedCachefiles: CacheFileInfo[] = cachefiles.sort((a, b) => a.ctime - b.ctime)
for (let i = 0; i < sortedCachefiles.length; i++) { for (let i = 0; i < sortedCachefiles.length; i++) {
let buf: ArrayBuffer | undefined = await FileUtils.getInstance().readFile(this.path + sortedCachefiles[i].file) const fileSize: number = sortedCachefiles[i].size;
if (buf !== undefined) { // 处理数量超过size的场景移除即将排除的文件
// 处理数量超过size的场景移除即将排除的文件 if (this.lruCache.length == this.maxSize && !this.lruCache.contains(sortedCachefiles[i].file)) {
if (this.lruCache.length == this.maxSize && !this.lruCache.contains(sortedCachefiles[i].file)) { let remove: number | undefined = this.lruCache.remove(this.lruCache.keys()[0])
let remove: number | undefined = this.lruCache.remove(this.lruCache.keys()[0]) if (remove !== undefined) {
if (remove !== undefined) { FileUtils.getInstance().deleteFile(this.path + this.lruCache.keys()[0])
FileUtils.getInstance().deleteFile(this.path + this.lruCache.keys()[0]) this.removeMemorySize(fileSize)
this.removeMemorySize(buf)
}
} }
this.lruCache.put(sortedCachefiles[i].file, buf.byteLength)
this.addMemorySize(buf)
} }
this.lruCache.put(sortedCachefiles[i].file, fileSize)
this.addMemorySize(fileSize)
} }
this.trimToSize(); this.trimToSize();
LogUtil.info('image init initFileCache:' + (Date.now() - startTime) + ',num:' + filenames.length + ',nums:' + this.lruCache.length + ',size:' + this.currentMemory)
this.isInited = true this.isInited = true
} }
@ -153,11 +151,11 @@ export class FileCache {
this.remove(this.lruCache.keys()[0]) this.remove(this.lruCache.keys()[0])
} else if (this.lruCache.contains(key)) { } else if (this.lruCache.contains(key)) {
this.lruCache.remove(key) this.lruCache.remove(key)
this.lruCache.put(key, typeof value == "number" ? value : value.byteLength) this.lruCache.put(key, typeof value == 'number' ? value : value.byteLength)
return return
} }
this.lruCache.put(key, typeof value == "number" ? value : value.byteLength) this.lruCache.put(key, typeof value == 'number' ? value : value.byteLength)
this.addMemorySize(value) this.addMemorySize(value)
this.trimToSize() this.trimToSize()
} }
@ -194,7 +192,6 @@ export class FileCache {
if (!this.isInited) { if (!this.isInited) {
return return
} }
this.isInited = false
this.lruCache.clear() this.lruCache.clear()
this.currentMemory = 0; this.currentMemory = 0;
@ -202,8 +199,6 @@ export class FileCache {
for (let i = 0; i < filenames.length; i++) { for (let i = 0; i < filenames.length; i++) {
await FileUtils.getInstance().deleteFile(this.path + filenames[i]) await FileUtils.getInstance().deleteFile(this.path + filenames[i])
} }
this.isInited = true
} }
size(): number { size(): number {
@ -227,23 +222,23 @@ export class FileCache {
} }
private removeMemorySize(value: ArrayBuffer | number): void { private removeMemorySize(value: ArrayBuffer | number): void {
if (typeof value == "number") { if (typeof value == 'number') {
this.currentMemory -= value this.currentMemory -= value
} }
else if (value != undefined) { else if (value != undefined) {
this.currentMemory -= value.byteLength this.currentMemory -= value.byteLength
LogUtil.debug("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.debug("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.debug("FileCache addMemorySize: " + value.byteLength + " currentMemory" + this.currentMemory) LogUtil.debug('FileCache addMemorySize: ' + value.byteLength + ' currentMemory' + this.currentMemory)
} }
} }
@ -279,13 +274,13 @@ export class FileCache {
*/ */
getFileToPath(key: string): string { getFileToPath(key: string): string {
if(!!!key) { if(!!!key) {
throw new Error("key is null,checking the parameter") throw new Error('key is null,checking the parameter')
} }
let path = this.path + key let path = this.path + key
if(FileUtils.getInstance().exist(path)) { if(FileUtils.getInstance().exist(path)) {
return path return path
} else { } else {
return "" return ''
} }
} }
} }

View File

@ -21,23 +21,23 @@ export class MemoryLruCache implements IMemoryCache {
currentMemory: number = 0 currentMemory: number = 0
maxSize: number = 0 maxSize: number = 0
private lruCache: util.LRUCache<string, ImageKnifeData> private lruCache: util.LRUCache<string, ImageKnifeData>
readonly defaultMaxSize: number = 4096 readonly defaultMaxSize: number = 65536;
readonly defaultSize: number = 512 readonly defaultSize: number = 512;
readonly defaultMaxMemorySize: number = 1024 * 1024 * 1024 readonly defaultMaxMemorySize: number = 10 * 1024 * 1024 * 1024;
readonly defaultMemorySize: number = 128 * 1024 * 1024 readonly defaultMemorySize: number = 1024 * 1024 * 1024;
constructor(size: number, memory: number) { constructor(size: number, memory: number) {
if (size <= 0 || size > this.defaultMaxSize) { if (size <= 0 || size > this.defaultMaxSize) {
size = this.defaultSize size = this.defaultSize;
} }
if (memory <= 0 || memory > this.defaultMaxMemorySize) { if (memory <= 0 || memory > this.defaultMaxMemorySize) {
memory = this.defaultMemorySize memory = this.defaultMemorySize;
} }
this.lruCache = new util.LRUCache(size); this.lruCache = new util.LRUCache(size);
this.maxMemory = memory this.maxMemory = memory;
this.maxSize = size this.maxSize = size;
this.currentMemory = 0 this.currentMemory = 0;
} }
// 添加缓存键值对 // 添加缓存键值对
@ -46,6 +46,11 @@ export class MemoryLruCache implements IMemoryCache {
throw new Error('key or value is invalid '); throw new Error('key or value is invalid ');
} }
let size = this.getImageKnifeDataSize(value)
if (size <= 0 || size >= this.maxMemory) {
return
}
// 如果size满了的话需要按照LRU的方式删除第一个 // 如果size满了的话需要按照LRU的方式删除第一个
if (this.lruCache.length == this.maxSize && !this.lruCache.contains(key)) { if (this.lruCache.length == this.maxSize && !this.lruCache.contains(key)) {
this.remove(this.lruCache.keys()[0]) this.remove(this.lruCache.keys()[0])
@ -53,12 +58,9 @@ export class MemoryLruCache implements IMemoryCache {
this.remove(key) this.remove(key)
} }
let pre: ImageKnifeData = this.lruCache.put(key, value) this.lruCache.put(key, value)
this.addMemorySize(value) this.currentMemory += size
// if (pre !== undefined) { // 当前返回不是key的之前value this.trimToSize()
// this.removeMemorySize(pre)
// }
this.trimToSize();
} }
get(key: string): ImageKnifeData | undefined { get(key: string): ImageKnifeData | undefined {
@ -104,34 +106,35 @@ export class MemoryLruCache implements IMemoryCache {
private removeMemorySize(value: ImageKnifeData): void { private removeMemorySize(value: ImageKnifeData): void {
if (value.source != undefined) { if (value.source != undefined) {
if (typeof value.source === 'string' && value.source != "") { if (typeof value.source === 'string' && value.source != '') {
this.currentMemory -= value.source.length this.currentMemory -= value.source.length
} else if (value.source == "") { } else if (value.source == '') {
for (let index = 0;index < value.imageAnimator!.length;index++) { for (let index = 0;index < value.imageAnimator!.length;index++) {
let pixelMap = value.imageAnimator![index].src as PixelMap let pixelMap = value.imageAnimator![index].src as PixelMap
this.currentMemory -= pixelMap.getPixelBytesNumber() this.currentMemory -= pixelMap.getPixelBytesNumber()
} }
} else { } else {
this.currentMemory -= value.source.getPixelBytesNumber(); this.currentMemory -= value.source.getPixelBytesNumber();
value.source.release() // value.source.release()
} }
// LogUtil.info("MemoryCache removeMemorySize: " + value.source.getPixelBytesNumber() + " currentMemory" + this.currentMemory)
} }
} }
private addMemorySize(value: ImageKnifeData): void { private getImageKnifeDataSize(value: ImageKnifeData): number {
if (value.source != undefined) { if (value.source != undefined) {
if (typeof value.source === 'string' && value.source != "") { if (typeof value.source === 'string' && value.source != '') {
this.currentMemory += value.source.length return value.source.length
} else if (value.source == "") { } else if (value.source == '') {
for (let index = 0;index < value.imageAnimator!.length;index++) { let size: number = 0
for (let index = 0; index < value.imageAnimator!.length; index++) {
let pixelMap = value.imageAnimator![index].src as PixelMap let pixelMap = value.imageAnimator![index].src as PixelMap
this.currentMemory += pixelMap.getPixelBytesNumber() size += pixelMap.getPixelBytesNumber()
} }
return size
} else { } else {
this.currentMemory += value.source.getPixelBytesNumber(); return value.source.getPixelBytesNumber();
} }
//LogUtil.log("MemoryCache addMemorySize: " + value.source.getPixelBytesNumber() + " currentMemory" + this.currentMemory)
} }
return 0
} }
} }

View File

@ -18,58 +18,63 @@ 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';
import { ImageKnifeRequestSource } from '../model/ImageKnifeData'; import { ImageKnifeRequestSource } from '../model/ImageKnifeData';
import { emitter } from '@kit.BasicServicesKit';
@ComponentV2 @Component
export struct ImageKnifeAnimatorComponent { export struct ImageKnifeAnimatorComponent {
@Param animatorOption: AnimatorOption = new AnimatorOption(); @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
@Local pixelMap: PixelMap | string | undefined = undefined @State animatorOption: AnimatorOption = new AnimatorOption();
@Local imageAnimator: Array<ImageFrameInfo> | undefined = undefined @State pixelMap: PixelMap | string | undefined = undefined
@Local adaptiveWidth: Length = '100%' @State imageAnimator: Array<ImageFrameInfo> | undefined = undefined
@Local adaptiveHeight: Length = '100%' @State adaptiveWidth: Length = '100%'
@Local objectFit: ImageFit = ImageFit.Contain @State adaptiveHeight: Length | undefined = '100%'
@State objectFit: ImageFit = ImageFit.Contain
private componentId: number = 0
private request: ImageKnifeRequest | undefined private request: ImageKnifeRequest | undefined
private lastWidth: number = 0 private lastWidth: number = 0
private lastHeight: number = 0 private lastHeight: number = 0
private isImageFitAutoResize: boolean = false
private currentWidth: number = 0 private currentWidth: number = 0
private currentHeight: number = 0 private currentHeight: number = 0
private componentVersion: number = 0 private componentVersion: number = 0
private currentContext: common.UIAbilityContext | undefined = undefined private currentContext: common.UIAbilityContext | undefined = undefined
@Param imageKnifeOption: ImageKnifeOption = new ImageKnifeOption();
@Monitor('imageKnifeOption',
"imageKnifeOption.loadSrc","imageKnifeOption.signature","imageKnifeOption.transformation","imageKnifeOption.border","imageKnifeOption.objectFit")
watchImageKnifeOption() {
if (this.request !== undefined) {
this.request.requestState = ImageKnifeRequestState.DESTROY
}
this.request = undefined
this.componentVersion++
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight))
}
aboutToAppear(): void { aboutToAppear(): void {
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
this.componentId = this.getUniqueId()
} }
aboutToDisappear(): void { aboutToDisappear(): void {
if (this.request !== undefined) { this.emitterDestroy()
this.request.requestState = ImageKnifeRequestState.DESTROY this.clearLastRequest()
this.request = undefined
}
} }
aboutToRecycle() { aboutToRecycle() {
this.emitterDestroy()
this.clearLastRequest()
}
emitterDestroy() {
if (typeof this.request?.imageKnifeOption.loadSrc === 'string' && !this.request?.drawMainSuccess) {
emitter.emit(this.request.imageKnifeOption.loadSrc + this.componentId)
}
}
/**
* 对已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() {
ImageAnimator() ImageAnimator()
.images(this.imageAnimator) .images(this.imageAnimator)
.width(this.adaptiveWidth) .width(this.adaptiveWidth)
.height(this.adaptiveHeight) .height(this.adaptiveHeight)
.border(this.imageKnifeOption.border) .border(this.imageKnifeOption.border)
.clip(this.imageKnifeOption.border?.radius == undefined ? false : true)
.state(this.animatorOption.state == undefined ? AnimationStatus.Running : this.animatorOption.state) .state(this.animatorOption.state == undefined ? AnimationStatus.Running : this.animatorOption.state)
.iterations(this.animatorOption.iterations == undefined ? -1 : this.animatorOption.iterations) .iterations(this.animatorOption.iterations == undefined ? -1 : this.animatorOption.iterations)
.reverse(this.animatorOption.reverse == undefined ? false : this.animatorOption.reverse) .reverse(this.animatorOption.reverse == undefined ? false : this.animatorOption.reverse)
@ -83,8 +88,18 @@ export struct ImageKnifeAnimatorComponent {
} else { } else {
// 前提:宽高值均有效,值>0. 条件1当前宽高与上一次宽高不同 条件2:当前是第一次绘制 // 前提:宽高值均有效,值>0. 条件1当前宽高与上一次宽高不同 条件2:当前是第一次绘制
if (this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth) { if (this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth) {
LogUtil.log("execute request:width=" + this.currentWidth + " height= " + this.currentHeight) LogUtil.log('onSizeChange execute request:width=' + this.currentWidth + ' height= ' + this.currentHeight +
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight),true) ' loadSrc = ' + this.imageKnifeOption.loadSrc +
' placeholderSrc = ' + this.imageKnifeOption.placeholderSrc +
' errorholderSrc = ' + this.imageKnifeOption.errorholderSrc +
' componentId = ' + this.componentId)
if (this.imageKnifeOption.objectFit === ImageFit.Auto && this.isImageFitAutoResize) {
this.isImageFitAutoResize = false
} else {
ImageKnife.getInstance().execute(this.getRequest(
this.currentWidth, this.currentHeight, this.componentId))
}
} }
} }
}) })
@ -95,6 +110,20 @@ export struct ImageKnifeAnimatorComponent {
.onRepeat(this.animatorOption.onRepeat) .onRepeat(this.animatorOption.onRepeat)
} }
watchImageKnifeOption() {
this.clearLastRequest()
this.componentVersion++
this.isImageFitAutoResize = false
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
LogUtil.log('watchImageKnifeOption execute request:width=' + this.currentWidth + ' height= ' + this.currentHeight +
' loadSrc = ' + this.imageKnifeOption.loadSrc +
' placeholderSrc = ' + this.imageKnifeOption.placeholderSrc +
' errorholderSrc = ' + this.imageKnifeOption.errorholderSrc +
' componentId = ' + this.componentId)
ImageKnife.getInstance().execute(this.getRequest(
this.currentWidth, this.currentHeight, this.componentId))
}
getCurrentContext(): common.UIAbilityContext { getCurrentContext(): common.UIAbilityContext {
if (this.currentContext == undefined) { if (this.currentContext == undefined) {
this.currentContext = getContext(this) as common.UIAbilityContext this.currentContext = getContext(this) as common.UIAbilityContext
@ -102,43 +131,52 @@ export struct ImageKnifeAnimatorComponent {
return this.currentContext return this.currentContext
} }
getRequest(width: number, height: number): ImageKnifeRequest { getRequest(width: number, height: number,componentId: number): ImageKnifeRequest {
if (this.request == undefined) { this.request = new ImageKnifeRequest(
this.request = new ImageKnifeRequest( this.imageKnifeOption,
this.imageKnifeOption, this.imageKnifeOption.context !== undefined ? this.imageKnifeOption.context : this.getCurrentContext(),
this.imageKnifeOption.context !== undefined ? this.imageKnifeOption.context : this.getCurrentContext(), width,
width, height,
height, this.componentVersion,
this.componentVersion, {
{ showPixelMap: (version: number, pixelMap: PixelMap | string, size: Size, requestSource: ImageKnifeRequestSource,
showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource,imageAnimator?: Array<ImageFrameInfo>) => { imageAnimator?: Array<ImageFrameInfo>) => {
if (version !== this.componentVersion) { if (version !== this.componentVersion) {
return //针对reuse场景不显示历史图片 return //针对reuse场景不显示历史图片
} }
if (imageAnimator != undefined) { if (imageAnimator != undefined) {
this.imageAnimator = imageAnimator this.imageAnimator = imageAnimator
} else { } else {
this.imageAnimator = [ this.imageAnimator = [
{ {
src: pixelMap src: pixelMap
} }
] ]
}
if (requestSource == ImageKnifeRequestSource.SRC) {
this.objectFit =
this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
} else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) {
this.objectFit =
this.imageKnifeOption.placeholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.placeholderObjectFit
} else {
this.objectFit =
this.imageKnifeOption.errorholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.errorholderObjectFit
}
} }
})
}
if (this.imageKnifeOption.objectFit === ImageFit.Auto && this.isImageFitAutoResize == false &&
requestSource == ImageKnifeRequestSource.SRC) {
this.adaptiveHeight = undefined
this.isImageFitAutoResize = true
}
if (requestSource == ImageKnifeRequestSource.SRC) {
this.objectFit =
this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
} else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) {
this.objectFit =
this.imageKnifeOption.placeholderObjectFit === undefined ?
(this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) :
this.imageKnifeOption.placeholderObjectFit
} else {
this.objectFit =
this.imageKnifeOption.errorholderObjectFit === undefined ?
(this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) :
this.imageKnifeOption.errorholderObjectFit
}
}
})
this.request.animator = true
return this.request return this.request
} }
} }

View File

@ -20,56 +20,46 @@ import { LogUtil } from '../utils/LogUtil';
import { ImageKnifeData, ImageKnifeRequestSource } from '../model/ImageKnifeData'; import { ImageKnifeData, ImageKnifeRequestSource } from '../model/ImageKnifeData';
import { IEngineKey } from '../key/IEngineKey'; import { IEngineKey } from '../key/IEngineKey';
import { DefaultEngineKey } from '../key/DefaultEngineKey'; import { DefaultEngineKey } from '../key/DefaultEngineKey';
import { emitter } from '@kit.BasicServicesKit';
@ComponentV2 @Component
export struct ImageKnifeComponent { export struct ImageKnifeComponent {
@Local pixelMap: PixelMap | string | undefined = undefined @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
@Param syncLoad: boolean = false @State pixelMap: PixelMap | string | ImageContent | undefined = ImageContent.EMPTY
@Local adaptiveWidth: Length = '100%' @State syncLoad: boolean = false
@Local adaptiveHeight: Length = '100%' @State adaptiveWidth: Length = '100%'
@Local objectFit: ImageFit = ImageFit.Contain @State adaptiveHeight: Length | undefined = '100%'
@State objectFit: ImageFit = ImageFit.Contain
private componentId: number = 0
private request: ImageKnifeRequest | undefined private request: ImageKnifeRequest | undefined
private lastWidth: number = 0 private lastWidth: number = 0
private lastHeight: number = 0 private lastHeight: number = 0
private currentWidth: number = 0 private currentWidth: number = 0
private isImageFitAutoResize: boolean = false
private currentHeight: number = 0 private currentHeight: number = 0
private componentVersion: number = 0 private componentVersion: number = 0
private currentContext: common.UIAbilityContext | undefined = undefined private currentContext: common.UIAbilityContext | undefined = undefined
@Param imageKnifeOption: ImageKnifeOption = new ImageKnifeOption();
@Monitor('imageKnifeOption',
"imageKnifeOption.loadSrc","imageKnifeOption.signature","imageKnifeOption.transformation","imageKnifeOption.border","imageKnifeOption.objectFit")
watchImageKnifeOption() {
this.clearLastRequest()
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))
}
aboutToAppear(): void { aboutToAppear(): void {
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit this.objectFit = (this.imageKnifeOption.objectFit === undefined || this.imageKnifeOption.objectFit === ImageFit.Auto) ? ImageFit.Contain : this.imageKnifeOption.objectFit
this.componentId = this.getUniqueId()
if(this.syncLoad) { //针对部分消息列表最新消息的图片闪动问题建议使用同步方式在aboutToAppear时加载图片 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 success load loadSrc from memory cache for loadSrc = "+ this.imageKnifeOption.loadSrc) 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) LogUtil.log('aboutToAppear fail load loadSrc from memory cache for loadSrc = '+ this.imageKnifeOption.loadSrc)
if (this.imageKnifeOption.placeholderSrc !== undefined){ 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 success load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) LogUtil.log('aboutToAppear success load placeholderSrc from memory cache for placeholderSrc = ' + this.imageKnifeOption.placeholderSrc)
this.pixelMap = memoryCachePlace.source; this.pixelMap = memoryCachePlace.source;
}else{ }else{
LogUtil.log("aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = " + this.imageKnifeOption.placeholderSrc) LogUtil.log('aboutToAppear fail load placeholderSrc from memory cache for placeholderSrc = ' + this.imageKnifeOption.placeholderSrc)
} }
} }
} }
@ -77,13 +67,21 @@ export struct ImageKnifeComponent {
} }
aboutToDisappear(): void { aboutToDisappear(): void {
this.emitterDestroy()
this.clearLastRequest() this.clearLastRequest()
} }
aboutToRecycle() { aboutToRecycle() {
this.pixelMap = ImageContent.EMPTY
this.emitterDestroy()
this.clearLastRequest() this.clearLastRequest()
} }
emitterDestroy() {
if (typeof this.request?.imageKnifeOption.loadSrc === 'string' && !this.request?.drawMainSuccess) {
emitter.emit(this.request.imageKnifeOption.loadSrc + this.componentId)
}
}
/** /**
* 对已DESTROY的组件不再发起请求 * 对已DESTROY的组件不再发起请求
*/ */
@ -93,7 +91,6 @@ export struct ImageKnifeComponent {
this.request = undefined this.request = undefined
} }
} }
build() { build() {
Image(this.pixelMap) Image(this.pixelMap)
.colorFilter(this.imageKnifeOption.drawingColorFilter) .colorFilter(this.imageKnifeOption.drawingColorFilter)
@ -109,19 +106,42 @@ export struct ImageKnifeComponent {
this.currentHeight = newValue.height as number this.currentHeight = newValue.height as number
this.lastWidth = oldValue.width as number this.lastWidth = oldValue.width as number
this.lastHeight = oldValue.height as number this.lastHeight = oldValue.height as number
if (this.currentWidth <= 0 || this.currentHeight <= 0) {
// 存在宽或者高为0,此次重回无意义,无需进行request请求
} else {
// 前提:宽高值均有效,值>0. 条件1当前宽高与上一次宽高不同 条件2:当前是第一次绘制
if (this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth) {
LogUtil.log('onSizeChange execute request:width=' + this.currentWidth + ' height= ' + this.currentHeight +
' loadSrc = ' + this.imageKnifeOption.loadSrc +
' placeholderSrc = ' + this.imageKnifeOption.placeholderSrc +
' errorholderSrc = ' + this.imageKnifeOption.errorholderSrc +
' componentId = ' + this.componentId)
// 条件1: 宽高值均有效,值>0. 条件2当前宽高与上一次宽高不同 if (this.imageKnifeOption.objectFit === ImageFit.Auto && this.isImageFitAutoResize) {
if (this.currentWidth > 0 && this.currentHeight > 0 && this.isImageFitAutoResize = false
(this.currentHeight != this.lastHeight || this.currentWidth != this.lastWidth)) { } else {
LogUtil.log("onSizeChange execute request:width=" + this.currentWidth + " height= " + this.currentHeight ImageKnife.getInstance().execute(this.getRequest(
+ " loadSrc = " + this.request?.imageKnifeOption.loadSrc this.currentWidth, this.currentHeight, this.componentId))
+ " placeholderSrc = " + this.request?.imageKnifeOption.placeholderSrc }
+ " errorholderSrc = " + this.request?.imageKnifeOption.errorholderSrc) }
ImageKnife.getInstance().execute(this.getRequest(this.currentWidth, this.currentHeight))
} }
}) })
} }
watchImageKnifeOption() {
this.clearLastRequest()
this.componentVersion++
this.isImageFitAutoResize = false
this.objectFit = this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
LogUtil.log('watchImageKnifeOption execute request:width=' + this.currentWidth + ' height= ' + this.currentHeight +
' loadSrc = ' + this.imageKnifeOption.loadSrc +
' placeholderSrc = ' + this.imageKnifeOption.placeholderSrc +
' errorholderSrc = ' + this.imageKnifeOption.errorholderSrc +
' componentId = ' + this.componentId)
ImageKnife.getInstance().execute(this.getRequest(
this.currentWidth, this.currentHeight, this.componentId))
}
getCurrentContext(): common.UIAbilityContext { getCurrentContext(): common.UIAbilityContext {
if (this.currentContext == undefined) { if (this.currentContext == undefined) {
this.currentContext = getContext(this) as common.UIAbilityContext this.currentContext = getContext(this) as common.UIAbilityContext
@ -129,40 +149,45 @@ export struct ImageKnifeComponent {
return this.currentContext return this.currentContext
} }
getRequest(width: number, height: number): ImageKnifeRequest { getRequest(width: number, height: number,componentId: number): ImageKnifeRequest {
if (this.request == undefined) { this.request = new ImageKnifeRequest(
this.request = new ImageKnifeRequest( this.imageKnifeOption,
this.imageKnifeOption, this.imageKnifeOption.context !== undefined ? this.imageKnifeOption.context : this.getCurrentContext(),
this.imageKnifeOption.context !== undefined ? this.imageKnifeOption.context : this.getCurrentContext(), width,
width, height,
height, this.componentVersion,
this.componentVersion, {
{ showPixelMap: (version: number, pixelMap: PixelMap | string,size:Size, requestSource: ImageKnifeRequestSource) => {
showPixelMap: async (version: number, pixelMap: PixelMap | string, requestSource: ImageKnifeRequestSource) => { if (version !== this.componentVersion) {
if (version !== this.componentVersion) { return //针对reuse场景不显示历史图片
return //针对reuse场景不显示历史图片 }
} this.pixelMap = pixelMap
this.pixelMap = pixelMap LogUtil.info('image load showPixelMap:' + this.request?.componentId + ',srcType:' + requestSource +
if (typeof this.pixelMap !== 'string' && this.imageKnifeOption.objectFit === ImageFit.Auto) { //针对静态图高度自适应 ',version:' + this.request?.componentVersion +
let info = await this.pixelMap.getImageInfo() ',size:' + JSON.stringify(size))
this.adaptiveWidth = this.currentWidth if (this.imageKnifeOption.objectFit === ImageFit.Auto && this.isImageFitAutoResize == false && requestSource == ImageKnifeRequestSource.SRC) {
this.adaptiveHeight = info.size.height * this.currentWidth / info.size.width this.adaptiveHeight = undefined
} this.isImageFitAutoResize = true
if (requestSource == ImageKnifeRequestSource.SRC) {
this.objectFit =
this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
} else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) {
this.objectFit =
this.imageKnifeOption.placeholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.placeholderObjectFit
} else {
this.objectFit =
this.imageKnifeOption.errorholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.errorholderObjectFit
}
} }
})
}
if (requestSource == ImageKnifeRequestSource.SRC) {
this.objectFit =
this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit
} else if (requestSource == ImageKnifeRequestSource.PLACE_HOLDER) {
this.objectFit =
this.imageKnifeOption.placeholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.placeholderObjectFit
} else {
this.objectFit =
this.imageKnifeOption.errorholderObjectFit === undefined ? (this.imageKnifeOption.objectFit === undefined ? ImageFit.Contain : this.imageKnifeOption.objectFit) : this.imageKnifeOption.errorholderObjectFit
}
}
},
componentId
)
return this.request return this.request
} }
}
interface KeyCanvas {
keyId: string
} }

View File

@ -0,0 +1,21 @@
/*
* 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 { DownsampleStrategy } from './DownsampleStartegy';
export interface BaseDownsampling {
getName(): string
getScaleFactor(sourceWidth: number, sourceHeight: number, requestWidth: number, requestHeight: number,downsampType?:DownsampleStrategy): number
}

Some files were not shown because too many files have changed in this diff Show More