Merge remote-tracking branch 'origin/master'

# Conflicts:
#	entry/src/main/ets/pages/pngjTestCasePage.ets
#	library/src/main/ets/components/imageknife/pngj/Pngj.ts
This commit is contained in:
24186 2024-04-26 19:58:17 +08:00
commit 9a37765b1f
125 changed files with 6746 additions and 1671 deletions

View File

@ -1,5 +1,70 @@
## 2.2.0-rc.1
- 修改ImageKnife跳过网络,点击默认,图片没有传入宽高,无显示bug
- ImageKnife支持根据自定义key获取已缓存的图片
- ImageKnife加载图片支持自定义网络栈和图片加载组件
- 适配复用场景触发懒加载onDataReloaded
- ImageKnife控制重要图片请求加载优先级
## 2.2.0-rc.0
- 修复自定义DataFetch接口实现不生效问题
- 修改磁盘缓存到子线程
- 更新SDK到API12
- 适配Sendable内存共享优化
- 修改全局请求头覆盖request请求头
- imageKnife支持heic测试demo独立页面展示
- drawLifeCycle支持gif图
## 2.1.2
- 修改ImageKnife跳过网络从内存中获取图片 cacheType参数未使用bug
- 新增WEBP图片解析能力。
- 新增gif图片支持暂停播放功能
## 2.1.2-rc.12
- 新增gif播放次数功能
- 新增磁盘预加载返回文件路径接口prefetchToDiskCache
- 新增跳过网络判断缓存或者磁盘中是否存在图片接口isUrlExist
- 删除多余操作磁盘记录读写
- 清除定时器改为Gif图时清除
- uuid改为util.generateRandomUUID()
## 2.1.2-rc.11
- 修复设置磁盘容量最大值出现闪退
- 修复概率出现jscrash问题
- 修复进度条问题
- 修复单帧gif图片加载失败
- removeRunning删除running队列log设置开关
- ImageKnife新增图片宽高自适应功能
- 修复onlyRetrieveFromCache属性(仅磁盘和内存获取资源)失效
- 修改拼写错误
- 新增多线程优先级
- 修复复用场景下图片闪动以及概率错位
- 获取组件宽高改为使用CanvasRenderingContext2D对象获取宽高并修复改变字体大小导致部分图片消失
- 修复获取不到磁盘缓存文件问题
- 修复获取不到网络请求错误回调问题
## 2.1.2-rc.10
- 修复部分gif图片识别成静态图
- 修复同一张图片发送多次请求
- 复用场景缓存到树aboutToRecycle清理定时器
## 2.1.2-rc.9
- 使用taskpool实现多线程加载图片资源
- 修复部分gif图片识别成静态图
- 修复同一张图片发送多次请求
- disAppear生命周期清空定时器只在gif图片时执行
## 2.1.2-rc.8
- onAreaChange绘制图片改为component Util绘制
## 2.1.2-rc.7
- 修复图片圆角图形变换导致抗锯齿、ScaleType失效
- 修复使用模糊化出现图片变模糊和变形
## 2.1.2-rc.6 ## 2.1.2-rc.6
- 修复手机调节显示大小时图片消失 - 修复手机调节显示大小时图片消失
- imageKnife防盗链header请求头属性设置
- pngWorker线程改为taskpool
- 修复正方形裁剪有些图片裁剪创建pixelMap失败
## 2.1.2-rc.5 ## 2.1.2-rc.5
- moduleContext新增缓存策略缓存上限5缓存策略Lru - moduleContext新增缓存策略缓存上限5缓存策略Lru

18
OAT.xml
View File

@ -1,4 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2021 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.
This is the configuration file template for OpenHarmony OSS Audit Tool, please copy it to your project root dir and modify it refer to OpenHarmony/tools_oat/README.
-->
<configuration> <configuration>
<oatconfig> <oatconfig>
<filefilterlist> <filefilterlist>
@ -32,6 +49,7 @@
<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="*.json5" desc="hvigor配置文件"/> <filteritem type="filename" name="*.json5" desc="hvigor配置文件"/>
<filteritem type="filename" name="*.heic" desc="heic图片格式文件,用于展示示例"/>
</filefilter> </filefilter>
<filefilter name="defaultFilter" desc="Files not to check"> <filefilter name="defaultFilter" desc="Files not to check">
<filteritem type="filepath" name="library/src/main/ets/components/3rd_party/.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/> <filteritem type="filepath" name="library/src/main/ets/components/3rd_party/.*" desc="第三方开源软件源码,不修改版权头,以防有修改版权风险"/>

View File

@ -2,9 +2,9 @@
{ {
"Name": "glide", "Name": "glide",
"License": "Apache License 2.0", "License": "Apache License 2.0",
"License File": "https://github.com/bumptech/glide/blob/master/LICENSE", "License File": "LICENSE",
"Version Number": "4.13.1", "Version Number": "4.13.1",
"Owner" : "bumptech", "Owner" : "xiafeng@huawei.com",
"Upstream URL": "https://github.com/bumptech/glide", "Upstream URL": "https://github.com/bumptech/glide",
"Description": "An image loading and caching library focused on smooth scrolling" "Description": "An image loading and caching library focused on smooth scrolling"
}, },
@ -12,9 +12,9 @@
{ {
"Name": "glide-transformations", "Name": "glide-transformations",
"License": "Apache License 2.0", "License": "Apache License 2.0",
"License File": "https://github.com/wasabeef/glide-transformations/blob/main/LICENSE", "License File": "LICENSE",
"Version Number": "4.3.0", "Version Number": "4.3.0",
"Owner" : "wasabeef", "Owner" : "xiafeng@huawei.com",
"Upstream URL": "https://github.com/wasabeef/glide-transformations", "Upstream URL": "https://github.com/wasabeef/glide-transformations",
"Description": " An transformation library providing a variety of image transformations for Glide. " "Description": " An transformation library providing a variety of image transformations for Glide. "
}, },
@ -22,9 +22,9 @@
{ {
"Name": "fresco", "Name": "fresco",
"License": "MIT License", "License": "MIT License",
"License File": "https://github.com/facebook/fresco/blob/main/LICENSE", "License File": "LICENSE",
"Version Number": "2.6.0", "Version Number": "2.6.0",
"Owner" : "facebook", "Owner" : "xiafeng@huawei.com",
"Upstream URL": "https://github.com/facebook/fresco", "Upstream URL": "https://github.com/facebook/fresco",
"Description": " An library for managing images and the memory they use. " "Description": " An library for managing images and the memory they use. "
}, },
@ -32,9 +32,9 @@
{ {
"Name": "UPNG.js", "Name": "UPNG.js",
"License": "MIT License", "License": "MIT License",
"License File": "https://github.com/photopea/UPNG.js/blob/master/LICENSE", "License File": "LICENSE",
"Version Number": "1.0.0", "Version Number": "1.0.0",
"Owner" : "photopea", "Owner" : "xiafeng@huawei.com",
"Upstream URL": "https://github.com/photopea/UPNG.js", "Upstream URL": "https://github.com/photopea/UPNG.js",
"Description": " Fast and advanced PNG (APNG) decoder and encoder (lossy / lossless) " "Description": " Fast and advanced PNG (APNG) decoder and encoder (lossy / lossless) "
}, },
@ -42,9 +42,9 @@
{ {
"Name": "Luban", "Name": "Luban",
"License": "Apache License 2.0", "License": "Apache License 2.0",
"License File": "https://github.com/Curzibn/Luban/blob/master/LICENSE", "License File": "LICENSE",
"Version Number": "1.1.8", "Version Number": "1.1.8",
"Owner" : " Curzibn", "Owner" : " xiafeng@huawei.com",
"Upstream URL": "https://github.com/Curzibn/Luban", "Upstream URL": "https://github.com/Curzibn/Luban",
"Description": " Luban(鲁班)—Image compression with efficiency very close to WeChat Moments/可能是最接近微信朋友圈的图片压缩算法 " "Description": " Luban(鲁班)—Image compression with efficiency very close to WeChat Moments/可能是最接近微信朋友圈的图片压缩算法 "
}, },
@ -54,16 +54,16 @@
"License": "Apache License 2.0", "License": "Apache License 2.0",
"License File": "https://github.com/Yalantis/uCrop/blob/develop/README.md", "License File": "https://github.com/Yalantis/uCrop/blob/develop/README.md",
"Version Number": "2.2.8", "Version Number": "2.2.8",
"Owner" : " Yalantis", "Owner" : " xiafeng@huawei.com",
"Upstream URL": "https://github.com/Yalantis/uCrop", "Upstream URL": "https://github.com/Yalantis/uCrop",
"Description": " Image Cropping Library " "Description": " Image Cropping Library "
}, },
{ {
"Name": "js-spark-md5", "Name": "js-spark-md5",
"License": "MIT", "License": "MIT",
"License File": "https://github.com/satazor/js-spark-md5/blob/master/LICENSE", "License File": "LICENSE",
"Version Number": "v3.0.2", "Version Number": "v3.0.2",
"Owner" : "satazor", "Owner" : "xiafeng@huawei.com",
"Upstream URL": "https://github.com/satazor/js-spark-md5", "Upstream URL": "https://github.com/satazor/js-spark-md5",
"Description": "Lightning fast normal and incremental md5 for javascript" "Description": "Lightning fast normal and incremental md5 for javascript"
} }

155
README.md
View File

@ -86,6 +86,10 @@ svg类型图片即可。
加载GIF其实和普通流程也没有区别只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.gifSample'),` 加载GIF其实和普通流程也没有区别只要将 `loadSrc: $r('app.media.jpgSample'),` `改成一张 loadSrc: $r('app.media.gifSample'),`
GIF图片即可。 GIF图片即可。
#### 4.1加载GIF图片
更改ImageKnifeOption对象的autoPlay可选autoPlay = true为开始播放autoPlay = false为暂停播放
### 5.自定义Key ### 5.自定义Key
因为通常改变标识符比较困难或者根本不可能所以ImageKnife也提供了 签名 API 来混合(你可以控制的)额外数据到你的缓存键中。 因为通常改变标识符比较困难或者根本不可能所以ImageKnife也提供了 签名 API 来混合(你可以控制的)额外数据到你的缓存键中。
签名(signature)适用于媒体内容,也适用于你可以自行维护的一些版本元数据。 签名(signature)适用于媒体内容,也适用于你可以自行维护的一些版本元数据。
@ -101,39 +105,44 @@ imageKnifeOption = {
代码示例 代码示例
### 6.自定义请求头规格
设置全局header并且设置request的header时当key不同时全局和request并行当key相同时request的header覆盖全局的header
## 进阶使用 ## 进阶使用
如果简单的加载一张图像无法满足需求我们可以看看ImageKnifeOption这个类提供了哪些扩展能力。 如果简单的加载一张图像无法满足需求我们可以看看ImageKnifeOption这个类提供了哪些扩展能力。
### ImageKnifeOption参数列表 ### ImageKnifeOption参数列表
| 参数名称 | 入参内容 | 功能简介 | | 参数名称 | 入参内容 | 功能简介 |
| ---------------------------- | ------------------------------------------------------------ |-----------------------------------------------| |------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------|
| loadSrc | string\| PixelMap\ |Resource | 图片数据源 | | loadSrc | string\ | PixelMap\ |Resource | 图片数据源 |
| mainScaleType | ScaleType | 设置主图展示样式(可选) | | mainScaleType | ScaleType | 设置主图展示样式(可选) |
| strategy | DiskStrategy | 设置磁盘缓存策略(可选) | | strategy | DiskStrategy | 设置磁盘缓存策略(可选) |
| dontAnimateFlag | boolean | gif加载展示一帧可选 | | dontAnimateFlag | boolean | gif加载展示一帧可选 |
| placeholderSrc | PixelMap\| Resource | 占位图数据源 | | placeholderSrc | string\ (占位图不支持gif图且不支持网络下载功能) | PixelMap\ |Resource | 占位图数据源 |
| placeholderScaleType | ScaleType | 设置占位图展示样式(可选) | | placeholderScaleType | ScaleType | 设置占位图展示样式(可选) |
| errorholderSrc | PixelMap\| Resource | 错误占位图数据源 | | errorholderSrc | PixelMap\ | Resource | 错误占位图数据源 |
| errorholderSrcScaleType | ScaleType | 设置失败占位图展示样式(可选) | | errorholderSrcScaleType | ScaleType | 设置失败占位图展示样式(可选) |
| retryholderSrc | PixelMap\| Resource | 重试占位图数据源 | | retryholderSrc | PixelMap\ | Resource | 重试占位图数据源 |
| retryholderScaleType | ScaleType | 设置重试占位图展示样式(可选) | | retryholderScaleType | ScaleType | 设置重试占位图展示样式(可选) |
| thumbSizeMultiplier | number 范围(0,1] | 设置缩略图占比(可选) | | fallbackSrc | PixelMap\ | Resource | 后备回调符数据源 |
| thumbSizeDelay | number | 设置缩略图展示时间(可选) | | thumbSizeMultiplier | number 范围(0,1] | 设置缩略图占比(可选) |
| thumbSizeMultiplierScaleType | ScaleType | 设置缩略图展示样式(可选) | | thumbSizeDelay | number | 设置缩略图展示时间(可选) |
| displayProgress | boolean | 设置是否展示下载进度条(可选) | | thumbSizeMultiplierScaleType | ScaleType | 设置缩略图展示样式(可选) |
| canRetryClick | boolean | 设置重试图层是否点击重试(可选) | | displayProgress | boolean | 设置是否展示下载进度条(可选) |
| onlyRetrieveFromCache | boolean | 仅使用缓存加载数据(可选) | | canRetryClick | boolean | 设置重试图层是否点击重试(可选) |
| isCacheable | boolean | 是否开启一级内存缓存(可选) | | onlyRetrieveFromCache | boolean | 仅使用缓存加载数据(可选) |
| gif | {<br/> // 返回一周期动画gif消耗的时间<br/> loopFinish?: (loopTime?) => void<br/> // gif播放速率相关<br/> speedFactory?: number<br/> // 直接展示gif第几帧数据<br/> seekTo?: number<br/> } | GIF播放控制能力可选 | | isCacheable | boolean | 是否开启一级内存缓存(可选) |
| transformation | BaseTransform<PixelMap> | 单个变换(可选) | | gif | {<br/> // 返回一周期动画gif消耗的时间<br/> loopFinish?: (loopTime?) => void<br/> // gif播放速率相关<br/> speedFactory?: number<br/> // 直接展示gif第几帧数据<br/> seekTo?: number<br/> playTimes?: number<br/> } | GIF播放控制能力可选 |
| transformations | Array<BaseTransform<PixelMap>> | 多个变换,目前仅支持单个变换(可选) | | transformation | BaseTransform<PixelMap> | 单个变换(可选) |
| allCacheInfoCallback | IAllCacheInfoCallback | 输出缓存相关内容和信息(可选) | | transformations | Array<BaseTransform<PixelMap>> | 多个变换,目前仅支持单个变换(可选) |
| signature | ObjectKey | 自定key可选 | | allCacheInfoCallback | IAllCacheInfoCallback | 输出缓存相关内容和信息(可选) |
| **drawLifeCycle** | **IDrawLifeCycle** | **用户自定义实现绘制方案(可选)** | | signature | ObjectKey | 自定key可选 |
| imageSmoothingEnabled | boolean | 抗锯齿是否开启属性配置设置为false时imageSmoothingQuality失效 | | **drawLifeCycle** | **IDrawLifeCycle** | **用户自定义实现绘制方案(可选)** |
| imageSmoothingQuality | AntiAliasing | 抗锯齿属性配置 | | imageSmoothingEnabled | boolean | 抗锯齿是否开启属性配置设置为false时imageSmoothingQuality失效 |
| imageSmoothingQuality | AntiAliasing | 抗锯齿属性配置 |
| autoPlay | boolean | GIF播放暂停控制可选 |
其他参数只需要在ImageKnifeOption对象上按需添加即可。 其他参数只需要在ImageKnifeOption对象上按需添加即可。
@ -312,9 +321,10 @@ request.skipMemoryCache(true)
| load(src: string \| PixelMap \|Resource) | src:string\|PixelMap\|Resource | 用户加载图片源 | | load(src: string \| PixelMap \|Resource) | src:string\|PixelMap\|Resource | 用户加载图片源 |
| setImageViewSize(imageSize: { width: number, height: number }) | imageSize:{width: number, height: number } | 传入显示图片组件的大小,变换的时候需要作为参考 | | setImageViewSize(imageSize: { width: number, height: number }) | imageSize:{width: number, height: number } | 传入显示图片组件的大小,变换的时候需要作为参考 |
| diskCacheStrategy(strategy: DiskStrategy) | strategy:DiskStrategy | 配置磁盘缓存策略 NONE SOURCE RESULT ALL AUTOMATIC | | diskCacheStrategy(strategy: DiskStrategy) | strategy:DiskStrategy | 配置磁盘缓存策略 NONE SOURCE RESULT ALL AUTOMATIC |
| placeholder(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 占位图占位图回调数据ImageKnifeData | | placeholder(src: string \| PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: string\|PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 占位图占位图回调数据ImageKnifeData |
| errorholder(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 错误占位图错误占位图回调数据ImageKnifeData | | errorholder(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 错误占位图错误占位图回调数据ImageKnifeData |
| retryholder(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 重试占位图重试占位图回调数据ImageKnifeData | | retryholder(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 重试占位图重试占位图回调数据ImageKnifeData |
| fallback(src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData>) | src: PixelMap\|Resource, func?: AsyncSuccess<ImageKnifeData> | 重试占位图重试占位图回调数据ImageKnifeData |
| addListener(func: AsyncCallback<ImageKnifeData>) | func: AsyncCallback<ImageKnifeData> | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 | | addListener(func: AsyncCallback<ImageKnifeData>) | func: AsyncCallback<ImageKnifeData> | 配置整个监听回调,数据正常加载返回,加载失败返回错误信息 |
| thumbnail(sizeMultiplier:number, func?: AsyncSuccess<ImageKnifeData>) | sizeMultiplier:number, func?: AsyncSuccess<ImageKnifeData> | 设置缩略图比例,缩略图返回后,加载并展示缩略图 | | thumbnail(sizeMultiplier:number, func?: AsyncSuccess<ImageKnifeData>) | sizeMultiplier:number, func?: AsyncSuccess<ImageKnifeData> | 设置缩略图比例,缩略图返回后,加载并展示缩略图 |
| addProgressListener(func?: AsyncSuccess<number>) | func?: AsyncSuccess<number> | 设置网络下载百分比监听,返回数据加载百分比数值 | | addProgressListener(func?: AsyncSuccess<number>) | func?: AsyncSuccess<number> | 设置网络下载百分比监听,返回数据加载百分比数值 |
@ -327,12 +337,14 @@ request.skipMemoryCache(true)
### ImageKnife 启动器/门面类 ### ImageKnife 启动器/门面类
| 方法名 | 入参 | 接口描述 | | 方法名 | 入参 | 接口描述 |
| ------------------------------- | ---------------------- | ---------------------------------- | |----------------------------------| ---------------------- | ------------------------------------------------------------ |
| call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 | | call(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行加载流程 |
| preload(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行预加载流程 | | preload(request: RequestOption) | request: RequestOption | 根据用户配置参数具体执行预加载流程 |
| pauseRequests() | | 全局暂停请求 | | pauseRequests() | | 全局暂停请求 |
| resumeRequests() | | 全局恢复暂停 | | resumeRequests() | | 全局恢复暂停 |
| isUrlExist(url, cacheType, size) | url, CacheType, Size | 判断图片是否在 缓存和磁盘中存在,如果入参是缓存,需要传入值图片大小,参数 CacheType, Size可选 |
| setMaxRequests(count: number) | count | 设置请求的最大并发数量 |
### 缓存策略相关 ### 缓存策略相关
@ -352,6 +364,14 @@ request.skipMemoryCache(true)
| AntiAliasing.FIT_MEDIUM | String | 图像抗锯齿设置为中画质 | | AntiAliasing.FIT_MEDIUM | String | 图像抗锯齿设置为中画质 |
| AntiAliasing.FIT_LOW | String | 图像抗锯齿设置为低画质 | | AntiAliasing.FIT_LOW | String | 图像抗锯齿设置为低画质 |
### CacheType类型展示效果
| 使用方法 | 类型 | 策略描述 |
|-------------------------|-----|-----------------------------------|
| CacheType.Default| int | 默认值,先从内存获取,无值则从磁盘获取 |
| CacheType.Cache| int | 缓存 |
| CacheType.Disk | int | 磁盘 |
### ScaleType类型展示效果 ### ScaleType类型展示效果
| 使用方法 | 类型 | 策略描述 | | 使用方法 | 类型 | 策略描述 |
@ -364,33 +384,36 @@ request.skipMemoryCache(true)
| ScaleType.FIT_XY | int | 图像拉伸至组件大小 | | ScaleType.FIT_XY | int | 图像拉伸至组件大小 |
| ScaleType.CENTER_INSIDE | int | 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER | | ScaleType.CENTER_INSIDE | int | 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER |
| ScaleType.NONE | int | 如果不想适配,直接展示原图大小 | | ScaleType.NONE | int | 如果不想适配,直接展示原图大小 |
| ScaleType.AUTO_HEIGHT | int | 设置宽的时候,图片高度自适应 |
| ScaleType.AUTO_WIDTH | int | 设置高的时候,图片宽度自适应 |
| ScaleType.AUTO | int | 没有设置宽和高,图片按照自身宽高显示 |
### 图片变换相关 ### 图片变换相关
| 使用方法 | 类型 | 相关描述 | | 使用方法 | 类型 | 相关描述 |
|--------------------------------|------------------------------------|----------------------------------| |--------------------------------|------------------------------------|--------------------------------|
| request.centerCrop() | CenterCrop | 可以根据图片文件目标显示大小进行对应centerCrop | | request.centerCrop() | CenterCrop | 可以根据图片文件目标显示大小进行对应centerCrop |
| request.centerInside() | CenterInside | 可以根据图片文件目标显示大小进行对应centerInside | | request.centerInside() | CenterInside | 可以根据图片文件目标显示大小进行对应centerInside |
| request.fitCenter() | FitCenter | 可以根据图片文件目标显示大小进行对应fitCenter | | request.fitCenter() | FitCenter | 可以根据图片文件目标显示大小进行对应fitCenter |
| request.blur() | BlurTransformation | 模糊处理 | | request.blur() | BlurTransformation | 模糊处理(图片分辨率较大建议传递第二个参数将图片进行缩小) |
| request.brightnessFilter() | BrightnessFilterTransformation | 亮度滤波器 | | request.brightnessFilter() | BrightnessFilterTransformation | 亮度滤波器 |
| request.contrastFilter() | ContrastFilterTransformation | 对比度滤波器 | | request.contrastFilter() | ContrastFilterTransformation | 对比度滤波器 |
| request.cropCircle() | CropCircleTransformation | 圆形剪裁显示 | | request.cropCircle() | CropCircleTransformation | 圆形剪裁显示 |
| request.cropCircleWithBorder() | CropCircleWithBorderTransformation | 圆环展示 | | request.cropCircleWithBorder() | CropCircleWithBorderTransformation | 圆环展示 |
| request.cropSquare() | CropSquareTransformation | 正方形剪裁 | | request.cropSquare() | CropSquareTransformation | 正方形剪裁 |
| request.crop() | CropTransformation | 自定义矩形剪裁 | | request.crop() | CropTransformation | 自定义矩形剪裁 |
| request.grayscale() | GrayscaleTransformation | 灰度级转换 | | request.grayscale() | GrayscaleTransformation | 灰度级转换 |
| request.invertFilter() | InvertFilterTransformation | 反转滤波器 | | request.invertFilter() | InvertFilterTransformation | 反转滤波器 |
| request.pixelationFilter() | PixelationFilterTransformation | 像素化滤波器 | | request.pixelationFilter() | PixelationFilterTransformation | 像素化滤波器 |
| request.rotateImage() | RotateImageTransformation | 图片旋转 | | request.rotateImage() | RotateImageTransformation | 图片旋转 |
| request.roundedCorners() | RoundedCornersTransformation | 圆角剪裁 | | request.roundedCorners() | RoundedCornersTransformation | 圆角剪裁 |
| request.sepiaFilter() | SepiaFilterTransformation | 乌墨色滤波器 | | request.sepiaFilter() | SepiaFilterTransformation | 乌墨色滤波器 |
| request.sketchFilter() | SketchFilterTransformation | 素描滤波器 | | request.sketchFilter() | SketchFilterTransformation | 素描滤波器 |
| request.mask() | MaskTransformation | 遮罩 | | request.mask() | MaskTransformation | 遮罩 |
| request.swirlFilter() | SwirlFilterTransformation | 扭曲滤波器 | | request.swirlFilter() | SwirlFilterTransformation | 扭曲滤波器 |
| request.kuwaharaFilter() | KuwaharaFilterTransform | 桑原滤波器 | | request.kuwaharaFilter() | KuwaharaFilterTransform | 桑原滤波器 |
| request.toonFilter() | ToonFilterTransform | 动画滤波器 | | request.toonFilter() | ToonFilterTransform | 动画滤波器 |
| request.vignetteFilter() | VignetteFilterTransform | 装饰滤波器 | | request.vignetteFilter() | VignetteFilterTransform | 装饰滤波器 |
<img src="screenshot/gif4.gif" width="50%"/> <img src="screenshot/gif4.gif" width="50%"/>
@ -426,10 +449,18 @@ export default class EntryAbility extends UIAbility {
} }
``` ```
### Queue
| 方法名 | 入参 | 接口描述 |
| ----------------------------------- | ----------------------- | ------------------------------ |
| getQueueLength(): number | | 获取队列总长度 |
| add(request: RequestOption) | request:RequestOption | 在队列尾部插入元素 |
| pop(): RequestOption &#124; undefined | | 删除队列头元素并返回该删除元素 |
## 约束与限制 ## 约束与限制
在下述版本验证通过: 在下述版本验证通过:
DevEco Studio 4.14.1.3.520--SDK:API11 4.1.0.63
DevEco Studio 4.14.1.3.418--SDK:API11 4.1.0.56 DevEco Studio 4.14.1.3.418--SDK:API11 4.1.0.56
DevEco Studio 4.14.1.3.322--SDK:API11 4.1.0.36 DevEco Studio 4.14.1.3.322--SDK:API11 4.1.0.36
DevEco Studio 4.04.0.3.700--SDK:API10 4.0.10.15 DevEco Studio 4.04.0.3.700--SDK:API10 4.0.10.15
@ -442,6 +473,10 @@ HSP场景适配:
非HSP场景不影响原功能, ImageKnifeOption配置类新增的可选参数context可以不传, RquestOption配置类新增的接口可以不调用。 非HSP场景不影响原功能, ImageKnifeOption配置类新增的可选参数context可以不传, RquestOption配置类新增的接口可以不调用。
注意:
基于性能优化的原因2.1.2-rc.13及以后版本引用了API12 Sendable接口至此以后的版本只支持API12。
## 目录结构 ## 目录结构
``` ```
@ -502,6 +537,9 @@ HSP场景适配:
- storageTestDiskLruCache.ets # 磁盘缓存测试 - storageTestDiskLruCache.ets # 磁盘缓存测试
- storageTestLruCache.ets # 内存缓存测试 - storageTestLruCache.ets # 内存缓存测试
- testAllCacheInfoPage.ets # 所有缓存信息获取测试 - testAllCacheInfoPage.ets # 所有缓存信息获取测试
- testImageKnifeAutoHeightPage.ets # 图片高度自适应测试
- testImageKnifeAutoWidthPage.ets # 图片宽度自适应测试
- testImageKnifeAutoPage.ets # 图片宽高自适应测试
- testImageKnifeOptionChangedPage.ets # 数据切换测试 - testImageKnifeOptionChangedPage.ets # 数据切换测试
- testImageKnifeOptionChangedPage2.ets # 数据切换测试,部分变换 - testImageKnifeOptionChangedPage2.ets # 数据切换测试,部分变换
- testImageKnifeOptionChangedPage3.ets # 数据切换测试,组件动画 - testImageKnifeOptionChangedPage3.ets # 数据切换测试,组件动画
@ -510,9 +548,12 @@ HSP场景适配:
- testPreloadPage.ets # 预加载测试 - testPreloadPage.ets # 预加载测试
- transformPixelMapPage.ets # 所有类型变换测试 - transformPixelMapPage.ets # 所有类型变换测试
- testSingleFrameGifPage.ets # 单帧gif加载测试 - testSingleFrameGifPage.ets # 单帧gif加载测试
- TestStopPlayingGifPage # gif播放暂停测试
- TestImageKnifeNetPlaceholder # 缓存获取string类型占位图以及后备回调符测试
- OptionTestPage.ets # 图片缓存测试 - OptionTestPage.ets # 图片缓存测试
- testManyGifLoadWithPage # 测试gif加载页面 - testManyGifLoadWithPage # 测试gif加载页面
- testImageKnifeCache # 测试图片是否在缓存或者磁盘中
-workers -workers
- upngWorkerTestCase.ets # png子线程解析 - upngWorkerTestCase.ets # png子线程解析
- upngWorkerDepend.ts # png子线程解析具体执行 - upngWorkerDepend.ts # png子线程解析具体执行

View File

@ -4,8 +4,8 @@
{ {
"name": "default", "name": "default",
"signingConfig": "default", "signingConfig": "default",
"compileSdkVersion": 10, "compileSdkVersion": 12,
"compatibleSdkVersion": 10 "compatibleSdkVersion": 12
} }
], ],
"buildModeSet": [ "buildModeSet": [

View File

@ -4,7 +4,7 @@
"name": "entry", "name": "entry",
"description": "example description", "description": "example description",
"repository": {}, "repository": {},
"version": "2.1.2-rc.6", "version": "2.1.2-rc.12",
"dependencies": { "dependencies": {
"@ohos/libraryimageknife": "file:../sharedlibrary", "@ohos/libraryimageknife": "file:../sharedlibrary",
"@ohos/sharedlibrary2": "file:../sharedlibrary2", "@ohos/sharedlibrary2": "file:../sharedlibrary2",

View File

@ -49,6 +49,9 @@ export default class EntryAbility extends UIAbility {
imageKnife.setEngineKeyImpl(new CustomEngineKeyImpl()) imageKnife.setEngineKeyImpl(new CustomEngineKeyImpl())
// 设置全局内存缓存大小张数 // 设置全局内存缓存大小张数
imageKnife.setLruCacheSize(100, 100 * 1204 * 1024) imageKnife.setLruCacheSize(100, 100 * 1204 * 1024)
// 全局配置请求头
imageKnife.addHeader('refer', "http://1.94.37.200:7070/AntiTheftChain/downloadImage");
imageKnife.deleteHeader('refer');
} }
// 开启ImageKnife所有级别日志开关 // 开启ImageKnife所有级别日志开关
LogUtil.mLogLevel = LogUtil.ALL LogUtil.mLogLevel = LogUtil.ALL

View File

@ -19,7 +19,8 @@ import {
Size, Size,
ImageKnife, ImageKnife,
ImageKnifeGlobal, ImageKnifeGlobal,
ImageKnifeComponent ImageKnifeComponent,
ObjectKey
} from '@ohos/libraryimageknife' } from '@ohos/libraryimageknife'
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
@ -34,6 +35,10 @@ struct RequestOptionLoadImage {
load(src: string | image.PixelMap | Resource) { load(src: string | image.PixelMap | Resource) {
clearTimeout(timeId) clearTimeout(timeId)
let request = new RequestOption() let request = new RequestOption()
//*requestOption调用*
request.addHeader('refer', 'http://1.94.37.200:7070/AntiTheftChain/downloadImage');
//通过时间戳去清除缓存
request.signature = new ObjectKey(new Date().getTime().toString())
request.load(src) request.load(src)
.addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => { .addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => {
if (data.isPixelMap()) { if (data.isPixelMap()) {

View File

@ -69,10 +69,14 @@ struct basicTestFileIOPage {
return return
} }
console.log('files目录创建Folder1和Folder2 验证statSync mkdirSync') console.log('files目录创建Folder1和Folder2 验证statSync mkdirSync')
FileUtils.getInstance() try {
.createFolder(this.appFilePath + '/Folder1'); FileUtils.getInstance()
FileUtils.getInstance() .createFolder(this.appFilePath + '/Folder1');
.createFolder(this.appFilePath + '/Folder2'); FileUtils.getInstance()
.createFolder(this.appFilePath + '/Folder2');
} catch (e) {
console.log('appFilePath未取到值,请按顺序从上往下,从左往右依次测试"'+JSON.stringify(e));
}
}) })
Button('将media资源存入Folder1 验证writeSync mkdirSync createStreamSync') Button('将media资源存入Folder1 验证writeSync mkdirSync createStreamSync')
.margin({ top: 10 }) .margin({ top: 10 })
@ -105,13 +109,18 @@ struct basicTestFileIOPage {
this.imageHint2 = 'appFilePath未取到值,请按顺序从上往下,从左往右依次测试' this.imageHint2 = 'appFilePath未取到值,请按顺序从上往下,从左往右依次测试'
return return
} }
let filePath1 = this.appFilePath + '/Folder1/jpgSample.gif'; try {
let filePath2 = this.appFilePath + '/Folder2/jpgSample.gif'; let filePath1 = this.appFilePath + '/Folder1/jpgSample.gif';
FileUtils.getInstance().createFolder(this.appFilePath + '/Folder1') let filePath2 = this.appFilePath + '/Folder2/jpgSample.gif';
FileUtils.getInstance().createFolder(this.appFilePath + '/Folder2') FileUtils.getInstance().createFolder(this.appFilePath + '/Folder1')
FileUtils.getInstance().copyFile(filePath1, filePath2); FileUtils.getInstance().createFolder(this.appFilePath + '/Folder2')
this.imageFile = 'file://' + this.appFilePath + '/Folder2/jpgSample.gif' FileUtils.getInstance().copyFile(filePath1, filePath2);
console.log('Folder2 imaeFile =' + this.imageFile) this.imageFile = 'file://' + this.appFilePath + '/Folder2/jpgSample.gif'
console.log('Folder2 imaeFile =' + this.imageFile)
} catch (e) {
console.log('appFilePath未取到值,请按顺序从上往下,从左往右依次测试:'+JSON.stringify(e))
}
}) })
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('显示空PixelMap') Button('显示空PixelMap')

View File

@ -15,7 +15,6 @@
import router from '@ohos.router'; import router from '@ohos.router';
@Entry @Entry
@Component @Component
struct IndexFunctionDemo { struct IndexFunctionDemo {
@ -36,8 +35,13 @@ struct IndexFunctionDemo {
console.log("测试文件子系统") console.log("测试文件子系统")
router.pushUrl({ url: "pages/basicTestFileIOPage" }); router.pushUrl({ url: "pages/basicTestFileIOPage" });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
Button("优先级加载")
.onClick(() => {
console.log("优先级加载")
router.pushUrl({ url: "pages/testPriorityComponent" });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("测试全球化") Button("测试全球化")
.onClick(() => { .onClick(() => {
@ -53,8 +57,6 @@ struct IndexFunctionDemo {
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Text("测试图片切换功能点").fontSize(15) Text("测试图片切换功能点").fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
@ -63,8 +65,32 @@ struct IndexFunctionDemo {
console.log("测试ImageKnifeComponent所有图片切换") console.log("测试ImageKnifeComponent所有图片切换")
router.pushUrl({ url: "pages/testImageKnifeOptionChangedPage" }); router.pushUrl({ url: "pages/testImageKnifeOptionChangedPage" });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
Button("测试图片高度自适应")
.onClick(() => {
console.log("测试ImageKnifeComponent图片高度自适应")
router.pushUrl({ url: "pages/testImageKnifeAutoHeightPage" });
}).margin({ top: 5, left: 3 })
Button("测试gif播放次数")
.onClick(() => {
router.pushUrl({ url: "pages/testGifPlayTimesPage" });
}).margin({ top: 15 })
}.width('100%').height(60).backgroundColor(Color.Pink)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("测试图片宽度自适应")
.onClick(() => {
console.log("测试ImageKnifeComponent图片宽度自适应")
router.pushUrl({ url: "pages/testImageKnifeAutoWidthPage" });
}).margin({ top: 5, left: 3 })
Button("测试图片宽高自适应")
.onClick(() => {
console.log("测试ImageKnifeComponent图片宽高自适应")
router.pushUrl({ url: "pages/testImageKnifeAutoPage" });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("测试thumbnail") Button("测试thumbnail")
.onClick(() => { .onClick(() => {
@ -94,7 +120,20 @@ struct IndexFunctionDemo {
}.width('100%') }.width('100%')
.height(60).backgroundColor(Color.Pink) .height(60).backgroundColor(Color.Pink)
Text("测试复用场景").fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("懒加载复用列表")
.onClick(() => {
console.log("测试一级内存缓存")
router.pushUrl({ url: "pages/testReusePhotoPage" });
}).margin({ top: 5, left: 3 })
Button("适配复用场景")
.onClick(() => {
console.log("测试一级内存缓存")
router.pushUrl({ url: "pages/testReuseAblePages" });
}).margin({ top: 5, left: 3 })
}.width('100%')
.height(60).backgroundColor(Color.Pink)
Text("测试占位图 失败占位图 功能点").fontSize(15) Text("测试占位图 失败占位图 功能点").fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("测试失败占位图") Button("测试失败占位图")
@ -111,6 +150,11 @@ struct IndexFunctionDemo {
console.log("测试预加载") console.log("测试预加载")
router.pushUrl({ url: "pages/testPreloadPage" }); router.pushUrl({ url: "pages/testPreloadPage" });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
Button("测试磁盘预加载返回string")
.onClick(() => {
console.log("测试预加载测试磁盘预加载返回string")
router.pushUrl({ url: "pages/testDiskPreLoadPage" });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
@ -190,6 +234,7 @@ struct IndexFunctionDemo {
}).margin({ top: 15 }) }).margin({ top: 15 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("组件显式动画") Button("组件显式动画")
@ -211,7 +256,6 @@ struct IndexFunctionDemo {
}).margin({ top: 15 }) }).margin({ top: 15 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
@ -253,6 +297,10 @@ struct IndexFunctionDemo {
.onClick(() => { .onClick(() => {
router.pushUrl({ url: "pages/testSingleFrameGifPage" }); router.pushUrl({ url: "pages/testSingleFrameGifPage" });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
Button("webp测试")
.onClick(() => {
router.pushUrl({ url: "pages/webpImageTestPage" });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Text("worker测试").fontSize(15) Text("worker测试").fontSize(15)
@ -262,13 +310,14 @@ struct IndexFunctionDemo {
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Text("HSP相关测试").fontSize(15) Text("HSP相关测试").fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("进入HSP的library共享包") Button("进入HSP的library共享包")
.onClick(() => { .onClick(() => {
router.pushUrl({url:'@bundle:com.openharmony.imageknife/sharedlibrary/ets/pages/Index'}) router.pushUrl({ url: '@bundle:com.openharmony.imageknife/sharedlibrary/ets/pages/Index' })
.then(()=>{ .then(() => {
console.log('push page suceess') console.log('push page suceess')
}) })
}).margin({ top: 15 }) }).margin({ top: 15 })
@ -278,23 +327,29 @@ struct IndexFunctionDemo {
router.pushUrl({ url: "pages/hspCacheTestPage" }); router.pushUrl({ url: "pages/hspCacheTestPage" });
}).margin({ top: 15 }) }).margin({ top: 15 })
Button("不同的hsp资源加载") Button("不同的hsp资源加载")
.onClick(()=>{ .onClick(() => {
console.log("pages/multiHspTestPage 页面跳转") console.log("pages/multiHspTestPage 页面跳转")
router.pushUrl({ url: "pages/multiHspTestPage" }); router.pushUrl({ url: "pages/multiHspTestPage" });
}) })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Text("测试图片加载稳定").fontSize(15) Text("测试图片加载稳定").fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("测试多张网络图片加载速度") Button("测试多张网络图片加载速度")
.onClick(() => { .onClick(() => {
router.pushUrl({ url: "pages/testManyNetImageLoadWithPage" }); router.pushUrl({ url: "pages/testManyNetImageLoadWithPage" });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
Button("多线程加载大量网络图片加载速度")
.onClick(() => {
router.pushUrl({ url: "pages/testManyNetImageLoadWithPage2" });
}).margin({ top: 5, left: 3 })
Button("测试多张gif加载位置") Button("测试多张gif加载位置")
.onClick(() => { .onClick(() => {
router.pushUrl({ url: "pages/testManyGifLoadWithPage" }); router.pushUrl({ url: "pages/testManyGifLoadWithPage" });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试图片抗锯齿').fontSize(15) Text('测试图片抗锯齿').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('测试图片抗锯齿') Button('测试图片抗锯齿')
@ -306,6 +361,62 @@ struct IndexFunctionDemo {
router.pushUrl({ url: 'pages/testImageKnifeRouter1' }); router.pushUrl({ url: 'pages/testImageKnifeRouter1' });
}).margin({ top: 5, left: 3 }) }).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink) }.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试图片header属性').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('图片header属性设置')
.onClick(() => {
router.pushUrl({ url: 'pages/testImageKnifeHttpRequestHeader' });
}).margin({ top: 5, left: 3 })
Button('测试自定义DataFetch属性')
.onClick(() => {
router.pushUrl({ url: 'pages/testImageKnifeDataFetch' });
}).margin({ top: 5, left: 3 })
Button('全局header和request的header')
.onClick(() => {
router.pushUrl({ url: 'pages/testImageKnifeHttpRequestHeader1' });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试图片缓存内存').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('测试图片缓存内存')
.onClick(() => {
router.pushUrl({ url: 'pages/testImageKnifeCache' });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试gif暂停播放属性').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('测试gif暂停播放属性')
.onClick(() => {
router.pushUrl({ url: 'pages/testStopPlayingGifPage' });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试heic图片加载').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('测试heic')
.onClick(() => {
router.pushUrl({ url: 'pages/testImageKnifeHeic' });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试string类型占位图').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('测试string类型占位图以及后备回调符')
.onClick(() => {
router.pushUrl({ url: 'pages/testImageKnifeNetPlaceholder' });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink)
Text('测试加载图片自定义网络栈').fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button('加载图片自定义网络栈')
.onClick(() => {
router.pushUrl({ url: 'pages/testCustomDataFetchClientWithPage' });
}).margin({ top: 5, left: 3 })
}.width('100%').height(60).backgroundColor(Color.Pink)
} }
} }
.width('100%') .width('100%')

View File

@ -17,7 +17,8 @@ import {
ImageKnifeComponent, ImageKnifeComponent,
ImageKnifeOption, ImageKnifeOption,
ImageKnifeGlobal, ImageKnifeGlobal,
ImageKnife ImageKnife,
HeaderOptions
} from '@ohos/libraryimageknife' } from '@ohos/libraryimageknife'
import { ObjectKey } from '@ohos/libraryimageknife'; import { ObjectKey } from '@ohos/libraryimageknife';
@ -25,23 +26,24 @@ import { ObjectKey } from '@ohos/libraryimageknife';
@Entry @Entry
@Component @Component
struct IndexFunctionDemo { struct IndexFunctionDemo {
@State headerOptions1: HeaderOptions = {
key: "refer",
value: "http://1.94.37.200:7070/AntiTheftChain/downloadImage"
};
@State imageKnifeOption1: ImageKnifeOption = @State imageKnifeOption1: ImageKnifeOption =
{ {
loadSrc: $r('app.media.icon'), loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed') errorholderSrc: $r('app.media.icon_failed'),
headerOption: [this.headerOptions1]
}; };
@State imageKnifeOption2: ImageKnifeOption = @State imageKnifeOption2: ImageKnifeOption =
{ {
loadSrc: $r('app.media.icon'), loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed') errorholderSrc: $r('app.media.icon_failed'),
headerOption: [this.headerOptions1]
}; };
build() { build() {
Scroll() { Scroll() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
@ -51,7 +53,6 @@ struct IndexFunctionDemo {
.onClick(() => { .onClick(() => {
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: $r('app.media.pngSample'), loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
signature: new ObjectKey('ccccccc') signature: new ObjectKey('ccccccc')

View File

@ -18,9 +18,8 @@ import {ImageKnifeGlobal} from '@ohos/libraryimageknife'
import {RotateImageTransformation} from '@ohos/libraryimageknife' import {RotateImageTransformation} from '@ohos/libraryimageknife'
import {Material} from './model/Material' import {Material} from './model/Material'
import {TestDataSource} from './model/TestDataSource' import {TestDataSource} from './model/TestDataSource'
import {DiskLruCache} from '@ohos/disklrucache'
import ArkWorker from '@ohos.worker'
import Prompt from '@system.prompt'
@Entry @Entry
@Component @Component
struct photosPausedResumedPage { struct photosPausedResumedPage {

View File

@ -12,15 +12,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import router from '@system.router';
import { Pngj } from '@ohos/libraryimageknife' import { Pngj } from '@ohos/libraryimageknife'
import resourceManager from '@ohos.resourceManager'; import resourceManager from '@ohos.resourceManager';
import { FileUtils,ImageKnifeGlobal } from '@ohos/libraryimageknife' import { FileUtils,ImageKnifeGlobal } from '@ohos/libraryimageknife'
import featureability from '@ohos.ability.featureAbility'
import ArkWorker from '@ohos.worker'
import worker from '@ohos.worker';
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import common from '@ohos.app.ability.common'; import common from '@ohos.app.ability.common';
interface WorkerType {
type: string
name: string
}
@Entry @Entry
@Component @Component
struct PngjTestCasePage { struct PngjTestCasePage {
@ -115,18 +115,17 @@ struct PngjTestCasePage {
if (!this.pngdecodeRun2) { if (!this.pngdecodeRun2) {
this.pngdecodeRun2 = true; this.pngdecodeRun2 = true;
let pngj = new Pngj(); let pngj = new Pngj();
// let png_worker = new worker.ThreadWorker('entry/ets/workers/upngWorkerTestCase.ets', ) let png_worker: WorkerType = {
let obj ={ type: 'classic',
type: 'classic', name: 'readPngImageAsync'
name: 'readPngImageAsync' }
} pngj.readPngImageAsync(png_worker, this.pngSource2!, (value:ESObject) => {
pngj.readPngImageAsync(obj, this.pngSource2!, {pngCallback: (sender:ArrayBuffer, value:Record<string,Object>) => {
this.pngSource2 = sender
this.hint8 = '重新获取buffer才能测试' this.hint8 = '重新获取buffer才能测试'
this.hint2 = 'img with=' + value.width + ' img height=' + value.height this.hint2 = 'img with=' + value.width + ' img height=' + value.height
+ ' img depth=' + value.depth + ' img ctype=' + value.ctype + ' img depth=' + value.depth + ' img ctype=' + value.ctype
this.pngdecodeRun2 = false; this.pngdecodeRun2 = false;
}}) })
} else { } else {
this.hint8 = '已经在执行了,请稍等' this.hint8 = '已经在执行了,请稍等'
} }
@ -161,12 +160,11 @@ struct PngjTestCasePage {
if (!this.pngdecodeRun3) { if (!this.pngdecodeRun3) {
this.pngdecodeRun3 = true; this.pngdecodeRun3 = true;
let pngj = new Pngj(); let pngj = new Pngj();
let png_worker = new worker.ThreadWorker('entry/ets/workers/upngWorkerTestCase.ets', { let png_worker: WorkerType = {
type: 'classic', type: 'classic',
name: 'writePngWithStringAsync' name: 'writePngWithStringAsync'
}) }
pngj.writePngWithStringAsync(png_worker, 'hello world', this.pngSource3, {pngCallback: (sender:ArrayBuffer, value:ArrayBuffer) => { pngj.writePngWithStringAsync(png_worker, this.pngSource3, ( value:ESObject) => {
this.pngSource3 = sender
FileUtils.getInstance().createFileProcess( FileUtils.getInstance().createFileProcess(
this.rootFolder + '/pngj', this.rootFolder + '/pngj',
this.rootFolder + '/pngj/newPng.png', this.rootFolder + '/pngj/newPng.png',
@ -174,7 +172,7 @@ struct PngjTestCasePage {
let png1 = new Uint8Array(value) let png1 = new Uint8Array(value)
this.hint3 = 'png写入后长度' + png1.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng.png' + '保存后使用2进制查看数据是否新增' this.hint3 = 'png写入后长度' + png1.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng.png' + '保存后使用2进制查看数据是否新增'
this.pngdecodeRun3 = false; this.pngdecodeRun3 = false;
}}) },'hello world')
} else { } else {
this.hint9 = '已经在执行了,请稍等' this.hint9 = '已经在执行了,请稍等'
} }
@ -210,12 +208,11 @@ struct PngjTestCasePage {
if (!this.pngdecodeRun4) { if (!this.pngdecodeRun4) {
this.pngdecodeRun4 = true; this.pngdecodeRun4 = true;
let pngj = new Pngj(); let pngj = new Pngj();
let png_worker = new worker.ThreadWorker('entry/ets/workers/upngWorkerTestCase.ets', { let png_worker: WorkerType = {
type: 'classic', type: 'classic',
name: 'writePngAsync' name: 'writePngAsync'
}) }
pngj.writePngAsync(png_worker, this.pngSource4,{pngCallback: (sender:ArrayBuffer, value:ArrayBuffer) => { pngj.writePngAsync(png_worker, this.pngSource4, ( value:ESObject) => {
this.pngSource4 = sender
FileUtils.getInstance().createFileProcess( FileUtils.getInstance().createFileProcess(
this.rootFolder + '/pngj', this.rootFolder + '/pngj',
this.rootFolder + '/pngj/newPng2.png', this.rootFolder + '/pngj/newPng2.png',
@ -223,7 +220,7 @@ struct PngjTestCasePage {
let png2 = new Uint8Array(value) let png2 = new Uint8Array(value)
this.hint4 = 'png2未写入长度' + png2.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng2.png' + '保存后使用2进制查看数据是否新增' this.hint4 = 'png2未写入长度' + png2.byteLength + '目录文件:' + this.rootFolder + '/pngj/newPng2.png' + '保存后使用2进制查看数据是否新增'
this.pngdecodeRun4 = false; this.pngdecodeRun4 = false;
}}) })
} else { } else {
this.hint10 = '已经在执行了,请稍等' this.hint10 = '已经在执行了,请稍等'
} }

View File

@ -0,0 +1,237 @@
/*
* 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 {
CustomDataFetchClient,
DataFetchResult,
DownloadClient,
ImageKnifeComponent,
ImageKnifeGlobal,
ImageKnifeOption,
LogUtil,
ScaleType
} from '@ohos/libraryimageknife';
import http from '@ohos.net.http';
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
@Component
struct TestCustomDataFetchClientWithPage {
@State hotCommendList: CommonDataSource<string> = new CommonDataSource<string>([])
@State singleImageKnifeOption: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
@State isSingleImageVisible: boolean = true;
@State isAllImageVisible: boolean = false;
@State isCustom: boolean = false;
private data: Array<string> = [
"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg"
]
private addData: Array<string> = [
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg"
]
private cancelData: Array<string> = [
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg"
]
aboutToAppear(): void {
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.data)
LogUtil.log('TestCustomDataFetch about to appear.')
}
build() {
Scroll() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("单个图片").margin(16).onClick(() => {
LogUtil.log('TestCustomDataFetch click single.');
this.isSingleImageVisible = true;
this.isAllImageVisible = false;
ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new CustomDataFetchClient());
this.singleImageKnifeOption = {
loadSrc: 'http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg',
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
customGetImage: custom
}
})
Button("全部图片").margin(16).onClick(() => {
LogUtil.log('TestCustomDataFetch click all.');
this.isSingleImageVisible = false;
this.isAllImageVisible = true;
ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new CustomDataFetchClient());
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.addData)
})
Button("取消自定义全部图片").margin(16).onClick(() => {
LogUtil.log('TestCustomDataFetch click cancel.');
this.isSingleImageVisible = false;
this.isAllImageVisible = true;
ImageKnifeGlobal.getInstance().getImageKnife()?.replaceDataFetch(new DownloadClient());
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.cancelData)
})
}
// 单个图片使用自定义网络栈
ImageKnifeComponent({ imageKnifeOption: this.singleImageKnifeOption })
.width(200)
.height(200)
.margin({ top: 50 })
.visibility(this.isSingleImageVisible ? Visibility.Visible : Visibility.None)
// 全部图片使用自定义网络栈
Column() {
Grid() {
LazyForEach(this.hotCommendList, (item: string) => {
GridItem() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item,
placeholderSrc: $r('app.media.icon'),
errorholderSrc: $r('app.media.icon_failed'),
placeholderScaleType: ScaleType.CENTER_CROP,
mainScaleType: ScaleType.CENTER_CROP,
}
}).width('100%').height('100%')
}.width('40%').height(200)
}, (item: string) => JSON.stringify(item))
}
.columnsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(10)
.width('100%')
.hitTestBehavior(HitTestMode.None)
.maxCount(10)
}.margin({ top: 5 })
.visibility(this.isAllImageVisible ? Visibility.Visible : Visibility.None)
}
}
.width('100%')
.height('100%')
}
}
@Concurrent
async function custom(context: Context, loadSrc: string): Promise<DataFetchResult> {
let result: DataFetchResult = new DataFetchResult();
try {
let arrayBuffers = new Array<ArrayBuffer>();
let httpRequest = http.createHttp()
httpRequest.on('headersReceive', (header: Object) => {
// 跟服务器连接成功准备下载
})
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
// 下载数据流多次返回
arrayBuffers.push(data);
})
httpRequest.on('dataEnd', () => {
// 下载完毕
})
const resultCode = await httpRequest.requestInStream(loadSrc as string,
{
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
connectTimeout: 60000, // 可选 默认60000ms
readTimeout: 0, // 可选, 默认为60000ms
usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
usingCache: false
}).catch((err: Error) => {
result.error = 'TestCustomDataFetchClientWithPage requestInStream error.' + JSON.stringify(err);
})
if (resultCode == 200) {
//let combineArray = this.combineArrayBuffers(arrayBuffers);
// 计算多个ArrayBuffer的总字节大小
let totalByteLength = 0;
for (const arrayBuffer of arrayBuffers) {
totalByteLength += arrayBuffer.byteLength;
}
// 创建一个新的ArrayBuffer
const combinedArrayBuffer = new ArrayBuffer(totalByteLength);
// 创建一个Uint8Array来操作新的ArrayBuffer
const combinedUint8Array = new Uint8Array(combinedArrayBuffer);
// 依次复制每个ArrayBuffer的内容到新的ArrayBuffer中
let offset = 0;
for (const arrayBuffer of arrayBuffers) {
const sourceUint8Array = new Uint8Array(arrayBuffer);
combinedUint8Array.set(sourceUint8Array, offset);
offset += sourceUint8Array.length;
}
result.data = combinedArrayBuffer;
} else {
result.error = 'TestCustomDataFetchClientWithPage error. resultCode = ' + resultCode;
}
console.log('TestCustomDataFetch single onComplete, code = ' + resultCode + ',length = ' + result.data?.byteLength);
} catch (error) {
result.error = 'TestCustomDataFetchClientWithPage error' + error.stack;
}
return result;
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 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,ImageKnifeGlobal,ImageKnifeOption,ImageKnifeComponent} from '@ohos/libraryimageknife'
@Entry
@Component
struct DiskPreLoadPage {
@State imageKnifeOption2: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
build() {
Row() {
Column() {
Button("预加载图片").onClick(()=>{
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
if(imageKnife != undefined){
imageKnife.prefetchToDiskCache("https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658")
.then((resolve)=>{
console.log("成功回调 " + resolve)
})
.catch((reject: ESObject) => {
console.log("失败回调 " + reject)
})
}
})
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("加载GIF")
.onClick(() => {
this.imageKnifeOption2 = {
loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658',
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
displayProgress:true,
}
}).margin({ top: 5, left: 3 })
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 }).width(300).height(300)
}.width('100%').backgroundColor(Color.Pink)
}
.width('100%')
}
.height('100%')
}
}

View File

@ -0,0 +1,64 @@
/*
* 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'
@Entry
@Component
struct TestGifPlayTimesPage {
@State ImageKnifeOption1: ImageKnifeOption = {
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
build() {
Scroll() {
Column() {
Text("测试gif播放次数").fontSize(25)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("加载网络gif").onClick(() => {
this.ImageKnifeOption1 = {
loadSrc: "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button("设置gif播放1次").onClick(() => {
this.ImageKnifeOption1 = {
loadSrc: "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
gif: {
playTimes: 1
}
}
})
Button("设置gif播放2次").onClick(() => {
this.ImageKnifeOption1 = {
loadSrc: "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
gif: {
playTimes: 2
}
}
})
}
ImageKnifeComponent({ imageKnifeOption: this.ImageKnifeOption1 }).width(300).height(300).borderWidth(3)
}
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2021 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 { ComponentUtils } from '@ohos.arkui.UIContext'
import display from '@ohos.display';
import { ImageKnifeComponent,
ScaleType } from '@ohos/libraryimageknife'
import componentUtils from '@ohos.arkui.componentUtils';
@Entry
@Component
struct testImageKnifeAutoHeightPage {
private currentWidth: number =0
private currentHeight: number =0
@State value : componentUtils.ComponentInfo = componentUtils.getRectangleById("ImageKnifeCanvas");
aboutToAppear(){
let displayClas : ESObject =null
try {
displayClas = display.getDefaultDisplaySync()
console.info('........width'+ displayClas.width)
console.info('........height'+ displayClas.height)
}catch (e){
console.error('error' + e)
}
}
build(){
Scroll(){
Column(){
ImageKnifeComponent({
imageKnifeOption:{
loadSrc :$r('app.media.pngSample'),
mainScaleType:ScaleType.AUTO_HEIGHT,
}
})
.width("100%")
Button(){
Text('getRectangleById').fontSize(40).fontWeight(FontWeight.Bold);
}
.onClick(()=> {
this.value = componentUtils.getRectangleById("ImageKnifeCanvas")
this.currentWidth = px2vp(this.value.size.width)
this.currentHeight = px2vp(this.value.size.height)
console.log('currentWidth'+this.currentWidth)
console.log('currentHeight'+this.currentHeight)
})
}
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2021 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 { ComponentUtils } from '@ohos.arkui.UIContext'
import display from '@ohos.display';
import { ImageKnifeComponent,
ScaleType } from '@ohos/libraryimageknife'
import componentUtils from '@ohos.arkui.componentUtils';
@Entry
@Component
struct testImageKnifeAutoPage {
private currentWidth: number =0
private currentHeight: number =0
@State value : componentUtils.ComponentInfo = componentUtils.getRectangleById("ImageKnifeCanvas");
aboutToAppear(){
let displayClas : ESObject =null
try {
displayClas = display.getDefaultDisplaySync()
console.info('........width'+ displayClas.width)
console.info('........height'+ displayClas.height)
}catch (e){
console.error('error' + e)
}
}
build(){
Scroll(){
Column(){
ImageKnifeComponent({
imageKnifeOption:{
loadSrc :$r('app.media.pngSample'),
mainScaleType:ScaleType.AUTO,
}
})
Button(){
Text('getRectangleById').fontSize(40).fontWeight(FontWeight.Bold);
}
.onClick(()=> {
this.value = componentUtils.getRectangleById("ImageKnifeCanvas")
this.currentWidth = px2vp(this.value.size.width)
this.currentHeight = px2vp(this.value.size.height)
console.log('currentWidth'+this.currentWidth)
console.log('currentHeight'+this.currentHeight)
})
}
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2021 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 { ComponentUtils } from '@ohos.arkui.UIContext'
import display from '@ohos.display';
import { ImageKnifeComponent,
ScaleType } from '@ohos/libraryimageknife'
import componentUtils from '@ohos.arkui.componentUtils';
@Entry
@Component
struct testImageKnifeAutoWidthPage {
private currentWidth: number =0
private currentHeight: number =0
@State value : componentUtils.ComponentInfo = componentUtils.getRectangleById("ImageKnifeCanvas");
aboutToAppear(){
let displayClas : ESObject =null
try {
displayClas = display.getDefaultDisplaySync()
console.info('........width'+ displayClas.width)
console.info('........height'+ displayClas.height)
}catch (e){
console.error('error' + e)
}
}
build(){
Scroll(){
Column(){
ImageKnifeComponent({
imageKnifeOption:{
loadSrc :$r('app.media.pngSample'),
mainScaleType:ScaleType.AUTO_WIDTH,
}
})
.height(400)
Button(){
Text('getRectangleById').fontSize(40).fontWeight(FontWeight.Bold);
}
.onClick(()=> {
this.value = componentUtils.getRectangleById("ImageKnifeCanvas")
this.currentWidth = px2vp(this.value.size.width)
this.currentHeight = px2vp(this.value.size.height)
console.log('currentWidth'+this.currentWidth)
console.log('currentHeight'+this.currentHeight)
})
}
}
}
}

View File

@ -0,0 +1,239 @@
/*
* Copyright (C) 2022 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,
ImageKnifeGlobal,
ImageKnife,
ImageKnifeData,
RequestOption,
Size,
CacheType
} from '@ohos/libraryimageknife'
import image from '@ohos.multimedia.image';
import { BusinessError } from '@ohos.base';
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
@Entry
@Component
struct testImageKnifeCache {
@State url: string = '';
@State urlGif: string = 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658';
@State urlPng: string = 'https://img-blog.csdnimg.cn/20191215043500229.png';
@State urlJpg: string = 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB';
@State urlBmp: string = 'https://img-blog.csdn.net/20140514114029140';
@State urlWebp: string = 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp';
@State imagePixelMap: PixelMap | undefined = undefined;
@State imagePixelMap_: PixelMap | undefined = undefined;
private index_: number = -1;
private tempSize: number = 200;
private timeId = -1;
private comSize: Size = {
width: this.tempSize,
height: this.tempSize,
}
@State imageKnifeOption: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
};
loadSuccess = (data: ImageKnifeData) => {
clearTimeout(this.timeId);
if (data.isPixelMap()) {
if (data.drawPixelMap) {
let pixelmap = data.drawPixelMap.imagePixelMap
if (pixelmap) {
if (this.index_ == 1) {
this.imagePixelMap = pixelmap;
} else if (this.index_ == 2) {
this.imagePixelMap_ = pixelmap;
}
}
}
}
if (data.isGIFFrame()) {
let index: number = 0
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let renderGif = () => {
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let pixelmap = data.drawGIFFrame.imageGIFFrames[index].drawPixelMap
let delay = data.drawGIFFrame.imageGIFFrames[index].delay
if (pixelmap) {
if (this.index_ == 1) {
this.imagePixelMap = pixelmap;
} else if (this.index_ == 2) {
this.imagePixelMap_ = pixelmap;
}
}
index++;
if (index == data.drawGIFFrame.imageGIFFrames.length - 1) {
index = 0
}
this.timeId = setTimeout(renderGif, data!.drawGIFFrame!.imageGIFFrames![index].delay)
}
}
}
renderGif()
}
}
}
}
loadError = (err: BusinessError) => {
}
build() {
Scroll() {
Column() {
Text('图片内存和磁盘读取').fontSize(30);
Text('加载的缓存时候关闭掉网络').fontSize(15);
Row() {
Button('png')
.onClick(() => {
this.index_ = 0;
this.url = this.urlPng;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('bmp')
.onClick(() => {
this.index_ = 0;
this.url = this.urlBmp;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('webp')
.onClick(() => {
this.index_ = 0;
this.url = this.urlWebp;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('jpg')
.onClick(() => {
this.index_ = 0;
this.url = this.urlJpg;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
Button('gif')
.onClick(() => {
this.index_ = 0;
this.url = this.urlGif;
this.imageKnifeOption =
{
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed')
}
})
}
Row() {
Button('缓存图片')
.onClick(() => {
this.index_ = 1;
imageKnife?.isUrlExist(this.url, CacheType.Cache, this.comSize).then(this.loadSuccess)
.catch(this.loadError);
})
Button('磁盘图片')
.onClick(() => {
this.index_ = 2;
imageKnife?.isUrlExist(this.url, CacheType.Disk, this.comSize).then(this.loadSuccess)
.catch(this.loadError);
})
Button('默认')
.onClick(() => {
this.index_ = 2;
imageKnife?.isUrlExist(this.url, CacheType.Default, this.comSize).then(this.loadSuccess)
.catch(this.loadError);
})
}
Text('网络图').fontSize(15);
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption })
.width(200)
.height(200)
.backgroundColor(Color.Orange)
Text('缓存图').fontSize(15);
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.imagePixelMap as image.PixelMap
}
})
.width(200)
.height(200)
.backgroundColor(Color.Orange)
Text('磁盘图').fontSize(15);
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.imagePixelMap_ as image.PixelMap
}
})
.width(200)
.height(200)
.backgroundColor(Color.Orange)
}
.alignItems(HorizontalAlign.Center)
.width('100%')
}
.width('100%')
.height('100%')
}
aboutToAppear() {
}
aboutToDisappear() {
}
onBackPress() {
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2023 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 {
Base64,
IDataFetch,
ImageKnife,
ImageKnifeComponent,
ImageKnifeGlobal,
ImageKnifeOption,
DataFetchResult,
RequestOption} from '@ohos/libraryimageknife'
import common from '@ohos.app.ability.common';
import resourceManager from '@ohos.resourceManager';
import { BusinessError } from '@ohos.base'
@Entry
@Component
struct TestImageKnifeDataFetch {
@State imageKnifeOption1: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
build() {
Column(){
Text("简单示例1加载一张本地png图片").fontSize(15)
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("加载PNG")
.onClick(() => {
let dataFetch:MyDataFetch = new MyDataFetch();
let imageKnife:ImageKnife|undefined = ImageKnifeGlobal.getInstance().getImageKnife()
if(imageKnife != undefined) {
imageKnife.replaceDataFetch(dataFetch)
}
this.imageKnifeOption1 = {
loadSrc: "",
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
isCacheable: false,
}
}).margin({ top: 5, left: 3 })
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
}.width('100%').backgroundColor(Color.Pink)
}
}
}
@Sendable
class MyDataFetch implements IDataFetch{
loadData(option: RequestOption) {
let result:DataFetchResult = new DataFetchResult();
((ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).resourceManager as resourceManager.ResourceManager)
.getMediaContentBase64($r('app.media.pngSample').id)
.then(data => {
let matchReg = ';base64,';
let firstIndex = data.indexOf(matchReg);
data = data.substring(firstIndex + matchReg.length, data.length)
console.log('MyDataFetch - 本地加载资源 解析后数据剔除非必要数据后data= ' + data)
let arrayBuffer = Base64.getInstance()
.decode(data);
result.data = arrayBuffer;
}).catch((err:BusinessError) => {
result.error = 'MyDataFetch - 本地加载资源err' + JSON.stringify(err);
})
return result;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2022 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'
@Entry
@Component
struct testImageKnifeHeic {
@State imageKnifeOption1: ImageKnifeOption =
{
loadSrc: $r('app.media.yunHeic'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
@State flag: boolean = true;
build() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Button("heic图片测试")
.onClick(() => {
this.flag = !this.flag
if (this.flag) {
this.imageKnifeOption1.errorholderSrc = $r('app.media.icon_loading')
} else {
this.imageKnifeOption1.errorholderSrc = $r('app.media.icon_failed')
}
}).margin({ top: 15 })
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 }).width(300).height(300)
}.width('100%').height(300).backgroundColor(Color.Pink)
}
}

View File

@ -0,0 +1,256 @@
/*
* 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 {
HeaderOptions,ImageKnife,ImageKnifeComponent,ImageKnifeData,ImageKnifeGlobal,RequestOption,ImageKnifeOption,ObjectKey
} from '@ohos/libraryimageknife'
import image from '@ohos.multimedia.image'
import { BusinessError } from '@ohos.base'
const TAG = "TEST-"
let timeId = -1
@Entry
@Component
struct testImageKnifeHttpRequestHeader {
@State pixelMap: PixelMap | undefined = undefined;
@State pixelMap1: PixelMap | undefined = undefined;
@State pixelMap2: PixelMap | undefined = undefined;
@State pixelMap3: PixelMap | undefined = undefined;
@State domeType1: boolean = false;
@State domeType2: boolean = false;
@State domeType3: boolean = false;
@State domeType4: boolean = false;
@State domeType5: boolean = false;
@State domeType6: boolean = false;
@State successHeader: string = "requestOption调用成功";
@State errorHeader: string = "requestOption调用失败";
@State successHeader1: string = "全局调用imageKnife成功";
@State errorHeader1: string = "全局调用imageKnife失败";
@State successHeader2: string = "单个imageKnife组件调用成功";
@State errorHeader2: string = "单个imageKnife组件调用失败";
@State message: string = "图片header属性测试";
@State headerOptions1: HeaderOptions = {
key: "refer",
value: "http://1.94.37.200:7070/AntiTheftChain/downloadImage"
};
@State headerOptions2: HeaderOptions = {
key: "xx",
value: "http://1.94.37.200:7070/AntiTheftChain/downloadImage"
};
@State imageKnifeOption1: ImageKnifeOption =
{
loadSrc: 'http://1.94.37.200:7070/AntiTheftChain/downloadImage',
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
headerOption: [this.headerOptions1]
};
@State imageKnifeOption2: ImageKnifeOption =
{
loadSrc: 'http://1.94.37.200:7070/AntiTheftChain/downloadImage',
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
headerOption: [this.headerOptions2]
};
// RequestOption调用
load(src: string | image.PixelMap | Resource, type: string, num: number) {
clearTimeout(timeId)
let request = new RequestOption()
if (type == 'error') {
request.addHeader('xx', src)
} else {
request.addHeader('refer', src)
}
//清理缓存
request.signature = new ObjectKey(new Date().getTime().toString())
request.load(src)
.addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => {
if (data.isPixelMap()) {
if (data.drawPixelMap) {
let pixelmap = data.drawPixelMap.imagePixelMap
if (pixelmap) {
if (num == 1) {
this.pixelMap = pixelmap
} else if (num == 2) {
this.pixelMap1 = pixelmap
} else if (num == 3) {
this.pixelMap2 = pixelmap
} else if (num == 4) {
this.pixelMap3 = pixelmap
}
}
}
}
if (data.isGIFFrame()) {
let index: number = 0
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let renderGif = () => {
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let pixelmap = data.drawGIFFrame.imageGIFFrames[index].drawPixelMap
let delay = data.drawGIFFrame.imageGIFFrames[index].delay
if (pixelmap) {
if (num == 1) {
this.pixelMap = pixelmap
} else if (num == 2) {
this.pixelMap1 = pixelmap
} else if (num == 3) {
this.pixelMap2 = pixelmap
} else if (num == 4) {
this.pixelMap3 = pixelmap
}
}
index++;
if (index == data.drawGIFFrame.imageGIFFrames.length - 1) {
index = 0
}
timeId = setTimeout(renderGif, data!.drawGIFFrame!.imageGIFFrames![index].delay)
}
}
}
renderGif()
}
}
}
if (err) {
console.log(TAG + "error:" + JSON.stringify(err));
}
return false
}
})
let imageknife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife()
if (imageknife != undefined) {
imageknife.call(request)
}
}
@Builder
setHeader() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.pixelMap as image.PixelMap
}
}).width(200).height(200).borderWidth(1)
}
@Builder
setHeader3() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.pixelMap1 as image.PixelMap
}
}).width(200).height(200).borderWidth(1)
}
@Builder
setHeader1() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.pixelMap2 as image.PixelMap
}
}).width(200).height(200).borderWidth(1)
}
@Builder
setHeader4() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.pixelMap3 as image.PixelMap
}
}).width(200).height(200).borderWidth(1)
}
@Builder
setHeader2() {
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 })
.margin(16)
.width(200)
.height(200)
}
@Builder
setHeader5() {
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 })
.margin(16)
.width(200)
.height(200)
}
build() {
Scroll() {
Column() {
Text(`${this.message}`)
.width("300vp")
.height("60vp")
.textAlign(TextAlign.Center)
.fontSize("30fp")
.fontWeight(FontWeight.Bold)
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Button(this.successHeader)
.margin(16)
.onClick(() => {
this.domeType1 = !this.domeType1
this.load('http://1.94.37.200:7070/AntiTheftChain/downloadImage', 'success', 1)
})
if (this.domeType1) {
this.setHeader()
}
Button(this.errorHeader)
.margin(16)
.onClick(() => {
this.domeType2 = !this.domeType2
this.load('http://1.94.37.200:7070/AntiTheftChain/downloadImage', 'error', 2)
})
if (this.domeType2) {
this.setHeader3()
}
Button(this.successHeader1)
.margin(16)
.onClick(() => {
this.domeType3 = !this.domeType3
this.load('http://1.94.37.200:7070/AntiTheftChain/downloadImage', 'success', 3)
})
if (this.domeType3) {
this.setHeader1()
}
Button(this.errorHeader1)
.margin(16)
.onClick(() => {
this.domeType4 = !this.domeType4
this.load('http://1.94.37.200:7070/AntiTheftChain/downloadImage', 'error', 4)
})
if (this.domeType4) {
this.setHeader4()
}
Button(this.successHeader2)
.margin(16)
.onClick(() => {
this.domeType5 = !this.domeType5
})
if (this.domeType5) {
this.setHeader2()
}
Button(this.errorHeader2)
.margin(16)
.onClick(() => {
this.domeType6 = !this.domeType6
})
if (this.domeType6) {
this.setHeader5()
}
}
}.width("100%")
.justifyContent(FlexAlign.Start)
}
}
}

View File

@ -0,0 +1,172 @@
/*
* Copyright (C) 2022 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 {
HeaderOptions,ImageKnife,ImageKnifeComponent,ImageKnifeData,ImageKnifeGlobal,RequestOption,ImageKnifeOption,ObjectKey
} from '@ohos/libraryimageknife'
import image from '@ohos.multimedia.image'
import { BusinessError } from '@ohos.base'
const TAG = "TEST-"
let timeId = -1
@Entry
@Component
struct testImageKnifeHttpRequestHeader1 {
@State pixelMap: PixelMap | undefined = undefined;
@State pixelMap1: PixelMap | undefined = undefined;
@State domeType1: boolean = false;
@State domeType2: boolean = false;
@State successHeader: string = "requestOption调用成功";
@State errorHeader: string = "requestOption调用失败";
@State allKeySame: string = "全局添加header和request成功的键相同值不同";
@State allKeyNoSame: string = "全局添加header和request成功的键不同";
@State clearnAllHeader: string = "清空全局header";
@State message: string = "图片header属性测试";
imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife()
// RequestOption调用
load(src: string | image.PixelMap | Resource, type: string, num: number) {
clearTimeout(timeId)
let request = new RequestOption()
if (type == 'error') {
request.addHeader('xx', src)
} else {
request.addHeader('refer', src)
}
//清理缓存
request.signature = new ObjectKey(new Date().getTime().toString())
request.load(src)
.addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => {
if (data.isPixelMap()) {
if (data.drawPixelMap) {
let pixelmap = data.drawPixelMap.imagePixelMap
if (pixelmap) {
if (num == 1) {
this.pixelMap = pixelmap
} else if (num == 2) {
this.pixelMap1 = pixelmap
}
}
}
}
if (data.isGIFFrame()) {
let index: number = 0
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let renderGif = () => {
if (data.drawGIFFrame) {
if (data.drawGIFFrame.imageGIFFrames) {
let pixelmap = data.drawGIFFrame.imageGIFFrames[index].drawPixelMap
let delay = data.drawGIFFrame.imageGIFFrames[index].delay
if (pixelmap) {
if (num == 1) {
this.pixelMap = pixelmap
} else if (num == 2) {
this.pixelMap1 = pixelmap
}
}
index++;
if (index == data.drawGIFFrame.imageGIFFrames.length - 1) {
index = 0
}
timeId = setTimeout(renderGif, data!.drawGIFFrame!.imageGIFFrames![index].delay)
}
}
}
renderGif()
}
}
}
if (err) {
console.log(TAG + "error:" + JSON.stringify(err));
}
return false
}
})
let imageknife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife()
if (imageknife != undefined) {
imageknife.call(request)
}
}
@Builder
setHeader() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.pixelMap as image.PixelMap
}
}).width(200).height(200).borderWidth(1)
}
@Builder
setHeader1() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.pixelMap1 as image.PixelMap
}
}).width(200).height(200).borderWidth(1)
}
build() {
Scroll() {
Column() {
Text(`${this.message}`)
.width("300vp")
.height("60vp")
.textAlign(TextAlign.Center)
.fontSize("30fp")
.fontWeight(FontWeight.Bold)
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
Button(this.successHeader)
.margin(16)
.onClick(() => {
this.domeType1 = !this.domeType1
this.load('http://1.94.37.200:7070/AntiTheftChain/downloadImage', 'success', 1)
})
if (this.domeType1) {
this.setHeader()
}
Button(this.errorHeader)
.margin(16)
.onClick(() => {
this.domeType2 = !this.domeType2
this.load('http://1.94.37.200:7070/AntiTheftChain/downloadImage', 'error', 2)
})
if (this.domeType2) {
this.setHeader1()
}
Button(this.allKeySame)
.margin(16)
.onClick(() => {
this.imageKnife?.addHeader('refer','test')
})
Button(this.allKeyNoSame)
.margin(16)
.onClick(() => {
this.imageKnife?.addHeader('ceshi','http://1.94.37.200:7070/AntiTheftChain/downloadImage')
})
Button(this.clearnAllHeader)
.margin(16)
.onClick(() => {
this.imageKnife?.deleteHeader('refer');
this.imageKnife?.deleteHeader('ceshi');
})
}
}.width("100%")
.justifyContent(FlexAlign.Start)
}
}
}

View File

@ -0,0 +1,133 @@
/*
* 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'
@Entry
@Component
struct testImageKnifeNetPlaceholder {
@State imageKnifeOption: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
@State imageKnifeOption1: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
@State imageKnifeOption2: ImageKnifeOption =
{
loadSrc: $r('app.media.icon'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
build() {
Scroll() {
Column() {
Text('string类型占位图支持内存和磁盘读取').fontSize(30);
Text('验证磁盘有无图片可以先主图缓存一张图片,再退出应用').fontSize(15);
Text('仅第一次打开应用加载主图可以看到效果,因主图第二次加载速度很快').fontSize(15);
Row() {
Button('缓存一张图片作为占位图 图一')
.onClick(() => {
this.imageKnifeOption =
{
loadSrc: 'https://img-blog.csdn.net/20140514114029140',
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
}
})
}
Text('当图一没有展示,会从磁盘中拿占位图').fontSize(15);
Text('当图一展示时,会从内存中拿占位图,不会走磁盘逻辑').fontSize(15);
Text('下图展示的为后备回调符的图片').fontSize(15);
ImageKnifeComponent({ imageKnifeOption: {loadSrc:$r('app.media.mask_starfish')} })
.width(200)
.height(200)
.backgroundColor(Color.Orange)
Text('下图展示的主图为图二string类型的占位图').fontSize(15);
Text('图一:').fontSize(20);
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption })
.width(200)
.height(200)
.backgroundColor(Color.Orange)
Row() {
Button('展示已缓存的占位图')
.onClick(() => {
this.imageKnifeOption1 =
{
loadSrc : $r('app.media.pngSample'),
placeholderSrc: 'https://img-blog.csdn.net/20140514114029140',
fallbackSrc: $r('app.media.mask_starfish'),
errorholderSrc: $r('app.media.icon_failed'),
}
})
Button('当占位图未缓存时展示后备回调符')
.onClick(() => {
this.imageKnifeOption2 =
{
loadSrc : $r('app.media.gifSample'),
placeholderSrc: 'https://img0.baidu.com/it/u=2794536113,2700219306&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500',
fallbackSrc: $r('app.media.mask_starfish'),
errorholderSrc: $r('app.media.icon_failed'),
}
})
}
Text('展示已缓存的占位图,如图一未加载过则会显示后备回调符').fontSize(15);
Text('图二:').fontSize(20);
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption1 })
.width(200)
.height(200)
.backgroundColor(Color.Orange)
Text('占位图未缓存展示后备回调符,如图三').fontSize(15);
Text('图三:').fontSize(20);
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption2 })
.width(200)
.height(200)
.backgroundColor(Color.Orange)
}
.alignItems(HorizontalAlign.Center)
.width('100%')
}
.width('100%')
.height('100%')
}
aboutToAppear() {
}
aboutToDisappear() {
}
onBackPress() {
}
}

View File

@ -27,6 +27,9 @@ import {
ImageKnifeDrawFactory ImageKnifeDrawFactory
} from '@ohos/libraryimageknife' } from '@ohos/libraryimageknife'
import worker from '@ohos.worker'; import worker from '@ohos.worker';
let gifUrl: string = 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658';
@Entry @Entry
@Component @Component
struct TestImageKnifeOptionChangedPage5 { struct TestImageKnifeOptionChangedPage5 {
@ -83,6 +86,64 @@ struct TestImageKnifeOptionChangedPage5 {
}; };
}).margin({ left: 5 }).backgroundColor(Color.Blue) }).margin({ left: 5 }).backgroundColor(Color.Blue)
}.margin({ top: 15 }) }.margin({ top: 15 })
Flex({ direction: FlexDirection.Row }) {
Button("本地gif")
.onClick(() => {
this.imageKnifeOption1 = {
loadSrc: $r('app.media.gifSample'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
}).margin({ left: 5 }).backgroundColor(Color.Blue)
Button("网络gif")
.onClick(() => {
this.imageKnifeOption1 = {
loadSrc: gifUrl,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
};
}).margin({ left: 5 }).backgroundColor(Color.Blue)
}.margin({ top: 15 })
Flex({ direction: FlexDirection.Row }) {
Button("网络gif - 圆角小")
.onClick(() => {
this.imageKnifeOption1 = {
loadSrc: gifUrl,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
drawLifeCycle: ImageKnifeDrawFactory.createRoundLifeCycle(3, "#ff0000", 30)
};
}).margin({ left: 5 }).backgroundColor(Color.Blue)
Button("本地gif - 圆角大")
.onClick(() => {
this.imageKnifeOption1 = {
loadSrc: $r('app.media.gifSample'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
drawLifeCycle: ImageKnifeDrawFactory.createRoundLifeCycle(5, "#ffff00", 300)
};
}).margin({ left: 5 }).backgroundColor(Color.Blue)
}.margin({ top: 15 })
Flex({ direction: FlexDirection.Row }) {
Button("网络gif-椭圆长方形资源")
.onClick(() => {
this.imageKnifeOption1 = {
loadSrc: gifUrl,
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
drawLifeCycle: ImageKnifeDrawFactory.createOvalLifeCycle(8, "#88ee00")
};
}).margin({ left: 5 }).backgroundColor(Color.Blue)
Button("本地gif-椭圆正方形资源")
.onClick(() => {
this.imageKnifeOption1 = {
loadSrc: $r('app.media.gifSample'),
placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'),
drawLifeCycle: ImageKnifeDrawFactory.createOvalLifeCycle(5, "#ff00ff")
};
}).margin({ left: 5 }).backgroundColor(Color.Blue)
}.margin({ top: 15 })
Text("下面为展示图片区域").margin({ top: 5 }) Text("下面为展示图片区域").margin({ top: 5 })
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2023 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 { ScaleType, ImageKnifeComponent, NONE, DiskStrategy } from "@ohos/libraryimageknife"
import { Material } from './model/Material';
import { TestDataSource } from './model/TestDataSource';
@Entry
@Component
struct TestManyNetImageLoadWithPage2 {
private data: TestDataSource = new TestDataSource();
private setting: DiskStrategy = new NONE();
private scroller: Scroller = new Scroller()
build() {
Scroll() {
Column() {
Grid(this.scroller) {
LazyForEach(this.data, (item: Material, index) => {
GridItem() {
Stack({ alignContent: Alignment.BottomEnd }) {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item.thumbnail,
placeholderSrc: $r('app.media.icon_loading'),
mainScaleType: ScaleType.CENTER_CROP,
placeholderScaleType: ScaleType.CENTER_CROP,
isCacheable: false,
strategy: this.setting
}
}).width('100%').height('100%')
Text(index + "." + item.name)
.fontSize(10)
.maxLines(1)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.layoutWeight(1)
.width('100%')
.backgroundColor(Color.Orange)
}
}.width('45%').height(200)
}, (item: Material,index:number) => item.material_id + index.toString())
}
.columnsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(10)
.width('100%')
.cachedCount(3)
.height('100%')
}.margin({ top: 5 })
}
}
}

View File

@ -88,59 +88,59 @@ struct TestPreloadPage {
if (err) { if (err) {
console.log('预加载本地资源gif 出现错误! err=' + err) console.log('预加载本地资源gif 出现错误! err=' + err)
} else { } else {
console.log('预加载本地资源gif成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载本地资源gif成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('本地资源gif') Button('本地资源gif')
.onClick(() => { .onClick(() => {
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: $r('app.media.gifSample'), loadSrc: $r('app.media.gifSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
} }
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('预加载本地资源gif静态') Button('预加载本地资源gif静态')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load($r('app.media.gifSample')) request.load($r('app.media.gifSample'))
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.dontAnimate() .dontAnimate()
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err ) { if (err ) {
console.log('预加载本地资源gif静态 出现错误! err=' + err) console.log('预加载本地资源gif静态 出现错误! err=' + err)
} else { } else {
console.log('预加载本地资源gif静态成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载本地资源gif静态成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('本地资源gif静态') Button('本地资源gif静态')
.onClick(() => { .onClick(() => {
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: $r('app.media.gifSample'), loadSrc: $r('app.media.gifSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
dontAnimateFlag: true dontAnimateFlag: true
} }
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
} }
@ -150,64 +150,64 @@ struct TestPreloadPage {
Button('预加载网络资源gif') Button('预加载网络资源gif')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load('https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658') request.load('https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658')
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err) { if (err) {
console.log('预加载网络资源gif 出现错误! err=' + err) console.log('预加载网络资源gif 出现错误! err=' + err)
} else { } else {
console.log('预加载网络资源gif成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载网络资源gif成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('网络资源gif') Button('网络资源gif')
.onClick(() => { .onClick(() => {
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658', loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658',
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
}; };
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('预加载网络资源gif静态') Button('预加载网络资源gif静态')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load('https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658') request.load('https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658')
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.dontAnimate() .dontAnimate()
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err) { if (err) {
console.log('预加载网络资源gif静态 出现错误! err=' + err) console.log('预加载网络资源gif静态 出现错误! err=' + err)
} else { } else {
console.log('预加载网络资源gif静态成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载网络资源gif静态成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('网络资源gif静态') Button('网络资源gif静态')
.onClick(() => { .onClick(() => {
this.imageKnifeOption1 = { this.imageKnifeOption1 = {
loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658', loadSrc: 'https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658',
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
dontAnimateFlag: true dontAnimateFlag: true
}; };
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
} }
@ -228,27 +228,27 @@ struct TestPreloadPage {
if (err ) { if (err ) {
console.log('预加载本地资源svg 出现错误! err=' + err) console.log('预加载本地资源svg 出现错误! err=' + err)
} else { } else {
console.log('预加载本地资源svg成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载本地资源svg成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('本地资源svg') Button('本地资源svg')
.onClick(() => { .onClick(() => {
this.imageKnifeOption = { this.imageKnifeOption = {
loadSrc: $r('app.media.svgSample'), loadSrc: $r('app.media.svgSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
} }
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
@ -275,32 +275,32 @@ struct TestPreloadPage {
Button('预加载网络资源svg') Button('预加载网络资源svg')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load(this.svgUrl) request.load(this.svgUrl)
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err) { if (err) {
console.log('预加载网络资源gif 出现错误! err=' + err) console.log('预加载网络资源gif 出现错误! err=' + err)
} else { } else {
console.log('预加载网络资源gif成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载网络资源gif成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('网络资源svg') Button('网络资源svg')
.onClick(() => { .onClick(() => {
this.imageKnifeOption = { this.imageKnifeOption = {
loadSrc: this.svgUrl, loadSrc: this.svgUrl,
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
}; };
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
@ -323,27 +323,27 @@ struct TestPreloadPage {
if (err) { if (err) {
console.log('预加载本地资源webp 出现错误! err=' + err) console.log('预加载本地资源webp 出现错误! err=' + err)
} else { } else {
console.log('预加载本地资源webp成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载本地资源webp成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('本地资源webp') Button('本地资源webp')
.onClick(() => { .onClick(() => {
this.imageKnifeOption3 = { this.imageKnifeOption3 = {
loadSrc: $r('app.media.jpgSample'), loadSrc: $r('app.media.jpgSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
} }
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
@ -355,32 +355,32 @@ struct TestPreloadPage {
Button('预加载网络资源webp') Button('预加载网络资源webp')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp') request.load('https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp')
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err) { if (err) {
console.log('预加载网络资源webp 出现错误! err=' + err) console.log('预加载网络资源webp 出现错误! err=' + err)
} else { } else {
console.log('预加载网络资源webp成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载网络资源webp成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('网络资源webp') Button('网络资源webp')
.onClick(() => { .onClick(() => {
this.imageKnifeOption3 = { this.imageKnifeOption3 = {
loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp', loadSrc: 'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp',
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
}; };
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
} }
@ -401,27 +401,27 @@ struct TestPreloadPage {
if (err) { if (err) {
console.log('预加载本地资源bmp 出现错误! err=' + err) console.log('预加载本地资源bmp 出现错误! err=' + err)
} else { } else {
console.log('预加载本地资源bmp成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载本地资源bmp成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('本地资源bmp') Button('本地资源bmp')
.onClick(() => { .onClick(() => {
this.imageKnifeOption4 = { this.imageKnifeOption4 = {
loadSrc: $r('app.media.bmpSample'), loadSrc: $r('app.media.bmpSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
} }
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
@ -433,32 +433,32 @@ struct TestPreloadPage {
Button('预加载网络资源bmp') Button('预加载网络资源bmp')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load('https://img-blog.csdn.net/20140514114029140') request.load('https://img-blog.csdn.net/20140514114029140')
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err) { if (err) {
console.log('预加载网络资源bmp 出现错误! err=' + err) console.log('预加载网络资源bmp 出现错误! err=' + err)
} else { } else {
console.log('预加载网络资源bmp成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载网络资源bmp成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('网络资源bmp') Button('网络资源bmp')
.onClick(() => { .onClick(() => {
this.imageKnifeOption4 = { this.imageKnifeOption4 = {
loadSrc: 'https://img-blog.csdn.net/20140514114029140', loadSrc: 'https://img-blog.csdn.net/20140514114029140',
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
}; };
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
} }
@ -479,27 +479,27 @@ struct TestPreloadPage {
if (err) { if (err) {
console.log('预加载本地资源png 出现错误! err=' + err) console.log('预加载本地资源png 出现错误! err=' + err)
} else { } else {
console.log('预加载本地资源png成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载本地资源png成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('本地资源png') Button('本地资源png')
.onClick(() => { .onClick(() => {
this.imageKnifeOption5 = { this.imageKnifeOption5 = {
loadSrc: $r('app.media.pngSample'), loadSrc: $r('app.media.pngSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
} }
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
@ -511,32 +511,32 @@ struct TestPreloadPage {
Button('预加载网络资源png') Button('预加载网络资源png')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load('https://img-blog.csdnimg.cn/20191215043500229.png') request.load('https://img-blog.csdnimg.cn/20191215043500229.png')
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err) { if (err) {
console.log('预加载网络资源bmp 出现错误! err=' + err) console.log('预加载网络资源bmp 出现错误! err=' + err)
} else { } else {
console.log('预加载网络资源bmp成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载网络资源bmp成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('网络资源png') Button('网络资源png')
.onClick(() => { .onClick(() => {
this.imageKnifeOption5 = { this.imageKnifeOption5 = {
loadSrc: 'https://img-blog.csdnimg.cn/20191215043500229.png', loadSrc: 'https://img-blog.csdnimg.cn/20191215043500229.png',
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
}; };
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
} }
@ -557,27 +557,27 @@ struct TestPreloadPage {
if (err) { if (err) {
console.log('预加载本地资源jpg 出现错误! err=' + err) console.log('预加载本地资源jpg 出现错误! err=' + err)
} else { } else {
console.log('预加载本地资源jpg成功! imageKnifedata=' + JSON.stringify(data)) console.log('预加载本地资源jpg成功! imageKnifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('本地资源jpg') Button('本地资源jpg')
.onClick(() => { .onClick(() => {
this.imageKnifeOption6 = { this.imageKnifeOption6 = {
loadSrc: $r('app.media.jpgSample'), loadSrc: $r('app.media.jpgSample'),
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
} }
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
@ -589,32 +589,32 @@ struct TestPreloadPage {
Button('预加载网络资源jpg') Button('预加载网络资源jpg')
.onClick(() => { .onClick(() => {
let request = new RequestOption(); let request = new RequestOption();
request.load('https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB') request.load('https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB')
.setImageViewSize({ width: 300, height: 300 }) .setImageViewSize({ width: 300, height: 300 })
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
if (err) { if (err) {
console.log('预加载网络资源jpg 出现错误! err=' + err) console.log('预加载网络资源jpg 出现错误! err=' + err)
} else { } else {
console.log('预加载网络资源jpg成功! imageknifedata=' + JSON.stringify(data)) console.log('预加载网络资源jpg成功! imageknifedata=' + JSON.stringify(data))
} }
return false; return false;
}}) }})
ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request); ImageKnifeGlobal.getInstance().getImageKnife()?.preload(request);
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
Button('网络资源jpg') Button('网络资源jpg')
.onClick(() => { .onClick(() => {
this.imageKnifeOption6 = { this.imageKnifeOption6 = {
loadSrc: 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB', loadSrc: 'https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB',
placeholderSrc: $r('app.media.icon_loading'), placeholderSrc: $r('app.media.icon_loading'),
errorholderSrc: $r('app.media.icon_failed'), errorholderSrc: $r('app.media.icon_failed'),
}; };
}) })
.margin({ left: 15 }) .margin({ left: 15 })
.backgroundColor(Color.Grey) .backgroundColor(Color.Grey)
} }

View File

@ -0,0 +1,188 @@
/*
* 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, Priority, NONE, ImageKnifeGlobal } from '@ohos/libraryimageknife';
const dataBak: ImageKnifeOption[] = [
{
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg",
priority: Priority.HIGH
},
{
loadSrc: "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
priority: Priority.MEDIUM
},
{
loadSrc: "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "https://img-blog.csdn.net/20140514114029140",
priority: Priority.MEDIUM
},
{
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
priority: Priority.LOW
},
{
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
priority: Priority.LOW
},
{
loadSrc: "http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
priority: Priority.LOW
},
{
loadSrc: "http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
priority: Priority.LOW
},
{
loadSrc:"http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
priority: Priority.LOW
}
];
@Entry
@Component
struct TestPriorityComponent {
@State data: ImageKnifeOption[] = [
{
loadSrc: "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658",
priority: Priority.HIGH
},
{
loadSrc: "http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
priority: Priority.HIGH
},
{
loadSrc: "http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
priority: Priority.MEDIUM
},
{
loadSrc: "https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
priority: Priority.LOW
},
{
loadSrc: "https://img-blog.csdnimg.cn/20191215043500229.png",
priority: Priority.LOW
},
{
loadSrc: "https://img-blog.csdn.net/20140514114029140",
priority: Priority.LOW
},
{
loadSrc: "https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp",
priority: Priority.LOW
},
{
loadSrc: "http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
priority: Priority.LOW
}
];
@State maxRequests: number | undefined = ImageKnifeGlobal?.getInstance()?.getImageKnife()?.maxRequests;
build() {
Scroll() {
Column() {
Text('最大并发数: ' + this.maxRequests).width('50%').height(30)
Button('修改最大并发数为1').width('50%').height(30)
.onClick(() => {
if (ImageKnifeGlobal?.getInstance()?.getImageKnife()) {
ImageKnifeGlobal?.getInstance()?.getImageKnife()?.setMaxRequests(1);
this.maxRequests = ImageKnifeGlobal?.getInstance()?.getImageKnife()?.maxRequests;
this.data = [...dataBak, ...dataBak, ...dataBak];
}
})
Grid() {
ForEach(this.data, (item: ImageKnifeOption, index: number) => {
GridItem() {
Flex() {
Text(item?.priority?.toString() || '')
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: item.loadSrc,
placeholderSrc: $r('app.media.icon_loading'),
strategy: new NONE(),
isCacheable: false,
priority: item.priority
}
})
}.height(60)
}
})
}
.width("100%")
.height("100%")
.columnsTemplate("1fr 1fr 1fr 1fr 1fr")
.columnsGap(10)
.rowsGap(10)
.backgroundColor(0xFAEEE0)
.maxCount(10)
}
.backgroundColor(Color.Pink)
.margin({ top: 5 })
}
}
}

View File

@ -0,0 +1,204 @@
/*
* 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 BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [];
private originDataArray: StringData[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): StringData {
return this.originDataArray[index];
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener');
this.listeners.push(listener);
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener');
this.listeners.splice(pos, 1);
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to);
})
}
}
class MyDataSource extends BasicDataSource {
private dataArray: StringData[] = [];
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): StringData {
return this.dataArray[index];
}
public addData(index: number, data: StringData): void {
this.dataArray.splice(index, 0, data);
this.notifyDataAdd(index);
}
public pushData(data: StringData): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
public reloadData(): void {
this.notifyDataReload();
}
}
class StringData {
message: string;
imgSrc: string;
constructor(message: string, imgSrc: string) {
this.message = message;
this.imgSrc = imgSrc;
}
}
@Entry
@Component
struct TestReuseAbleComponent {
@State dataArray: Array<string> = [
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.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://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
'https://img-blog.csdnimg.cn/20191215043500229.png',
'https://img-blog.csdn.net/20140514114029140',
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'
]
private data: MyDataSource = new MyDataSource();
private index: number = 0
private timeId: number = -1
aboutToAppear() {
for (let i = 0; i <= 4; i++) {
this.data.pushData(new StringData(`Hello ${i}`, this.dataArray[i]));
}
}
build() {
List({ space: 3 }) {
LazyForEach(this.data, (item: StringData, index: number) => {
ListItem() {
Column() {
Text(item.message).fontSize(50)
.onAppear(() => {
console.info("appear:" + item.message)
})
ReusableComponent({ url: item.imgSrc })
.width(500)
.height(200)
}.margin({ left: 10, right: 10 })
}
.onClick(() => {
item.message += '00';
this.data.reloadData();
})
}, (item: StringData, index: number) => JSON.stringify(item))
}.cachedCount(5)
.onReachEnd(()=>{
clearTimeout(this.timeId)
this.timeId = setTimeout(()=>{
this.data.reloadData()
if(this.data.totalCount() <= this.dataArray.length) {
this.index = this.data.totalCount()
for (let index = this.index; index <= this.index + 4; index++) {
this.data.addData(index,new StringData(`Hello ${index}`, this.dataArray[index]));
}
}
},1500)
})
}
}
@Reusable
@Component
struct ReusableComponent {
@State url: string = ""
aboutToReuse(params: Record<string, string>) {
this.url = params.url
}
build() {
Column() {
ImageKnifeComponent({
imageKnifeOption: {
loadSrc: this.url,
placeholderSrc: $r('app.media.icon_loading')
}
})
}.width("100%").height("100%")
}
}

View File

@ -0,0 +1,203 @@
/*
* 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, ScaleType } from '@ohos/libraryimageknife'
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
@Component
struct TestReusePhotoPage {
@State hotCommendList: CommonDataSource<string> = new CommonDataSource<string>([])
private data: Array<string> = [
"http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg",
"http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg",
"http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.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://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg",
"http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg",
"http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg",
"http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg",
"http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg",
"http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg",
"http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg",
"https://hbimg.huabanimg.com/cc6af25f8d782d3cf3122bef4e61571378271145735e9-vEVggB",
'https://img-blog.csdnimg.cn/20191215043500229.png',
'https://img-blog.csdn.net/20140514114029140',
'https://hbimg.huabanimg.com/95a6d37a39aa0b70d48fa18dc7df8309e2e0e8e85571e-x4hhks_fw658/format/webp'
]
aboutToAppear() {
this.hotCommendList.addData(this.hotCommendList.totalCount(), this.data)
AppStorage.set("image_size",1)
}
build() {
Column() {
Button("up").onClick(()=>{
AppStorage.set("image_size",1.6)
})
Button("down").onClick(()=>{
AppStorage.set("image_size",0.9)
})
List() {
LazyForEach(this.hotCommendList, (item: string) => {
ListItem() {
ReuseComponent({ url: item }).width("100%").height("100%")
}.width(200).height(200).backgroundColor(Color.Orange)
})
}
.width("100%")
.height("100%")
.backgroundColor(0xFAEEE0)
}.width("100%").height("100%")
}
}
@Reusable
@Component
struct ReuseComponent {
@Prop url: string = ""
imgSize: number = 100
@StorageProp("image_size") @Watch("updateImageSize") image_size: number = 0
scaleAble: boolean = true
@State calcImgSize: number = 100
aboutToReuse(params: Record<string, string>) {
this.url = params.url
}
aboutToAppear(){
this.setImageSize()
}
updateImageSize() {
this.setImageSize()
}
setImageSize() {
if (!this.scaleAble) {
this.calcImgSize = this.imgSize
} else if (this.image_size < 0.9) {
this.calcImgSize = this.imgSize * 0.9
} else if (this.image_size > 1.6) {
this.calcImgSize = this.imgSize * 1.6
} else {
this.calcImgSize = this.imgSize * this.image_size
}
}
build() {
Column() {
ImageKnifeComponent({
imageKnifeOption:{
loadSrc: this.url,
mainScaleType: ScaleType.FIT_XY,
placeholderSrc: $r('app.media.icon_loading'),
placeholderScaleType: ScaleType.FIT_XY,
errorholderSrc: $r('app.media.icon_failed'),
errorholderSrcScaleType: ScaleType.FIT_XY
}
}).width(this.calcImgSize).height(this.calcImgSize)
}.width("100%").height("100%")
}
}
@Component
struct PhotoComponent {
@Watch("updateTheUrl") @Prop url: string = ""
imgSize: number = 100
@State imageKnifeOption: ImageKnifeOption = new ImageKnifeOption()
@StorageProp("image_size") @Watch("updateImageSize") image_size: number = 0
scaleAble: boolean = true
@State calcImgSize: number = 100
updateImageSize() {
this.setImageSize()
}
setImageSize() {
if (!this.scaleAble) {
this.calcImgSize = this.imgSize
} else if (this.image_size < 0.9) {
this.calcImgSize = this.imgSize * 0.9
} else if (this.image_size > 1.6) {
this.calcImgSize = this.imgSize * 1.6
} else {
this.calcImgSize = this.imgSize * this.image_size
}
}
updateTheUrl() {
this.imageKnifeOption = {
loadSrc: this.url,
mainScaleType: ScaleType.FIT_XY,
placeholderSrc: $r('app.media.icon_loading'),
placeholderScaleType: ScaleType.FIT_XY,
errorholderSrc: $r('app.media.icon_failed'),
errorholderSrcScaleType: ScaleType.FIT_XY
}
}
build() {
Column() {
ImageKnifeComponent({ imageKnifeOption: this.imageKnifeOption })
}.width(this.calcImgSize).height(this.calcImgSize)
}
}

View File

@ -0,0 +1,75 @@
/*
* 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 { ImageKnifeOption } from '@ohos/libraryimageknife'
import display from '@ohos.display';
@Entry
@Component
struct TestStopPlayingGifPage {
@State message: string = 'gif暂停播放测试'
@State eventType: string = '';
@State options: ImageKnifeOption = {
loadSrc: $r('app.media.app_icon'),
}
build() {
Column() {
Column() {
Text(`${this.message}`)
.width("300vp")
.height("60vp")
.textAlign(TextAlign.Center)
.fontSize("30fp")
.fontWeight(FontWeight.Bold)
Button("加载gif图")
.margin(16)
.onClick(() => {
console.log("加载多帧gif")
this.options = {
loadSrc: $r('app.media.gifSample'),
placeholderSrc:$r('app.media.icon_loading'),
}
})
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text("控制")
Button("开启")
.onClick(() => {
this.options.autoPlay = true;
}).margin({ left: 3 })
Button("暂停")
.onClick(() => {
this.options.autoPlay = false;
}).margin({ left: 3 })
}.width('100%')
.height(40).backgroundColor(Color.Pink).margin({bottom:5})
ImageKnifeComponent({ imageKnifeOption: this.options })
.margin(16)
.width(300)
.height(300)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
.width("100%")
.height("100%")
}
aboutToAppear() {
console.log('CTTTestManyNetImageLoadWithPage display Height: '+ display.getDefaultDisplaySync().height)
}
}

View File

@ -406,7 +406,7 @@ struct TransformPixelMapPage {
.width(120) .width(120)
.margin({ top: 10 }) .margin({ top: 10 })
.onClick(() => { .onClick(() => {
this.blurHandlePixelMap(20); this.blurHandlePixelMap(20,3);
}); });
Image(this.mBlurPixelMap==undefined?'':this.mBlurPixelMap!) Image(this.mBlurPixelMap==undefined?'':this.mBlurPixelMap!)
.objectFit(ImageFit.Fill) .objectFit(ImageFit.Fill)
@ -847,9 +847,9 @@ struct TransformPixelMapPage {
/** /**
*模糊 *模糊
*/ */
blurHandlePixelMap(radius: number) { blurHandlePixelMap(radius: number,sampling: number) {
let imageKnifeOption = new RequestOption(); let imageKnifeOption = new RequestOption();
let transformation = new BlurTransformation(radius); let transformation = new BlurTransformation(radius,sampling);
imageKnifeOption.load(mUrl) imageKnifeOption.load(mUrl)
.addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => { .addListener({callback:(err:BusinessError|string, data:ImageKnifeData) => {
@ -860,7 +860,7 @@ struct TransformPixelMapPage {
.setImageViewSize({ width: vp2px(200), height: vp2px(200) }) .setImageViewSize({ width: vp2px(200), height: vp2px(200) })
.skipMemoryCache(true) .skipMemoryCache(true)
.enableGPU() .enableGPU()
.blur(radius) .blur(radius,sampling)
ImageKnife?.call(imageKnifeOption); ImageKnife?.call(imageKnifeOption);
} }

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2021 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 { ImageKnifeOption,ScaleType } from '@ohos/libraryimageknife'
@Entry
@Component
struct webpImageTestPage {
@State message: string = 'webp图片'
@State options: ImageKnifeOption = {
loadSrc: $r('app.media.app_icon')
}
build() {
Column() {
Column() {
Text(`${this.message}`)
.width("300vp")
.height("60vp")
.textAlign(TextAlign.Center)
.fontSize("50fp")
.fontWeight(FontWeight.Bold)
Button("加载单帧webp")
.margin(16)
.onClick(() => {
console.log("加载单帧webp")
this.options = {
loadSrc: $r('app.media.webpSample'),
placeholderSrc:$r('app.media.icon_loading'),
mainScaleType:ScaleType.FIT_XY
}
})
Button("加载多帧webp")
.margin(16)
.onClick(() => {
console.log("加载多帧webp")
this.options = {
loadSrc: $r('app.media.webpAtanta'),
placeholderSrc:$r('app.media.icon_loading'),
mainScaleType:ScaleType.FIT_XY
}
})
ImageKnifeComponent({ imageKnifeOption: this.options })
.margin(16)
.width(200)
.height(100)
.clip(true)
.borderRadius(50)
}
.width("100%")
.height("100%")
.justifyContent(FlexAlign.Center)
}
.width("100%")
.height("100%")
}
}

View File

@ -22,7 +22,7 @@
"abilities": [ "abilities": [
{ {
"name": "MainAbility", "name": "MainAbility",
"srcEntrance": "./ets/entryability/EntryAbility.ets", "srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:MainAbility_desc", "description": "$string:MainAbility_desc",
"icon": "$media:icon", "icon": "$media:icon",
"label": "$string:MainAbility_label", "label": "$string:MainAbility_label",
@ -53,6 +53,7 @@
}, },
{ {
"name": "ohos.permission.MEDIA_LOCATION", "name": "ohos.permission.MEDIA_LOCATION",
"reason": "$string:app_permission_MEDIA_LOCATION",
"usedScene": { "usedScene": {
"abilities": [ "abilities": [
"EntryAbility" "EntryAbility"
@ -62,6 +63,7 @@
}, },
{ {
"name": "ohos.permission.READ_MEDIA", "name": "ohos.permission.READ_MEDIA",
"reason": "$string:app_permission_READ_MEDIA",
"usedScene": { "usedScene": {
"abilities": [ "abilities": [
"EntryAbility" "EntryAbility"

View File

@ -112,6 +112,14 @@
{ {
"name": "image_pixel", "name": "image_pixel",
"value": "马赛克处理" "value": "马赛克处理"
},
{
"name": "app_permission_MEDIA_LOCATION",
"value": "获取媒体图片"
},
{
"name": "app_permission_READ_MEDIA",
"value": "读媒体图片"
} }
] ]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 KiB

Binary file not shown.

View File

@ -12,11 +12,13 @@
"pages/showErrorholderTestCasePage", "pages/showErrorholderTestCasePage",
"pages/transformPixelMapPage", "pages/transformPixelMapPage",
"pages/testPreloadPage", "pages/testPreloadPage",
"pages/testDiskPreLoadPage",
"pages/testImageKnifeOptionChangedPage", "pages/testImageKnifeOptionChangedPage",
"pages/testImageKnifeOptionChangedPage2", "pages/testImageKnifeOptionChangedPage2",
"pages/testImageKnifeOptionChangedPage3", "pages/testImageKnifeOptionChangedPage3",
"pages/testImageKnifeOptionChangedPage4", "pages/testImageKnifeOptionChangedPage4",
"pages/testImageKnifeOptionChangedPage5", "pages/testImageKnifeOptionChangedPage5",
"pages/testGifPlayTimesPage",
"pages/compressPage", "pages/compressPage",
"pages/testAllCacheInfoPage", "pages/testAllCacheInfoPage",
"pages/cropImagePage2", "pages/cropImagePage2",
@ -34,10 +36,26 @@
"pages/hspCacheTestPage", "pages/hspCacheTestPage",
"pages/multiHspTestPage", "pages/multiHspTestPage",
"pages/testManyNetImageLoadWithPage", "pages/testManyNetImageLoadWithPage",
"pages/testManyNetImageLoadWithPage2",
"pages/testManyGifLoadWithPage", "pages/testManyGifLoadWithPage",
"pages/testImageAntiAliasingWithPage", "pages/testImageAntiAliasingWithPage",
"pages/testImageKnifeRouter1", "pages/testImageKnifeRouter1",
"pages/testImageKnifeRouter2", "pages/testImageKnifeRouter2",
"pages/RequestOptionLoadImage" "pages/RequestOptionLoadImage",
"pages/testImageKnifeHttpRequestHeader",
"pages/testImageKnifeHttpRequestHeader1",
"pages/testImageKnifeAutoPage",
"pages/testImageKnifeAutoWidthPage",
"pages/testImageKnifeAutoHeightPage",
"pages/testPriorityComponent",
"pages/testReusePhotoPage",
"pages/testImageKnifeCache",
"pages/webpImageTestPage",
"pages/testStopPlayingGifPage",
"pages/testImageKnifeDataFetch",
"pages/testImageKnifeHeic",
"pages/testImageKnifeNetPlaceholder",
"pages/testCustomDataFetchClientWithPage",
"pages/testReuseAblePages"
] ]
} }

View File

@ -0,0 +1,64 @@
/*
* 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, it, expect } from '@ohos/hypium';
import { ImageKnife, ImageKnifeGlobal, RequestOption } from '@ohos/imageknife/Index';
import { DefaultJobQueue } from '@ohos/imageknife/src/main/ets/components/imageknife/utils/DefaultJobQueue';
import { IJobQueue } from '@ohos/imageknife/src/main/ets/components/imageknife/utils/IJobQueue';
import taskpool from '@ohos.taskpool';
import common from '@ohos.app.ability.common';
export default function DefaultJobQueueTest() {
describe('DefaultJobQueueTest', () => {
it('testJob', 0, () => {
let job: IJobQueue = new DefaultJobQueue();
job.add(makeRequest("medium1", getContext() as common.UIAbilityContext));
job.add(makeRequest("medium2", getContext() as common.UIAbilityContext, taskpool.Priority.MEDIUM));
job.add(makeRequest("medium3", getContext() as common.UIAbilityContext));
job.add(makeRequest("low1", getContext() as common.UIAbilityContext, taskpool.Priority.LOW));
job.add(makeRequest("high1", getContext() as common.UIAbilityContext, taskpool.Priority.HIGH));
job.add(makeRequest("low2", getContext() as common.UIAbilityContext, taskpool.Priority.LOW));
job.add(makeRequest("medium4", getContext() as common.UIAbilityContext));
expect(job.getQueueLength()).assertEqual(7);
expect(job.pop()!.loadSrc).assertEqual("high1");
expect(job.pop()!.loadSrc).assertEqual("medium1");
expect(job.pop()!.loadSrc).assertEqual("medium2");
expect(job.pop()!.loadSrc).assertEqual("medium3");
expect(job.pop()!.loadSrc).assertEqual("medium4");
expect(job.pop()!.loadSrc).assertEqual("low1");
expect(job.pop()!.loadSrc).assertEqual("low2");
expect(job.pop()).assertEqual(undefined);
expect(job.getQueueLength()).assertEqual(0);
});
it("testMaxRequests", 1, () => {
let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
if (imageKnife) {
expect(imageKnife.maxRequests).assertEqual(64);
imageKnife.setMaxRequests(10);
expect(imageKnife.maxRequests).assertEqual(10);
};
})
});
}
function makeRequest(src: string, context: common.UIAbilityContext, priority: taskpool.Priority = taskpool.Priority.MEDIUM): RequestOption {
let request: RequestOption = new RequestOption()
request.loadSrc = src;
request.priority = priority;
request.moduleContext = context;
return request;
}

View File

@ -15,15 +15,21 @@
import abilityTest from './Ability.test' import abilityTest from './Ability.test'
import lruCacheTest from './lrucache.test' import lruCacheTest from './lrucache.test'
import LogUtilTest from './logutil.test' import LogUtilTest from './logutil.test'
import Transform from './transfrom.test' import Transfrom from './transfrom.test'
import RequestOptionTest from './requestoption.test' import RequestOptionTest from './requestoption.test'
import ImageKnifeTest from './imageknife.test' import ImageKnifeTest from './imageknife.test'
import DiskLruCacheTest from './diskLruCache.test'
import SendableDataTest from './SendableData.test'
import DefaultJobQueueTest from './DefaultJobQueueTest.test';
export default function testsuite() { export default function testsuite() {
abilityTest() abilityTest()
lruCacheTest() lruCacheTest()
DiskLruCacheTest()
LogUtilTest() LogUtilTest()
Transform() Transfrom()
RequestOptionTest() RequestOptionTest()
ImageKnifeTest(); ImageKnifeTest();
SendableDataTest();
DefaultJobQueueTest();
} }

View File

@ -0,0 +1,52 @@
/*
* 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

@ -0,0 +1,162 @@
/*
* 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 { DiskLruCache, DiskCacheEntry } from '@ohos/imageknife'
import { common } from '@kit.AbilityKit';
import fs from '@ohos.file.fs';
import { GlobalContext } from '../testability/GlobalContext'
const BASE_COUNT: number = 2000;
export default function DiskLruCacheTest() {
describe('DiskLruCacheTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
//ImageKnife.with(this.context.createModuleContext("entry_test"));
// 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('testSetCahe', 0, () => {
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let disLruCache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
let startTime = new Date().getTime();
disLruCache.set('test', "Hello World Simple Example.");
disLruCache.set('testABC', "Hello World ABC");
disLruCache.set('testDE', "Hello World Simple DE");
expect(String.fromCharCode(...new Uint8Array(disLruCache.get('test') as ArrayBufferLike)) == "Hello World Simple Example.")
.assertTrue()
expect(String.fromCharCode(...new Uint8Array(disLruCache.get('testABC') as ArrayBufferLike)) == "Hello World ABC")
.assertTrue()
expect(String.fromCharCode(...new Uint8Array(disLruCache.get('testDE') as ArrayBufferLike)) == "Hello World Simple DE")
.assertTrue()
let str: string = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
for (let index = 0; index < 100; index++) {
str += index;
disLruCache.set('test' + index, str);
}
expect(disLruCache.getSize() <= 1024).assertTrue()
endTime(startTime, 'testSetCahe');
disLruCache.cleanCacheData();
})
it('testGetCacheAsync', 1, () => {
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let filesDir: object | undefined = GlobalContext.getInstance().getObject("filesDir");
let cache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
let startTime = new Date().getTime();
let path = filesDir + '/testFile.txt';
let file = fs.openSync(path, 0o102);
fs.writeSync(file.fd, "hello, world!");
let length = fs.statSync(path).size;
let dataArr = new ArrayBuffer(length);
fs.readSync(file.fd, dataArr);
cache.set('testFile', dataArr);
expect(cache.get('testFile')?.byteLength == 13).assertTrue()
endTime(startTime, 'testGetCacheAsync');
cache.cleanCacheData();
})
it('testDeleteCacheDataByKey', 2, () => {
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let cache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
cache.set('testABC', "Hello World ABC");
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike)))
.assertEqual("Hello World Simple Example.");
expect(String.fromCharCode(...new Uint8Array(cache.get('testABC') as ArrayBufferLike)))
.assertEqual("Hello World ABC");
cache.deleteCacheDataByKey('test');
cache.deleteCacheDataByKey('testABC');
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike))).assertEqual('');
expect(String.fromCharCode(...new Uint8Array(cache.get('testABC') as ArrayBufferLike))).assertEqual('');
endTime(startTime, 'testDeleteCacheDataByKey');
cache.cleanCacheData();
})
it('testGetPath', 3, () => {
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let cache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
let path: string = cache.getFileToPath('test');
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike)) == "Hello World Simple Example.")
.assertTrue()
expect(cache.getFileToPath('test') == path).assertTrue()
expect(cache.getPath() + cache.getCacheMap().getFirstKey() == path).assertTrue()
endTime(startTime, 'testGetPath');
cache.cleanCacheData();
})
it('testGetCacheMap', 6, () => {
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let cache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
expect(cache.getCacheMap().getFirstKey() == '098f6bcd4621d373cade4e832627b4f6').assertTrue()
expect(cache.getCacheMap().hasKey('098f6bcd4621d373cade4e832627b4f6') == true).assertTrue()
endTime(startTime, 'testGetCacheMap');
cache.cleanCacheData();
})
it('testGetSize', 7, () => {
let context: object | undefined = GlobalContext.getInstance().getObject("hapContext");
let cache: DiskLruCache = DiskLruCache.create(context as common.UIAbilityContext, 1024);
let startTime = new Date().getTime();
cache.set('test', "Hello World Simple Example.");
expect(String.fromCharCode(...new Uint8Array(cache.get('test') as ArrayBufferLike)) == "Hello World Simple Example.")
.assertTrue()
expect(cache.getSize() == 27).assertTrue()
endTime(startTime, 'testGetSize');
cache.cleanCacheData();
})
it('testDiskCacheEntry', 8, () => {
let startTime = new Date().getTime();
let dentry = new DiskCacheEntry('test', 30 * 1024 * 1024)
expect(dentry.getKey() == 'test').assertTrue()
dentry.setKey('newtest')
expect(dentry.getKey() == 'newtest').assertTrue()
expect(dentry.getLength() == 30 * 1024 * 1024).assertTrue()
dentry.setLength(12 * 1024 * 1024)
expect(dentry.getLength() == 12 * 1024 * 1024).assertTrue()
expect(dentry.toString() == dentry.getKey() + ' - ' + dentry.getLength()).assertTrue()
endTime(startTime, 'testDiskCacheEntry');
})
})
}
function endTime(startTime: number, tag: string) {
let endTime: number = new Date().getTime();
let averageTime = ((endTime - startTime) * 1000 / BASE_COUNT)
console.info(tag + " startTime: " + endTime)
console.info(tag + " endTime: " + endTime)
console.log(tag + " averageTime: " + averageTime + "μs");
}

View File

@ -91,6 +91,18 @@ export default function RequestOptionTest() {
expect(option.loadThumbnailReady).assertFalse() expect(option.loadThumbnailReady).assertFalse()
}) })
it('TestPlaceHolder', 4, () => {
let url: string = "https://gd-hbimg.huaban.com/e0a25a7cab0d7c2431978726971d61720732728a315ae-57EskW_fw658";
let option = new RequestOption();
option.placeholder(url);
expect(option.placeholderSrc).assertEqual(url);
})
it('TestFallBack', 5, () => {
let url: PixelMap | Resource = $r('app.media.icon_loading');
let option = new RequestOption();
option.fallback(url);
expect(JSON.stringify(option.fallbackSrc)).assertEqual(JSON.stringify(url));
})
}) })
} }

View File

@ -64,11 +64,11 @@ export default function Transform() {
it('TestBlurTransformation', 0, ()=>{ it('TestBlurTransformation', 0, ()=>{
let startTime = new Date().getTime(); let startTime = new Date().getTime();
for (let index = 0; index < BASE_COUNT; index++) { for (let index = 0; index < BASE_COUNT; index++) {
new BlurTransformation(15); new BlurTransformation(15,3);
} }
endTime(startTime, 'TestBlurTransformation'); endTime(startTime, 'TestBlurTransformation');
let blur = new BlurTransformation(15); let blur = new BlurTransformation(15,3);
expect(blur.getName()).assertEqual('BlurTransformation _mRadius:15') expect(blur.getName()).assertEqual('BlurTransformation _mRadius:15==BlurTransformation sampling:3')
}) })
it('TestBrightnessFilterTransformation', 1, ()=>{ it('TestBrightnessFilterTransformation', 1, ()=>{
let startTime = new Date().getTime(); let startTime = new Date().getTime();
@ -85,8 +85,8 @@ export default function Transform() {
new ContrastFilterTransformation(30); new ContrastFilterTransformation(30);
} }
endTime(startTime, 'TestContrastFilterTransformation'); endTime(startTime, 'TestContrastFilterTransformation');
let constrast = new ContrastFilterTransformation(30); let contrast = new ContrastFilterTransformation(30);
expect(constrast.getName()).assertEqual("ContrastFilterTransformation:30") expect(contrast.getName()).assertEqual("ContrastFilterTransformation:30")
}) })
it('TestCropCircleTransformation', 3, ()=>{ it('TestCropCircleTransformation', 3, ()=>{
let startTime = new Date().getTime(); let startTime = new Date().getTime();

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.
*/
export class GlobalContext {
private constructor() {
}
private static instance: GlobalContext;
private _objects = new Map<string, Object>();
public static getInstance(): GlobalContext {
if (!GlobalContext.instance) {
GlobalContext.instance = new GlobalContext();
}
return GlobalContext.instance;
}
getObject(value: string): Object | undefined {
return this._objects.get(value);
}
setObject(key: string, objectClass: Object): void {
this._objects.set(key, objectClass);
}
}

View File

@ -22,6 +22,7 @@ import {ImageKnife,ImageKnifeDrawFactory,ImageKnifeGlobal} from '@ohos/libraryim
import AbilityConstant from '@ohos.app.ability.AbilityConstant'; import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import Want from '@ohos.app.ability.Want'; import Want from '@ohos.app.ability.Want';
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import {GlobalContext } from './GlobalContext'
export default class TestAbility extends UIAbility { export default class TestAbility extends UIAbility {
onCreate(want: Want, param: AbilityConstant.LaunchParam) { onCreate(want: Want, param: AbilityConstant.LaunchParam) {
@ -33,6 +34,8 @@ export default class TestAbility extends UIAbility {
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
// 初始化xts的ImageKnife // 初始化xts的ImageKnife
ImageKnife.with(this.context.createModuleContext("entry_test")); ImageKnife.with(this.context.createModuleContext("entry_test"));
GlobalContext.getInstance().setObject("hapContext",this.context.createModuleContext("entry_test"));
GlobalContext.getInstance().setObject("filesDir",this.context.createModuleContext("entry_test").filesDir);
} }
onDestroy() { onDestroy() {

View File

@ -1,3 +1,9 @@
## 1.0.3
- 安全编译开启Strip和Ftrapv
## 1.0.2
- 支持x86编译
## 1.0.1 ## 1.0.1
- 更新libc++sheared.so版本 - 更新libc++sheared.so版本

View File

@ -68,6 +68,8 @@
在下述版本验证通过: 在下述版本验证通过:
- DevEco Studio (5.0.3.122), SDK: API12 (5.0.0.17)
- DevEco Studio: (4.1.3.414), SDK: API11 (4.1.0.56) - DevEco Studio: (4.1.3.414), SDK: API11 (4.1.0.56)
## 贡献代码 ## 贡献代码

View File

@ -3,10 +3,11 @@
"buildOption": { "buildOption": {
"externalNativeOptions": { "externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt", "path": "./src/main/cpp/CMakeLists.txt",
"arguments": "", "arguments": " -DCMAKE_BUILD_TYPE=Release",
"abiFilters": [ "abiFilters": [
"armeabi-v7a", "armeabi-v7a",
"arm64-v8a" "arm64-v8a",
"x86_64"
], ],
"cppFlags": "" "cppFlags": ""
}, },

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": "1.0.1", "version": "1.0.3",
"tags": [ "tags": [
"Tool" "Tool"
], ],

View File

@ -30,4 +30,4 @@ find_library (
GLES-lib GLES-lib
GLESv3 ) GLESv3 )
target_link_libraries(nativeGpu PUBLIC ${hilog-lib} ${EGL-lib} ${GLES-lib} libace_napi.z.so libc++.a) target_link_libraries(nativeGpu PUBLIC ${hilog-lib} ${EGL-lib} ${GLES-lib} libace_napi.z.so libc++.a -s -ftrapv)

61
library/PngWork.ets Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2021 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 taskpool from '@ohos.taskpool';
import { UPNG } from './src/main/ets/components/3rd_party/upng/UPNG'
import { WorkerType } from "./src/main/ets/components/imageknife/pngj/PngCallback"
export function handler(e: WorkerType, source: ArrayBuffer, pngCallback: (value:ESObject) => void, info?: string) {
let task: taskpool.Task | undefined = undefined
if (info == undefined) {
task = new taskpool.Task(printArgs, e)
} else {
task = new taskpool.Task(printArgs, e, source)
}
let val1: ESObject = taskpool.execute(task)
pngCallback(val1)
try {
taskpool.cancel(task)
} catch (e) {
console.error("taskpool.cancel occur error:" + e)
}
}
@Concurrent
function printArgs(e: WorkerType, pngSource: ArrayBuffer, info?: string): Object | ArrayBufferLike | void {
let a: Object | ArrayBufferLike | undefined = undefined
let png = UPNG.decode(pngSource)
switch (e.name) {
case 'readPngImageAsync':
let array: Uint8Array = png.data;
let arrayData = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset)
png.data = arrayData;
a = png
break;
case 'writePngWithStringAsync':
let addInfo: string | undefined = info;
let newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(png), png.width, png.height, 0)
a = newPng
break;
case 'writePngAsync':
let newPng3 = UPNG.encode(UPNG.toRGBA8(png), png.width, png.height, 0)
a = newPng3
break;
default:
break
}
if(a != undefined) { return a }
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2021 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 arkWorker from '@ohos.worker';
import {UPNG} from './src/main/ets/components/3rd_party/upng/UPNG'
export function handler (e) {
var data = e.data;
switch (data.type) {
case 'readPngImageAsync':
var png = UPNG.decode(data.data);
let array = png.data;
let arrayData = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset)
png.data = arrayData;
let dataObj = { type: 'readPngImageAsync', data: png, receiver: data.data}
arkWorker.parentPort.postMessage(dataObj, [png.data, data.data]);
break;
case 'writePngWithStringAsync':
let addInfo = data.info;
let pngDecode = UPNG.decode(data.data);
let newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0)
let dataObj2 = { type: 'writePngWithStringAsync', data: newPng, receiver: data.data}
arkWorker.parentPort.postMessage(dataObj2, [newPng, data.data]);
break;
case 'writePngAsync':
let pngDecode3 = UPNG.decode(data.data);
let newPng3 = UPNG.encode(UPNG.toRGBA8(pngDecode3), pngDecode3.width, pngDecode3.height, 0)
let dataObj3 = { type: 'writePngAsync', data: newPng3, receiver: data.data}
arkWorker.parentPort.postMessage(dataObj3, [newPng3, data.data]);
break;
default:
break
}
}

View File

@ -21,6 +21,8 @@
export { FileUtils } from './src/main/ets/components/cache/FileUtils' export { FileUtils } from './src/main/ets/components/cache/FileUtils'
export { Base64 } from './src/main/ets/components/cache/Base64' export { Base64 } from './src/main/ets/components/cache/Base64'
export { LruCache } from './src/main/ets/components/cache/LruCache' export { LruCache } from './src/main/ets/components/cache/LruCache'
export { DiskLruCache } from './src/main/ets/components/cache/DiskLruCache'
export { DiskCacheEntry } from './src/main/ets/components/cache/DiskCacheEntry'
export { DiskStrategy } from './src/main/ets/components/cache/diskstrategy/DiskStrategy' export { DiskStrategy } from './src/main/ets/components/cache/diskstrategy/DiskStrategy'
export { ALL } from './src/main/ets/components/cache/diskstrategy/enum/ALL' export { ALL } from './src/main/ets/components/cache/diskstrategy/enum/ALL'
export { AUTOMATIC } from './src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC' export { AUTOMATIC } from './src/main/ets/components/cache/diskstrategy/enum/AUTOMATIC'
@ -29,6 +31,7 @@ export { NONE } from './src/main/ets/components/cache/diskstrategy/enum/NONE'
export { RESOURCE } from './src/main/ets/components/cache/diskstrategy/enum/RESOURCE' export { RESOURCE } from './src/main/ets/components/cache/diskstrategy/enum/RESOURCE'
export { EngineKeyInterface } from './src/main/ets/components/cache/key/EngineKeyInterface' export { EngineKeyInterface } from './src/main/ets/components/cache/key/EngineKeyInterface'
export { EngineKeyFactories } from './src/main/ets/components/cache/key/EngineKeyFactories' export { EngineKeyFactories } from './src/main/ets/components/cache/key/EngineKeyFactories'
export { DataFetchResult } from './src/main/ets/components/imageknife/networkmanage/DataFetchResult'
/** /**
* compress * compress
@ -96,10 +99,10 @@ export { UPNG } from './src/main/ets/components/3rd_party/upng/UPNG'
export { ImageKnife } from './src/main/ets/components/imageknife/ImageKnife' export { ImageKnife } from './src/main/ets/components/imageknife/ImageKnife'
export { ImageKnifeGlobal } from './src/main/ets/components/imageknife/ImageKnifeGlobal' export { ImageKnifeGlobal } from './src/main/ets/components/imageknife/ImageKnifeGlobal'
export { ObjectKey } from './src/main/ets/components/imageknife/ObjectKey' export { ObjectKey } from './src/main/ets/components/imageknife/ObjectKey'
export {RequestOption,Size,DetachFromLayout} from './src/main/ets/components/imageknife/RequestOption' export {RequestOption,Size,DetachFromLayout,Priority,CacheType} from './src/main/ets/components/imageknife/RequestOption'
export { ImageKnifeComponent, ScaleType, ScaleTypeHelper, AntiAliasing} from './src/main/ets/components/imageknife/ImageKnifeComponent' export { ImageKnifeComponent, ScaleType, ScaleTypeHelper, AntiAliasing} from './src/main/ets/components/imageknife/ImageKnifeComponent'
export { ImageKnifeDrawFactory } from './src/main/ets/components/imageknife/ImageKnifeDrawFactory' export { ImageKnifeDrawFactory } from './src/main/ets/components/imageknife/ImageKnifeDrawFactory'
export {ImageKnifeOption,CropCircleWithBorder,Crop,GifOptions,TransformOptions} from './src/main/ets/components/imageknife/ImageKnifeOption' export {ImageKnifeOption,CropCircleWithBorder,Crop,GifOptions,TransformOptions,HeaderOptions} from './src/main/ets/components/imageknife/ImageKnifeOption'
export { ImageKnifeData } from './src/main/ets/components/imageknife/ImageKnifeData' export { ImageKnifeData } from './src/main/ets/components/imageknife/ImageKnifeData'
export {IAllCacheInfoCallback,AllCacheInfo,ResourceCacheInfo,MemoryCacheInfo,DataCacheInfo} from './src/main/ets/components/imageknife/interface/IAllCacheInfoCallback' export {IAllCacheInfoCallback,AllCacheInfo,ResourceCacheInfo,MemoryCacheInfo,DataCacheInfo} from './src/main/ets/components/imageknife/interface/IAllCacheInfoCallback'
export {IParseImage} from './src/main/ets/components/imageknife/interface/IParseImage' export {IParseImage} from './src/main/ets/components/imageknife/interface/IParseImage'
@ -107,6 +110,8 @@ export {IDataFetch} from './src/main/ets/components/imageknife/networkmanage/IDa
export {ICache} from './src/main/ets/components/imageknife/requestmanage/ICache' export {ICache} from './src/main/ets/components/imageknife/requestmanage/ICache'
export { FileTypeUtil } from './src/main/ets/components/imageknife/utils/FileTypeUtil' export { FileTypeUtil } from './src/main/ets/components/imageknife/utils/FileTypeUtil'
export { ParseImageUtil } from './src/main/ets/components/imageknife/utils/ParseImageUtil' export { ParseImageUtil } from './src/main/ets/components/imageknife/utils/ParseImageUtil'
export { DownloadClient } from './src/main/ets/components/imageknife/networkmanage/DownloadClient';
export { CustomDataFetchClient } from './src/main/ets/components/imageknife/networkmanage/CustomDataFetchClient';
/** /**
* svg parse * svg parse

View File

@ -14,10 +14,9 @@
"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": "2.1.2-rc.6", "version": "2.1.2-rc.12",
"dependencies": { "dependencies": {
"pako": "^2.1.0", "pako": "^2.1.0",
"@ohos/disklrucache": "^2.0.2-rc.0",
"@ohos/gpu_transform": "^1.0.0" "@ohos/gpu_transform": "^1.0.0"
}, },
"tags": [ "tags": [

View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2021 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 { collections } from '@kit.ArkTS'
import { DiskCacheEntry } from './DiskCacheEntry';
@Sendable
export class CustomSendableMap {
map: collections.Map<string, DiskCacheEntry> = new collections.Map<string, DiskCacheEntry>()
// 获取键对应的值
get(key: string): DiskCacheEntry | undefined{
if (key == null) {
throw new Error('key is null,checking the parameter');
}
return this.map.get(key)
}
/**
* 是否含有key的缓存
*/
hasKey(key: string):boolean {
if (key == null) {
throw new Error('key is null,checking the parameter');
}
return this.map.has(key)
}
// 添加键值对
put(key: string, value: DiskCacheEntry): DiskCacheEntry | undefined{
if (key == null || value == null) {
throw new Error('key or value is invalid,checking the parameter');
}
let pre = this.map.get(key) as DiskCacheEntry | undefined;
if (this.hasKey(key)) {
this.map.delete(key)
}
this.map.set(key, value);
return pre
}
// 去除键值,(去除键数据中的键名及对应的值)
remove(key: string): boolean {
if (key == null) {
throw new Error('key is null,checking the parameter');
}
return this.map.delete(key)
}
/**
* 获取最先存储的数据的key
*/
getFirstKey(): string{ // keys()可以遍历后需要优化put()方法暂时仅获取index=0的key
return this.map.keys().next().value
}
// 判断键值元素是否为空
isEmpty(): boolean{
return this.map.size == 0;
}
// 获取键值元素大小
size(): number{
return this.map.size;
}
// 遍历Map,执行处理函数. 回调函数 function(key,value,index){..}
each(fn: (value: DiskCacheEntry, key: string, map: collections.Map<string, DiskCacheEntry>) => void) {
this.map.forEach(fn)
}
// 清除键值对
clear() {
this.map.clear()
}
// 遍历key
keys(): IterableIterator<string>{
return this.map.keys()
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.
*/
@Sendable
export class DiskCacheEntry {
// 缓存的key
key: string = ''
// 缓存文件大小
length: number = 0
constructor(key: string, length?: number) {
this.key = key
this.length = length as number
}
setKey(key: string) {
this.key = key
}
getKey(): string {
return this.key
}
setLength(length: number) {
this.length = length
}
getLength(): number {
return this.length
}
toString(): string {
return this.key + ' - ' + this.length
}
}

View File

@ -0,0 +1,388 @@
/*
* 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 { FileUtils } from './FileUtils'
import { DiskCacheEntry } from './DiskCacheEntry'
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'
import common from '@ohos.app.ability.common'
import { CustomSendableMap } from './CustomSendableMap'
@Sendable
export class DiskLruCache {
// 默认缓存数据最大值
private static readonly DEFAULT_MAX_SIZE: number = 300 * 1024 * 1024
// 默认缓存文件名
private static readonly DEFAULT_NAME: string = 'diskLruCache'
// 缓存文件路径地址
private path: string = ''
// 缓存数据最大值
private maxSize: number = DiskLruCache.DEFAULT_MAX_SIZE
// 当前缓存数据值
private size: number = 0
// 缓存数据集合
private cacheMap: CustomSendableMap = new CustomSendableMap()
constructor(path: string, maxSize: number) {
this.path = path
this.maxSize = maxSize
}
/**
* 打开context获取的cache路径中的缓存如果不存在缓存则创建新缓存
*
* @param context 上下文
* @param maxSize 缓存数据最大值默认值为300M
*/
public static create(context: common.UIAbilityContext, maxSize?: number): DiskLruCache {
if (!!!context) {
throw new Error('DiskLruCache create context is empty, checking the parameter');
}
if (!!!maxSize) {
maxSize = DiskLruCache.DEFAULT_MAX_SIZE
}
if (maxSize <= 0) {
throw new Error("DiskLruCache create maxSize <= 0, checking the parameter");
}
// 使用默认应用在内部存储上的缓存路径,作为存储地址
let path = context.cacheDir + FileUtils.SEPARATOR + DiskLruCache.DEFAULT_NAME
if (!FileUtils.getInstance().existFolder(path)) {
FileUtils.getInstance().createFolder(path)
}
if (path.endsWith(FileUtils.SEPARATOR)) {
path = path
} else {
path = path + FileUtils.SEPARATOR
}
return new DiskLruCache(path, maxSize)
}
/**
* 设置disk缓存最大数据值
*
* @param max 缓存数据最大值
*/
setMaxSize(max: number) {
if (max <= 0 || max > DiskLruCache.DEFAULT_MAX_SIZE) {
throw new Error('setMaxSize error, checking the parameter');
}
this.maxSize = max
this.trimToSize()
}
/**
* 存储disk缓存数据
*
* @param key 键值
* @param content 文件内容
*/
set(key: string, content: ArrayBuffer | string) {
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
let fileSize = 0;
if (content instanceof ArrayBuffer) {
if (content == null || content.byteLength == 0) {
throw new Error('content is null. checking the parameter')
}
fileSize = content.byteLength
} else {
if (!!!content) {
throw new Error('content is null, checking the parameter')
}
fileSize = content.length;
}
if (this.fileSizeMoreThenMaxSize(fileSize)) {
throw new Error('content must be less then DiskLruCache Size, checking the parameter')
return
}
key = SparkMD5.hashBinary(key)
this.size = this.size + fileSize
this.putCacheMap(key, fileSize)
this.trimToSize()
let tempPath = this.path + key
FileUtils.getInstance().writeNewFile(tempPath, content)
}
/**
* 异步存储disk缓存数据
*
* @param key 键值
* @param content 文件内容
*/
async setAsync(key: string, content: ArrayBuffer | string): Promise<void> {
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
let fileSize = 0;
if (content instanceof ArrayBuffer) {
if (content == null || content.byteLength == 0) {
throw new Error('content is null. checking the parameter')
}
fileSize = content.byteLength
} else {
if (!!!content) {
throw new Error('content is null, checking the parameter')
}
fileSize = content.length;
}
if (this.fileSizeMoreThenMaxSize(fileSize)) {
throw new Error('content must be less then DiskLruCache Size, checking the parameter')
return
}
key = SparkMD5.hashBinary(key)
this.size = this.size + fileSize
this.putCacheMap(key, fileSize)
this.trimToSize()
let tempPath = this.path + key
await FileUtils.getInstance().writeNewFileAsync(tempPath, content)
}
/**
* 获取key缓存数据
*
* @param key key 键值
*/
get(key: string): ArrayBuffer | undefined {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
let ab: ArrayBuffer = FileUtils.getInstance().readFile(path)
this.putCacheMap(key, ab.byteLength)
return ab
} else {
return undefined;
}
}
/**
* 异步获取key缓存数据
*
* @param key 键值
*/
async getAsync(key: string): Promise<ArrayBuffer | undefined> {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
let ab: ArrayBuffer = await FileUtils.getInstance().readFileAsync(path)
this.putCacheMap(key, ab.byteLength)
return ab
} else {
return undefined;
}
}
/**
* 获取key缓存数据绝对路径
*
* @param key 键值
*/
getFileToPath(key: string): string {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key);
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
return path
} else {
return "";
}
}
/**
* 异步获取key缓存数据绝对路径
*
* @param key 键值
*/
async getFileToPathAsync(key: string): Promise<string> {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key);
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
return path
} else {
return ""
}
}
/**
* 获取缓存路径
*/
getPath(): string {
return this.path;
}
/**
* 删除key缓存数据
*
* @param key 键值
*/
deleteCacheDataByKey(key: string): DiskCacheEntry {
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let path = this.path + key;
if (FileUtils.getInstance().exist(path)) {
let ab = FileUtils.getInstance().readFile(path)
this.size = this.size - ab.byteLength
this.cacheMap.remove(key)
FileUtils.getInstance().deleteFile(path)
}
return this.cacheMap.get(key) as DiskCacheEntry;
}
/**
*遍历当前的磁盘缓存数据
*
* @param fn 遍历后方法回调
*/
foreachDiskLruCache(fn: Function) {
this.cacheMap.each(fn())
}
/**
* 清除所有disk缓存数据
*/
cleanCacheData() {
this.cacheMap.each((value, key) => {
FileUtils.getInstance().deleteFile(this.path + key)
})
this.cacheMap.clear()
this.size = 0
}
getCacheMap() {
return this.cacheMap;
}
/**
* 返回当前DiskLruCache的size大小
*/
getSize() {
return this.size;
}
/**
* 缓存数据map集合
*
* @param key 键值
* @param length 缓存文件大小
*/
private putCacheMap(key: string, length?: number) {
if (length && length > 0) {
this.cacheMap.put(key, new DiskCacheEntry(key, length))
} else {
this.cacheMap.put(key, new DiskCacheEntry(key))
}
}
/**
* 根据LRU算法删除多余缓存数据
*/
private trimToSize() {
while (this.size > this.maxSize) {
let tempKey: string = this.cacheMap.getFirstKey()
let fileSize = FileUtils.getInstance().getFileSize(this.path + tempKey)
if (fileSize > 0) {
this.size = this.size - fileSize
}
FileUtils.getInstance().deleteFile(this.path + tempKey)
this.cacheMap.remove(tempKey)
}
}
/**
* 图片文件过大 直接超过DiskLruCache上限
*/
private fileSizeMoreThenMaxSize(fileSize: number): boolean {
if (fileSize > this.maxSize) {
return true;
}
return false;
}
/**
* 子线程里只写入缓存文件
* @param context
* @param key
* @param value
*/
static saveFileCacheOnlyFile(path: string, key: string, value: ArrayBuffer): boolean {
// 写文件
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
key = SparkMD5.hashBinary(key);
FileUtils.getInstance().writeNewFile(path + key, value);
return true
}
/**
* 子线程中,通过文件名,直接查找是否有文件缓存
* @param context
* @param key
* @returns
*/
static getFileCacheByFile(path: string, key: string): ArrayBuffer | undefined {
// 从文件获取查看是否有缓存
if (!!!key) {
throw new Error('key is null,checking the parameter');
}
key = SparkMD5.hashBinary(key)
let filepath = path + key;
if (FileUtils.getInstance().exist(filepath)) {
let ab: ArrayBuffer = FileUtils.getInstance().readFile(filepath)
return ab
} else {
return undefined;
}
}
// 添加缓存键值对,但不写文件(用于子线程已经写文件的场景)
setCacheMapAndSize(key: string, content: ArrayBuffer | string): void {
if (!!!key) {
throw new Error('key is null, checking the parameter')
}
let fileSize = 0;
if (content instanceof ArrayBuffer) {
if (content == null || content.byteLength == 0) {
throw new Error('content is null. checking the parameter')
}
fileSize = content.byteLength
} else {
if (!!!content) {
throw new Error('content is null, checking the parameter')
}
fileSize = content.length;
}
if (this.fileSizeMoreThenMaxSize(fileSize)) {
throw new Error('content must be less then DiskLruCache Size, checking the parameter')
}
key = SparkMD5.hashBinary(key);
this.size = this.size + fileSize;
this.putCacheMap(key, fileSize);
this.trimToSize();
}
}

View File

@ -0,0 +1,94 @@
/*
* 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 fs from '@ohos.file.fs';
import { RequestOption } from '../imageknife/RequestOption';
export class FileReader {
// 换行符
static readonly LF: string = '\n'
// CR符
static readonly CR: string = '\r'
// 文件大小
fileLength: number = 0
// 读取的长度
length: number = 0
// 读写stream
stream: fs.Stream
// 缓存buf
buf: ArrayBuffer = new ArrayBuffer(1)
/**
* 读取文件行
*
* @param path 文件路径
*/
constructor(path: string) {
if (!!!path) {
throw new Error('FileReader constructor path is null, checking the parameter')
return;
}
this.stream = fs.createStreamSync(path, 'r+');
let stat = fs.statSync(path)
this.fileLength = stat.size
}
/**
* 循环读取文件数据
*/
readLine(): string {
let line = ''
while (this.stream && this.length < this.fileLength) {
this.stream?.readSync(this.buf, { offset: this.length })
this.length++
let temp = String.fromCharCode(...new Uint8Array(this.buf));
line = line + temp
// check CRLF
if (temp == FileReader.CR) {
// 边界判断 首先拿到下一个字符判断是否是LF 如果是CRLF需要再向后挪一位
if (this.length < this.fileLength) {
let nextBuf = new ArrayBuffer(1)
this.stream?.readSync(nextBuf, { offset: this.length })
let nextTemp = String.fromCharCode(...new Uint8Array(nextBuf));
// 如果是CRLF 需要给当前length+1 向后挪一位
if (nextTemp == FileReader.LF) {
this.length++
}
}
// 如果不是CRLF 只有一个CR结尾length不用变
return line;
} else {
// 判断LF情况
if (temp == FileReader.LF) {
return line
}
}
}
return line
}
/**
* 判断文件是否结束
*/
isEnd() {
return this.fileLength <= 0 || this.length == this.fileLength
}
/**
* 关闭stream
*/
close() {
this.stream?.closeSync()
}
}

View File

@ -16,6 +16,7 @@
import fs from '@ohos.file.fs'; import fs from '@ohos.file.fs';
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
export class FileUtils { export class FileUtils {
static readonly SEPARATOR: string = '/'
base64Str: string = '' base64Str: string = ''
private static sInstance: FileUtils; private static sInstance: FileUtils;
@ -32,13 +33,21 @@ export class FileUtils {
/** /**
* 新建文件 * 新建文件
*
* @param path 文件绝对路径及文件名 * @param path 文件绝对路径及文件名
* @return number 文件句柄id * @return number 文件句柄id
*/ */
createFile(path: string): number { createFile(path: string): number {
return fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE).fd let num = -1;
try {
num = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE).fd
} catch (e) {
console.log("createFile err :" + e)
}
return num;
} }
/** /**
* 删除文件 * 删除文件
* @param path 文件绝对路径及文件名 * @param path 文件绝对路径及文件名
@ -143,16 +152,20 @@ export class FileUtils {
/** /**
* 判断path文件是否存在 * 判断path文件是否存在
*
* @param path 文件绝对路径
*/ */
exist(path: string): boolean { exist(path: string): boolean {
try { try {
let stat = fs.statSync(path) if (fs.accessSync(path)) {
return stat.isFile() let stat = fs.statSync(path)
} catch (e) { return stat.isFile()
console.debug("FileUtils - fileutils exsit e" + e) }
console.log("path=>" + path) } catch (error) {
return false let err: BusinessError = error as BusinessError;
console.error("accessSync failed with error message: " + err.message + ", error code: " + err.code);
} }
return false
} }
/** /**
@ -285,7 +298,7 @@ export class FileUtils {
let stat = fs.statSync(path) let stat = fs.statSync(path)
return stat.isDirectory() return stat.isDirectory()
} catch (e) { } catch (e) {
console.debug("fileutils folder exsit error=" + e) console.debug("fileutils folder exist error=" + e)
return false return false
} }
} }
@ -318,9 +331,84 @@ export class FileUtils {
return tmpUint8Array return tmpUint8Array
} }
/**
* 异步向path写入数据
*
* @param path 文件绝对路径
* @param content 文件内容
*/
async writeDataAsync(path: string, content: ArrayBuffer | string): Promise<void> {
let fd = (await fs.open(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)).fd
let stat = await fs.stat(path)
await fs.write(fd, content, { offset: stat.size })
await fs.close(fd)
}
/**
* 异步拷贝文件
*
* @param src 文件绝对路径及文件名
* @param dest 拷贝到对应的路径
*/
async copyFileAsync(src: string, dest: string): Promise<void> {
await fs.copyFile(src, dest);
}
/**
* 读取路径path的文件
*
* @param path 文件绝对路径
*/
async readFileAsync(path: string): Promise<ArrayBuffer> {
let stat = await fs.stat(path);
let fd = (await fs.open(path, fs.OpenMode.READ_WRITE)).fd;
let length = stat.size;
let buf = new ArrayBuffer(length);
await fs.read(fd, buf);
return buf
}
/**
* 向path写入数据
*
* @param path 文件绝对路径
* @param data 文件内容
*/
async writeNewFileAsync(path: string, data: ArrayBuffer | string): Promise<void> {
let fd = (await fs.open(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)).fd
await fs.truncate(fd)
await fs.write(fd, data)
await fs.fsync(fd)
await fs.close(fd)
}
uint8ArrayToBuffer(array: Uint8Array): ArrayBuffer { uint8ArrayToBuffer(array: Uint8Array): ArrayBuffer {
return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset) return array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset)
} }
/**
* 向path写入数据
*
* @param path 文件绝对路径
* @param data 文件内容
*/
writeNewFile(path: string, data: ArrayBuffer | string) {
this.createFile(path)
this.writeFile(path, data)
}
/**
* 读取路径path的文件
*
* @param path 文件绝对路径
*/
readFile(path: string): ArrayBuffer {
let fd = fs.openSync(path, fs.OpenMode.READ_WRITE).fd;
let length = fs.statSync(path).size
let buf = new ArrayBuffer(length);
fs.readSync(fd, buf)
return buf
}
} }

View File

@ -0,0 +1,2 @@
/*
* asdfasdfasdfasdfasdf*/

View File

@ -0,0 +1,2 @@
/*
* dsasdafasdfasdf*/

View File

@ -0,0 +1,2 @@
/*
* asdfasdfasdfasdfasdf*/

View File

@ -13,10 +13,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { DiskLruCache } from "@ohos/disklrucache" import { DiskLruCache } from "../cache/DiskLruCache"
import { EngineKeyFactories } from "../cache/key/EngineKeyFactories" import { EngineKeyFactories } from "../cache/key/EngineKeyFactories"
import { EngineKeyInterface } from "../cache/key/EngineKeyInterface" import { EngineKeyInterface } from "../cache/key/EngineKeyInterface"
import { RequestOption } from "../imageknife/RequestOption" import { CacheType, RequestOption, Size } from "../imageknife/RequestOption"
import { AsyncCallback } from "../imageknife/interface/AsyncCallback" import { AsyncCallback } from "../imageknife/interface/AsyncCallback"
import { PlaceHolderManager } from "../imageknife/holder/PlaceHolderManager" import { PlaceHolderManager } from "../imageknife/holder/PlaceHolderManager"
import { RetryHolderManager } from "../imageknife/holder/RetryHolderManager" import { RetryHolderManager } from "../imageknife/holder/RetryHolderManager"
@ -31,30 +31,46 @@ import { IResourceFetch } from '../imageknife/resourcemanage/IResourceFetch'
import { ImageKnifeData, ImageKnifeType } from '../imageknife/ImageKnifeData' import { ImageKnifeData, ImageKnifeType } from '../imageknife/ImageKnifeData'
import { ImageKnifeGlobal } from '../imageknife/ImageKnifeGlobal' import { ImageKnifeGlobal } from '../imageknife/ImageKnifeGlobal'
import image from "@ohos.multimedia.image" import image from "@ohos.multimedia.image"
import http from '@ohos.net.http'
import { CompressBuilder } from "../imageknife/compress/CompressBuilder" import { CompressBuilder } from "../imageknife/compress/CompressBuilder"
import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle' import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
import { LogUtil } from '../imageknife/utils/LogUtil' import { LogUtil } from '../imageknife/utils/LogUtil'
import { EasyLinkedHashMap } from './utils/base/EasyLinkedHashMap'
import { MethodMutex } from './utils/base/MethodMutex' import { MethodMutex } from './utils/base/MethodMutex'
import worker from '@ohos.worker' import worker from '@ohos.worker'
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import HashMap from '@ohos.util.HashMap'
import LinkedList from '@ohos.util.LinkedList'
import { MemoryLruCache } from '../cache/MemoryLruCache' import { MemoryLruCache } from '../cache/MemoryLruCache'
import { BusinessError } from '@ohos.base'
import taskpool from '@ohos.taskpool'
import { DefaultJobQueue } from './utils/DefaultJobQueue';
import { IJobQueue } from './utils/IJobQueue';
import LightWeightMap from '@ohos.util.LightWeightMap';
import List from '@ohos.util.List';
import { GIFFrame } from './utils/gif/GIFFrame'
import emitter from '@ohos.events.emitter';
import { MemoryCacheProxy } from './requestmanage/MemoryCacheProxy'
import { ObjectKey } from './ObjectKey'
import { Constants } from './constants/Constants'
import { TransformUtils } from './transform/TransformUtils'
import { GIFParseImpl } from './utils/gif/GIFParseImpl'
import { IParseImage } from './interface/IParseImage'
import { ParseImageUtil } from './utils/ParseImageUtil'
import { SVGParseImpl } from './utils/svg/SVGParseImpl'
import { SendableData } from './SendableData'
import { collections } from '@kit.ArkTS'
import { TaskParams } from './TaskParams'
import { MResource } from './utils/MResource'
export class ImageKnife { export class ImageKnife {
static readonly SEPARATOR: string = '/' static readonly SEPARATOR: string = '/'
memoryCache: MemoryLruCache; memoryCache: MemoryLruCache;
diskMemoryCache: DiskLruCache;
dataFetch: IDataFetch; dataFetch: IDataFetch;
resourceFetch: IResourceFetch<ArrayBuffer>; resourceFetch: IResourceFetch<ArrayBuffer>;
filesPath: string = ""; // data/data/包名/files目录 filesPath: string = ""; // data/data/包名/files目录
diskMemoryCache: DiskLruCache;
memoryCacheProxy: MemoryCacheProxy<string, ImageKnifeData> = new MemoryCacheProxy(new MemoryLruCache(100, 100 * 1024 * 1024));
headerMap: Map<string, Object> = new Map<string, Object>(); //定义全局map
placeholderCache: string = "placeholderCache" placeholderCache: string = "placeholderCache"
runningMaps: EasyLinkedHashMap<string, RequestOption>;
pendingMaps: EasyLinkedHashMap<string, RequestOption>;
pausedMaps: EasyLinkedHashMap<string, RequestOption>;
isPaused: boolean = false; isPaused: boolean = false;
mutex: MethodMutex = new MethodMutex(); mutex: MethodMutex = new MethodMutex();
fileTypeUtil: FileTypeUtil; // 通用文件格式辨别 fileTypeUtil: FileTypeUtil; // 通用文件格式辨别
@ -70,18 +86,19 @@ export class ImageKnife {
defaultLifeCycle: IDrawLifeCycle | undefined = undefined; defaultLifeCycle: IDrawLifeCycle | undefined = undefined;
// 开发者可配置全局缓存 // 开发者可配置全局缓存
engineKeyImpl: EngineKeyInterface; engineKeyImpl: EngineKeyInterface;
private mParseImageUtil: IParseImage<PixelMap>;
// 最大并发
maxRequests: number = 64;
// 排队队列
private jobQueue: IJobQueue = new DefaultJobQueue();
// 执行中的请求
private executingJobMap: LightWeightMap<string, List<RequestOption>> = new LightWeightMap();
private constructor() { private constructor() {
this.mParseImageUtil = new ParseImageUtil();
this.runningMaps = new EasyLinkedHashMap();
this.pendingMaps = new EasyLinkedHashMap();
this.pausedMaps = new EasyLinkedHashMap();
// 构造方法传入size 为保存文件个数 // 构造方法传入size 为保存文件个数
this.memoryCache = new MemoryLruCache(100,100*1024*1024); this.memoryCache = new MemoryLruCache(100, 100 * 1024 * 1024);
// 创建disk缓存 传入的size 为多少比特 比如20KB 传入20*1024
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext());
// 创建网络下载能力 // 创建网络下载能力
this.dataFetch = new DownloadClient(); this.dataFetch = new DownloadClient();
@ -92,18 +109,33 @@ export class ImageKnife {
// 初始化本地 文件保存 // 初始化本地 文件保存
this.filesPath = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).filesDir as string; this.filesPath = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).filesDir as string;
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext);
// 通用文件格式识别初始化 // 通用文件格式识别初始化
this.fileTypeUtil = new FileTypeUtil(); this.fileTypeUtil = new FileTypeUtil();
this.engineKeyImpl = new EngineKeyFactories(); this.engineKeyImpl = new EngineKeyFactories();
}
//全局设置请求头调用方法
addHeader(key: string, value: Object) {
this.headerMap.set(key, value);
}
deleteHeader(key: string) {
this.headerMap.delete(key);
} }
getMemoryCache(): MemoryLruCache { getMemoryCache(): MemoryLruCache {
return this.memoryCache; return this.memoryCache;
} }
getMemoryCacheProxy(): MemoryCacheProxy<string, ImageKnifeData> {
return this.memoryCacheProxy;
}
public static with(context: Object): ImageKnifeGlobal { public static with(context: Object): ImageKnifeGlobal {
// 存入hapContext; // 存入hapContext;
let global: ImageKnifeGlobal = ImageKnifeGlobal.getInstance(); let global: ImageKnifeGlobal = ImageKnifeGlobal.getInstance();
@ -174,13 +206,12 @@ export class ImageKnife {
return new CompressBuilder(); return new CompressBuilder();
} }
// 设置缓存张数,缓存大小,单位字节 // 设置缓存张数,缓存大小,单位字节
public setLruCacheSize(size: number,memory:number) { public setLruCacheSize(size: number, memory: number) {
if (this.memoryCache.map.size() <= 0) { if (this.memoryCache.map.size() <= 0) {
this.memoryCache = new MemoryLruCache(size,memory); this.memoryCache = new MemoryLruCache(size, memory);
} else { } else {
let newLruCache = new MemoryLruCache(size,memory); let newLruCache = new MemoryLruCache(size, memory);
this.memoryCache.foreachLruCache((value: ImageKnifeData, key: string, map: Object) => { this.memoryCache.foreachLruCache((value: ImageKnifeData, key: string, map: Object) => {
newLruCache.put(key, value); newLruCache.put(key, value);
}) })
@ -192,17 +223,19 @@ export class ImageKnife {
this.dataFetch = fetch; this.dataFetch = fetch;
} }
// 替代原来的DiskLruCache // 替代原来的DiskLruCache
public replaceDiskLruCache(size: number) { public replaceDiskLruCache(size: number) {
if (this.diskMemoryCache.getCacheMap().size() <= 0) { this.diskMemoryCache.setMaxSize(size)
this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size); // if (this.diskMemoryCache.getCacheMap().size() <= 0) {
} else { // this.diskMemoryCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size);
let newDiskLruCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size); // } else {
this.diskMemoryCache.foreachDiskLruCache((value: string | ArrayBuffer, key: string, map: Object) => { // let newDiskLruCache = DiskLruCache.create(ImageKnifeGlobal.getInstance().getHapContext(), size);
newDiskLruCache.set(key, value); // this.diskMemoryCache.foreachDiskLruCache((value: string | ArrayBuffer, key: string, map: Object) => {
}) // newDiskLruCache.set(key, value);
this.diskMemoryCache = newDiskLruCache; // })
} // this.diskMemoryCache = newDiskLruCache;
// }
} }
// 预加载 resource资源一级缓存string资源实现二级缓存 // 预加载 resource资源一级缓存string资源实现二级缓存
@ -216,28 +249,6 @@ export class ImageKnife {
async pauseRequests(): Promise<void> { async pauseRequests(): Promise<void> {
await this.mutex.lock(async () => { await this.mutex.lock(async () => {
this.isPaused = true; this.isPaused = true;
// 将未删除的所有request [run pend] 放入 [pause]
LogUtil.log('dodo pauseRequests start1 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
// 将run存入pause
let runNode = this.runningMaps.getHead();
while (runNode) {
let request = runNode.value;
this.pausedMaps.put(request.uuid, request)
runNode = runNode.next;
}
this.runningMaps.clear();
LogUtil.log('dodo pauseRequests start2 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
let pendNode = this.pendingMaps.getHead();
while (pendNode) {
let request = pendNode.value;
this.pausedMaps.put(request.uuid, request)
pendNode = pendNode.next
}
this.pendingMaps.clear()
LogUtil.log('dodo pauseRequests start3 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
}) })
} }
@ -245,28 +256,19 @@ export class ImageKnife {
async resumeRequests(): Promise<void> { async resumeRequests(): Promise<void> {
await this.mutex.lock(async () => { await this.mutex.lock(async () => {
this.isPaused = false; this.isPaused = false;
LogUtil.log('dodo resumeRequest start1 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size()) if (this.executingJobMap.length > 0) {
// 重启了之后需要把paused 里面的所有request重新发送 this.executingJobMap.forEach((list: List<RequestOption>) => {
let headNode = this.pausedMaps.getHead(); this.taskpoolLoadResource(list.get(0), Constants.MAIN_HOLDER);
while (headNode) { })
let request = headNode.value } else {
this.loadCacheManager(request) this.dispatchNextJob();
headNode = headNode.next
} }
this.pausedMaps.clear()
LogUtil.log('dodo resumeRequest start1 pausedMaps size=' + this.pausedMaps.size() + ' runMaps Size=' + this.runningMaps.size() + ' pendMaps Size=' + this.pendingMaps.size())
}) })
} }
// 删除 请求 // 删除 请求
remove(uuid: string) { remove(uuid: string) {
if (this.isPaused) { this.executingJobMap.remove(uuid);
this.pausedMaps.remove(uuid)
} else {
// TODO 哪些请求可以删除
this.pendingMaps.remove(uuid)
this.runningMaps.remove(uuid)
}
} }
// 正常加载 // 正常加载
@ -279,27 +281,132 @@ export class ImageKnife {
// 每个request 公共信息补充 // 每个request 公共信息补充
request.setFilesPath(this.filesPath); request.setFilesPath(this.filesPath);
if (this.headerMap.size > 0) {
request.addHeaderMap(this.headerMap)
}
this.generateDataCacheKey(request)
// 首先执行占位图 解析任务 // 首先执行占位图 解析任务
if (request.placeholderSrc) { if (request.placeholderSrc) {
PlaceHolderManager.execute(request) this.taskpoolLoadResource(request, Constants.PLACE_HOLDER);
} }
// 其次执行重试占位图 解析任务 // 其次执行重试占位图 解析任务
if (request.retryholderSrc) { if (request.retryholderSrc) {
RetryHolderManager.execute(request) this.taskpoolLoadResource(request, Constants.RETRY_HOLDER);
} }
// 最后解析错误占位图 // 最后解析错误占位图
if (request.errorholderSrc) { if (request.errorholderSrc) {
ErrorHolderManager.execute(request) this.taskpoolLoadResource(request, Constants.ERROR_HOLDER);
} }
return this.parseSource(request); return this.parseSource(request);
} }
loadResources(request: RequestOption) {
public isUrlExist(url: string, cacheType: CacheType = CacheType.Default, size: Size = {
width: 0,
height: 0
}): Promise<ImageKnifeData> {
return new Promise((resolve, reject) => {
let request = new RequestOption();
request.load(url)
.setImageViewSize(size)
this.generateDataCacheKey(request);
let loadComplete = (imageKnifeData: ImageKnifeData) => {
resolve(imageKnifeData);
}
let loadError = (err ?: BusinessError | string) => {
if (cacheType == CacheType.Default) {
this.loadMemoryDiskIsUrl(request, loadComplete, loadError);
}
reject(err);
}
if (cacheType == CacheType.Cache) {
this.loadMemoryCacheIsUrl(request, loadComplete, loadError);
} else if (cacheType == CacheType.Disk) {
this.loadMemoryDiskIsUrl(request, loadComplete, loadError);
}
else if (cacheType == CacheType.Default) {
this.loadMemoryCacheIsUrl(request, loadComplete, loadError);
}
})
}
loadMemoryCacheIsUrl(request: RequestOption, onComplete: (imageKnifeData: ImageKnifeData) => void | PromiseLike<ImageKnifeData>, onError: (err?: BusinessError | string) => void) {
let cache = this.memoryCacheProxy.loadMemoryCache(request.generateCacheKey, true);
if (cache == null || typeof cache == 'undefined') {
onError("No data in cache!")
} else {
cache.waitSaveDisk = false;
//2.网络缓存有数据,返回
onComplete(cache);
}
}
loadMemoryDiskIsUrl(request: RequestOption, onComplete: (imageKnifeData: ImageKnifeData) => void | PromiseLike<ImageKnifeData>, onError: (err?: BusinessError | string) => void) {
let cached = this.diskMemoryCache.get(request.generateDataKey);
if (cached != null) {
let filetype: string | null = this.fileTypeUtil.getFileType(cached);
if (filetype == null) {
onError('请检查数据源');
return;
}
if (!this.fileTypeUtil.isImage(cached)) {
onError('暂不支持的类型!类型=' + filetype);
}
if ((ImageKnifeData.GIF == filetype || ImageKnifeData.WEBP == filetype) && !request.dontAnimateFlag) {
let gifParseImpl = new GIFParseImpl()
gifParseImpl.parseGifs(cached, (data?: GIFFrame[], err?: BusinessError | string) => {
if (err) {
onError(err)
}
LogUtil.log("gifProcess data is null:" + (data == null));
if (!!data) {
let imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, data);
LogUtil.log('gifProcess 生成gif 返回数据类型')
onComplete(imageKnifeData)
} else {
onError('Parse GIF callback data is null, you need check callback data!')
}
})
} else if (ImageKnifeData.SVG == filetype) {
let svgParseImpl = new SVGParseImpl()
let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
onComplete(imageKnifeData);
}
svgParseImpl.parseSvg(request, cached, success, onError)
} else {
//5.磁盘有数据解析错误返回onError
let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value);
onComplete(imageKnifeData);
}
this.mParseImageUtil.parseImage(cached, success, onError)
}
} else {
//6.磁盘无数据返回onError
onError("No data in disk cache!")
}
}
generateDataCacheKey(request: RequestOption) {
let factories: EngineKeyInterface; let factories: EngineKeyInterface;
let cacheKey: string; let cacheKey: string;
let transferKey: string; let transferKey: string;
let dataKey: string; let dataKey: string;
//设置全局缓存key
if (this.engineKeyImpl) { if (this.engineKeyImpl) {
factories = this.engineKeyImpl; factories = this.engineKeyImpl;
} else { } else {
@ -331,133 +438,265 @@ export class ImageKnife {
let signature = request.signature; let signature = request.signature;
cacheKey = factories.generateMemoryCacheKey(loadKey,size,transformed,dontAnimateFlag,signature); cacheKey = factories.generateMemoryCacheKey(loadKey, size, transformed, dontAnimateFlag, signature);
// 生成磁盘缓存变换后数据key 变换后数据保存在磁盘 // 生成磁盘缓存变换后数据key 变换后数据保存在磁盘
transferKey = factories.generateTransformedDiskCacheKey(loadKey,size,transformed,dontAnimateFlag,signature); transferKey = factories.generateTransformedDiskCacheKey(loadKey, size, transformed, dontAnimateFlag, signature);
// 生成磁盘缓存源数据key 原始数据保存在磁盘 // 生成磁盘缓存源数据key 原始数据保存在磁盘
dataKey = factories.generateOriginalDiskCacheKey(loadKey,signature); dataKey = factories.generateOriginalDiskCacheKey(loadKey, signature);
if (request.placeholderSrc) {
let placeholderLoadKey = '';
if (typeof request.placeholderSrc == 'string') {
placeholderLoadKey = request.placeholderSrc;
// string类型占位图生成内存缓存源数据key
request.placeholderRegisterMemoryCacheKey = factories.generateMemoryCacheKey(placeholderLoadKey, size, transformed, dontAnimateFlag, signature);
// string类型占位图生成磁盘缓存源数据key 原始数据保存在磁盘
request.placeholderRegisterCacheKey = factories.generateOriginalDiskCacheKey(placeholderLoadKey, signature);
} else {
placeholderLoadKey = JSON.stringify(request.placeholderSrc);
request.placeholderCacheKey = this.generateCacheKey(placeholderLoadKey, size, dontAnimateFlag, signature);
}
}
if (request.retryholderSrc) {
let retryholderLoadKey = '';
if (typeof request.retryholderSrc == 'string') {
retryholderLoadKey = request.retryholderSrc;
} else {
retryholderLoadKey = JSON.stringify(request.retryholderSrc);
}
request.retryholderCacheKey = this.generateCacheKey(retryholderLoadKey, size, dontAnimateFlag, signature)
}
if (request.errorholderSrc) {
let errorholderLoadKey = '';
if (typeof request.errorholderSrc == 'string') {
errorholderLoadKey = request.errorholderSrc;
} else {
errorholderLoadKey = JSON.stringify(request.errorholderSrc);
}
request.errorholderCacheKey = this.generateCacheKey(errorholderLoadKey, size, dontAnimateFlag, signature)
}
request.generateCacheKey = cacheKey; request.generateCacheKey = cacheKey;
request.generateResourceKey = transferKey; request.generateResourceKey = transferKey;
request.generateDataKey = dataKey; request.generateDataKey = dataKey;
}
this.loadCacheManager(request); private generateCacheKey(loadkey: string, size: string, dontAnimateFlag: boolean, signature?: ObjectKey) {
let factories: EngineKeyInterface;
//设置全局缓存key
if (this.engineKeyImpl) {
factories = this.engineKeyImpl;
} else {
factories = new EngineKeyFactories();
}
return factories.generateMemoryCacheKey(loadkey, size, '', dontAnimateFlag, signature);
} }
// 删除执行结束的running // 删除执行结束的running
removeRunning(request: RequestOption) { removeRunning(request: RequestOption) {
if (this.isPaused) { if (!this.isPaused) {
//不暂停则继续加载
} else { this.executingJobMap.remove(request.uuid);
this.runningMaps.remove(request.uuid); this.dispatchNextJob();
console.log('dodo runningMaps length =' + this.runningMaps.size())
let previousRequest = request;
this.loadNextPending(previousRequest);
}
}
// 执行相同key的pending队列请求
private keyEqualPendingToRun(nextPending: RequestOption) {
this.pendingMaps.remove(nextPending.uuid)
this.runningMaps.put(nextPending.uuid, nextPending);
RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
}
private searchNextKeyToRun() {
// 其次则寻找pending中第一个和running不重复的requestOrKey
let pendingTailNode = this.pendingMaps.getTail();
while (pendingTailNode) {
let pendingRequest = pendingTailNode.value;
let hasEqual = false;
let runningTailNode = this.runningMaps.getTail();
while (runningTailNode) {
let runningRequest = runningTailNode.value;
if (this.requestOrKeyEqual(pendingRequest, runningRequest)) {
hasEqual = true;
break
}
runningTailNode = runningTailNode.prev;
}
if (hasEqual) {
break;
}
pendingTailNode = pendingTailNode.prev;
}
if (pendingTailNode != null && pendingTailNode.value != null) {
let nextPending = pendingTailNode.value;
this.runningMaps.put(nextPending.uuid, nextPending)
this.pendingMaps.remove(nextPending.uuid)
RequestManager.execute((nextPending as RequestOption), this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
}
}
// 加载下一个key的请求
private loadNextPending(request: RequestOption) {
let hasEqualRunning = false;
let tailNode = this.pendingMaps.getTail();
while (tailNode) {
if (this.requestOrKeyEqual(request, tailNode.value)) {
hasEqualRunning = true;
break;
}
tailNode = tailNode.prev;
}
if (hasEqualRunning) {
if(tailNode != null && tailNode.value != null) {
this.keyEqualPendingToRun(tailNode.value);
}
} else {
this.searchNextKeyToRun();
} }
} }
// 启动新线程 去磁盘取 去网络取 // 启动新线程 去磁盘取 去网络取
private loadCacheManager(request: RequestOption) { private loadCacheManager(request: RequestOption) {
if (this.isPaused) { if (this.keyNotEmpty(request)) {
// 将当前request存入pausedMaps if (this.executingJobMap.length > this.maxRequests) {
this.pausedMaps.put(request.uuid, request); this.jobQueue.add(request);
} else { return
// 正常逻辑
if (this.keyNotEmpty(request)) {
let hasRunningRequest = false;
// 遍历双向链表 从尾巴到头
let tailNode = this.runningMaps.getTail();
while (tailNode) {
if (this.requestOrKeyEqual(request, tailNode.value)) {
hasRunningRequest = true;
break;
}
tailNode = tailNode.prev
}
if (hasRunningRequest) {
this.pendingMaps.put(request.uuid, request);
} else {
this.runningMaps.put(request.uuid, request)
// 不存在相同key的 任务可以并行
RequestManager.execute(request, this.memoryCache, this.diskMemoryCache, this.dataFetch, this.resourceFetch)
}
} }
else { let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid);
LogUtil.log("key没有生成无法进入存取") if (requestList == undefined) {
requestList = new List();
requestList.add(request);
this.executingJobMap.set(request.uuid, requestList);
if (!this.isPaused) {
LogUtil.log("loadCacheManager start uuid : " + request.uuid + " url : " + request.loadSrc);
//暂停则不开启加载
this.taskpoolLoadResource(request, Constants.MAIN_HOLDER);
}
} else {
requestList.add(request);
this.executingJobMap.set(request.uuid, requestList);
LogUtil.log("loadCacheManager reuse uuid : " + request.uuid + " url : " + request.loadSrc);
return;
}
} else {
LogUtil.log("key没有生成无法进入存取");
}
}
private assembleSendableData(request: RequestOption, usageType: string){
//图片变换方法无法直接传递到子线程,这里先把对象名和构造参数传递到子线程,然后在子线程中实例化变换方法
let transformations: collections.Array<collections.Array<string>> = new collections.Array<collections.Array<string>>();
if (usageType == Constants.MAIN_HOLDER) {
for (let i = 0; i < request.transformations.length; i++) {
let item = collections.Array.from([request.transformations[i].getClassName(), request.transformations[i].getConstructorParams()]) as collections.Array<string>;
transformations.push(item)
} }
} }
let displayProgress = request.progressFunc ? true : false;
let data: SendableData = new SendableData();
data.setUsageType(usageType)
data.setDisplayProgress(displayProgress)
data.setUuid(request.uuid)
data.setDontAnimateFlag(request.dontAnimateFlag)
data.setThumbSizeMultiplier(request.thumbSizeMultiplier)
data.setThumbDelayTime(request.thumbDelayTime)
data.setOnlyRetrieveFromCache(request.onlyRetrieveFromCache)
data.setIsCacheable(request.isCacheable)
data.setGpuEnabled(request.gpuEnabled)
data.setGenerateCacheKey(request.generateCacheKey)
data.setGenerateResourceKey(request.generateResourceKey)
data.setGenerateDataKey(request.generateDataKey)
data.setSignature(request.signature)
data.setTransformations(transformations)
data.setDiskMemoryCache(this.diskMemoryCache)
data.setDataFetch(this.dataFetch)
data.setDiskMemoryCachePath(this.diskMemoryCache.getPath())
data.setPlaceHolderRegisterCacheKey(request.placeholderRegisterCacheKey);
data.setPlaceHolderRegisterMemoryCacheKey(request.placeholderRegisterMemoryCacheKey);
return data;
}
private assembleSTaskData(request: RequestOption){
let data: TaskParams = {
headers: request.headers,
moduleContext: request.moduleContext,
priority: request.priority,
size: request.size,
loadSrc: this.transformResource(request.loadSrc) as string | PixelMap | MResource,
placeholderSrc: this.transformResource(request.placeholderSrc) as string | PixelMap | MResource | undefined,
errorholderSrc: this.transformResource(request.errorholderSrc) as PixelMap | MResource | undefined,
retryholderSrc:this.transformResource(request.retryholderSrc) as PixelMap | MResource | undefined,
fallbackSrc: this.transformResource(request.fallbackSrc) as PixelMap | MResource | undefined,
customGetImage: request.customGetImage
}
return data;
}
private transformResource(loadSrc:string | PixelMap | Resource | undefined):string | PixelMap | MResource | undefined{
let res = loadSrc as Resource
if (res && res.id && res.type) {
return {
bundleName: res.bundleName,
moduleName: res.moduleName,
id: res.id,
params: res.params,
type: res.type
} as MResource;
}
return loadSrc as string | PixelMap | undefined;
}
//多线程请求加载资源
private taskpoolLoadResource(request: RequestOption, usageType: string) {
// string类型占位图实现从缓存中获取图片
if (request.placeholderSrc == 'string') {
request.placeholderCacheKey = request.placeholderRegisterMemoryCacheKey;
}
let mainCache = this.memoryCacheProxy.loadMemoryCache(request.generateCacheKey, request.isCacheable);
let placeholderCache = this.memoryCacheProxy.loadMemoryCache(request.placeholderCacheKey, request.isCacheable);
let retryholderCache = this.memoryCacheProxy.loadMemoryCache(request.retryholderCacheKey, request.isCacheable);
let errorholderCacheKey = this.memoryCacheProxy.loadMemoryCache(request.errorholderCacheKey, request.isCacheable);
if (usageType == Constants.PLACE_HOLDER && placeholderCache && !mainCache && !retryholderCache && !errorholderCacheKey) {
LogUtil.info("imageknife load placeholder from MemoryCache")
request.placeholderOnComplete(placeholderCache);
return;
} else if (usageType == Constants.RETRY_HOLDER && retryholderCache && !mainCache && !errorholderCacheKey) {
LogUtil.info("imageknife load retryholder from MemoryCache")
request.retryholderOnComplete(retryholderCache);
return;
} else if (usageType == Constants.ERROR_HOLDER && errorholderCacheKey && !mainCache) {
LogUtil.info("imageknife load errorholder from MemoryCache")
request.errorholderOnComplete(errorholderCacheKey);
return;
} else if (usageType == Constants.MAIN_HOLDER && mainCache) {
LogUtil.info("imageknife load mainsource from MemoryCache")
mainCache.waitSaveDisk = false;
let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid);
if(requestList != undefined) {
requestList.forEach((requestOption: RequestOption)=>{
requestOption.loadComplete(mainCache as ImageKnifeData);
})
}
return;
}
//组装可以通过sendable传递的数据
let sendData:SendableData = this.assembleSendableData(request, usageType);
//其他不能sendable发送的数据
let taskData:TaskParams = this.assembleSTaskData(request);
//使用taskpool多线程执行资源下载
let task: ESObject = new taskpool.Task(taskExecute,sendData,taskData)
if (request.progressFunc){
emitter.on(Constants.PROGRESS_EMITTER as ESObject, (data: ESObject) => {
if (request.progressFunc && data?.data?.value) {
let percent = data.data.value as number;
request.progressFunc.asyncSuccess(percent);
}
});
}
taskpool.execute(task,request.priority).then((data: ESObject) => {
if (usageType == Constants.PLACE_HOLDER) {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.placeholderOnComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.placeholderCacheKey,imageKnifeData)
} else {
request.placeholderOnError("request placeholder error")
}
} else if (usageType == Constants.RETRY_HOLDER) {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.retryholderOnComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.retryholderCacheKey,imageKnifeData)
} else {
request.retryholderOnError("request retryholder error")
}
} else if (usageType == Constants.ERROR_HOLDER) {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
request.errorholderOnComplete(imageKnifeData)
this.memoryCacheProxy.putValue(request.errorholderCacheKey,imageKnifeData)
} else {
request.errorholderOnError("request errorholder error")
}
} else {
if ((typeof (data as PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, data as PixelMap);
let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid)
if(requestList != undefined) {
requestList.forEach((requestOption: RequestOption)=>{
requestOption.loadComplete(imageKnifeData);
})
}
this.memoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
} else if ((data as GIFFrame[]).length > 0) {
let imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, data as GIFFrame[]);
let requestList: List<RequestOption> | undefined = this.executingJobMap.get(request.uuid);
if(requestList != undefined) {
requestList.forEach((requestOption: RequestOption)=>{
requestOption.loadComplete(imageKnifeData);
})
}
this.memoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
} else {
request.loadError("request resources error")
}
}
}).catch((err: BusinessError | string) => {
request.loadError(err)
})
} }
private keyNotEmpty(request: RequestOption): boolean { private keyNotEmpty(request: RequestOption): boolean {
@ -471,61 +710,162 @@ export class ImageKnife {
return false; return false;
} }
private keyEqual(request1: RequestOption, request2: RequestOption): boolean {
// key 完全相等的情况
if (
request1.generateCacheKey == request2.generateCacheKey &&
request1.generateResourceKey == request2.generateResourceKey &&
request1.generateDataKey == request2.generateDataKey
) {
return true;
}
return false;
}
// 非严格校验模式,如果所有key相等我们认为一定相等, 如果请求类型是string 网络请求url或者uri相等 我们也认为该请求应该只发送一个即可,后续请求会去缓存或者磁盘读取
private requestOrKeyEqual(request1: RequestOption, request2: RequestOption): boolean {
// key 完全相等的情况
if (
request1.generateCacheKey == request2.generateCacheKey &&
request1.generateResourceKey == request2.generateResourceKey &&
request1.generateDataKey == request2.generateDataKey
) {
return true;
}
// 如果加载的是网络url或者是本地文件uri读取,那么loadSrc相同就认为是同一个请求
if (
typeof request1.loadSrc == 'string' && typeof request2.loadSrc == 'string' && request1.loadSrc == request2.loadSrc
) {
return true;
}
return false;
}
private parseSource(request: RequestOption): void { private parseSource(request: RequestOption): void {
if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') { if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, request.loadSrc as PixelMap) let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, request.loadSrc as PixelMap)
request.loadComplete(imageKnifeData); request.loadComplete(imageKnifeData);
} else } else if (typeof request.loadSrc == 'string') {
if (typeof request.loadSrc == 'string') { // 进入三级缓存模型
// 进入三级缓存模型 return this.loadCacheManager(request);
return this.loadResources(request); } else {
} else {
let res = request.loadSrc as Resource; let res = request.loadSrc as Resource;
if (typeof res.id != 'undefined' && typeof res.type != 'undefined') { if (typeof res.id != 'undefined' && typeof res.type != 'undefined') {
// 进入三级缓存模型 本地资源不参与磁盘缓存 // 进入三级缓存模型 本地资源不参与磁盘缓存
let none = new NONE(); let none = new NONE();
request.diskCacheStrategy(none); request.diskCacheStrategy(none);
this.loadResources(request); this.loadCacheManager(request);
} else { } else {
LogUtil.error("输入参数有问题!") LogUtil.error("输入参数有问题!")
} }
} }
} }
prefetchToDiskCache(url: string): Promise<string> {
return new Promise((resolve, reject) => {
let key = this.engineKeyImpl.generateOriginalDiskCacheKey(url, undefined);
let cachedPath = this.getDiskMemoryCache().getFileToPath(key);
if (cachedPath == null || cachedPath == "" || cachedPath == undefined) {
let request = new RequestOption();
request.load(url)
.addListener({ callback: (err: BusinessError | string, data: ImageKnifeData) => {
if (err) {
reject(err)
} else {
let cachedPath = this.getDiskMemoryCache().getFileToPath(key);
resolve(cachedPath);
}
return false;
}
})
this.call(request);
} else {
resolve(cachedPath);
}
})
}
// 分发下一个任务
dispatchNextJob() {
let request: RequestOption | undefined = this.jobQueue.pop();
if (request != undefined) {
this.loadCacheManager(request);
}
}
// 设置请求的最大并发数量
setMaxRequests(count: number) {
if (count > 0) {
this.maxRequests = count;
}
}
} }
/**
* 加载资源子线程包含流程:网络请求资源->下载资源到本地->解码成ixelMap | GIFFrame[]->缓存到内存和磁盘
* @param taskParams:任务参数JSON字符串类型
* @param headers请求头
* @param moduleContext模块上下文
* @returns
*/
@Concurrent
async function taskExecute(sendData:SendableData,taskData:TaskParams): Promise<PixelMap | GIFFrame[]> {
//sendable里面加载http模块有问题需要在@Concurrent先使用下临时规避方法待Sendable解决后删除
let unused_arg0 = http.CertType;
let emitProgressPercent = (percentValue: number) => {
let eventData: emitter.EventData = {
data: {
"value": percentValue,
}
};
emitter.emit(Constants.PROGRESS_EMITTER as ESObject, eventData)
}
let transformations = sendData.getTransformations();
let usageType = sendData.getUsageType();
let displayProgress = sendData.getDisplayProgress();
//子线程构造RequestOption对象
let newRequestOption = new RequestOption();
newRequestOption.priority = taskData.priority;
newRequestOption.uuid = sendData.getUuid();
newRequestOption.loadSrc = taskData.loadSrc as string | PixelMap | Resource;
newRequestOption.dontAnimateFlag = sendData.getDontAnimateFlag();
newRequestOption.generateCacheKey = sendData.getGenerateCacheKey();
newRequestOption.generateResourceKey = sendData.getGenerateResourceKey();
newRequestOption.generateDataKey = sendData.getGenerateDataKey();
newRequestOption.thumbSizeMultiplier = sendData.getThumbSizeMultiplier();
newRequestOption.thumbDelayTime = sendData.getThumbDelayTime();
newRequestOption.size = taskData.size;
newRequestOption.placeholderRegisterCacheKey = sendData.getPlaceHolderRegisterCacheKey();
newRequestOption.placeholderRegisterMemoryCacheKey = sendData.getPlaceHolderRegisterMemoryCacheKey();
if(taskData.placeholderSrc){
newRequestOption.placeholderSrc = taskData.placeholderSrc as string | PixelMap | Resource | undefined;
}
if(taskData.fallbackSrc){
newRequestOption.fallbackSrc = taskData.fallbackSrc as PixelMap | Resource | undefined;
}
if(taskData.errorholderSrc){
newRequestOption.errorholderSrc = taskData.errorholderSrc as PixelMap | Resource | undefined;
}
if(taskData.retryholderSrc){
newRequestOption.retryholderSrc = taskData.retryholderSrc as PixelMap | Resource | undefined;
}
newRequestOption.onlyRetrieveFromCache = sendData.getOnlyRetrieveFromCache();
newRequestOption.gpuEnabled = sendData.getGpuEnabled();
newRequestOption.headers = taskData.headers;
newRequestOption.signature = sendData.getSignature();
ImageKnifeGlobal.getInstance().setHapContext(taskData.moduleContext as common.UIAbilityContext);
newRequestOption.moduleContext = taskData.moduleContext as common.UIAbilityContext;
newRequestOption.isCacheable = sendData.getIsCacheable();
//设置磁盘缓存路径
newRequestOption.diskMemoryCachePath = sendData.getDiskMemoryCachePath();
newRequestOption.customGetImage = taskData.customGetImage;
if (displayProgress) {
newRequestOption.addProgressListener({
asyncSuccess: (percentValue: number) => {
// 如果进度条百分比 未展示大小,展示其动画
emitProgressPercent(percentValue)
}
})
}
//如果是本地图片不作磁盘缓存
if (typeof newRequestOption.loadSrc !== 'string') {
let none = new NONE();
newRequestOption.diskCacheStrategy(none);
}
if (usageType == Constants.PLACE_HOLDER) {
let manager = new PlaceHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else if (usageType == Constants.RETRY_HOLDER) {
let manager = new RetryHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else if (usageType == Constants.ERROR_HOLDER) {
let manager = new ErrorHolderManager<PixelMap>(newRequestOption);
return await new Promise<PixelMap>(manager.process);
} else {
if (transformations) {
newRequestOption.setTransformations(TransformUtils.addTransformations(transformations))
}
let diskMemoryCache = sendData.getDiskMemoryCache();
let newDataFetch = sendData.getDataFetch();
let newResourceFetch = new ParseResClient();
let manager = new RequestManager(newRequestOption, diskMemoryCache as DiskLruCache, newDataFetch, newResourceFetch);
return await new Promise<PixelMap | GIFFrame[]>(manager.process);
}
}

View File

@ -23,27 +23,41 @@ import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
import { LogUtil } from '../imageknife/utils/LogUtil' import { LogUtil } from '../imageknife/utils/LogUtil'
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { ObjectKey } from './ObjectKey'
import componentUtils from '@ohos.arkui.componentUtils'
import inspector from '@ohos.arkui.inspector'
import util from '@ohos.util'
import { ImageKnifeDrawFactory } from './ImageKnifeDrawFactory'
interface KeyCanvas {
keyId:string
}
@Component @Component
export struct ImageKnifeComponent { export struct ImageKnifeComponent {
@Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption; @Watch('watchImageKnifeOption') @ObjectLink imageKnifeOption: ImageKnifeOption;
autoPlay: boolean = true
private settings: RenderingContextSettings = new RenderingContextSettings(true) private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private hasDisplayRetryholder = false; private hasDisplayRetryholder = false;
private lastWidth: number = 0 private lastWidth: number = 0
private lastHeight: number = 0 private lastHeight: number = 0
private currentWidth: number = 0 // 当前帧数位置
private currentHeight: number = 0 private renderFrames_index = 0;
// 定时器id // 定时器id
private gifTimerId: number = -1 private gifTimerId: number = -1
// 完整gif播放时间 // 完整gif播放时间
private gifLoopDuration: number = 0 private gifLoopDuration: number = 0
private startGifLoopTime: number = 0 private startGifLoopTime: number = 0
private endGifLoopTime: number = 0 private endGifLoopTime: number = 0
// gif 播放次数
private playTimes: number = 0
// 抗锯齿属性 // 抗锯齿属性
private imageSmoothingQuality: ImageSmoothingQuality = 'low'; private imageSmoothingQuality: ImageSmoothingQuality = 'low';
private imageSmoothingEnabled: boolean = true; private imageSmoothingEnabled: boolean = true;
// 是否是gif图片
private isGif: boolean = false
@State keyCanvas: KeyCanvas = {
keyId: util.generateRandomUUID()
}
defaultLifeCycle: IDrawLifeCycle = { defaultLifeCycle: IDrawLifeCycle = {
// 展示占位图 // 展示占位图
@ -91,33 +105,20 @@ export struct ImageKnifeComponent {
private detachFromLayoutGIF :DetachFromLayout|undefined = undefined; private detachFromLayoutGIF :DetachFromLayout|undefined = undefined;
private detachFromLayoutPixelMap :DetachFromLayout|undefined = undefined; private detachFromLayoutPixelMap :DetachFromLayout|undefined = undefined;
private lastSrc: string | Resource | PixelMap = ""
listener: inspector.ComponentObserver = inspector.createComponentObserver(this.keyCanvas.keyId)
@State currentSize : Size = {
width: 0.01,
height: 0.01
}
build() { build() {
Canvas(this.context) Canvas(this.context)
.width('100%') .key(this.keyCanvas.keyId)
.height('100%') .width((this.imageKnifeOption!=undefined && this.imageKnifeOption.mainScaleType!= undefined && this.imageKnifeOption.mainScaleType == ScaleType.AUTO_WIDTH )? this.currentSize.width:'100%')
.height((this.imageKnifeOption!=undefined && this.imageKnifeOption.mainScaleType!= undefined && this.imageKnifeOption.mainScaleType == ScaleType.AUTO_HEIGHT )? this.currentSize.height:'100%')
.renderFit(RenderFit.RESIZE_FILL) .renderFit(RenderFit.RESIZE_FILL)
.onAreaChange((oldValue: Area, newValue: Area) => {
if(newValue != undefined && newValue.width != undefined && newValue.height != undefined) {
this.currentWidth = newValue.width as number
this.currentHeight = newValue.height as number
this.lastWidth = oldValue.width 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) || this.firstDrawFlag) {
this.firstDrawFlag = false;
LogUtil.log('ImageKnifeComponent onAreaChange And Next To Execute. Canvas currentWidth =' + this.currentWidth + ' currentHeight=' + this.currentHeight)
this.imageKnifeExecute()
}
}
}else{
LogUtil.log('ImageKnifeComponent onAreaChange Error newValue is undefined')
}
})
.onReady(() => { .onReady(() => {
let ctx = this.context; let ctx = this.context;
ctx.imageSmoothingEnabled = this.imageSmoothingEnabled; ctx.imageSmoothingEnabled = this.imageSmoothingEnabled;
@ -140,9 +141,24 @@ export struct ImageKnifeComponent {
} }
}) })
} }
onLayoutComplete:()=>void = ():void=>{
if (this.context.width <= 0 || this.context.height <= 0) {
// 存在宽或者高为0,此次重回无意义,无需进行request请求
} else {
// 前提:宽高值均有效,值>0. 条件1当前宽高与上一次宽高不同 条件2:当前是第一次绘制
if ((this.context.height != this.lastHeight || this.context.width != this.lastWidth) || this.firstDrawFlag) {
this.firstDrawFlag = false;
LogUtil.log('ImageKnifeComponent onAreaChange And Next To Execute. Canvas currentWidth =' + this.context.width + ' currentHeight=' + this.context.height)
this.lastWidth = this.context.width
this.lastHeight = this.context.height
this.imageKnifeExecute()
}
}
}
watchImageKnifeOption() { watchImageKnifeOption() {
LogUtil.log('ImageKnifeComponent watchImageKnifeOption is happened!') LogUtil.log('ImageKnifeComponent watchImageKnifeOption is happened!')
this.lastSrc = this.imageKnifeOption.loadSrc
this.whetherWaitSize(); this.whetherWaitSize();
} }
@ -152,7 +168,7 @@ export struct ImageKnifeComponent {
* @param drawFirst 是否是aboutToAppear第一次绘制 * @param drawFirst 是否是aboutToAppear第一次绘制
*/ */
whetherWaitSize(drawFirst?: boolean) { whetherWaitSize(drawFirst?: boolean) {
if (this.currentHeight <= 0 || this.currentWidth <= 0) { if (this.context.height <= 0 || this.context.width <= 0) {
// 宽或者高没有高度,需要等待canvas组件初始化完成 // 宽或者高没有高度,需要等待canvas组件初始化完成
if (drawFirst) { if (drawFirst) {
this.firstDrawFlag = true; this.firstDrawFlag = true;
@ -188,11 +204,18 @@ export struct ImageKnifeComponent {
request.load(this.imageKnifeOption.loadSrc) request.load(this.imageKnifeOption.loadSrc)
.addListener({ callback: (err:BusinessError|string, data:ImageKnifeData) => { .addListener({ callback: (err:BusinessError|string, data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.load callback') LogUtil.log('ImageKnifeComponent request.load callback')
this.runNextFunction(this.displayMainSource,data); if(data.isGIFFrame()) {
this.isGif = true
} else {
this.isGif = false
}
if(this.lastSrc !== request.loadSrc && this.lastSrc !== ""){}
else {
this.runNextFunction(this.displayMainSource,data);
}
return false; return false;
} }
}) })
let realSize:Size = { let realSize:Size = {
width: this.context.width, width: this.context.width,
height: this.context.height height: this.context.height
@ -222,25 +245,42 @@ export struct ImageKnifeComponent {
} }
configDisplay(request: RequestOption) { configDisplay(request: RequestOption) {
//单个image组件多个请求头调用
if (this.imageKnifeOption.headerOption != undefined && this.imageKnifeOption.headerOption?.length > 0) {
for (let i = 0; i < this.imageKnifeOption.headerOption.length; i++) {
let headerOptions = this.imageKnifeOption.headerOption[i];
request.addHeader(headerOptions.key, headerOptions.value);
request.signature = new ObjectKey(new Date().getTime().toString())
}
}
if( this.imageKnifeOption.priority != undefined) {
request.setPriority(this.imageKnifeOption.priority)
}
if (this.imageKnifeOption.placeholderSrc) { if (this.imageKnifeOption.placeholderSrc) {
request.placeholder(this.imageKnifeOption.placeholderSrc, {asyncSuccess:(data:ImageKnifeData) => { request.placeholder(this.imageKnifeOption.placeholderSrc, {asyncSuccess:(data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.placeholder callback') LogUtil.log('ImageKnife ImageKnifeComponent request.placeholder callback')
this.runNextFunction(this.displayPlaceholder,data) this.runNextFunction(this.displayPlaceholder,data)
} }
}) })
} }
if (this.imageKnifeOption.thumbSizeMultiplier) { if (this.imageKnifeOption.thumbSizeMultiplier) {
request.thumbnail(this.imageKnifeOption.thumbSizeMultiplier, {asyncSuccess:(data:ImageKnifeData) => { request.thumbnail(this.imageKnifeOption.thumbSizeMultiplier, {asyncSuccess:(data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.thumbnail callback') LogUtil.log('ImageKnife ImageKnifeComponent request.thumbnail callback')
this.runNextFunction(this.displayThumbSizeMultiplier,data) this.runNextFunction(this.displayThumbSizeMultiplier,data)
}}, this.imageKnifeOption.thumbSizeDelay) }}, this.imageKnifeOption.thumbSizeDelay)
} }
if (this.imageKnifeOption.errorholderSrc) { if (this.imageKnifeOption.errorholderSrc) {
request.errorholder(this.imageKnifeOption.errorholderSrc, {asyncSuccess:(data:ImageKnifeData) => { request.errorholder(this.imageKnifeOption.errorholderSrc, {asyncSuccess:(data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.errorholder callback') LogUtil.log('ImageKnife ImageKnifeComponent request.errorholder callback')
this.runNextFunction(this.displayErrorholder,data) this.runNextFunction(this.displayErrorholder,data)
}}) }})
} }
if (this.imageKnifeOption.fallbackSrc) {
request.fallback(this.imageKnifeOption.fallbackSrc, {asyncSuccess:(data:ImageKnifeData) => {
LogUtil.log('ImageKnife ImageKnifeComponent request.fallback callback');
this.runNextFunction(this.displayPlaceholder,data);
}})
}
if (this.imageKnifeOption.transform) { if (this.imageKnifeOption.transform) {
this.requestAddTransform(request) this.requestAddTransform(request)
@ -259,18 +299,21 @@ export struct ImageKnifeComponent {
if (this.imageKnifeOption.displayProgress) { if (this.imageKnifeOption.displayProgress) {
request.addProgressListener({asyncSuccess:(percentValue: number) => { request.addProgressListener({asyncSuccess:(percentValue: number) => {
// 如果进度条百分比 未展示大小,展示其动画 // 如果进度条百分比 未展示大小,展示其动画
LogUtil.log('ImageKnifeComponent request.addProgressListener callback') LogUtil.log('ImageKnife ImageKnifeComponent request.addProgressListener callback')
this.runNextFunction(this.displayProgress,percentValue) this.runNextFunction(this.displayProgress,percentValue)
}}) }})
} }
if (this.imageKnifeOption.retryholderSrc) { if (this.imageKnifeOption.retryholderSrc) {
request.retryholder(this.imageKnifeOption.retryholderSrc,{asyncSuccess: (data:ImageKnifeData) => { request.retryholder(this.imageKnifeOption.retryholderSrc,{asyncSuccess: (data:ImageKnifeData) => {
LogUtil.log('ImageKnifeComponent request.retryholder callback') LogUtil.log('ImageKnife ImageKnifeComponent request.retryholder callback')
this.hasDisplayRetryholder = true this.hasDisplayRetryholder = true
this.runNextFunction(this.displayRetryholder,data) this.runNextFunction(this.displayRetryholder,data)
}}) }})
} }
if (this.imageKnifeOption.customGetImage) {
request.customGetImage = this.imageKnifeOption.customGetImage;
}
} }
configHspContext(request: RequestOption){ configHspContext(request: RequestOption){
@ -296,7 +339,7 @@ export struct ImageKnifeComponent {
this.resetGifData() this.resetGifData()
if (this.canvasHasReady) { if (this.canvasHasReady) {
// 如果canvas已经初始化好了清空原有的canvas内容 // 如果canvas已经初始化好了清空原有的canvas内容
this.context.clearRect(0, 0, this.currentWidth, this.currentHeight) this.context.clearRect(0, 0, this.context.width, this.context.height)
} }
return return
} }
@ -306,7 +349,7 @@ export struct ImageKnifeComponent {
this.configNecessary(request); this.configNecessary(request);
this.configCacheStrategy(request); this.configCacheStrategy(request);
this.configDisplay(request); this.configDisplay(request);
this.configHspContext(request) this.configHspContext(request);
this.configRenderGpu(request); this.configRenderGpu(request);
if(ImageKnifeGlobal.getInstance().getImageKnife()!=undefined) { if(ImageKnifeGlobal.getInstance().getImageKnife()!=undefined) {
ImageKnifeGlobal.getInstance().getImageKnife()?.call(request); ImageKnifeGlobal.getInstance().getImageKnife()?.call(request);
@ -318,15 +361,15 @@ export struct ImageKnifeComponent {
return return
} }
if (!this.drawLifeCycleHasConsumed( 'displayPlaceholder', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayPlaceholder', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},this.imageKnifeOption.drawLifeCycle)) { },this.imageKnifeOption.drawLifeCycle)) {
if (!this.drawLifeCycleHasConsumed( 'displayPlaceholder', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayPlaceholder', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) { },(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) {
if(this.defaultLifeCycle.displayPlaceholder != undefined) { if(this.defaultLifeCycle.displayPlaceholder != undefined) {
this.defaultLifeCycle.displayPlaceholder(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => { this.defaultLifeCycle.displayPlaceholder(this.context, data, this.imageKnifeOption, this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
}) })
} }
@ -341,15 +384,15 @@ export struct ImageKnifeComponent {
return return
} }
if (!this.drawLifeCycleHasConsumed( 'displayProgress', this.context, percent, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayProgress', this.context, percent, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},this.imageKnifeOption.drawLifeCycle)) { },this.imageKnifeOption.drawLifeCycle)) {
if (!this.drawLifeCycleHasConsumed( 'displayProgress', this.context, percent, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayProgress', this.context, percent, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) { },(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) {
if(this.defaultLifeCycle.displayProgress != undefined) { if(this.defaultLifeCycle.displayProgress != undefined) {
this.defaultLifeCycle.displayProgress(this.context, percent, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => { this.defaultLifeCycle.displayProgress(this.context, percent, this.imageKnifeOption, this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
}) })
} }
@ -364,15 +407,15 @@ export struct ImageKnifeComponent {
return return
} }
if (!this.drawLifeCycleHasConsumed( 'displayThumbSizeMultiplier', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayThumbSizeMultiplier', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},this.imageKnifeOption.drawLifeCycle)) { },this.imageKnifeOption.drawLifeCycle)) {
if (!this.drawLifeCycleHasConsumed( 'displayThumbSizeMultiplier', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayThumbSizeMultiplier', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) { },(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) {
if(this.defaultLifeCycle.displayThumbSizeMultiplier != undefined) { if(this.defaultLifeCycle.displayThumbSizeMultiplier != undefined) {
this.defaultLifeCycle.displayThumbSizeMultiplier(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => { this.defaultLifeCycle.displayThumbSizeMultiplier(this.context, data, this.imageKnifeOption, this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
}) })
} }
@ -381,19 +424,20 @@ export struct ImageKnifeComponent {
} }
displayMainSource = (data: ImageKnifeData|number|undefined)=> { displayMainSource = (data: ImageKnifeData|number|undefined)=> {
ImageKnifeDrawFactory.type = undefined;
if(data == undefined || typeof data == 'number'){ if(data == undefined || typeof data == 'number'){
return return
} }
if (!this.drawLifeCycleHasConsumed( 'displayMainSource', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayMainSource', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},this.imageKnifeOption.drawLifeCycle)) { },this.imageKnifeOption.drawLifeCycle)) {
if (!this.drawLifeCycleHasConsumed( 'displayMainSource', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayMainSource', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) { },(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) {
if(this.defaultLifeCycle.displayMainSource != undefined) { if(this.defaultLifeCycle.displayMainSource != undefined) {
this.defaultLifeCycle.displayMainSource(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => { this.defaultLifeCycle.displayMainSource(this.context, data, this.imageKnifeOption, this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
}) })
} }
@ -408,15 +452,15 @@ export struct ImageKnifeComponent {
return return
} }
if (!this.drawLifeCycleHasConsumed( 'displayRetryholder', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayRetryholder', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},this.imageKnifeOption.drawLifeCycle)) { },this.imageKnifeOption.drawLifeCycle)) {
if (!this.drawLifeCycleHasConsumed( 'displayRetryholder', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayRetryholder', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) { },(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) {
if( this.defaultLifeCycle.displayRetryholder != undefined) { if( this.defaultLifeCycle.displayRetryholder != undefined) {
this.defaultLifeCycle.displayRetryholder(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => { this.defaultLifeCycle.displayRetryholder(this.context, data, this.imageKnifeOption, this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
}) })
} }
@ -430,15 +474,15 @@ export struct ImageKnifeComponent {
return return
} }
if (!this.drawLifeCycleHasConsumed( 'displayErrorholder', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayErrorholder', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},this.imageKnifeOption.drawLifeCycle)) { },this.imageKnifeOption.drawLifeCycle)) {
if (!this.drawLifeCycleHasConsumed( 'displayErrorholder', this.context, data, this.imageKnifeOption, if (!this.drawLifeCycleHasConsumed( 'displayErrorholder', this.context, data, this.imageKnifeOption,
this.currentWidth, this.currentHeight, (gifTimeId) => { this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
},(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) { },(ImageKnifeGlobal.getInstance().getImageKnife())?.getDefaultLifeCycle())) {
if(this.defaultLifeCycle.displayErrorholder != undefined) { if(this.defaultLifeCycle.displayErrorholder != undefined) {
this.defaultLifeCycle.displayErrorholder(this.context, data, this.imageKnifeOption, this.currentWidth, this.currentHeight, (gifTimeId) => { this.defaultLifeCycle.displayErrorholder(this.context, data, this.imageKnifeOption, this.context.width, this.context.height, (gifTimeId) => {
this.setGifTimeId(gifTimeId) this.setGifTimeId(gifTimeId)
}) })
} }
@ -450,7 +494,18 @@ export struct ImageKnifeComponent {
drawPlaceholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) { drawPlaceholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
LogUtil.log('ImageKnifeComponent default drawPlaceholder start!') LogUtil.log('ImageKnifeComponent default drawPlaceholder start!')
// API12 getImageInfoSync同步
// if(data.drawPixelMap?.imagePixelMap != undefined) {
// let imageInfo = data.drawPixelMap?.imagePixelMap.getImageInfoSync()
// LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
// let scaleType = (typeof imageKnifeOption.placeholderScaleType == 'number') ? imageKnifeOption.placeholderScaleType : ScaleType.FIT_CENTER
// context.save();
// context.clearRect(0, 0, compWidth, compHeight)
// ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0)
// context.restore();
// LogUtil.log('ImageKnifeComponent default drawPlaceholder end!')
// }
// getImageInfo异步
data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => { data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => {
LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height) LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
let scaleType = (typeof imageKnifeOption.placeholderScaleType == 'number') ? imageKnifeOption.placeholderScaleType : ScaleType.FIT_CENTER let scaleType = (typeof imageKnifeOption.placeholderScaleType == 'number') ? imageKnifeOption.placeholderScaleType : ScaleType.FIT_CENTER
@ -505,7 +560,18 @@ export struct ImageKnifeComponent {
drawThumbSizeMultiplier(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) { drawThumbSizeMultiplier(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
LogUtil.log('ImageKnifeComponent default drawThumbSizeMultiplier start!') LogUtil.log('ImageKnifeComponent default drawThumbSizeMultiplier start!')
// API12 getImageInfoSync同步
// if(data.drawPixelMap?.imagePixelMap != undefined) {
// let imageInfo = data.drawPixelMap?.imagePixelMap.getImageInfoSync()
// LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
// let scaleType = (typeof imageKnifeOption.thumbSizeMultiplierScaleType == 'number') ? imageKnifeOption.thumbSizeMultiplierScaleType : ScaleType.FIT_CENTER
// context.save();
// context.clearRect(0, 0, compWidth, compHeight)
// ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0)
// context.restore();
// LogUtil.log('ImageKnifeComponent default drawThumbSizeMultiplier end!')
// }
// getImageInfo异步
data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => { data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => {
LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height) LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
let scaleType = (typeof imageKnifeOption.thumbSizeMultiplierScaleType == 'number') ? imageKnifeOption.thumbSizeMultiplierScaleType : ScaleType.FIT_CENTER let scaleType = (typeof imageKnifeOption.thumbSizeMultiplierScaleType == 'number') ? imageKnifeOption.thumbSizeMultiplierScaleType : ScaleType.FIT_CENTER
@ -520,11 +586,33 @@ export struct ImageKnifeComponent {
drawMainSource(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) { drawMainSource(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
LogUtil.log('ImageKnifeComponent default drawMainSource start!') LogUtil.log('ImageKnifeComponent default drawMainSource start!')
if (data.isPixelMap()) { if (data.isPixelMap()) {
// API12 getImageInfoSync同步
// if(data.drawPixelMap?.imagePixelMap != undefined) {
// let imageInfo = data.drawPixelMap?.imagePixelMap.getImageInfoSync()
// let scaleType = (typeof imageKnifeOption.mainScaleType == 'number') ? imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER
// LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height + 'scaleType=' + scaleType)
// context.save();
// context.clearRect(0, 0, compWidth, compHeight)
// ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0)
// context.restore();
// LogUtil.log('ImageKnifeComponent default drawMainSource end!')
// }
// getImageInfo异步
data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => { data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => {
let scaleType = (typeof imageKnifeOption.mainScaleType == 'number') ? imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER let scaleType = (typeof imageKnifeOption.mainScaleType == 'number') ? imageKnifeOption.mainScaleType : ScaleType.FIT_CENTER
LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height + 'scaleType=' + scaleType) LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height + 'scaleType=' + scaleType)
context.save(); context.save();
context.clearRect(0, 0, compWidth, compHeight) context.clearRect(0, 0, compWidth, compHeight)
let scaleHeight = imageInfo.size.height/imageInfo.size.width
let scaleWidth = imageInfo.size.width/imageInfo.size.height
if (this.imageKnifeOption.mainScaleType == ScaleType.AUTO_WIDTH){
this.currentSize.width=this.context.height*scaleWidth
}else if (this.imageKnifeOption.mainScaleType == ScaleType.AUTO_HEIGHT){
this.currentSize.height=this.context.width*scaleHeight
}else if (this.imageKnifeOption.mainScaleType == ScaleType.AUTO){
this.currentSize.height=imageInfo.size.height
this.currentSize.width =imageInfo.size.width
}
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0) ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0)
context.restore(); context.restore();
LogUtil.log('ImageKnifeComponent default drawMainSource end!') LogUtil.log('ImageKnifeComponent default drawMainSource end!')
@ -544,7 +632,18 @@ export struct ImageKnifeComponent {
drawRetryholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) { drawRetryholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
LogUtil.log('ImageKnifeComponent default drawRetryholder start!') LogUtil.log('ImageKnifeComponent default drawRetryholder start!')
// API12 getImageInfoSync同步
// if(data.drawPixelMap?.imagePixelMap != undefined) {
// let imageInfo = data.drawPixelMap?.imagePixelMap.getImageInfoSync()
// LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
// let scaleType = (typeof imageKnifeOption.retryholderScaleType == 'number') ? imageKnifeOption.retryholderScaleType : ScaleType.FIT_CENTER
// context.save();
// context.clearRect(0, 0, compWidth, compHeight)
// ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0)
// context.restore();
// LogUtil.log('ImageKnifeComponent default drawRetryholder end!')
// }
// getImageInfo异步
data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => { data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => {
LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height) LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
let scaleType = (typeof imageKnifeOption.retryholderScaleType == 'number') ? imageKnifeOption.retryholderScaleType : ScaleType.FIT_CENTER let scaleType = (typeof imageKnifeOption.retryholderScaleType == 'number') ? imageKnifeOption.retryholderScaleType : ScaleType.FIT_CENTER
@ -558,7 +657,18 @@ export struct ImageKnifeComponent {
drawErrorholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) { drawErrorholder(context: CanvasRenderingContext2D, data: ImageKnifeData, imageKnifeOption: ImageKnifeOption, compWidth: number, compHeight: number, setGifTimeId?: (timeId: number) => void) {
LogUtil.log('ImageKnifeComponent default drawErrorholder start!') LogUtil.log('ImageKnifeComponent default drawErrorholder start!')
// API12 getImageInfoSync同步
// if(data.drawPixelMap?.imagePixelMap != undefined) {
// let imageInfo = data.drawPixelMap?.imagePixelMap.getImageInfoSync()
// LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
// let scaleType = (typeof imageKnifeOption.errorholderSrcScaleType == 'number') ? imageKnifeOption.errorholderSrcScaleType : ScaleType.FIT_CENTER
// context.save();
// context.clearRect(0, 0, compWidth, compHeight)
// ScaleTypeHelper.drawImageWithScaleType(context, scaleType, data.drawPixelMap?.imagePixelMap, px2vp(imageInfo.size.width), px2vp(imageInfo.size.height), compWidth, compHeight, 0, 0)
// context.restore();
// LogUtil.log('ImageKnifeComponent default drawErrorholder end!')
// }
// getImageInfo异步
data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => { data.drawPixelMap?.imagePixelMap?.getImageInfo().then((imageInfo) => {
LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height) LogUtil.log('ImageKnifeComponent imageinfo width =' + imageInfo.size.width + ' height=' + imageInfo.size.height)
let scaleType = (typeof imageKnifeOption.errorholderSrcScaleType == 'number') ? imageKnifeOption.errorholderSrcScaleType : ScaleType.FIT_CENTER let scaleType = (typeof imageKnifeOption.errorholderSrcScaleType == 'number') ? imageKnifeOption.errorholderSrcScaleType : ScaleType.FIT_CENTER
@ -572,7 +682,7 @@ export struct ImageKnifeComponent {
requestAddTransform(request: RequestOption) { requestAddTransform(request: RequestOption) {
if (TransformType.BlurTransformation == this.imageKnifeOption.transform?.transformType) { if (TransformType.BlurTransformation == this.imageKnifeOption.transform?.transformType) {
request.blur(this.imageKnifeOption.transform?.blur) request.blur(this.imageKnifeOption.transform?.blur?.radius,this.imageKnifeOption.transform?.blur?.sampling)
} else if (TransformType.BrightnessFilterTransformation == this.imageKnifeOption.transform?.transformType) { } else if (TransformType.BrightnessFilterTransformation == this.imageKnifeOption.transform?.transformType) {
request.brightnessFilter(this.imageKnifeOption.transform?.brightnessFilter) request.brightnessFilter(this.imageKnifeOption.transform?.brightnessFilter)
} else if (TransformType.ContrastFilterTransformation == this.imageKnifeOption.transform?.transformType) { } else if (TransformType.ContrastFilterTransformation == this.imageKnifeOption.transform?.transformType) {
@ -611,11 +721,18 @@ export struct ImageKnifeComponent {
request.fitCenter() request.fitCenter()
} }
} }
aboutToRecycle(){
this.resetGifData()
}
aboutToReuse(params: ESObject) {
this.context.clearRect(0,0,this.context.width,this.context.height)
}
aboutToAppear() { aboutToAppear() {
LogUtil.log('ImageKnifeComponent aboutToAppear happened!') LogUtil.log('ImageKnifeComponent aboutToAppear happened!')
this.canvasHasReady = false; this.canvasHasReady = false;
this.whetherWaitSize(true); this.whetherWaitSize(true);
this.listener.on("layout",this.onLayoutComplete)
} }
aboutToDisappear() { aboutToDisappear() {
@ -629,7 +746,10 @@ export struct ImageKnifeComponent {
if (this.detachFromLayoutPixelMap != undefined) { if (this.detachFromLayoutPixelMap != undefined) {
this.detachFromLayoutPixelMap.detach(); this.detachFromLayoutPixelMap.detach();
} }
this.resetGifData(); if(this.isGif){
this.resetGifData();
}
this.listener.off("layout",this.onLayoutComplete)
} }
onPageShow() { onPageShow() {
@ -658,15 +778,15 @@ export struct ImageKnifeComponent {
let frames = data.drawGIFFrame?.imageGIFFrames as GIFFrame[] let frames = data.drawGIFFrame?.imageGIFFrames as GIFFrame[]
LogUtil.log('ImageKnifeComponent gifFrameLength =' + frames.length); LogUtil.log('ImageKnifeComponent gifFrameLength =' + frames.length);
if (imageKnifeOption.gif && (typeof (imageKnifeOption.gif.seekTo) == 'number') && imageKnifeOption.gif.seekTo >= 0) { if (imageKnifeOption.gif && (typeof (imageKnifeOption.gif.seekTo) == 'number') && imageKnifeOption.gif.seekTo >= 0) {
this.autoPlay = false;
context.clearRect(0, 0, compWidth, compHeight) context.clearRect(0, 0, compWidth, compHeight)
this.drawSeekToFrame(frames, context, compWidth, compHeight) this.drawSeekToFrame(frames, context, compWidth, compHeight)
} else { } else {
this.autoPlay = true
context.clearRect(0, 0, compWidth, compHeight) context.clearRect(0, 0, compWidth, compHeight)
this.renderFrames_frames = frames this.renderFrames_frames = frames
this.renderFrames_index = 0 if (this.imageKnifeOption.autoPlay == undefined) {
this.renderFrames_index = 0;
}
this.renderFrames_context = context this.renderFrames_context = context
this.renderFrames_compWidth = compWidth this.renderFrames_compWidth = compWidth
this.renderFrames_compHeight = compHeight this.renderFrames_compHeight = compHeight
@ -676,10 +796,12 @@ export struct ImageKnifeComponent {
} }
private resetGifData() { private resetGifData() {
clearTimeout(this.gifTimerId) if(this.isGif) {
this.gifLoopDuration = 0; clearTimeout(this.gifTimerId)
this.startGifLoopTime = 0; this.gifLoopDuration = 0;
this.endGifLoopTime = 0; this.startGifLoopTime = 0;
this.endGifLoopTime = 0;
}
} }
/** /**
@ -688,13 +810,13 @@ export struct ImageKnifeComponent {
private drawSeekToFrame(frames: GIFFrame[], context: CanvasRenderingContext2D, compWidth: number, compHeight: number) { private drawSeekToFrame(frames: GIFFrame[], context: CanvasRenderingContext2D, compWidth: number, compHeight: number) {
if(this.imageKnifeOption.gif != undefined && this.imageKnifeOption.gif.seekTo != undefined) { if(this.imageKnifeOption.gif != undefined && this.imageKnifeOption.gif.seekTo != undefined) {
for (let i = 0; i < this.imageKnifeOption.gif.seekTo; i++) { for (let i = 0; i < this.imageKnifeOption.gif.seekTo; i++) {
this.renderFrames_index = i;
this.drawFrame(frames, i, context, compWidth, compHeight); this.drawFrame(frames, i, context, compWidth, compHeight);
} }
} }
} }
renderFrames_frames: GIFFrame[] | undefined = undefined renderFrames_frames: GIFFrame[] | undefined = undefined
renderFrames_index: number = 0;
renderFrames_context: CanvasRenderingContext2D | undefined = undefined; renderFrames_context: CanvasRenderingContext2D | undefined = undefined;
renderFrames_compWidth: number = 0; renderFrames_compWidth: number = 0;
renderFrames_compHeight: number = 0 renderFrames_compHeight: number = 0
@ -708,6 +830,14 @@ export struct ImageKnifeComponent {
} }
// draw Frame // draw Frame
this.drawFrame(this.renderFrames_frames, this.renderFrames_index, this.renderFrames_context, this.renderFrames_compWidth, this.renderFrames_compHeight); this.drawFrame(this.renderFrames_frames, this.renderFrames_index, this.renderFrames_context, this.renderFrames_compWidth, this.renderFrames_compHeight);
// gif播放次数
if (this.renderFrames_frames != undefined && this.renderFrames_index === (this.renderFrames_frames.length - 1) && this.imageKnifeOption.gif != undefined ) {
this.playTimes++
if (this.imageKnifeOption.gif.playTimes == this.playTimes){
this.imageKnifeOption.autoPlay = false;
this.playTimes = 0
}
}
//如果gif动图只有一帧的情况下不进行后面代码的逐帧绘制循环 //如果gif动图只有一帧的情况下不进行后面代码的逐帧绘制循环
if (this.renderFrames_frames != undefined && this.renderFrames_frames.length <= 1) { if (this.renderFrames_frames != undefined && this.renderFrames_frames.length <= 1) {
return return
@ -717,7 +847,7 @@ export struct ImageKnifeComponent {
let end = new Date().getTime(); let end = new Date().getTime();
let diff = end - start let diff = end - start
if (this.autoPlay) { if ((this.imageKnifeOption.autoPlay == undefined) || (this.imageKnifeOption.autoPlay)) {
// 理论上该帧在屏幕上保留的时间 // 理论上该帧在屏幕上保留的时间
let stayTime:number= 0 let stayTime:number= 0
@ -782,10 +912,58 @@ export struct ImageKnifeComponent {
ScaleTypeHelper.drawImageWithScaleType(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, compHeight, px2vp(frame.dims.left), px2vp(frame.dims.top)) ScaleTypeHelper.drawImageWithScaleType(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth, compHeight, px2vp(frame.dims.left), px2vp(frame.dims.top))
// tips:worker如果不是在展示页面中创建,使用子线程回来的数据创建的图片,会导致canvas绘制不出来 // tips:worker如果不是在展示页面中创建,使用子线程回来的数据创建的图片,会导致canvas绘制不出来
context.restore(); context.restore();
LogUtil.log('ImageKnifeComponent default drawMainSource end!') if (ImageKnifeDrawFactory.type === undefined) {
return;
}
// 通过 destination-in 裁剪出圆角
if (ImageKnifeDrawFactory?.type === DrawType.Round || ImageKnifeDrawFactory?.type === DrawType.Oval) {
context.save();
context.globalCompositeOperation = 'destination-in';
if (ImageKnifeDrawFactory.type === DrawType.Round) {
ImageKnifeDrawFactory.setRect(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth,
compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth, ImageKnifeDrawFactory.connerRadius);
} else {
context.beginPath();
ImageKnifeDrawFactory.setOval(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth,
compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth);
context.closePath();
}
context.fill();
context.restore();
if (ImageKnifeDrawFactory.borderWidth > 0) {
// 为圆角添加边框
context.save();
context.strokeStyle = ImageKnifeDrawFactory.colorString;
context.lineWidth = ImageKnifeDrawFactory.borderWidth;
context.globalCompositeOperation = 'source-over';
if (ImageKnifeDrawFactory.type === DrawType.Round) {
ImageKnifeDrawFactory.setRect(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth,
compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth, ImageKnifeDrawFactory.connerRadius);
} else {
context.beginPath();
ImageKnifeDrawFactory.setOval(context, scaleType, pixelmap, px2vp(frameW), px2vp(frameH), compWidth,
compHeight, 0, 0, ImageKnifeDrawFactory.borderWidth);
context.closePath();
}
context.stroke();
context.restore();
}
context.restore();
}
LogUtil.log('ImageKnifeComponent canvasDrawPixelMap end!')
} }
} }
export enum DrawType{
Normal = 0,
Oval = 1,
Round = 2
}
export enum FrameDisposalType { export enum FrameDisposalType {
// 0 - No disposal specified. The decoder is not required to take any action. // 0 - No disposal specified. The decoder is not required to take any action.
// 不使用处置方法 // 不使用处置方法
@ -825,7 +1003,13 @@ export enum ScaleType {
// 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER // 如果图像大于组件则执行FIT_CENTER,小于组件则CENTER
CENTER_INSIDE = 7, CENTER_INSIDE = 7,
// 如果不想适配,直接展示原图大小 // 如果不想适配,直接展示原图大小
NONE = 8 NONE = 8,
// 设置宽的时候,图片高度自适应
AUTO_HEIGHT =9,
// 设置高的时候,图片宽度自适应
AUTO_WIDTH =10,
//没有设置宽和高,图片按照自身宽高显示
AUTO =11
} }
@ -862,7 +1046,7 @@ export class ScaleTypeHelper {
ScaleTypeHelper.drawNone(context, source, imageWidth, imageHeight, imageOffsetX, imageOffsetY) ScaleTypeHelper.drawNone(context, source, imageWidth, imageHeight, imageOffsetX, imageOffsetY)
break; break;
default: default:
ScaleTypeHelper.drawNone(context, source, imageWidth, imageHeight, imageOffsetX, imageOffsetY) ScaleTypeHelper.drawFitCenter(context, source, minScale, imageWidth, imageHeight, compWidth, compHeight, imageOffsetX, imageOffsetY)
break break
} }

View File

@ -16,9 +16,13 @@ import { ImageKnifeOption } from '../imageknife/ImageKnifeOption'
import { ImageKnifeData } from '../imageknife/ImageKnifeData' import { ImageKnifeData } from '../imageknife/ImageKnifeData'
import { GIFFrame } from '../imageknife/utils/gif/GIFFrame' import { GIFFrame } from '../imageknife/utils/gif/GIFFrame'
import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle' import { IDrawLifeCycle } from '../imageknife/interface/IDrawLifeCycle'
import { ScaleTypeHelper,ScaleType } from '../imageknife/ImageKnifeComponent' import { ScaleTypeHelper,ScaleType, DrawType } from '../imageknife/ImageKnifeComponent'
export class ImageKnifeDrawFactory{ export class ImageKnifeDrawFactory{
public static borderWidth: number;
public static type: DrawType | undefined = undefined;
public static colorString: string;
public static connerRadius: number;
/** /**
* 绘制PixelMap内容情况下,主图的椭圆裁剪,可添加边框 * 绘制PixelMap内容情况下,主图的椭圆裁剪,可添加边框
@ -81,6 +85,11 @@ export class ImageKnifeDrawFactory{
}) })
return true; return true;
} }
if (data.isGIFFrame()) {
ImageKnifeDrawFactory.type = DrawType.Oval;
ImageKnifeDrawFactory.borderWidth = borderWidth;
ImageKnifeDrawFactory.colorString = colorString;
}
return false; return false;
}, },
// 展示重试图层 // 展示重试图层
@ -108,7 +117,7 @@ export class ImageKnifeDrawFactory{
* @param imageOffsetY * @param imageOffsetY
* @param borderWidth * @param borderWidth
*/ */
private static setOval(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number public static setOval(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number
,borderWidth:number) { ,borderWidth:number) {
let scaleW = compWidth / imageWidth let scaleW = compWidth / imageWidth
let scaleH = compHeight / imageHeight let scaleH = compHeight / imageHeight
@ -240,6 +249,12 @@ export class ImageKnifeDrawFactory{
}) })
return true; return true;
} }
if (data.isGIFFrame()) {
ImageKnifeDrawFactory.type = DrawType.Round;
ImageKnifeDrawFactory.borderWidth = borderWidth;
ImageKnifeDrawFactory.colorString = colorString;
ImageKnifeDrawFactory.connerRadius = connerRadius;
}
return false; return false;
}, },
// 展示重试图层 // 展示重试图层
@ -268,7 +283,7 @@ export class ImageKnifeDrawFactory{
* @param borderWidth * @param borderWidth
* @param cornerRadius * @param cornerRadius
*/ */
private static setRect(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number public static setRect(context: CanvasRenderingContext2D, scaleType: ScaleType, source: PixelMap | undefined, imageWidth: number, imageHeight: number, compWidth: number, compHeight: number, imageOffsetX:number,imageOffsetY:number
,borderWidth:number,cornerRadius:number) { ,borderWidth:number,cornerRadius:number) {
let scaleW = compWidth / imageWidth let scaleW = compWidth / imageWidth
let scaleH = compHeight / imageHeight let scaleH = compHeight / imageHeight

View File

@ -26,6 +26,8 @@ import { rgbColor } from './transform/CropCircleWithBorderTransformation'
import { RoundCorner } from './transform/RoundedCornersTransformation' import { RoundCorner } from './transform/RoundedCornersTransformation'
import { ObjectKey } from './ObjectKey' import { ObjectKey } from './ObjectKey'
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { Priority } from './RequestOption'
import { DataFetchResult } from './networkmanage/DataFetchResult'
export interface CropCircleWithBorder{ export interface CropCircleWithBorder{
border: number, border: number,
@ -37,15 +39,19 @@ export interface Crop{
height: number, height: number,
cropType: CropType cropType: CropType
} }
export interface BlurType {
radius: number,
sampling: number
}
export interface GifOptions{ export interface GifOptions{
loopFinish?: (loopTime?:number) => void loopFinish?: (loopTime?:number) => void
speedFactory?: number speedFactory?: number
seekTo?: number seekTo?: number
playTimes?: number
} }
export interface TransformOptions{ export interface TransformOptions{
transformType: number, transformType: number,
blur?: number, blur?: BlurType,
roundedCorners?: RoundCorner roundedCorners?: RoundCorner
cropCircleWithBorder?: CropCircleWithBorder cropCircleWithBorder?: CropCircleWithBorder
crop?:Crop crop?:Crop
@ -57,13 +63,22 @@ export interface TransformOptions{
rotateImage?: number rotateImage?: number
} }
export interface HeaderOptions {
key: string;
value: string;
}
@Observed @Observed
export class ImageKnifeOption { export class ImageKnifeOption {
//控制gif开关
autoPlay?: boolean = true;
// header请求列表
headerOption?: Array<HeaderOptions>;
// 主图资源 // 主图资源
loadSrc: string | PixelMap | Resource = ''; loadSrc: string | PixelMap | Resource = '';
mainScaleType?: ScaleType = ScaleType.FIT_CENTER mainScaleType?: ScaleType = ScaleType.FIT_CENTER
// 优先级
priority?: Priority = Priority.MEDIUM
enableGpu?:boolean = true; enableGpu?:boolean = true;
// 磁盘缓存策略 // 磁盘缓存策略
@ -73,9 +88,11 @@ export class ImageKnifeOption {
dontAnimateFlag? = false; dontAnimateFlag? = false;
// 占位图 // 占位图
placeholderSrc?: PixelMap | Resource; placeholderSrc?: string | PixelMap | Resource;
placeholderScaleType?: ScaleType = ScaleType.FIT_CENTER placeholderScaleType?: ScaleType = ScaleType.FIT_CENTER
// 后备回调符
fallbackSrc?: PixelMap | Resource;
// 失败占位图 // 失败占位图
errorholderSrc?: PixelMap | Resource; errorholderSrc?: PixelMap | Resource;
errorholderSrcScaleType?: ScaleType = ScaleType.FIT_CENTER errorholderSrcScaleType?: ScaleType = ScaleType.FIT_CENTER
@ -129,6 +146,9 @@ export class ImageKnifeOption {
context?: common.UIAbilityContext; context?: common.UIAbilityContext;
// sizeAnimate?: AnimateParam 由业务自定义不再支持 // sizeAnimate?: AnimateParam 由业务自定义不再支持
// 设置是否使用应用自定义的方式加载图片
customGetImage?: (context: Context, src: string) => Promise<DataFetchResult>;
constructor() { constructor() {
} }

View File

@ -12,6 +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.
*/ */
@Sendable
export class ObjectKey{ export class ObjectKey{
private objectKey: string; private objectKey: string;

View File

@ -12,15 +12,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import {ImageKnife} from './ImageKnife' import { ImageKnife } from './ImageKnife'
import { DiskStrategy } from "../cache/diskstrategy/DiskStrategy" import { DiskStrategy } from "../cache/diskstrategy/DiskStrategy"
import { AsyncCallback } from "../imageknife/interface/AsyncCallback" import { AsyncCallback } from "../imageknife/interface/AsyncCallback"
import { AsyncSuccess } from "../imageknife/interface/AsyncSuccess" import { AsyncSuccess } from "../imageknife/interface/AsyncSuccess"
import { IAllCacheInfoCallback } from "../imageknife/interface/IAllCacheInfoCallback" import { AllCacheInfo, IAllCacheInfoCallback } from "../imageknife/interface/IAllCacheInfoCallback"
import { AUTOMATIC } from "../cache/diskstrategy/enum/AUTOMATIC" import { AUTOMATIC } from "../cache/diskstrategy/enum/AUTOMATIC"
import { BaseTransform } from "../imageknife/transform/BaseTransform" import { BaseTransform } from "../imageknife/transform/BaseTransform"
import { RotateImageTransformation } from "../imageknife/transform/RotateImageTransformation" import { RotateImageTransformation } from "../imageknife/transform/RotateImageTransformation"
import { ImageKnifeData } from "../imageknife/ImageKnifeData" import { ImageKnifeData, ImageKnifeType } from "../imageknife/ImageKnifeData"
import { CenterCrop } from '../imageknife/transform/pixelmap/CenterCrop' import { CenterCrop } from '../imageknife/transform/pixelmap/CenterCrop'
import { CenterInside } from '../imageknife/transform/pixelmap/CenterInside' import { CenterInside } from '../imageknife/transform/pixelmap/CenterInside'
import { FitCenter } from '../imageknife/transform/pixelmap/FitCenter' import { FitCenter } from '../imageknife/transform/pixelmap/FitCenter'
@ -28,7 +28,10 @@ import { RoundedCornersTransformation, RoundCorner } from '../imageknife/transfo
import { CropCircleTransformation } from '../imageknife/transform/CropCircleTransformation' import { CropCircleTransformation } from '../imageknife/transform/CropCircleTransformation'
import { CropCircleWithBorderTransformation, rgbColor } from '../imageknife/transform/CropCircleWithBorderTransformation' import {
CropCircleWithBorderTransformation,
rgbColor
} from '../imageknife/transform/CropCircleWithBorderTransformation'
import { CropSquareTransformation } from '../imageknife/transform/CropSquareTransformation' import { CropSquareTransformation } from '../imageknife/transform/CropSquareTransformation'
import { CropTransformation } from '../imageknife/transform/CropTransformation' import { CropTransformation } from '../imageknife/transform/CropTransformation'
import { CropType } from '../imageknife/transform/CropTransformation' import { CropType } from '../imageknife/transform/CropTransformation'
@ -50,46 +53,85 @@ import { ImageKnifeGlobal } from './ImageKnifeGlobal'
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import { ObjectKey } from './ObjectKey' import { ObjectKey } from './ObjectKey'
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { GIFFrame } from './utils/gif/GIFFrame'
import { DiskCacheProxy } from './requestmanage/DiskCacheProxy'
import { DiskLruCache } from '../cache/DiskLruCache'
import { SparkMD5 } from '../3rd_party/sparkmd5/spark-md5'
import { FileUtils } from '../cache/FileUtils'
import util from '@ohos.util'
import { DataFetchResult } from './networkmanage/DataFetchResult'
export interface Size { export interface Size {
width: number, width: number,
height: number height: number
} }
export interface DetachFromLayout{
detach:()=>void export enum CacheType {
Default,
//缓存
Cache,
//磁盘
Disk
} }
export interface DetachFromLayout {
detach: () => void
}
export enum Priority {
HIGH = 0,
MEDIUM = 1,
LOW = 2
}
export class RequestOption { export class RequestOption {
uuid:string ='' // 唯一标识 // 遍历添加图片http请求头
headers: Map<string, Object> = new Map<string, Object>();
// RequestOption调用header对于的方法
addHeader(key: string, value: Object) {
this.headers.set(key, value);
}
// 全局调用header对应的方法包含RequestOption的形式
addHeaderMap(map: Map<string, Object>) {
map.forEach((value, key) => {
if (!this.headers.has(key)) {
this.addHeader(key, value);
}
})
}
// 优先级
priority: Priority = Priority.MEDIUM;
uuid: string = '' // 唯一标识
loadSrc: string | PixelMap | Resource = ''; loadSrc: string | PixelMap | Resource = '';
strategy: DiskStrategy = new AUTOMATIC(); strategy: DiskStrategy = new AUTOMATIC();
dontAnimateFlag = false; dontAnimateFlag = false;
placeholderSrc: PixelMap | Resource | undefined = undefined; placeholderSrc: string | PixelMap | Resource | undefined = undefined;
placeholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined; placeholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
errorholderSrc: PixelMap | Resource | undefined = undefined; errorholderSrc: PixelMap | Resource | undefined = undefined;
errorholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined; errorholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
errorholderData: ImageKnifeData | undefined = undefined;; errorholderData: ImageKnifeData | undefined = undefined;
thumbSizeMultiplier: number = 0; thumbSizeMultiplier: number = 0;
// 如果存在缩略图则主图延时1s加载 // 如果存在缩略图则主图延时1s加载
thumbDelayTime: number = 1000 thumbDelayTime: number = 1000
thumbHolderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined; thumbHolderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
requestListeners: Array<AsyncCallback<ImageKnifeData>> | undefined = undefined; requestListeners: Array<AsyncCallback<ImageKnifeData>> | undefined = undefined;
// 进度条 // 进度条
progressFunc: AsyncSuccess<number> | undefined = undefined; progressFunc: AsyncSuccess<number> | undefined = undefined;
// 后备回调符
fallbackSrc: PixelMap | Resource | undefined = undefined;
fallbackFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
fallbackData: ImageKnifeData | undefined = undefined;
// 重试图层 // 重试图层
retryholderSrc: PixelMap | Resource | undefined = undefined; retryholderSrc: PixelMap | Resource | undefined = undefined;
retryholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined; retryholderFunc: AsyncSuccess<ImageKnifeData> | undefined = undefined;
retryholderData: ImageKnifeData | undefined = undefined; retryholderData: ImageKnifeData | undefined = undefined;
size:Size= { width: -1, height: -1 }; size: Size = { width: -1, height: -1 };
// 网络下载数据回调 // 网络下载数据回调
allCacheInfoCallback: IAllCacheInfoCallback | undefined = undefined; allCacheInfoCallback: IAllCacheInfoCallback | undefined = undefined;
onlyRetrieveFromCache: boolean = false; onlyRetrieveFromCache: boolean = false;
isCacheable: boolean = true; isCacheable: boolean = true;
// 开启GPU变换绘制 // 开启GPU变换绘制
gpuEnabled: boolean = false; gpuEnabled: boolean = false;
// 变换相关 // 变换相关
@ -99,73 +141,76 @@ export class RequestOption {
generateDataKey: string = ""; generateDataKey: string = "";
filesPath: string = ""; // data/data/包名/files目录 filesPath: string = ""; // data/data/包名/files目录
cachesPath: string = ""; // 网络下载默认存储在data/data/包名/cache/ImageKnifeNetworkFolder/目标md5.img下面 cachesPath: string = ""; // 网络下载默认存储在data/data/包名/cache/ImageKnifeNetworkFolder/目标md5.img下面
placeholderCacheKey: string = "";
retryholderCacheKey: string = "";
errorholderCacheKey: string = "";
// string类型占位图相关缓存key值
placeholderRegisterCacheKey: string = "";
placeholderRegisterMemoryCacheKey: string = "";
fallbackCacheKey: string = "";
// 自定义缓存关键字 // 自定义缓存关键字
signature?: ObjectKey; signature?: ObjectKey;
// 设置是否使用应用自定义的方式加载图片
customGetImage?: (context: Context, src: string) => Promise<DataFetchResult>;
// 下载原始文件地址 // 下载原始文件地址
downloadFilePath: string = ""; downloadFilePath: string = "";
//磁盘缓存文件路径
diskMemoryCachePath: string ="";
// 网络文件下载统一存放 // 网络文件下载统一存放
networkCacheFolder: string = "ImageKnifeNetworkFolder" networkCacheFolder: string = "ImageKnifeNetworkFolder"
// 主线图片 状态变化 是否加载完成 // 主线图片 状态变化 是否加载完成
// 主图未加载成功 显示占位图 主图加载成功不展示占位图 // 主图未加载成功 显示占位图 主图加载成功不展示占位图
loadMainReady = false; loadMainReady = false;
// 失败占位图展示状态 当true 表示主图加载失败需要展示失败占位图 // 失败占位图展示状态 当true 表示主图加载失败需要展示失败占位图
loadErrorReady = false; loadErrorReady = false;
// 重试占位图展示状态 当true 表示主图加载失败需要展示失败占位图 // 重试占位图展示状态 当true 表示主图加载失败需要展示失败占位图
loadRetryReady = false; loadRetryReady = false;
// 后备回调符展示状态 当true 表占位图加载失败需要展示后备回调符
loadFallBackReady = false;
// 缩略图展示 // 缩略图展示
loadThumbnailReady = false; loadThumbnailReady = false;
detachFromLayout: DetachFromLayout = {
detachFromLayout:DetachFromLayout = { detach: () => {
detach: ()=>{ let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
let imageKnife:ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife(); if (imageKnife != undefined) {
if(imageKnife != undefined) {
imageKnife.remove(this.uuid); imageKnife.remove(this.uuid);
} }
} }
} }
// module资源的需要当前的module context // module资源的需要当前的module context
moduleContext?:common.UIAbilityContext = undefined; moduleContext?: common.UIAbilityContext = undefined;
constructor() { constructor() {
// 初始化全局监听 // 初始化全局监听
this.requestListeners = new Array(); this.requestListeners = new Array();
// 初始化唯一标识,可以用这个标识找到ImageKnife中的对象
this.uuid = this.generateUUID();
let ctx = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext
let ctx = ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext if (ctx != undefined) {
if(ctx != undefined){
this.moduleContext = ctx; this.moduleContext = ctx;
} }
} }
setPriority(priority: Priority) {
generateUUID(): string { this.priority = priority
let d = new Date().getTime();
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace( new RegExp("[xy]","g"), (c) => {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
} }
setModuleContext(moduleCtx:common.UIAbilityContext){ setTransformations( array:Array<BaseTransform<PixelMap>>){
this.transformations = array;
}
generateUUID(): string {
return SparkMD5.hashBinary(JSON.stringify(this.loadSrc)) as string;
}
setModuleContext(moduleCtx: common.UIAbilityContext) {
this.moduleContext = moduleCtx; this.moduleContext = moduleCtx;
} }
getModuleContext():common.UIAbilityContext | undefined{ getModuleContext(): common.UIAbilityContext | undefined {
return this.moduleContext; return this.moduleContext;
} }
/** /**
* set image Component size * set image Component size
*/ */
setImageViewSize(imageSize:Size) { setImageViewSize(imageSize: Size) {
this.size.width = imageSize.width; this.size.width = imageSize.width;
this.size.height = imageSize.height; this.size.height = imageSize.height;
return this; return this;
@ -189,6 +234,8 @@ export class RequestOption {
load(src: string | PixelMap | Resource) { load(src: string | PixelMap | Resource) {
this.loadSrc = src; this.loadSrc = src;
// 初始化唯一标识,可以用这个标识找到ImageKnife中的对象
this.uuid = this.generateUUID();
return this; return this;
} }
@ -203,7 +250,7 @@ export class RequestOption {
} }
// 仅支持 本地图片 // 仅支持 本地图片
placeholder(src: PixelMap | Resource, func?: AsyncSuccess<ImageKnifeData>) { placeholder(src: string | PixelMap | Resource, func?: AsyncSuccess<ImageKnifeData>) {
this.placeholderSrc = src; this.placeholderSrc = src;
this.placeholderFunc = func; this.placeholderFunc = func;
return this; return this;
@ -215,6 +262,12 @@ export class RequestOption {
return this; return this;
} }
fallback(src: PixelMap | Resource, func?: AsyncSuccess<ImageKnifeData>) {
this.fallbackSrc = src;
this.fallbackFunc = func;
return this;
}
retryholder(src: PixelMap | Resource, func?: AsyncSuccess<ImageKnifeData>) { retryholder(src: PixelMap | Resource, func?: AsyncSuccess<ImageKnifeData>) {
this.retryholderSrc = src; this.retryholderSrc = src;
this.retryholderFunc = func; this.retryholderFunc = func;
@ -236,7 +289,7 @@ export class RequestOption {
} }
addListener(func: AsyncCallback<ImageKnifeData>) { addListener(func: AsyncCallback<ImageKnifeData>) {
if(this.requestListeners != undefined) { if (this.requestListeners != undefined) {
this.requestListeners?.push(func); this.requestListeners?.push(func);
} }
return this; return this;
@ -256,8 +309,8 @@ export class RequestOption {
this.onlyRetrieveFromCache = flag; this.onlyRetrieveFromCache = flag;
} }
rotateImage(degreesToRotate: number|undefined) { rotateImage(degreesToRotate: number | undefined) {
if(degreesToRotate == undefined){ if (degreesToRotate == undefined) {
return return
} }
let rotateImage = new RotateImageTransformation(degreesToRotate); let rotateImage = new RotateImageTransformation(degreesToRotate);
@ -280,8 +333,8 @@ export class RequestOption {
return this; return this;
} }
roundedCorners(obj: RoundCorner|undefined) { roundedCorners(obj: RoundCorner | undefined) {
if(obj == undefined){ if (obj == undefined) {
return return
} }
let transformation = new RoundedCornersTransformation({ let transformation = new RoundedCornersTransformation({
@ -300,8 +353,8 @@ export class RequestOption {
return this; return this;
} }
cropCircleWithBorder(border: number|undefined, obj: rgbColor|undefined) { cropCircleWithBorder(border: number | undefined, obj: rgbColor | undefined) {
if(border == undefined || obj == undefined){ if (border == undefined || obj == undefined) {
return return
} }
let transformation = new CropCircleWithBorderTransformation(border, obj) let transformation = new CropCircleWithBorderTransformation(border, obj)
@ -315,8 +368,8 @@ export class RequestOption {
return this; return this;
} }
crop(width: number|undefined, height: number|undefined, cropType: CropType|undefined) { crop(width: number | undefined, height: number | undefined, cropType: CropType | undefined) {
if(width == undefined || height == undefined || cropType == undefined){ if (width == undefined || height == undefined || cropType == undefined) {
return return
} }
let transformation = new CropTransformation(width, height, cropType) let transformation = new CropTransformation(width, height, cropType)
@ -330,8 +383,8 @@ export class RequestOption {
return this; return this;
} }
brightnessFilter(brightness: number|undefined) { brightnessFilter(brightness: number | undefined) {
if(brightness == undefined){ if (brightness == undefined) {
return return
} }
let transformation = new BrightnessFilterTransformation(brightness) let transformation = new BrightnessFilterTransformation(brightness)
@ -339,8 +392,8 @@ export class RequestOption {
return this; return this;
} }
contrastFilter(contrast: number|undefined) { contrastFilter(contrast: number | undefined) {
if(contrast == undefined){ if (contrast == undefined) {
return return
} }
let transformation = new ContrastFilterTransformation(contrast) let transformation = new ContrastFilterTransformation(contrast)
@ -366,17 +419,22 @@ export class RequestOption {
return this; return this;
} }
blur(radius: number|undefined) { blur(radius: number | undefined, sampling?: number) {
if(radius == undefined){ if (radius == undefined) {
return return
} }
let transformation = new BlurTransformation(radius) if (sampling == undefined) {
this.transformations.push(transformation); let transformation = new BlurTransformation(radius)
this.transformations.push(transformation);
} else {
let transformation = new BlurTransformation(radius, sampling)
this.transformations.push(transformation);
}
return this; return this;
} }
pixelationFilter(pixel: number|undefined) { pixelationFilter(pixel: number | undefined) {
if(pixel == undefined){ if (pixel == undefined) {
return return
} }
let transformation = new PixelationFilterTransformation(pixel) let transformation = new PixelationFilterTransformation(pixel)
@ -384,8 +442,8 @@ export class RequestOption {
return this; return this;
} }
swirlFilter(degree: number|undefined) { swirlFilter(degree: number | undefined) {
if(degree == undefined){ if (degree == undefined) {
return return
} }
let transformation = new SwirlFilterTransformation(degree) let transformation = new SwirlFilterTransformation(degree)
@ -393,8 +451,8 @@ export class RequestOption {
return this; return this;
} }
mask(maskResource: Resource|undefined) { mask(maskResource: Resource | undefined) {
if(maskResource == undefined){ if (maskResource == undefined) {
return return
} }
let transformation = new MaskTransformation(maskResource) let transformation = new MaskTransformation(maskResource)
@ -402,8 +460,8 @@ export class RequestOption {
return this; return this;
} }
kuwaharaFilter(radius: number|undefined) { kuwaharaFilter(radius: number | undefined) {
if(radius == undefined){ if (radius == undefined) {
return return
} }
let transformation = new KuwaharaFilterTransform(radius); let transformation = new KuwaharaFilterTransform(radius);
@ -411,8 +469,8 @@ export class RequestOption {
return this; return this;
} }
toonFilter(threshold: number|undefined, quantizationLevels: number|undefined) { toonFilter(threshold: number | undefined, quantizationLevels: number | undefined) {
if(threshold == undefined || quantizationLevels == undefined){ if (threshold == undefined || quantizationLevels == undefined) {
return return
} }
let transformation = new ToonFilterTransform(threshold, quantizationLevels); let transformation = new ToonFilterTransform(threshold, quantizationLevels);
@ -420,8 +478,8 @@ export class RequestOption {
return this; return this;
} }
vignetteFilter(centerPoint: Array<number>|undefined, vignetteColor: Array<number>|undefined, vignetteSpace: Array<number>|undefined) { vignetteFilter(centerPoint: Array<number> | undefined, vignetteColor: Array<number> | undefined, vignetteSpace: Array<number> | undefined) {
if(centerPoint == undefined || vignetteColor == undefined || vignetteSpace == undefined){ if (centerPoint == undefined || vignetteColor == undefined || vignetteSpace == undefined) {
return return
} }
let transformation = new VignetteFilterTransform(centerPoint, vignetteColor, vignetteSpace); let transformation = new VignetteFilterTransform(centerPoint, vignetteColor, vignetteSpace);
@ -438,6 +496,7 @@ export class RequestOption {
this.transformations = inputs; this.transformations = inputs;
return this; return this;
} }
// 开启GPU变换绘制 // 开启GPU变换绘制
enableGPU() { enableGPU() {
this.gpuEnabled = true; this.gpuEnabled = true;
@ -445,72 +504,82 @@ export class RequestOption {
} }
// 占位图解析成功 // 占位图解析成功
placeholderOnComplete = (imageKnifeData: ImageKnifeData)=> { placeholderOnComplete = (imageKnifeData:ImageKnifeData) => {
LogUtil.log("placeholderOnComplete has called!"); LogUtil.log("placeholderOnComplete has called!");
LogUtil.log("Main Image is Ready:" + this.loadMainReady); LogUtil.log("Main Image is Ready:" + this.loadMainReady);
if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady) && !this.loadThumbnailReady) { if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady) && !this.loadThumbnailReady) {
// 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图 // 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
if(this.placeholderSrc != undefined) { if (this.placeholderSrc != undefined) {
this.placeholderFunc?.asyncSuccess(imageKnifeData) this.placeholderFunc?.asyncSuccess(imageKnifeData)
} }
} }
} }
// 占位图解析失败 // 占位图解析失败
placeholderOnError = (error:BusinessError|string)=>{ placeholderOnError = (error: BusinessError | string) => {
LogUtil.log("占位图解析失败 error =" + error) LogUtil.log("占位图解析失败 error =" + error)
} }
// 缩略图解析成功 // 缩略图解析成功
thumbholderOnComplete = (imageKnifeData: ImageKnifeData)=> { thumbholderOnComplete = (value: PixelMap | GIFFrame[]) => {
let imageKnifeData = new ImageKnifeData();
if ((typeof (value as PixelMap).isEditable) == 'boolean') {
imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value as PixelMap);
} else {
imageKnifeData = ImageKnifeData.createImageGIFFrame(ImageKnifeType.GIFFRAME, value as GIFFrame[]);
}
if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady)) { if (!this.loadMainReady && !(this.loadErrorReady || this.loadRetryReady)) {
// 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图 // 主图未加载成功,并且未加载失败 显示占位图 主图加载成功或者加载失败后=>不展示占位图
if(this.thumbHolderFunc != undefined) { if (this.thumbHolderFunc != undefined) {
this.thumbHolderFunc?.asyncSuccess(imageKnifeData) this.thumbHolderFunc?.asyncSuccess(imageKnifeData)
} }
} }
} }
// 缩略图解析失败 // 缩略图解析失败
thumbholderOnError=(error? :BusinessError|string)=>{ thumbholderOnError = (error?: BusinessError | string) => {
LogUtil.log("缩略图解析失败 error =" + error) LogUtil.log("缩略图解析失败 error =" + error)
} }
// 加载失败 占位图解析成功 // 加载失败 占位图解析成功
errorholderOnComplete = (imageKnifeData: ImageKnifeData)=> { errorholderOnComplete = (imageKnifeData:ImageKnifeData) => {
// 如果有错误占位图 先解析并保存在RequestOption中 等到加载失败时候进行调用 // 如果有错误占位图 先解析并保存在RequestOption中 等到加载失败时候进行调用
this.errorholderData = imageKnifeData; this.errorholderData = imageKnifeData;
if (this.loadErrorReady) { if (this.loadErrorReady) {
if(this.errorholderFunc != undefined) { if (this.errorholderFunc != undefined) {
this.errorholderFunc.asyncSuccess(imageKnifeData) this.errorholderFunc.asyncSuccess(imageKnifeData)
} }
} }
} }
// 加载失败 占位图解析失败 // 加载失败 占位图解析失败
errorholderOnError = (error:BusinessError|string)=> { errorholderOnError = (error: BusinessError | string) => {
LogUtil.log("失败占位图解析失败 error =" + error) LogUtil.log("失败占位图解析失败 error =" + error)
} }
retryholderOnComplete = (imageKnifeData:ImageKnifeData) => {
retryholderOnComplete = (imageKnifeData: ImageKnifeData)=>{
this.retryholderData = imageKnifeData; this.retryholderData = imageKnifeData;
if (this.loadRetryReady) { if (this.loadRetryReady) {
if(this.retryholderFunc != undefined) { if (this.retryholderFunc != undefined) {
this.retryholderFunc?.asyncSuccess(imageKnifeData) this.retryholderFunc?.asyncSuccess(imageKnifeData)
} }
} }
} }
retryholderOnError = (error: BusinessError | string) => {
retryholderOnError = (error:BusinessError|string)=>{
LogUtil.log("重试占位图解析失败 error =" + error) LogUtil.log("重试占位图解析失败 error =" + error)
} }
//占位图加载失败 后备回调符解析成功
loadComplete = (imageKnifeData: ImageKnifeData)=>{ fallbackOnComplete = (imageKnifeData:ImageKnifeData) => {
this.fallbackData = imageKnifeData;
if (this.loadFallBackReady) {
if (this.fallbackFunc != undefined) {
this.fallbackFunc?.asyncSuccess(imageKnifeData);
}
}
}
// 后备回调符解析失败
fallbackOnError = (error: BusinessError | string) => {
LogUtil.error("失败占位图解析失败 error =" + JSON.stringify(error));
}
loadComplete = (imageKnifeData: ImageKnifeData) => {
this.loadMainReady = true; this.loadMainReady = true;
// 三级缓存数据加载成功 // 三级缓存数据加载成功
if(this.requestListeners != undefined) { if (this.requestListeners != undefined) {
for (let i = 0;i < this.requestListeners.length; i++) { for (let i = 0; i < this.requestListeners.length; i++) {
let requestListener = this.requestListeners[i]; let requestListener = this.requestListeners[i];
let boolInterception = requestListener.callback("", imageKnifeData); let boolInterception = requestListener.callback("", imageKnifeData);
if (boolInterception) { if (boolInterception) {
@ -518,32 +587,52 @@ export class RequestOption {
} }
} }
} }
//输出缓存相关内容和信息
if (this.allCacheInfoCallback) {
// 内存缓存
let allCacheInfo: AllCacheInfo = {
memoryCacheInfo: { key: '', data: new ImageKnifeData() },
resourceCacheInfo: { key: '', path: '' },
dataCacheInfo: { key: '', path: '' }
};
allCacheInfo.memoryCacheInfo = {
key: this.generateCacheKey,
data: imageKnifeData
}
let mDiskCacheProxy = new DiskCacheProxy(DiskLruCache.create(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext))
// 变换后缓存
allCacheInfo.resourceCacheInfo = {
key: SparkMD5.hashBinary(this.generateResourceKey) as string,
path: (mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.generateResourceKey)) as string
};
if(imageKnifeData.waitSaveDisk){ // 原图缓存
allCacheInfo.dataCacheInfo = {
key: SparkMD5.hashBinary(this.generateDataKey) as string,
path: (mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.generateDataKey)) as string
}
this.allCacheInfoCallback.callback(allCacheInfo);
}
if (imageKnifeData.waitSaveDisk) {
// 等落盘结束后主动调用#removeCurrentAndSearchNext方法 // 等落盘结束后主动调用#removeCurrentAndSearchNext方法
}else{ } else {
// 非落盘情况,直接进行寻找下一个加载 // 非落盘情况,直接进行寻找下一个加载
let imageKnife:ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife(); let imageKnife: ImageKnife | undefined = ImageKnifeGlobal.getInstance().getImageKnife();
if(imageKnife != undefined) { if (imageKnife != undefined) {
imageKnife.removeRunning(this); imageKnife.removeRunning(this);
} }
} }
} }
// 图片文件落盘之后会自动去寻找下一个数据加载 // 图片文件落盘之后会自动去寻找下一个数据加载
removeCurrentAndSearchNext =()=>{ removeCurrentAndSearchNext = () => {
if(ImageKnifeGlobal.getInstance().getImageKnife() != undefined) { if (ImageKnifeGlobal.getInstance().getImageKnife() != undefined) {
(ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this); (ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this);
} }
} }
loadError = (err: BusinessError | string) => {
loadError = (err:BusinessError|string)=>{
LogUtil.log("loadError:" + err); LogUtil.log("loadError:" + err);
// 失败占位图展示规则 // 失败占位图展示规则
if (this.retryholderFunc) { if (this.retryholderFunc) {
@ -552,17 +641,32 @@ export class RequestOption {
if (this.retryholderData != null) { if (this.retryholderData != null) {
this.retryholderFunc.asyncSuccess(this.retryholderData) this.retryholderFunc.asyncSuccess(this.retryholderData)
} }
} else if (!this.retryholderFunc && !this.placeholderFunc && this.fallbackFunc) {
this.loadFallBackReady = true;
if (this.fallbackData != null) {
this.fallbackFunc.asyncSuccess(this.fallbackData);
}
} else { } else {
// 失败图层标记,如果已经有数据直接展示失败图层 // 失败图层标记,如果已经有数据直接展示失败图层
this.loadErrorReady = true; this.loadErrorReady = true;
if (this.errorholderData != null) { if (this.errorholderData != null) {
if(this.errorholderFunc != undefined) { if (this.errorholderFunc != undefined) {
this.errorholderFunc.asyncSuccess(this.errorholderData) this.errorholderFunc.asyncSuccess(this.errorholderData)
} }
} }
} }
if (this.requestListeners != undefined) {
for (let i = 0; i < this.requestListeners.length; i++) {
let requestListener = this.requestListeners[i];
let boolInterception = requestListener.callback(err as string, new ImageKnifeData());
if (boolInterception) {
break;
}
}
}
// 加载失败之后 // 加载失败之后
if(ImageKnifeGlobal.getInstance().getImageKnife() != undefined) { if (ImageKnifeGlobal.getInstance().getImageKnife() != undefined) {
(ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this); (ImageKnifeGlobal.getInstance().getImageKnife())?.removeRunning(this);
} }
} }

View File

@ -0,0 +1,197 @@
/*
* 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 { ObjectKey } from './ObjectKey';
import common from '@ohos.app.ability.common'
import { collections } from '@kit.ArkTS';
import { IDataFetch } from './networkmanage/IDataFetch';
import { DiskLruCache } from '../cache/DiskLruCache';
import { DownloadClient } from './networkmanage/DownloadClient';
@Sendable
export class SendableData{
private usageType: string = '';
private displayProgress: boolean = false
private uuid: string = '' // 唯一标识
private dontAnimateFlag: boolean = false;
private thumbSizeMultiplier: number = 0;
private thumbDelayTime: number = 1000;
private onlyRetrieveFromCache: boolean = false;
private isCacheable: boolean = true;
private gpuEnabled: boolean = false;
private generateCacheKey: string = "";
private generateResourceKey: string = "";
private generateDataKey: string = "";
private signature?: ObjectKey;
private transformations: collections.Array<collections.Array<string>> = new collections.Array<collections.Array<string>>();
private diskMemoryCachePath: string = '';
private diskMemoryCache?: DiskLruCache;
private dataFetch: IDataFetch = new DownloadClient();
private placeholderRegisterCacheKey: string = "";
private placeholderRegisterMemoryCacheKey: string = "";
public setDataFetch(value: IDataFetch) {
this.dataFetch = value;
}
public getDataFetch(): IDataFetch{
return this.dataFetch;
}
public setDiskMemoryCachePath(value: string) {
this.diskMemoryCachePath = value;
}
public getDiskMemoryCachePath(): string{
return this.diskMemoryCachePath;
}
public setDiskMemoryCache(value: DiskLruCache) {
this.diskMemoryCache = value;
}
public getDiskMemoryCache(): DiskLruCache | undefined{
return this.diskMemoryCache;
}
public setTransformations(value: collections.Array<collections.Array<string>>) {
this.transformations = value;
}
public getTransformations(): collections.Array<collections.Array<string>>{
return this.transformations;
}
public setSignature(value: ObjectKey | undefined) {
this.signature = value;
}
public getSignature(): ObjectKey | undefined{
return this.signature;
}
public setGenerateDataKey(value: string) {
this.generateDataKey = value;
}
public getGenerateDataKey(): string {
return this.generateDataKey;
}
public setGenerateResourceKey(value: string) {
this.generateResourceKey = value;
}
public getGenerateResourceKey(): string {
return this.generateResourceKey;
}
public setGenerateCacheKey(value: string) {
this.generateCacheKey = value;
}
public getGenerateCacheKey(): string {
return this.generateCacheKey;
}
public setGpuEnabled(value: boolean) {
this.gpuEnabled = value;
}
public getGpuEnabled(): boolean {
return this.gpuEnabled;
}
public setIsCacheable(value: boolean) {
this.isCacheable = value;
}
public getIsCacheable(): boolean {
return this.isCacheable;
}
public setOnlyRetrieveFromCache(value: boolean) {
this.onlyRetrieveFromCache = value;
}
public getOnlyRetrieveFromCache(): boolean {
return this.onlyRetrieveFromCache;
}
public setThumbDelayTime(value: number) {
this.thumbDelayTime = value;
}
public getThumbDelayTime(): number {
return this.thumbDelayTime;
}
public setThumbSizeMultiplier(value: number) {
this.thumbSizeMultiplier = value;
}
public getThumbSizeMultiplier(): number {
return this.thumbSizeMultiplier;
}
public setDontAnimateFlag(value: boolean) {
this.dontAnimateFlag = value;
}
public getDontAnimateFlag(): boolean {
return this.dontAnimateFlag;
}
public setUuid(value: string) {
this.uuid = value;
}
public getUuid(): string {
return this.uuid;
}
public setDisplayProgress(value: boolean) {
this.displayProgress = value;
}
public getDisplayProgress(): boolean {
return this.displayProgress;
}
public setUsageType(value: string) {
this.usageType = value;
}
public getUsageType(): string {
return this.usageType;
}
public setPlaceHolderRegisterCacheKey(value: string) {
this.placeholderRegisterCacheKey = value;
}
public getPlaceHolderRegisterCacheKey(): string {
return this.placeholderRegisterCacheKey;
}
public setPlaceHolderRegisterMemoryCacheKey(value: string) {
this.placeholderRegisterMemoryCacheKey = value;
}
public getPlaceHolderRegisterMemoryCacheKey(): string {
return this.placeholderRegisterMemoryCacheKey;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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 { ObjectKey } from './ObjectKey';
import { Priority, Size } from '../imageknife/RequestOption'
import common from '@ohos.app.ability.common'
import { MResource } from './utils/MResource';
import { DataFetchResult } from './networkmanage/DataFetchResult';
export class TaskParams {
headers: Map<string, Object> = new Map<string, Object>();
moduleContext?: common.UIAbilityContext = undefined;
priority: Priority = Priority.MEDIUM // 优先级
size: Size = { width: -1, height: -1 };
loadSrc: string | PixelMap | MResource = "";
placeholderSrc: string | PixelMap | MResource | undefined = undefined;
errorholderSrc: PixelMap | MResource | undefined = undefined;
retryholderSrc: PixelMap | MResource | undefined = undefined;
fallbackSrc: PixelMap | MResource | undefined = undefined;
customGetImage?: (context: Context, loadSrc: string) => Promise<DataFetchResult>;
}

View File

@ -14,5 +14,11 @@
*/ */
export class Constants { export class Constants {
public static PROJECT_TAG: string= "ImageKnife_js" public static PROJECT_TAG: string = "ImageKnife_js"
public static PROGRESS_EMITTER: string = "progressEmitter"
public static PLACE_HOLDER: string = "placeholder"
public static RETRY_HOLDER: string = "retryholder"
public static ERROR_HOLDER: string = "errorholder"
public static MAIN_HOLDER: string = "main"
public static FALL_BACK: string = "fallback"
} }

View File

@ -31,21 +31,15 @@ export class ErrorHolderManager<T> {
this.options = option; this.options = option;
} }
static execute(option: RequestOption) { process = (onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
let manager:ErrorHolderManager<ImageKnifeData> = new ErrorHolderManager<ImageKnifeData>(option);
return new Promise(manager.process)
.then(option.errorholderOnComplete).catch(option.errorholderOnError);
}
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
this.displayErrorholder(onComplete, onError); this.displayErrorholder(onComplete, onError);
} }
private displayErrorholder(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private displayErrorholder(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) {
LogUtil.log("displayErrorholder") LogUtil.log("displayErrorholder")
if ((typeof (this.options.errorholderSrc as image.PixelMap).isEditable) == 'boolean') { if ((typeof (this.options.errorholderSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.errorholderSrc as PixelMap) let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.errorholderSrc as PixelMap)
onComplete(imageKnifeData); onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
} else if (typeof this.options.errorholderSrc == 'string') { } else if (typeof this.options.errorholderSrc == 'string') {
} else { } else {
@ -67,6 +61,7 @@ export class ErrorHolderManager<T> {
case SupportFormat.gif: case SupportFormat.gif:
case SupportFormat.tiff: case SupportFormat.tiff:
case SupportFormat.webp: case SupportFormat.webp:
case SupportFormat.heic:
this.mediaImageProcess(onComplete, onError, arraybuffer, typeValue) this.mediaImageProcess(onComplete, onError, arraybuffer, typeValue)
break; break;
default: default:
@ -89,16 +84,16 @@ export class ErrorHolderManager<T> {
} }
} }
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private svgProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl:SVGParseImpl = new SVGParseImpl() let svgParseImpl:SVGParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError); svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
} }
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private mediaImageProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let parseImageUtil = new ParseImageUtil() let parseImageUtil = new ParseImageUtil()
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value) let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData) onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap)
} }
parseImageUtil.parseImage(arraybuffer, success, onError) parseImageUtil.parseImage(arraybuffer, success, onError)
} }

View File

@ -25,6 +25,9 @@ import {LogUtil} from '../../imageknife/utils/LogUtil'
import resourceManager from '@ohos.resourceManager'; import resourceManager from '@ohos.resourceManager';
import image from "@ohos.multimedia.image" import image from "@ohos.multimedia.image"
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import { GIFFrame } from '../utils/gif/GIFFrame'
import { DiskLruCache } from '../../cache/DiskLruCache'
export class PlaceHolderManager<T> { export class PlaceHolderManager<T> {
private options: RequestOption; private options: RequestOption;
@ -32,23 +35,84 @@ export class PlaceHolderManager<T> {
this.options = option; this.options = option;
} }
static execute(option: RequestOption) {
let manager:PlaceHolderManager<ImageKnifeData> = new PlaceHolderManager<ImageKnifeData>(option);
return new Promise(manager.process)
.then(option.placeholderOnComplete).catch(option.placeholderOnError);
}
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{ process = (onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
this.displayPlaceholder(onComplete, onError); this.displayPlaceholder(onComplete, onError);
} }
private displayPlaceholder(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){ private displayPlaceholder(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){
LogUtil.log("displayPlaceholder") LogUtil.log("ImageKnife displayPlaceholder")
if ((typeof (this.options.placeholderSrc as image.PixelMap).isEditable) == 'boolean') { if ((typeof (this.options.placeholderSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.placeholderSrc as PixelMap) let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.placeholderSrc as PixelMap)
onComplete(imageKnifeData); onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
} else if (typeof this.options.placeholderSrc == 'string') { } else if (typeof this.options.placeholderSrc == 'string') {
if (typeof this.options.placeholderCacheKey == 'string' && this.options.placeholderCacheKey != '') {
return;
}
let cached = DiskLruCache.getFileCacheByFile(this.options.diskMemoryCachePath,this.options.placeholderRegisterCacheKey);
if (cached != null && cached.byteLength > 0) {
let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(cached);
switch (typeValue) {
case SupportFormat.svg:
this.svgProcess(onComplete, onError, cached, typeValue);
break;
case SupportFormat.jpg:
case SupportFormat.png:
case SupportFormat.bmp:
case SupportFormat.gif:
case SupportFormat.tiff:
case SupportFormat.webp:
case SupportFormat.heic:
this.mediaImageProcess(onComplete, onError, cached, typeValue);
break;
default:
onError("PlaceHolderManager 文件类型不支持");
break;
}
} else {
if ((typeof (this.options.fallbackSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.fallbackSrc as PixelMap);
onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
} else {
let res = this.options.fallbackSrc as Resource;
if (typeof res.id != 'undefined' && typeof res.id != 'undefined') {
let resourceFetch = new ParseResClient();
let suc = (arraybuffer:ArrayBuffer) => {
let fileTypeUtil: FileTypeUtil = new FileTypeUtil();
let typeValue: string | null = fileTypeUtil.getFileType(arraybuffer);
if (typeValue != null) {
switch (typeValue) {
case SupportFormat.svg:
this.svgProcess(onComplete, onError, arraybuffer, typeValue);
break;
case SupportFormat.jpg:
case SupportFormat.png:
case SupportFormat.bmp:
case SupportFormat.gif:
case SupportFormat.tiff:
case SupportFormat.webp:
this.mediaImageProcess(onComplete, onError, arraybuffer, typeValue);
break;
default:
onError("FallBackManager 文件类型不支持");
break;
}
}else{
onError("FallBackManager 文件类型为null,请检查数据源arraybuffer");
}
}
let ctx = this.options.getModuleContext();
if(ctx != undefined){
resourceFetch.loadResource(ctx,res, suc, onError);
}else{
onError("FallBackManager moduleContext is undefined,please check it!");
}
} else {
onError("FallBackManager 输入参数有问题!");
}
}
}
} else { } else {
let res = this.options.placeholderSrc as Resource; let res = this.options.placeholderSrc as Resource;
if (typeof res.id != 'undefined' && typeof res.id != 'undefined') { if (typeof res.id != 'undefined' && typeof res.id != 'undefined') {
@ -66,6 +130,7 @@ export class PlaceHolderManager<T> {
case SupportFormat.gif: case SupportFormat.gif:
case SupportFormat.tiff: case SupportFormat.tiff:
case SupportFormat.webp: case SupportFormat.webp:
case SupportFormat.heic:
this.mediaImageProcess(onComplete, onError, arraybuffer, typeValue) this.mediaImageProcess(onComplete, onError, arraybuffer, typeValue)
break; break;
default: default:
@ -87,16 +152,16 @@ export class PlaceHolderManager<T> {
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private svgProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl:SVGParseImpl = new SVGParseImpl() let svgParseImpl:SVGParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError); svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
} }
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private mediaImageProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let parseImageUtil:ParseImageUtil = new ParseImageUtil() let parseImageUtil:ParseImageUtil = new ParseImageUtil()
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value) let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData) onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap)
} }
parseImageUtil.parseImage(arraybuffer, success, onError) parseImageUtil.parseImage(arraybuffer, success, onError)
} }

View File

@ -32,21 +32,15 @@ export class RetryHolderManager<T> {
this.options = option; this.options = option;
} }
static execute(option: RequestOption) { process = (onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
let manager:RetryHolderManager<ImageKnifeData> = new RetryHolderManager<ImageKnifeData>(option);
return new Promise(manager.process)
.then(option.retryholderOnComplete).catch(option.retryholderOnError);
}
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{
this.displayRetryholder(onComplete, onError); this.displayRetryholder(onComplete, onError);
} }
private displayRetryholder(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){ private displayRetryholder(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){
LogUtil.log("displayRetryholder") LogUtil.log("ImageKnife displayRetryholder")
if ((typeof (this.options.retryholderSrc as image.PixelMap).isEditable) == 'boolean') { if ((typeof (this.options.retryholderSrc as image.PixelMap).isEditable) == 'boolean') {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.placeholderSrc as PixelMap) let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, this.options.placeholderSrc as PixelMap)
onComplete(imageKnifeData); onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap);
} else if (typeof this.options.placeholderSrc == 'string') { } else if (typeof this.options.placeholderSrc == 'string') {
} else { } else {
@ -66,6 +60,7 @@ export class RetryHolderManager<T> {
case SupportFormat.gif: case SupportFormat.gif:
case SupportFormat.tiff: case SupportFormat.tiff:
case SupportFormat.webp: case SupportFormat.webp:
case SupportFormat.heic:
this.mediaImageProcess(onComplete, onError, arraybuffer, typeValue) this.mediaImageProcess(onComplete, onError, arraybuffer, typeValue)
break; break;
default: default:
@ -87,16 +82,16 @@ export class RetryHolderManager<T> {
private svgProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private svgProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let svgParseImpl = new SVGParseImpl() let svgParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError); svgParseImpl.parseSvg(this.options,arraybuffer, onComplete,onError);
} }
private mediaImageProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) { private mediaImageProcess(onComplete:(value:PixelMap)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string) {
let parseImageUtil = new ParseImageUtil() let parseImageUtil = new ParseImageUtil()
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value) let imageKnifeData = ImageKnifeData.createImagePixelMap(ImageKnifeType.PIXELMAP, value)
onComplete(imageKnifeData) onComplete(imageKnifeData?.drawPixelMap?.imagePixelMap as PixelMap)
} }
parseImageUtil.parseImage(arraybuffer, success, onError) parseImageUtil.parseImage(arraybuffer, success, onError)
} }

View File

@ -0,0 +1,113 @@
/*
* 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 { IDataFetch } from '../networkmanage/IDataFetch'
import { RequestOption } from '../RequestOption'
import { RequestData } from './RequestData'
import { ImageKnifeGlobal } from '../ImageKnifeGlobal'
import common from '@ohos.app.ability.common'
import http from '@ohos.net.http'
import { DataFetchResult } from './DataFetchResult'
@Sendable
export class CustomDataFetchClient implements IDataFetch {
async loadData(request: RequestOption) {
let result: DataFetchResult = new DataFetchResult();
if (!request || typeof request.loadSrc !== 'string') {
result.error = 'CustomDataFetchClient request or loadSrc error.';
return result;
}
// 自定义单个图片的网络栈
if (request.customGetImage) {
return await request.customGetImage(ImageKnifeGlobal.getInstance()
.getHapContext() as common.UIAbilityContext, request.loadSrc);
}
// 所有图片的网络栈
try {
let httpRequest = http.createHttp()
let arrayBuffers = new Array<ArrayBuffer>();
httpRequest.on('headersReceive', (header: Object) => {
// 跟服务器连接成功准备下载
if (request.progressFunc) {
// 进度条为0
request.progressFunc.asyncSuccess(0)
}
})
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
// 下载数据流多次返回
arrayBuffers.push(data);
})
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 (request.progressFunc) {
request.progressFunc.asyncSuccess(percent)
}
}
})
httpRequest.on('dataEnd', () => {
// 下载完毕
})
const headerObj: Record<string, Object> = {}
request.headers.forEach((value, key) => {
headerObj[key] = value
})
const data = await httpRequest.requestInStream(request.loadSrc as string, {
header: headerObj,
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
connectTimeout: 60000, // 可选 默认60000ms
readTimeout: 0, // 可选, 默认为60000ms
usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
usingCache: false
}).catch((err: Error) => {
result.error = 'CustomDataFetchClient has error, http code = ' + JSON.stringify(err);
})
if (data == 200) {
result.data = this.combineArrayBuffers(arrayBuffers);
} else {
result.error = 'CustomDataFetchClient resultCode error, code = ' + data;
}
console.log('TestCustomDataFetch all onComplete, code = ' + data + ',length = ' + result.data?.byteLength);
} catch (err) {
result.error = 'CustomDataFetchClient catch err request uuid =' + request.uuid;
}
return result;
}
combineArrayBuffers(arrayBuffers: ArrayBuffer[]): ArrayBuffer {
// 计算多个ArrayBuffer的总字节大小
let totalByteLength = 0;
for (const arrayBuffer of arrayBuffers) {
totalByteLength += arrayBuffer.byteLength;
}
// 创建一个新的ArrayBuffer
const combinedArrayBuffer = new ArrayBuffer(totalByteLength);
// 创建一个Uint8Array来操作新的ArrayBuffer
const combinedUint8Array = new Uint8Array(combinedArrayBuffer);
// 依次复制每个ArrayBuffer的内容到新的ArrayBuffer中
let offset = 0;
for (const arrayBuffer of arrayBuffers) {
const sourceUint8Array = new Uint8Array(arrayBuffer);
combinedUint8Array.set(sourceUint8Array, offset);
offset += sourceUint8Array.length;
}
return combinedArrayBuffer;
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2021 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 DataFetchResult{
data?: ArrayBuffer;
error?: string;
}

View File

@ -23,29 +23,42 @@ import loadRequest from '@ohos.request';
import { ImageKnifeGlobal } from '../ImageKnifeGlobal' import { ImageKnifeGlobal } from '../ImageKnifeGlobal'
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { NetworkDownloadClient } from './NetworkDownloadClient' import { NetworkDownloadClient } from './NetworkDownloadClient'
import { DataFetchResult } from './DataFetchResult'
// 数据加载器 // 数据加载器
@Sendable
export class DownloadClient implements IDataFetch { export class DownloadClient implements IDataFetch {
private networkDownloadClient = new NetworkDownloadClient(); private networkDownloadClient:NetworkDownloadClient = new NetworkDownloadClient();
private httpDownloadClient = new HttpDownloadClient(); private httpDownloadClient:HttpDownloadClient = new HttpDownloadClient();
private localFileClient = new LoadLocalFileClient(); private localFileClient:LoadLocalFileClient = new LoadLocalFileClient();
private dataShareFileClient = new LoadDataShareFileClient(); private dataShareFileClient:LoadDataShareFileClient = new LoadDataShareFileClient();
loadData(request: RequestOption, onCompleteFunction:(img: ArrayBuffer) => void, onErrorFunction: (err: string) => void) { async loadData(request: RequestOption): Promise<DataFetchResult> {
if (typeof request.loadSrc == 'string') { if (typeof request.loadSrc == 'string') {
let fileDir:string = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).filesDir as string; if (this.isLocalLoadSrc(ImageKnifeGlobal.getInstance().getHapContext(), request.loadSrc)) {
let cacheDir:string = (ImageKnifeGlobal.getInstance().getHapContext() as common.UIAbilityContext).cacheDir as string
if (request.loadSrc.startsWith(fileDir) ||
request.loadSrc.startsWith(cacheDir)) {
// 本地沙盒 // 本地沙盒
this.localFileClient.loadData(request, onCompleteFunction, onErrorFunction) return this.localFileClient.loadData(request)
} else if (request.loadSrc.startsWith('datashare://') || request.loadSrc.startsWith('file://')) { } else if (request.loadSrc.startsWith('datashare://') || request.loadSrc.startsWith('file://')) {
this.dataShareFileClient.loadData(request, onCompleteFunction, onErrorFunction) return this.dataShareFileClient.loadData(request)
} else { } else {
// 网络下载 // 网络下载
this.httpDownloadClient.loadData(request, onCompleteFunction, onErrorFunction) return await this.httpDownloadClient.loadData(request);
} }
}else{
let result:DataFetchResult = new DataFetchResult()
result.error ="参数错误!";
return result;
} }
} }
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;
}
} }

View File

@ -13,76 +13,68 @@
* limitations under the License. * limitations under the License.
*/ */
import { IDataFetch } from '../networkmanage/IDataFetch' import { IDataFetch } from '../networkmanage/IDataFetch'
import { RequestOption } from '../RequestOption' import { RequestOption } from '../RequestOption'
import { SparkMD5 } from '../../3rd_party/sparkmd5/spark-md5'
import { FileUtils } from '../../cache/FileUtils'
import loadRequest from '@ohos.request';
import { LogUtil } from '../utils/LogUtil'
import { ImageKnifeGlobal } from '../ImageKnifeGlobal'
import common from '@ohos.app.ability.common'
import { BusinessError } from '@ohos.base'
import http from '@ohos.net.http' import http from '@ohos.net.http'
// 数据加载器 import { RequestData } from './RequestData'
class RequestData{ import { DataFetchResult } from './DataFetchResult'
receiveSize: number = 2000
totalSize: number = 2000
}
@Sendable
export class HttpDownloadClient implements IDataFetch { export class HttpDownloadClient implements IDataFetch {
loadData(request: RequestOption, onComplete: (img: ArrayBuffer) => void, onError: (err: string) => void) { async loadData(request: RequestOption) {
try { let result:DataFetchResult = new DataFetchResult();
let httpRequest = http.createHttp() try {
let arrayBuffers = new Array<ArrayBuffer>(); let httpRequest = http.createHttp()
httpRequest.on('headersReceive', (header: Object) => { let arrayBuffers = new Array<ArrayBuffer>();
// 跟服务器连接成功准备下载 httpRequest.on('headersReceive', (header: Object) => {
if (request.progressFunc) { // 跟服务器连接成功准备下载
// 进度条为0 if (request.progressFunc) {
request.progressFunc.asyncSuccess(0) // 进度条为0
} request.progressFunc.asyncSuccess(0)
}) }
httpRequest.on('dataReceive', (data: ArrayBuffer) => { })
// 下载数据流多次返回 httpRequest.on('dataReceive', (data: ArrayBuffer) => {
arrayBuffers.push(data); // 下载数据流多次返回
}) arrayBuffers.push(data);
})
httpRequest.on('dataReceiveProgress', (data: RequestData) => { httpRequest.on('dataReceiveProgress', (data: RequestData) => {
// 下载进度 // 下载进度
if(data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number') ) { if (data != undefined && (typeof data.receiveSize == 'number') && (typeof data.totalSize == 'number')) {
let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100) let percent = Math.round(((data.receiveSize * 1.0) / (data.totalSize * 1.0)) * 100)
if (request.progressFunc) { if (request.progressFunc) {
request.progressFunc.asyncSuccess(percent) request.progressFunc.asyncSuccess(percent)
} }
} }
}) })
httpRequest.on('dataEnd', () => {
httpRequest.on('dataEnd', () => { // 下载完毕
// 下载完毕 })
let combineArray = this.combineArrayBuffers(arrayBuffers); const headerObj: Record<string, Object> = {}
onComplete(combineArray) request.headers.forEach((value, key) => {
}) headerObj[key] = value
})
httpRequest.requestInStream( const data = await httpRequest.requestInStream(request.loadSrc as string, {
request.loadSrc as string, header: headerObj,
{ method: http.RequestMethod.GET,
method: http.RequestMethod.GET, expectDataType: http.HttpDataType.ARRAY_BUFFER,
expectDataType: http.HttpDataType.ARRAY_BUFFER, connectTimeout: 60000, // 可选 默认60000ms
connectTimeout: 60000, // 可选 默认60000ms readTimeout: 0, // 可选, 默认为60000ms
readTimeout: 0, // 可选, 默认为60000ms usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定 usingCache: false
} }).catch((err: Error) => {
).then((data)=>{ result.error = `HttpDownloadClient has error, http code = ` + JSON.stringify(err);
if(data == 200) { })
if ( data == 200) {
} else { result.data = this.combineArrayBuffers(arrayBuffers);
onError(`HttpDownloadClient has error, http code = ${data}`) } else {
} result.error = `HttpDownloadClient has error, http code = ` + JSON.stringify(data);
}).catch((err:Error)=>{ }
onError(`HttpDownloadClient has error, http code = ${err}`) console.log('TestCustomDataFetch http onComplete, code = ' + data + ',length = ' + result.data?.byteLength);
}) } catch (err) {
} catch (err) { result.error ='HttpDownloadClient catch err request uuid =' + request.uuid;
onError('HttpDownloadClient catch err request uuid ='+request.uuid) }
} return result;
} }
combineArrayBuffers(arrayBuffers: ArrayBuffer[]): ArrayBuffer { combineArrayBuffers(arrayBuffers: ArrayBuffer[]): ArrayBuffer {

View File

@ -14,8 +14,11 @@
*/ */
import { RequestOption } from '../RequestOption' import { RequestOption } from '../RequestOption'
import lang from '@arkts.lang';
import { DataFetchResult } from './DataFetchResult';
type ISendable = lang.ISendable;
// 资源加载接口 // 资源加载接口
export interface IDataFetch { export interface IDataFetch extends ISendable{
loadData:(request: RequestOption, onComplete: (img: ArrayBuffer) => void, onError: (err: string) => void)=>void; loadData(request: RequestOption): DataFetchResult|Promise<DataFetchResult>;
} }

View File

@ -16,25 +16,29 @@ import { IDataFetch } from '../networkmanage/IDataFetch'
import { RequestOption } from '../RequestOption' import { RequestOption } from '../RequestOption'
import fs from '@ohos.file.fs'; import fs from '@ohos.file.fs';
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import { DataFetchResult } from './DataFetchResult';
@Sendable
export class LoadDataShareFileClient implements IDataFetch { export class LoadDataShareFileClient implements IDataFetch {
loadData(request: RequestOption, onComplete: (img: ArrayBuffer) => void, onError: (err: string) => void) { loadData(request: RequestOption) {
let result:DataFetchResult =new DataFetchResult()
if (typeof request.loadSrc == 'string') { if (typeof request.loadSrc == 'string') {
fs.open(request.loadSrc, fs.OpenMode.READ_ONLY).then((file) => { fs.open(request.loadSrc, fs.OpenMode.READ_ONLY).then((file) => {
fs.stat(file.fd).then(stat =>{ fs.stat(file.fd).then(stat =>{
let buf = new ArrayBuffer(stat.size); let buf = new ArrayBuffer(stat.size);
fs.read(file.fd, buf).then((readLen) => { fs.read(file.fd, buf).then((readLen) => {
onComplete(buf); result.data=buf;
fs.close(file.fd); fs.close(file.fd);
}).catch((err:BusinessError) => { }).catch((err:BusinessError) => {
onError('LoadDataShareFileClient fs.read err happened uri=' + request.loadSrc + " err.msg=" + err?.message + " err.code=" + err?.code) result.error = 'LoadDataShareFileClient fs.read err happened uri=' + request.loadSrc + " err.msg=" + err?.message + " err.code=" + err?.code;
}) })
}).catch((err:BusinessError) => { }).catch((err:BusinessError) => {
onError('LoadDataShareFileClient fs.stat err happened uri=' + request.loadSrc + " err.msg=" + err?.message + " err.code=" + err?.code) result.error = 'LoadDataShareFileClient fs.stat err happened uri=' + request.loadSrc + " err.msg=" + err?.message + " err.code=" + err?.code;
}) })
}).catch((err:BusinessError) => { }).catch((err:BusinessError) => {
onError('LoadDataShareFileClient fs.open err happened uri=' + request.loadSrc + " err.msg=" + err?.message + " err.code=" + err?.code) result.error ='LoadDataShareFileClient fs.open err happened uri=' + request.loadSrc + " err.msg=" + err?.message + " err.code=" + err?.code;
}) })
} }
return result;
} }
} }

View File

@ -17,19 +17,23 @@ import { IDataFetch } from '../networkmanage/IDataFetch'
import { RequestOption } from '../RequestOption' import { RequestOption } from '../RequestOption'
import { FileUtils } from '../../cache/FileUtils' import { FileUtils } from '../../cache/FileUtils'
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import { DataFetchResult } from './DataFetchResult'
@Sendable
export class LoadLocalFileClient implements IDataFetch { export class LoadLocalFileClient implements IDataFetch {
loadData(request: RequestOption, onComplete: (img: ArrayBuffer) => void, onError: (err: string) => void) { loadData(request: RequestOption) {
let result:DataFetchResult =new DataFetchResult()
if (typeof request.loadSrc == 'string') { if (typeof request.loadSrc == 'string') {
FileUtils.getInstance().readFilePicAsync(request.loadSrc).then(fileBuffer=>{ FileUtils.getInstance().readFilePicAsync(request.loadSrc).then(fileBuffer=>{
if (fileBuffer == null || fileBuffer.byteLength <= 0) { if (fileBuffer == null || fileBuffer.byteLength <= 0) {
onError('LoadLocalFileClient loadLocalFileData The File Does Not Exist!Check The File!') result.error = 'LoadLocalFileClient loadLocalFileData The File Does Not Exist!Check The File!';
} else { } else {
onComplete(fileBuffer); result.data = fileBuffer
} }
}).catch((err:BusinessError)=>{ }).catch((err:BusinessError)=>{
onError('LoadLocalFileClient loadLocalFileData Error Msg ='+err?.message) result.error ='LoadLocalFileClient loadLocalFileData Error Msg ='+err?.message;
}) })
} }
return result;
} }
} }

View File

@ -19,12 +19,16 @@ import { SparkMD5 } from '../../3rd_party/sparkmd5/spark-md5'
import { FileUtils } from '../../cache/FileUtils' import { FileUtils } from '../../cache/FileUtils'
import loadRequest from '@ohos.request'; import loadRequest from '@ohos.request';
import { LogUtil } from '../utils/LogUtil' import { LogUtil } from '../utils/LogUtil'
import { ImageKnifeGlobal } from '../ImageKnifeGlobal'
import common from '@ohos.app.ability.common' import common from '@ohos.app.ability.common'
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import { DataFetchResult } from './DataFetchResult'
// 数据加载器 // 数据加载器
@Sendable
export class NetworkDownloadClient implements IDataFetch { export class NetworkDownloadClient implements IDataFetch {
loadData(request: RequestOption, onComplete: (img: ArrayBuffer) => void, onError: (err: string) => void) { loadData(request: RequestOption) {
let result:DataFetchResult = new DataFetchResult()
let filename:string = SparkMD5.hashBinary(request.generateDataKey); let filename:string = SparkMD5.hashBinary(request.generateDataKey);
let downloadFolder = request.getFilesPath() + "/" + request.networkCacheFolder; let downloadFolder = request.getFilesPath() + "/" + request.networkCacheFolder;
let allpath = request.getFilesPath() + "/" + request.networkCacheFolder + "/" + filename + ".img"; let allpath = request.getFilesPath() + "/" + request.networkCacheFolder + "/" + filename + ".img";
@ -61,14 +65,14 @@ export class NetworkDownloadClient implements IDataFetch {
let downloadPath = allpath; let downloadPath = allpath;
request.downloadFilePath = downloadPath; request.downloadFilePath = downloadPath;
FileUtils.getInstance().readFilePicAsync(downloadPath).then(arraybuffer=>{ FileUtils.getInstance().readFilePicAsync(downloadPath).then(arraybuffer=>{
onComplete(arraybuffer); result.data=arraybuffer;
FileUtils.getInstance().deleteFileAsync(downloadPath).then(()=>{ FileUtils.getInstance().deleteFileAsync(downloadPath).then(()=>{
LogUtil.log('文件名:'+downloadPath+" 文件删除成功!") LogUtil.log('文件名:'+downloadPath+" 文件删除成功!")
}).catch((err:BusinessError)=>{ }).catch((err:BusinessError)=>{
LogUtil.log('文件名:'+downloadPath+" 文件删除失败!") LogUtil.log('文件名:'+downloadPath+" 文件删除失败!")
}); });
}).catch((err:BusinessError)=>{ }).catch((err:BusinessError)=>{
onError('NetworkDownloadClient Read File Async Error Msg='+ (err as BusinessError)?.message) result.error='NetworkDownloadClient Read File Async Error Msg='+ (err as BusinessError)?.message;
}) })
if(loadTask != null) { if(loadTask != null) {
@ -86,7 +90,7 @@ export class NetworkDownloadClient implements IDataFetch {
loadTask.on('remove', () => {}) loadTask.on('remove', () => {})
loadTask.on('fail', (err) => { loadTask.on('fail', (err) => {
onError('NetworkDownloadClient Download task fail err =' + err) result.error='NetworkDownloadClient Download task fail err =' + err;
if (loadTask!=null) { if (loadTask!=null) {
loadTask.delete().then(result => { loadTask.delete().then(result => {
if(loadTask != undefined) { if(loadTask != undefined) {
@ -104,11 +108,11 @@ export class NetworkDownloadClient implements IDataFetch {
} }
}) })
} else { } else {
onError('NetworkDownloadClient downloadTask dismiss!') result.error='NetworkDownloadClient downloadTask dismiss!'
} }
}) }).catch((err:BusinessError)=> {
.catch((err:BusinessError)=> { result.error="下载子系统download错误捕获,error=" + err.message;
onError("下载子系统download错误捕获,error=" + err.message);
}) })
return result;
} }
} }

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) 2021 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.
*/
// 数据加载器
@Sendable
export class RequestData {
receiveSize: number = 2000
totalSize: number = 2000
}

View File

@ -16,3 +16,8 @@
export interface PngCallback<R,T>{ export interface PngCallback<R,T>{
pngCallback: (sender:R, receover:T)=>void pngCallback: (sender:R, receover:T)=>void
} }
export interface WorkerType {
type: string
name: string
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2021 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 { UPNG } from '../../3rd_party/upng/UPNG';
import { PngCallback, WorkerType } from './PngCallback';
import image from '@ohos.multimedia.image';
import taskpool from '@ohos.taskpool';
import { BusinessError } from '@ohos.base'
export class Pngj {
readPngImageInfo(arraybuffer: ArrayBuffer, callback: PngCallback<ArrayBuffer, image.ImageInfo>) {
let imageSource: image.ImageSource = image.createImageSource(arraybuffer);
if (imageSource != undefined) {
imageSource.getImageInfo((err: BusinessError, value: image.ImageInfo) => {
if (err) {
return;
}
callback.pngCallback(arraybuffer, value);
});
}
}
/**
*
* @param pngBuffer ArrayBuffer containing the PNG file
* @param callback
* returns an image object with following properties:
* width: the width of the image
* height: the height of the image
* depth: number of bits per channel
* ctype: color type of the file (Truecolor, Grayscale, Palette ...)
* frames: additional info about frames (frame delays etc.)
* tabs: additional chunks of the PNG file
* data: pixel data of the image
*/
readPngImage(pngBuffer: ArrayBuffer, callback: PngCallback<ArrayBuffer, Object>) {
let png = UPNG.decode(pngBuffer);
callback.pngCallback(pngBuffer, png)
}
writePngWithString(addInfo: string, pngBuffer: ArrayBuffer, callback: PngCallback<ArrayBuffer, ArrayBufferLike>) {
let pngDecode = UPNG.decode(pngBuffer);
let newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0)
callback.pngCallback(pngBuffer, newPng);
}
writePng(pngBuffer: ArrayBuffer, callback: PngCallback<ArrayBuffer, ArrayBufferLike>) {
let pngDecode = UPNG.decode(pngBuffer);
let newPng = UPNG.encode(UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0)
callback.pngCallback(pngBuffer, newPng);
}
async readPngImageAsync(e: WorkerType, source: ArrayBuffer, pngCallback: (value: ESObject) => void) {
let task = new taskpool.Task(taskPngImage, e, source)
let val1: ESObject = await taskpool.execute(task)
pngCallback(val1)
try {
taskpool.cancel(task)
} catch (e) {
console.error("taskpool.cancel occur error:" + e)
}
}
async writePngWithStringAsync(e: WorkerType, source: ArrayBuffer, pngCallback: (value: ESObject) => void, info: string) {
let task = new taskpool.Task(taskPngImage, e, source, info)
let val1: ESObject = await taskpool.execute(task)
pngCallback(val1)
try {
taskpool.cancel(task)
} catch (e) {
console.error("taskpool.cancel occur error:" + e)
}
}
async writePngAsync(e: WorkerType, source: ArrayBuffer, pngCallback: (value: ESObject) => void) {
let task = new taskpool.Task(taskPngImage, e, source)
let val1: ESObject = await taskpool.execute(task)
pngCallback(val1)
try {
taskpool.cancel(task)
} catch (e) {
console.error("taskpool.cancel occur error:" + e)
}
}
}
@Concurrent
function taskPngImage(e: WorkerType, pngSource: ArrayBuffer, info?: string): Object | ArrayBufferLike | void {
let a: Object | ArrayBufferLike | undefined = undefined
let png = UPNG.decode(pngSource)
switch (e.name) {
case 'readPngImageAsync':
let array: Uint8Array = png.data;
let arrayData = array.buffer.slice(array.byteOffset, array.byteLength + array.byteOffset)
png.data = arrayData;
a = png
break;
case 'writePngWithStringAsync':
let addInfo: string | undefined = info;
let newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(png), png.width, png.height, 0)
a = newPng
break;
case 'writePngAsync':
let newPng3 = UPNG.encode(UPNG.toRGBA8(png), png.width, png.height, 0)
a = newPng3
break;
default:
break
}
if(a != undefined) { return a }
}

View File

@ -1,178 +0,0 @@
/*
* Copyright (C) 2021 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 {UPNG} from '../../3rd_party/upng/UPNG';
import {PngCallback} from './PngCallback';
import image from '@ohos.multimedia.image';
import resourceManager from '@ohos.resourceManager';
import ArkWorker from '@ohos.worker'
import { BusinessError } from '@ohos.base'
export class Pngj {
readPngImageInfo(arraybuffer: ArrayBuffer, callback:PngCallback<ArrayBuffer, image.ImageInfo>) {
let imageSource:image.ImageSource = image.createImageSource(arraybuffer);
if (imageSource != undefined){
imageSource.getImageInfo((err:BusinessError, value:image.ImageInfo) => {
if (err) {
return;
}
callback.pngCallback(arraybuffer, value);
});
}
}
/**
*
* @param pngBuffer ArrayBuffer containing the PNG file
* @param callback
* returns an image object with following properties:
* width: the width of the image
* height: the height of the image
* depth: number of bits per channel
* ctype: color type of the file (Truecolor, Grayscale, Palette ...)
* frames: additional info about frames (frame delays etc.)
* tabs: additional chunks of the PNG file
* data: pixel data of the image
*/
readPngImage(pngBuffer: ArrayBuffer, callback:PngCallback<ArrayBuffer, any>) {
var png = UPNG.decode(pngBuffer);
callback.pngCallback(pngBuffer, png)
}
writePngWithString(addInfo:string, pngBuffer: ArrayBuffer,callback:PngCallback<ArrayBuffer, any>) {
var pngDecode = UPNG.decode(pngBuffer);
var newPng = UPNG.encodeWithString(addInfo, UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0)
callback.pngCallback(pngBuffer, newPng);
}
writePng(pngBuffer: ArrayBuffer,callback:PngCallback<ArrayBuffer, any>) {
var pngDecode = UPNG.decode(pngBuffer);
var newPng = UPNG.encode(UPNG.toRGBA8(pngDecode), pngDecode.width, pngDecode.height, 0)
callback.pngCallback(pngBuffer, newPng);
}
readPngImageAsync(worker: any, pngBuffer: ArrayBuffer, callback: PngCallback<ArrayBuffer, any>) {
// worker.onerror = function (data) {
//
// }
//
// worker.onmessageerror = function (e) {
//
// }
//
// worker.onexit = function () {
//
// }
//
// worker.onmessage = function(e) {
// var data = e.data;
// switch (data.type) {
// case 'readPngImageAsync':
// callback.pngCallback(data.receiver, data.data)
// break;
// default:
// break
// }
// worker.terminate();
// }
// var obj = { type: 'readPngImageAsync', data: pngBuffer }
// worker.postMessage(obj, [pngBuffer])
let task = new taskpool.Task(taskParseImage, arrayBuffer, scale)
task.setTransferList([])
taskpool.execute(task).then((pixelmap: Object) => {
LogUtil.log('ceshi321 : Succeeded in creating pixelmap Ui .' + (pixelmap as image.PixelMap).getPixelBytesNumber())
onCompleteFunction(pixelmap as image.PixelMap);
}).catch((err: string) => {
LogUtil.log("ceshi321 : test occur error: " + err)
onErrorFunction(err);
});
}
writePngWithStringAsync(worker: any, addInfo: string, pngBuffer: ArrayBuffer, callback: PngCallback<ArrayBuffer, any>) {
worker.onerror = function (data) {
}
worker.onmessageerror = function (e) {
}
worker.onexit = function () {
}
worker.onmessage = function(e) {
var data = e.data;
switch (data.type) {
case 'writePngWithStringAsync':
callback.pngCallback(data.receiver, data.data)
break;
default:
break
}
worker.terminate();
}
var obj = { type: 'writePngWithStringAsync', data:pngBuffer, info: addInfo}
worker.postMessage(obj, [pngBuffer])
}
writePngAsync(worker: any, pngBuffer: ArrayBuffer, callback: PngCallback<ArrayBuffer, any>) {
worker.onerror = function (data) {
}
worker.onmessageerror = function (e) {
}
worker.onexit = function () {
}
worker.onmessage = function(e) {
var data = e.data;
switch (data.type) {
case 'writePngAsync':
callback.pngCallback(data.receiver, data.data)
break;
default:
break
}
worker.terminate();
}
var obj = { type: 'writePngAsync', data:pngBuffer}
worker.postMessage(obj, [pngBuffer])
}
}

View File

@ -14,7 +14,7 @@
*/ */
import { ICache } from "../requestmanage/ICache" import { ICache } from "../requestmanage/ICache"
import { DiskLruCache } from "@ohos/disklrucache" import { DiskLruCache } from "../../cache/DiskLruCache"
export class DiskCacheProxy implements ICache<string, ArrayBuffer> { export class DiskCacheProxy implements ICache<string, ArrayBuffer> {
private mDiskLruCache: DiskLruCache; private mDiskLruCache: DiskLruCache;
@ -29,7 +29,7 @@ export class DiskCacheProxy implements ICache<string, ArrayBuffer> {
} }
getCachePath():string{ getCachePath():string{
let folderPath = this.mDiskLruCache.getPath(); let folderPath:string = this.mDiskLruCache.getPath();
if (folderPath.endsWith('/')) { if (folderPath.endsWith('/')) {
return folderPath; return folderPath;
} else { } else {
@ -38,7 +38,7 @@ export class DiskCacheProxy implements ICache<string, ArrayBuffer> {
} }
getValue(key: string): ArrayBuffer{ getValue(key: string): ArrayBuffer{
return this.mDiskLruCache.get(key); return this.mDiskLruCache.get(key) as ArrayBuffer;
} }
putValue(key: string, value: ArrayBuffer) { putValue(key: string, value: ArrayBuffer) {

View File

@ -13,25 +13,26 @@
* limitations under the License. * limitations under the License.
*/ */
import { RequestOption,Size } from '../../imageknife/RequestOption' import { RequestOption, Size } from '../../imageknife/RequestOption'
import { DiskLruCache } from '@ohos/disklrucache' import { DiskLruCache } from "../../cache/DiskLruCache"
import { LruCache } from '../../cache/LruCache' import { LruCache } from '../../cache/LruCache'
import { SparkMD5 } from '../../3rd_party/sparkmd5/spark-md5' import { SparkMD5 } from '../../3rd_party/sparkmd5/spark-md5'
import { MemoryCacheProxy } from '../requestmanage/MemoryCacheProxy' import { MemoryCacheProxy } from '../requestmanage/MemoryCacheProxy'
import { DiskCacheProxy } from '../requestmanage/DiskCacheProxy' import { DiskCacheProxy } from '../requestmanage/DiskCacheProxy'
import { FileTypeUtil } from '../utils/FileTypeUtil' import { FileTypeUtil } from '../utils/FileTypeUtil'
import { IDataFetch } from '../../imageknife/networkmanage/IDataFetch' import { IDataFetch } from '../../imageknife/networkmanage/IDataFetch'
import { IResourceFetch } from '../../imageknife/resourcemanage/IResourceFetch' import { IResourceFetch } from '../../imageknife/resourcemanage/IResourceFetch'
import { ImageKnifeData, ImageKnifeType } from '../ImageKnifeData' import { ImageKnifeData, ImageKnifeType } from '../ImageKnifeData'
import { AllCacheInfo } from '../../imageknife/interface/IAllCacheInfoCallback' import { AllCacheInfo } from '../../imageknife/interface/IAllCacheInfoCallback'
import { ParseImageUtil } from '../utils/ParseImageUtil' import { ParseImageUtil } from '../utils/ParseImageUtil'
import { IParseImage } from '../interface/IParseImage' import { IParseImage } from '../interface/IParseImage'
import image from '@ohos.multimedia.image' import image from '@ohos.multimedia.image'
import { SVGParseImpl } from '../utils/svg/SVGParseImpl' import { SVGParseImpl } from '../utils/svg/SVGParseImpl'
import { GIFParseImpl } from '../utils/gif/GIFParseImpl' import { GIFParseImpl } from '../utils/gif/GIFParseImpl'
import { GIFFrame } from '../utils/gif/GIFFrame' import { GIFFrame } from '../utils/gif/GIFFrame'
import { LogUtil } from '../../imageknife/utils/LogUtil' import { LogUtil } from '../../imageknife/utils/LogUtil'
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import { DataFetchResult } from '../networkmanage/DataFetchResult'
export enum Stage { export enum Stage {
@ -62,19 +63,15 @@ export enum RunReason {
export class RequestManager { export class RequestManager {
private TAG: string = "RequestManager"; private TAG: string = "RequestManager";
private options: RequestOption; private options: RequestOption;
private mMemoryCacheProxy: MemoryCacheProxy<string, ImageKnifeData>;
private mDiskCacheProxy: DiskCacheProxy;
private mIDataFetch: IDataFetch; private mIDataFetch: IDataFetch;
private mIResourceFetch: IResourceFetch<ArrayBuffer>; private mIResourceFetch: IResourceFetch<ArrayBuffer>;
private mParseImageUtil: IParseImage<PixelMap>; private mParseImageUtil: IParseImage<PixelMap>;
private diskMemoryCache: DiskLruCache;
constructor(option: RequestOption, memoryCache1: LruCache<string, ImageKnifeData>, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch<ArrayBuffer>) { constructor(option: RequestOption,diskMemoryCache: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch<ArrayBuffer>) {
this.options = option; this.options = option;
// 缓存部分 this.diskMemoryCache = diskMemoryCache;
this.mMemoryCacheProxy = new MemoryCacheProxy(memoryCache1);
this.mDiskCacheProxy = new DiskCacheProxy(diskMemoryCache1);
// 网络下载能力 // 网络下载能力
this.mIDataFetch = dataFetch; this.mIDataFetch = dataFetch;
@ -85,63 +82,16 @@ export class RequestManager {
this.mParseImageUtil = new ParseImageUtil(); this.mParseImageUtil = new ParseImageUtil();
} }
static execute(option: RequestOption, memoryCache1: LruCache<string, ImageKnifeData>, diskMemoryCache1: DiskLruCache, dataFetch: IDataFetch, resourceFetch: IResourceFetch<ArrayBuffer>) {
LogUtil.log("RequestManager execute")
let manager = new RequestManager(option, memoryCache1, diskMemoryCache1, dataFetch, resourceFetch);
return new Promise<ImageKnifeData>(manager.process)
.then(option.loadComplete)
.then(manager.loadCompleteAfter)
.catch(option.loadError);
}
loadCompleteAfter =()=>{
try { // 内部消化问题
LogUtil.log("loadCompleteAfter!")
if (this.options.allCacheInfoCallback) {
LogUtil.log("RequestOption =" + JSON.stringify(this.options));
// 内存缓存
let allCacheInfo:AllCacheInfo = {
memoryCacheInfo:{key:'', data:new ImageKnifeData()},
resourceCacheInfo:{key:'', path:''},
dataCacheInfo:{key:'',path:''}
};
let memoryCache = this.mMemoryCacheProxy.getValue(this.options.generateCacheKey);
allCacheInfo.memoryCacheInfo = {
key: this.options.generateCacheKey,
data: memoryCache
}
// 变换后缓存
allCacheInfo.resourceCacheInfo = {
key: SparkMD5.hashBinary(this.options.generateResourceKey) as string,
path: (this.mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.options.generateResourceKey)) as string
};
// 原图缓存
allCacheInfo.dataCacheInfo = {
key: SparkMD5.hashBinary(this.options.generateDataKey) as string,
path: (this.mDiskCacheProxy.getCachePath() + SparkMD5.hashBinary(this.options.generateDataKey)) as string
}
this.options.allCacheInfoCallback.callback(allCacheInfo)
}
} catch (err) {
LogUtil.log("after err =" + err)
}
}
// DecodeJob work // DecodeJob work
private mStage: Stage = Stage.INITIALIZE; private mStage: Stage = Stage.INITIALIZE;
private mRunReason: RunReason = RunReason.INITIALIZE; private mRunReason: RunReason = RunReason.INITIALIZE;
process = (onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) => {
process = (onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void)=>{ LogUtil.log("ImageKnife RequestManager process !");
LogUtil.log("RequestManager process !");
this.loadLeve1MemoryCache(onComplete, onError) this.loadLeve1MemoryCache(onComplete, onError)
} }
private runWrapped(request: RequestOption, runReason: RunReason, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private runWrapped(request: RequestOption, runReason: RunReason, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("RequestManager runWrapped") LogUtil.log("ImageKnife RequestManager runWrapped")
if (runReason == RunReason.INITIALIZE) { if (runReason == RunReason.INITIALIZE) {
this.mStage = this.getNextStage(request, this.mStage); this.mStage = this.getNextStage(request, this.mStage);
this.searchLoadFrom(this.options, this.mStage, onComplete, onError); this.searchLoadFrom(this.options, this.mStage, onComplete, onError);
@ -150,7 +100,7 @@ export class RequestManager {
} }
} }
private getNextStage(request: RequestOption, current: Stage): Stage{ private getNextStage(request: RequestOption, current: Stage): Stage {
if (current == Stage.INITIALIZE) { if (current == Stage.INITIALIZE) {
return request.strategy.decodeCachedResource() return request.strategy.decodeCachedResource()
? Stage.RESOURCE_CACHE ? Stage.RESOURCE_CACHE
@ -166,13 +116,13 @@ export class RequestManager {
} else if (current == Stage.FINISHED) { } else if (current == Stage.FINISHED) {
return Stage.FINISHED; return Stage.FINISHED;
} else { } else {
throw new Error("Unrecognized stage: " + current); throw new Error("ImageKnife Unrecognized stage: " + current);
} }
} }
// 究竟从哪里加载数据 // 究竟从哪里加载数据
private searchLoadFrom(request: RequestOption, current: Stage, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private searchLoadFrom(request: RequestOption, current: Stage, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("RequestManager searchLoadFrom") LogUtil.log("ImageKnife RequestManager searchLoadFrom")
if (current == Stage.RESOURCE_CACHE) { if (current == Stage.RESOURCE_CACHE) {
this.loadDiskFromTransform(request, onComplete, onError); this.loadDiskFromTransform(request, onComplete, onError);
} else if (current == Stage.DATA_CACHE) { } else if (current == Stage.DATA_CACHE) {
@ -187,85 +137,90 @@ export class RequestManager {
} }
// 加载网络资源 // 加载网络资源
private loadSourceFromNetwork(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private async loadSourceFromNetwork(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
let success = (arraybuffer:ArrayBuffer) => { try {
this.downloadSuccess(request,arraybuffer, onComplete, onError) LogUtil.log("ImageKnife RequestManager loadSourceFromNetwork")
let result: DataFetchResult = await this.mIDataFetch.loadData(request);
if(result.error){
onError(result.error)
}else{
if(result.data){
this.downloadSuccess(request, result.data, onComplete, onError)
}else{
onError("datafetch data is null")
}
} }
let error = (errorMsg:string) =>{ } catch (e) {
onError(errorMsg) LogUtil.error("ImageKnife RequestManager loadSourceFromNetwork error")
} }
this.mIDataFetch.loadData(request, success, error);
} }
// 加载本地资源 // 加载本地资源
private loadSourceFormNative(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private loadSourceFormNative(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("RequestManager loadSourceFormNative") LogUtil.log("ImageKnife RequestManager loadSourceFormNative")
// 本地解析后进行一级缓存 // 本地解析后进行一级缓存
let success = (arrayBuffer:ArrayBuffer) => { let success = (arrayBuffer: ArrayBuffer) => {
// 使用媒体子系统 ImageSource解析文件 获取PixelMap // 使用媒体子系统 ImageSource解析文件 获取PixelMap
let fileTypeUtil = new FileTypeUtil(); let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(arrayBuffer) let typeValue = fileTypeUtil.getFileType(arrayBuffer)
LogUtil.log("RequestManager - 文件类型为= " + typeValue) LogUtil.log("ImageKnife RequestManager - 文件类型为= " + typeValue)
// gif处理 // gif、webp处理
if(ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag){ if ((ImageKnifeData.GIF == typeValue || ImageKnifeData.WEBP == typeValue) && !request.dontAnimateFlag) {
// 处理gif // 处理gif、webp
this.gifProcess(onComplete,onError, arrayBuffer,typeValue,(imageKnifeData)=>{ this.gifProcess(onComplete, onError, arrayBuffer, typeValue)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData) } else if (ImageKnifeData.SVG == typeValue) {
})
}else if(ImageKnifeData.SVG == typeValue){
// 处理svg // 处理svg
this.svgProcess(request,onComplete,onError,arrayBuffer,typeValue,(imageKnifeData)=>{ this.svgProcess(request, onComplete, onError, arrayBuffer, typeValue)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey,imageKnifeData)
})
} else { } else {
if (request.transformations[0]) { if (request.transformations[0]) {
request.transformations[0].transform(arrayBuffer, request, {asyncTransform:(error:BusinessError|string, pixelMap: PixelMap|null) => { request.transformations[0].transform(arrayBuffer, request, {
// 输出给Image asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) { // 输出给Image
if (pixelMap) {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap); onComplete(pixelMap);
this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData); } else {
onComplete(imageKnifeData); onError(error);
} else { }
onError(error);
} }
}}) })
} }
else { else {
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); onComplete(value);
this.mMemoryCacheProxy.putValue(request.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
} }
this.mParseImageUtil.parseImage(arrayBuffer, success, onError) this.mParseImageUtil.parseImage(arrayBuffer, success, onError)
} }
} }
} }
let ctx = request.getModuleContext(); let ctx = request.getModuleContext();
if(ctx!=undefined){ if (ctx != undefined) {
this.mIResourceFetch.loadResource(ctx,request.loadSrc as Resource, success, onError); this.mIResourceFetch.loadResource(ctx, request.loadSrc as Resource, success, onError);
}else{ } else {
onError('RequestManager loadSourceFormNative moduleContext is undefined! please check it') onError('ImageKnife RequestManager loadSourceFormNative moduleContext is undefined! please check it')
} }
} }
// 加载磁盘缓存 原图 // 加载磁盘缓存 原图
private loadDiskFromSource(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private loadDiskFromSource(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("RequestManager loadDiskFromSource") LogUtil.log("ImageKnife RequestManager loadDiskFromSource")
let cached = this.mDiskCacheProxy.getValue(request.generateDataKey) let cached = this.diskMemoryCache.get(request.generateDataKey);
if (cached != null && cached.byteLength > 0) { if (cached != null && cached.byteLength > 0) {
LogUtil.log("ImageKnife loadDiskFromSource load resource from DiskLruCache")
this.parseDiskFile2PixelMap(request, cached, onComplete, onError) this.parseDiskFile2PixelMap(request, cached, onComplete, onError)
} else { } else {
this.mStage = Stage.SOURCE; this.mStage = Stage.SOURCE;
this.mStage = request.onlyRetrieveFromCache? Stage.FINISHED : Stage.SOURCE
this.searchLoadFrom(this.options, this.mStage, onComplete, onError); this.searchLoadFrom(this.options, this.mStage, onComplete, onError);
} }
} }
// 加载磁盘缓存 变换后图片 // 加载磁盘缓存 变换后图片
private loadDiskFromTransform(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private loadDiskFromTransform(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("RequestManager loadDiskFromTransform") LogUtil.log("ImageKnife RequestManager loadDiskFromTransform")
let cached = this.mDiskCacheProxy.getValue(request.generateResourceKey) let cached = this.diskMemoryCache.get(request.generateResourceKey);
if (cached != null) { if (cached != null) {
LogUtil.log("ImageKnife loadDiskFromTransform load resource from DiskLruCache")
this.parseDiskTransformFile2PixelMap(request, cached, onComplete, onError) this.parseDiskTransformFile2PixelMap(request, cached, onComplete, onError)
} else { } else {
this.mStage = Stage.DATA_CACHE; this.mStage = Stage.DATA_CACHE;
@ -273,103 +228,95 @@ export class RequestManager {
} }
} }
parseSource(request: RequestOption, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { parseSource(request: RequestOption, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("RequestManager parseSource") LogUtil.log("ImageKnife RequestManager parseSource")
try {
if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') { if ((typeof (request.loadSrc as image.PixelMap).isEditable) == 'boolean') {
// PixelMap 外层捕获效率更高,不会进入这里 // PixelMap 外层捕获效率更高,不会进入这里
} else if (typeof request.loadSrc == 'string') { } else if (typeof request.loadSrc == 'string') {
this.loadSourceFromNetwork(request, onComplete, onError); this.loadSourceFromNetwork(request, onComplete, onError);
} else { } else {
let res = request.loadSrc as Resource; let res = request.loadSrc as Resource;
if (typeof res.id != 'undefined' && typeof res.id != 'undefined') { if (typeof res.id != 'undefined') {
this.loadSourceFormNative(request, onComplete, onError) this.loadSourceFormNative(request, onComplete, onError)
} else { } else {
LogUtil.log("输入参数有问题!") LogUtil.log("输入参数有问题!")
} }
} }
} catch (e) {
LogUtil.error("ImageKnife RequestManager parseSource error")
}
} }
private loadLeve1MemoryCache(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private loadLeve1MemoryCache(onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("RequestManager loadLeve1MemoryCache") try {
// 一级缓存 内存获取
let cache = this.mMemoryCacheProxy.loadMemoryCache(this.options.generateCacheKey, this.options.isCacheable);
if (cache == null || typeof cache == 'undefined') {
// 处理磁盘加载 网络加载
this.runWrapped(this.options, this.mRunReason, onComplete, onError) this.runWrapped(this.options, this.mRunReason, onComplete, onError)
} else { } catch (e) {
// 需要清理状态 LogUtil.error("ImageKnife loadLeve1MemoryCache error")
cache.waitSaveDisk = false;
onComplete(cache);
return
} }
} }
// 解析磁盘文件变成PixeMap // 解析磁盘文件变成PixeMap
private parseDiskFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private parseDiskFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager parseDiskFile2PixelMap")
// 步骤一文件转为pixelMap 然后变换 给Image组件 // 步骤一文件转为pixelMap 然后变换 给Image组件
let fileTypeUtil = new FileTypeUtil(); let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(source); let typeValue = fileTypeUtil.getFileType(source);
// 解析磁盘文件 gif 和 svg // 解析磁盘文件 gif、webp 和 svg
if(ImageKnifeData.GIF == typeValue && !request.dontAnimateFlag){ if ((ImageKnifeData.GIF == typeValue || ImageKnifeData.WEBP == typeValue) && !request.dontAnimateFlag) {
// 处理gif // 处理gif、webp
this.gifProcess(onComplete,onError,source,typeValue, (imageKnifeData)=>{ this.gifProcess(onComplete, onError, source, typeValue)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData) } else if (ImageKnifeData.SVG == typeValue) {
}) this.svgProcess(request, onComplete, onError, source, typeValue)
}else if(ImageKnifeData.SVG == typeValue){
this.svgProcess(request,onComplete,onError, source, typeValue, (imageKnifeData)=>{
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
} else { } else {
if (this.options.transformations[0]) { if (this.options.transformations[0]) {
if (this.options.thumbSizeMultiplier) { if (this.options.thumbSizeMultiplier) {
let thumbOption:RequestOption = new RequestOption(); let thumbOption: RequestOption = new RequestOption();
thumbOption.setImageViewSize({ thumbOption.setImageViewSize({
width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width), width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width),
height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height) height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height)
}) })
let ctx = this.options.getModuleContext() let ctx = this.options.getModuleContext()
if(ctx != undefined){ if (ctx != undefined) {
thumbOption.setModuleContext(ctx) thumbOption.setModuleContext(ctx)
}else{ } else {
onError('RequestManager parseDiskFile2PixelMap moduleContext is undefined, please check it!') onError('RequestManager parseDiskFile2PixelMap moduleContext is undefined, please check it!')
return return
} }
let thumbCallback = this.options.thumbholderOnComplete; let thumbCallback = this.options.thumbholderOnComplete;
let thumbError = this.options.thumbholderOnError; let thumbError = this.options.thumbholderOnError;
this.options.transformations[0].transform(source, thumbOption,{asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => { this.options.transformations[0].transform(source, thumbOption, {
if (pixelMap) { asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
thumbCallback(imageKnifeData);
} else {
thumbError(error);
}
}})
setTimeout(()=>{
this.options.transformations[0].transform(source, request, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
if (pixelMap) { if (pixelMap) {
// 保存一份变换后的图片PixelMap到MemoryCache thumbCallback(pixelMap);
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap); } else {
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); thumbError(error);
onComplete(imageKnifeData); }
}
})
setTimeout(() => {
this.options.transformations[0].transform(source, request, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
onComplete(pixelMap);
} else {
onError(error);
}
}
})
}, this.options.thumbDelayTime);
}
else {
this.options.transformations[0].transform(source, request, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
onComplete(pixelMap);
} else { } else {
onError(error); onError(error);
} }
}})
},this.options.thumbDelayTime);
}
else {
this.options.transformations[0].transform(source, request, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
if (pixelMap) {
// 保存一份变换后的图片PixelMap到MemoryCache
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
} else {
onError(error);
} }
}}) })
} }
} else { } else {
// thumbnail 缩略图部分 // thumbnail 缩略图部分
@ -377,24 +324,18 @@ export class RequestManager {
let thumbCallback = this.options.thumbholderOnComplete let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError let thumbError = this.options.thumbholderOnError
let thumbSuccess = (value: PixelMap) => { let thumbSuccess = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); thumbCallback(value);
thumbCallback(imageKnifeData);
} }
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError); this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(()=>{ setTimeout(() => {
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); onComplete(value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData); }
onComplete(imageKnifeData); this.mParseImageUtil.parseImage(source, success, onError)
} }, this.options.thumbDelayTime)
this.mParseImageUtil.parseImage(source, success, onError) } else {
},this.options.thumbDelayTime)
}
else {
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); onComplete(value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
} }
this.mParseImageUtil.parseImage(source, success, onError) this.mParseImageUtil.parseImage(source, success, onError)
} }
@ -403,7 +344,8 @@ export class RequestManager {
} }
// 解析磁盘变换后文件变成PixeMap // 解析磁盘变换后文件变成PixeMap
private parseDiskTransformFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private parseDiskTransformFile2PixelMap(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log("ImageKnife RequestManager parseDiskTransformFile2PixelMap")
let fileTypeUtil = new FileTypeUtil(); let fileTypeUtil = new FileTypeUtil();
let typeValue = fileTypeUtil.getFileType(source); let typeValue = fileTypeUtil.getFileType(source);
// thumbnail 缩略图部分 // thumbnail 缩略图部分
@ -411,33 +353,27 @@ export class RequestManager {
let thumbCallback = this.options.thumbholderOnComplete let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError let thumbError = this.options.thumbholderOnError
let thumbSuccess = (value: PixelMap) => { let thumbSuccess = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); thumbCallback(value);
thumbCallback(imageKnifeData);
} }
this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError); this.mParseImageUtil.parseImageThumbnail(request.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(()=>{ setTimeout(() => {
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); onComplete(value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
} }
this.mParseImageUtil.parseImage(source, success, onError) this.mParseImageUtil.parseImage(source, success, onError)
},this.options.thumbDelayTime) }, this.options.thumbDelayTime)
}else{ } else {
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value) onComplete(value);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
onComplete(imageKnifeData);
} }
this.mParseImageUtil.parseImage(source, success, onError) this.mParseImageUtil.parseImage(source, success, onError)
} }
} }
private downloadSuccess(request: RequestOption,source: ArrayBuffer, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void) { private downloadSuccess(request: RequestOption, source: ArrayBuffer, onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
LogUtil.log('Download task completed.');
if(source == null || source == undefined || source.byteLength <= 0){ if (source == null || source == undefined || source.byteLength <= 0) {
onError('Download task completed. but download file is empty!') onError('ImageKnife Download task completed. but download file is empty!')
return return
} }
@ -446,8 +382,8 @@ export class RequestManager {
// 步骤二: 文件名保存一份全局 // 步骤二: 文件名保存一份全局
// 步骤三:查看文件是否支持 非支持类型直接返回 // 步骤三:查看文件是否支持 非支持类型直接返回
let fileTypeUtil = new FileTypeUtil(); let fileTypeUtil = new FileTypeUtil();
let filetype:string|null = fileTypeUtil.getFileType(source); let filetype: string | null = fileTypeUtil.getFileType(source);
if(filetype == null){ if (filetype == null) {
onError("下载文件解析后类型为null,请检查数据源!"); onError("下载文件解析后类型为null,请检查数据源!");
return; return;
} }
@ -457,53 +393,51 @@ export class RequestManager {
return; return;
} }
// 解析磁盘文件 gif 和 svg // 解析磁盘文件 gif、webp 和 svg
if(ImageKnifeData.GIF == filetype && !this.options.dontAnimateFlag){ if ((ImageKnifeData.GIF == filetype || ImageKnifeData.WEBP == filetype) && !this.options.dontAnimateFlag) {
// 处理gif // 处理gif、webp
this.gifProcess(onComplete,onError,source,filetype, (imageKnifeData)=>{ this.gifProcess(onComplete, onError, source, filetype)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
// 保存二级磁盘缓存 // 保存二级磁盘缓存
Promise.resolve(source) Promise.resolve(source)
.then((arraybuffer: ArrayBuffer)=>{ .then((arraybuffer: ArrayBuffer) => {
this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer) this.diskMemoryCache.set(this.options.generateDataKey,arraybuffer);
}) })
.catch( (err:BusinessError)=>{ .catch((err: BusinessError) => {
LogUtil.log('download file is ='+ImageKnifeData.GIF+'and save diskLruCache error ='+ (err as BusinessError)) LogUtil.log('download file is =' + ImageKnifeData.GIF + 'and save diskLruCache error =' + (err as BusinessError))
}) })
}else if(ImageKnifeData.SVG == filetype){ } else if (ImageKnifeData.SVG == filetype) {
// 处理svg // 处理svg
this.svgProcess(request,onComplete,onError, source, filetype, (imageKnifeData)=>{ this.svgProcess(request, onComplete, onError, source, filetype)
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData)
})
// 保存二级磁盘缓存 // 保存二级磁盘缓存
Promise.resolve(source) Promise.resolve(source)
.then((arraybuffer: ArrayBuffer)=>{ .then((arraybuffer: ArrayBuffer) => {
this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer) this.diskMemoryCache.set(this.options.generateDataKey,arraybuffer);
}) })
.catch((err:BusinessError)=>{ .catch((err: BusinessError) => {
LogUtil.log('download file is ='+ImageKnifeData.SVG+'and save diskLruCache error ='+ (err as BusinessError)) LogUtil.log('download file is =' + ImageKnifeData.SVG + 'and save diskLruCache error =' + (err as BusinessError))
}) })
} else { } else {
// 进行变换 // 进行变换
if (this.options.transformations[0]) { if (this.options.transformations[0]) {
// thumbnail 缩略图部分 // thumbnail 缩略图部分
if (this.options.thumbSizeMultiplier) { if (this.options.thumbSizeMultiplier) {
if(filetype != null) { if (filetype != null) {
this.thumbnailProcess(source, filetype, onComplete, onError); this.thumbnailProcess(source, filetype, onComplete, onError);
} }
} else { } else {
this.options.transformations[0].transform(source, this.options, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => { this.options.transformations[0].transform(source, this.options, {
if (pixelMap) { asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if(filetype != null) { if (pixelMap) {
this.saveCacheAndDisk(pixelMap, filetype, onComplete, source); if (filetype != null) {
this.saveCacheAndDisk(pixelMap, filetype, onComplete, source);
}
} else {
onError(error);
} }
} else {
onError(error);
} }
}}) })
} }
} else { } else {
// thumbnail 缩略图部分 // thumbnail 缩略图部分
@ -511,13 +445,12 @@ export class RequestManager {
let thumbCallback = this.options.thumbholderOnComplete let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError let thumbError = this.options.thumbholderOnError
let thumbSuccess = (value: PixelMap) => { let thumbSuccess = (value: PixelMap) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); thumbCallback(value);
thumbCallback(imageKnifeData);
} }
this.mParseImageUtil.parseImageThumbnail(this.options.thumbSizeMultiplier, source, thumbSuccess, thumbError); this.mParseImageUtil.parseImageThumbnail(this.options.thumbSizeMultiplier, source, thumbSuccess, thumbError);
setTimeout(() => { setTimeout(() => {
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
if(filetype != null) { if (filetype != null) {
this.saveCacheAndDisk(value, filetype, onComplete, source); this.saveCacheAndDisk(value, filetype, onComplete, source);
} }
} }
@ -525,7 +458,7 @@ export class RequestManager {
}, this.options.thumbDelayTime) }, this.options.thumbDelayTime)
} else { } else {
let success = (value: PixelMap) => { let success = (value: PixelMap) => {
if(filetype != null) { if (filetype != null) {
this.saveCacheAndDisk(value, filetype, onComplete, source); this.saveCacheAndDisk(value, filetype, onComplete, source);
} }
} }
@ -535,94 +468,90 @@ export class RequestManager {
} }
} }
createImagePixelMap(imageKnifeType: ImageKnifeType, imageKnifeValue: PixelMap): ImageKnifeData{ createImagePixelMap(imageKnifeType: ImageKnifeType, imageKnifeValue: PixelMap): ImageKnifeData {
return ImageKnifeData.createImagePixelMap(imageKnifeType,imageKnifeValue); return ImageKnifeData.createImagePixelMap(imageKnifeType, imageKnifeValue);
} }
createImageGIFFrame(imageKnifeType: ImageKnifeType, imageKnifeValue: GIFFrame[]): ImageKnifeData{ createImageGIFFrame(imageKnifeType: ImageKnifeType, imageKnifeValue: GIFFrame[]): ImageKnifeData {
return ImageKnifeData.createImageGIFFrame(imageKnifeType,imageKnifeValue); return ImageKnifeData.createImageGIFFrame(imageKnifeType, imageKnifeValue);
} }
private async saveCacheAndDisk(value: PixelMap, filetype: string, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, source: ArrayBuffer) {
private saveCacheAndDisk(value: PixelMap, filetype:string, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, source:ArrayBuffer) { let save2DiskCache = (arraybuffer: ArrayBuffer) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, value); this.diskMemoryCache.set(this.options.generateDataKey,arraybuffer);
this.mMemoryCacheProxy.putValue(this.options.generateCacheKey, imageKnifeData);
let save2DiskCache = (arraybuffer:ArrayBuffer) => {
this.mDiskCacheProxy.putValue(this.options.generateDataKey, arraybuffer)
// 落盘之后需要主动移除当前request并且调用下一个加载 // 落盘之后需要主动移除当前request并且调用下一个加载
let removeCurrentAndSearchNextRun = this.options.removeCurrentAndSearchNext let removeCurrentAndSearchNextRun = this.options.removeCurrentAndSearchNext;
removeCurrentAndSearchNextRun(); removeCurrentAndSearchNextRun();
} }
let runSave2Disk = (resolve:(value:ArrayBuffer)=>void|PromiseLike<ArrayBuffer>, reject:(reason?:BusinessError|string)=>void) => { let runSave2Disk = (resolve: (value: ArrayBuffer) => void | PromiseLike<ArrayBuffer>, reject: (reason?: BusinessError | string) => void) => {
resolve(source); resolve(source);
} }
let promise = new Promise(runSave2Disk); let promise = new Promise(runSave2Disk);
promise.then(save2DiskCache); await promise.then(save2DiskCache);
imageKnifeData.waitSaveDisk = true; onComplete(value);
onComplete(imageKnifeData);
} }
thumbnailProcess(source:ArrayBuffer, filetype:string, onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void){ thumbnailProcess(source: ArrayBuffer, filetype: string, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void) {
let thumbOption = new RequestOption(); let thumbOption = new RequestOption();
let ctx = this.options.getModuleContext() let ctx = this.options.getModuleContext()
if(ctx != undefined){ if (ctx != undefined) {
thumbOption.setModuleContext(ctx) thumbOption.setModuleContext(ctx)
}else{ } else {
onError('RequestManager thumbnailProcess moduleContext is undefined, please check it!') onError('RequestManager thumbnailProcess moduleContext is undefined, please check it!')
return return
} }
thumbOption.setImageViewSize({ thumbOption.setImageViewSize({
width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width), width: Math.round(this.options.thumbSizeMultiplier * this.options.size.width),
height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height) height: Math.round(this.options.thumbSizeMultiplier * this.options.size.height)
}) })
let thumbCallback = this.options.thumbholderOnComplete let thumbCallback = this.options.thumbholderOnComplete
let thumbError = this.options.thumbholderOnError let thumbError = this.options.thumbholderOnError
this.options.transformations[0].transform(source, thumbOption, {asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => { this.options.transformations[0].transform(source, thumbOption, {
if (pixelMap) { asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
let imageKnifeData = this.createImagePixelMap(ImageKnifeType.PIXELMAP, pixelMap);
thumbCallback(imageKnifeData);
} else {
thumbError(error);
}
}})
setTimeout(() => {
this.options.transformations[0].transform(source, this.options,{asyncTransform: (error:BusinessError|string, pixelMap: PixelMap|null) => {
if (pixelMap) { if (pixelMap) {
this.saveCacheAndDisk(pixelMap, filetype, onComplete, source); thumbCallback(pixelMap);
} else {
thumbError(error);
}
}
})
setTimeout(() => {
this.options.transformations[0].transform(source, this.options, {
asyncTransform: (error: BusinessError | string, pixelMap: PixelMap | null) => {
if (pixelMap) {
this.saveCacheAndDisk(pixelMap, filetype, onComplete, source);
} else { } else {
onError(error); onError(error);
} }
}}) }
}, this.options.thumbDelayTime) })
} }, this.options.thumbDelayTime)
private svgProcess(option: RequestOption,onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
let svgParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(option,arraybuffer, onComplete,onError)
} }
private gifProcess(onComplete:(value:ImageKnifeData)=>void|PromiseLike<ImageKnifeData>, onError:(reason?:BusinessError|string)=>void, arraybuffer:ArrayBuffer, typeValue:string, cacheStrategy?: (cacheData: ImageKnifeData) => void) { private svgProcess(option: RequestOption, onComplete: (value: PixelMap) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void, arraybuffer: ArrayBuffer, typeValue: string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
let svgParseImpl = new SVGParseImpl()
svgParseImpl.parseSvg(option, arraybuffer, onComplete, onError)
}
private gifProcess(onComplete: (value: PixelMap | GIFFrame[]) => void | PromiseLike<ImageKnifeData>, onError: (reason?: BusinessError | string) => void, arraybuffer: ArrayBuffer, typeValue: string, cacheStrategy?: (cacheData: ImageKnifeData) => void) {
let gifParseImpl = new GIFParseImpl() let gifParseImpl = new GIFParseImpl()
gifParseImpl.parseGifs(arraybuffer, (data?:GIFFrame[],err?:BusinessError|string)=>{ gifParseImpl.parseGifs(arraybuffer, (data?: GIFFrame[], err?: BusinessError | string) => {
if(err){ if (err) {
onError(err) onError(err)
} }
LogUtil.log("gifProcess data is null:"+(data == null)); LogUtil.log("gifProcess data is null:" + (data == null));
if(!!data){ if (!!data) {
let imageKnifeData = this.createImageGIFFrame(ImageKnifeType.GIFFRAME,data) // let imageKnifeData = this.createImageGIFFrame(ImageKnifeType.GIFFRAME, data)
LogUtil.log('gifProcess 生成gif 返回数据类型') // LogUtil.log('gifProcess 生成gif 返回数据类型')
if(cacheStrategy){ // if (cacheStrategy) {
LogUtil.log('gifProcess 生成gif并且存入了缓存策略') // LogUtil.log('gifProcess 生成gif并且存入了缓存策略')
cacheStrategy(imageKnifeData) // cacheStrategy(imageKnifeData)
} // }
onComplete(imageKnifeData) onComplete(data)
}else{ } else {
onError('Parse GIF callback data is null, you need check callback data!') onError('Parse GIF callback data is null, you need check callback data!')
} }
}) })
} }
} }

View File

@ -29,7 +29,7 @@ export class ParseResClientBase64 implements IResourceFetch<ArrayBuffer> {
if (resType == ResourceTypeEts.MEDIA) { if (resType == ResourceTypeEts.MEDIA) {
let moduleContext = ContextCacheProxy.getInstance() let moduleContext = ContextCacheProxy.getInstance()
.contextGetValue(res.moduleName, context); .contextGetValue(res.moduleName, context);
(moduleContext.resourceManager as resourceManager.ResourceManager) (moduleContext?.resourceManager as resourceManager.ResourceManager)
.getMediaContentBase64(resId) .getMediaContentBase64(resId)
.then(data => { .then(data => {
let matchReg = ';base64,'; let matchReg = ';base64,';

View File

@ -20,5 +20,9 @@ export interface BaseTransform<T> {
// 实现类 返回作为key生成的一部分 // 实现类 返回作为key生成的一部分
getName(): string; getName(): string;
getClassName():string;
getConstructorParams():string;
transform(value: ArrayBuffer, request: RequestOption, func: AsyncTransform<T>):void; transform(value: ArrayBuffer, request: RequestOption, func: AsyncTransform<T>):void;
} }

View File

@ -26,13 +26,27 @@ import {Size} from '../../imageknife/RequestOption'
export class BlurTransformation implements BaseTransform<PixelMap> { export class BlurTransformation implements BaseTransform<PixelMap> {
private _mRadius: number; private _mRadius: number;
private sampling: number
constructor(radius: number) { constructor(radius: number,sampling?:number) {
this._mRadius = radius; this._mRadius = radius;
if(sampling == undefined){
this.sampling = 1
} else {
this.sampling = sampling
}
}
getClassName() {
return "BlurTransformation";
}
getConstructorParams() {
return JSON.stringify([this._mRadius,this.sampling]);
} }
getName() { getName() {
return "BlurTransformation _mRadius:" + this._mRadius; return "BlurTransformation _mRadius:" + this._mRadius +"==BlurTransformation sampling:"+ this.sampling;
} }
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) { transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
@ -63,8 +77,8 @@ export class BlurTransformation implements BaseTransform<PixelMap> {
let options:image.DecodingOptions = { let options:image.DecodingOptions = {
editable: true, editable: true,
desiredSize: { desiredSize: {
width: targetWidth, width: pixelMapWidth / this.sampling,
height: targetHeight height: pixelMapHeight / this.sampling
} }
} }
imageSource.createPixelMap(options) imageSource.createPixelMap(options)

View File

@ -33,6 +33,14 @@ export class BrightnessFilterTransformation implements BaseTransform<PixelMap> {
this._mBrightness = brightness; this._mBrightness = brightness;
} }
getClassName(){
return "BrightnessFilterTransformation";
}
getConstructorParams(){
return JSON.stringify([this._mBrightness]);
}
getName() { getName() {
return "BrightnessFilterTransformation:" + this._mBrightness; return "BrightnessFilterTransformation:" + this._mBrightness;
} }

View File

@ -45,6 +45,15 @@ export class ContrastFilterTransformation implements BaseTransform<PixelMap> {
this._mContrast = contrast; this._mContrast = contrast;
} }
getClassName(){
return "ContrastFilterTransformation";
}
getConstructorParams(){
return JSON.stringify([this._mContrast]);
}
getName() { getName() {
return "ContrastFilterTransformation:" + this._mContrast; return "ContrastFilterTransformation:" + this._mContrast;
} }

View File

@ -29,6 +29,14 @@ export class CropCircleTransformation implements BaseTransform<PixelMap> {
private mCenterY: number = 0; private mCenterY: number = 0;
private mRadius: number = 0; private mRadius: number = 0;
getClassName(){
return "CropCircleTransformation";
}
getConstructorParams(){
return "[]";
}
getName() { getName() {
return CropCircleTransformation.TAG + ";mCenterX:" + this.mCenterX return CropCircleTransformation.TAG + ";mCenterX:" + this.mCenterX
+ ";mCenterY:" + this.mCenterY + ";mCenterY:" + this.mCenterY

View File

@ -18,15 +18,17 @@ import { AsyncTransform } from "../transform/AsyncTransform"
import { Constants } from "../constants/Constants" import { Constants } from "../constants/Constants"
import { RequestOption } from "../../imageknife/RequestOption" import { RequestOption } from "../../imageknife/RequestOption"
import { TransformUtils } from "../transform/TransformUtils" import { TransformUtils } from "../transform/TransformUtils"
import {LogUtil} from '../../imageknife/utils/LogUtil' import { LogUtil } from '../../imageknife/utils/LogUtil'
import image from "@ohos.multimedia.image" import image from "@ohos.multimedia.image"
import { BusinessError } from '@ohos.base' import { BusinessError } from '@ohos.base'
import {Size} from '../../imageknife/RequestOption' import { Size } from '../../imageknife/RequestOption'
export interface rgbColor{
export interface rgbColor {
r_color: number, r_color: number,
g_color: number, g_color: number,
b_color: number, b_color: number,
} }
export class CropCircleWithBorderTransformation implements BaseTransform<PixelMap> { export class CropCircleWithBorderTransformation implements BaseTransform<PixelMap> {
private static TAG: string = "CropCircleTransformation"; private static TAG: string = "CropCircleTransformation";
private mBorderSize: number = 5; private mBorderSize: number = 5;
@ -35,7 +37,7 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
private mRadius: number = 0; private mRadius: number = 0;
private mRColor: number = 0; private mRColor: number = 0;
private mGColor: number = 0; private mGColor: number = 0;
private mBColor: number= 0; private mBColor: number = 0;
constructor(border_size: number, value: rgbColor) { constructor(border_size: number, value: rgbColor) {
this.mRColor = value.g_color; this.mRColor = value.g_color;
@ -44,14 +46,26 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
this.mBorderSize = border_size; this.mBorderSize = border_size;
} }
getClassName() {
return "CropCircleWithBorderTransformation";
}
getConstructorParams() {
return JSON.stringify([this.mBorderSize, {
r_color: this.mRColor,
g_color: this.mGColor,
b_color: this.mBColor
}]);
}
getName() { getName() {
return CropCircleWithBorderTransformation.TAG + ";mBorderSize:" + this.mBorderSize return CropCircleWithBorderTransformation.TAG + ";mBorderSize:" + this.mBorderSize
+ ";mCenterX:" + this.mCenterX + ";mCenterX:" + this.mCenterX
+ ";mCenterY:" + this.mCenterY + ";mCenterY:" + this.mCenterY
+ ";mRadius:" + this.mRadius + ";mRadius:" + this.mRadius
+ ";mRColor:" + this.mRColor + ";mRColor:" + this.mRColor
+ ";mGColor:" + this.mGColor + ";mGColor:" + this.mGColor
+ ";mBColor:" + this.mBColor; + ";mBColor:" + this.mBColor;
} }
transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) { transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
@ -62,28 +76,30 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
} }
return; return;
} }
let imageSource:image.ImageSource = image.createImageSource(buf); let imageSource: image.ImageSource = image.createImageSource(buf);
TransformUtils.getPixelMapSize(imageSource, {asyncTransform:(error:BusinessError|string, size:Size|null) => { TransformUtils.getPixelMapSize(imageSource, {
if (!size) { asyncTransform: (error: BusinessError | string, size: Size | null) => {
func?.asyncTransform(error, null) if (!size) {
return; func?.asyncTransform(error, null)
return;
}
let pixelMapWidth = size.width;
let pixelMapHeight = size.height;
let targetWidth = request.size.width;
let targetHeight = request.size.height;
if (pixelMapWidth < targetWidth) {
targetWidth = pixelMapWidth;
}
if (pixelMapHeight < targetHeight) {
targetHeight = pixelMapHeight;
}
this.updatePixelMapSize(imageSource, targetWidth, targetHeight, func);
} }
let pixelMapWidth = size.width; })
let pixelMapHeight = size.height;
let targetWidth = request.size.width;
let targetHeight = request.size.height;
if (pixelMapWidth < targetWidth) {
targetWidth = pixelMapWidth;
}
if (pixelMapHeight < targetHeight) {
targetHeight = pixelMapHeight;
}
this.updatePixelMapSize(imageSource, targetWidth, targetHeight, func);
}})
} }
private updatePixelMapSize(imageSource: image.ImageSource, outWith: number, outHeight: number, func?: AsyncTransform<PixelMap>) { private updatePixelMapSize(imageSource: image.ImageSource, outWith: number, outHeight: number, func?: AsyncTransform<PixelMap>) {
let options:image.DecodingOptions = { let options: image.DecodingOptions = {
editable: true, editable: true,
desiredSize: { desiredSize: {
width: outWith, width: outWith,
@ -91,13 +107,13 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
} }
} }
imageSource.createPixelMap(options) imageSource.createPixelMap(options)
.then((pixelMap:PixelMap) => { .then((pixelMap: PixelMap) => {
this.transformPixelMap(pixelMap, outWith, outHeight, func); this.transformPixelMap(pixelMap, outWith, outHeight, func);
imageSource.release() imageSource.release()
}) })
.catch((e:BusinessError) => { .catch((e: BusinessError) => {
LogUtil.log(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation e:" + e); LogUtil.log(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation e:" + e);
if (func!=undefined) { if (func != undefined) {
func?.asyncTransform(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation e:" + e, null); func?.asyncTransform(Constants.PROJECT_TAG + ";CropCircleWithBorderTransformation e:" + e, null);
} }
imageSource.release() imageSource.release()
@ -120,8 +136,8 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
let dataArray = new Uint8Array(bufferData); let dataArray = new Uint8Array(bufferData);
for (let h = 0;h <= height; h++) { for (let h = 0; h <= height; h++) {
for (let w = 0;w <= width; w++) { for (let w = 0; w <= width; w++) {
// 不在大圆之内的设置透明 // 不在大圆之内的设置透明
// 在大圆与小圆之间的 设置rgb值 // 在大圆与小圆之间的 设置rgb值
// 小圆之内的不变 // 小圆之内的不变
@ -154,16 +170,16 @@ export class CropCircleWithBorderTransformation implements BaseTransform<PixelMa
} }
isContainsCircle(x: number, y: number): boolean { isContainsCircle(x: number, y: number): boolean {
let a:number = Math.pow((this.mCenterX - x), 2); let a: number = Math.pow((this.mCenterX - x), 2);
let b:number = Math.pow((this.mCenterY - y), 2); let b: number = Math.pow((this.mCenterY - y), 2);
let c:number = Math.sqrt((a + b)); let c: number = Math.sqrt((a + b));
return c <= this.mRadius; return c <= this.mRadius;
} }
isContainsSmallCircle(x: number, y: number): boolean { isContainsSmallCircle(x: number, y: number): boolean {
let a:number = Math.pow((this.mCenterX - x), 2); let a: number = Math.pow((this.mCenterX - x), 2);
let b:number = Math.pow((this.mCenterY - y), 2); let b: number = Math.pow((this.mCenterY - y), 2);
let c:number = Math.sqrt((a + b)); let c: number = Math.sqrt((a + b));
return c <= (this.mRadius - this.mBorderSize); return c <= (this.mRadius - this.mBorderSize);
} }
} }

View File

@ -26,6 +26,14 @@ import image from "@ohos.multimedia.image"
export class CropSquareTransformation implements BaseTransform<PixelMap> { export class CropSquareTransformation implements BaseTransform<PixelMap> {
private static TAG: string = "CropSquareTransformation"; private static TAG: string = "CropSquareTransformation";
getClassName(){
return "CropSquareTransformation";
}
getConstructorParams(){
return '[]';
}
getName() { getName() {
return CropSquareTransformation.TAG; return CropSquareTransformation.TAG;
} }
@ -60,8 +68,8 @@ export class CropSquareTransformation implements BaseTransform<PixelMap> {
editable: true, editable: true,
rotate: 0, rotate: 0,
desiredSize: { desiredSize: {
width: outWidth, width: pw,
height: outHeight height: ph
}, },
desiredRegion: { size: { width: targetSize, height: targetSize }, desiredRegion: { size: { width: targetSize, height: targetSize },
x: pw / 2 - targetSize / 2, x: pw / 2 - targetSize / 2,

View File

@ -35,6 +35,14 @@ export class CropTransformation implements BaseTransform<PixelMap> {
this.mCropType = cropType; this.mCropType = cropType;
} }
getClassName(){
return "CropTransformation";
}
getConstructorParams(){
return JSON.stringify([this.mWidth,this.mHeight ,this.mCropType]);
}
getName() { getName() {
return CropTransformation.TAG + ";mWidth:" + this.mWidth return CropTransformation.TAG + ";mWidth:" + this.mWidth
+ ";mHeight:" + this.mHeight + ";mHeight:" + this.mHeight

View File

@ -29,6 +29,14 @@ export class GrayscaleTransformation implements BaseTransform<PixelMap> {
return "GrayscaleTransformation"; return "GrayscaleTransformation";
} }
getClassName(){
return "GrayscaleTransformation";
}
getConstructorParams(){
return '[]';
}
async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) { async transform(buf: ArrayBuffer, request: RequestOption, func?: AsyncTransform<PixelMap>) {
if (!buf || buf.byteLength <= 0) { if (!buf || buf.byteLength <= 0) {
LogUtil.log(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty"); LogUtil.log(Constants.PROJECT_TAG + ";GrayscaleTransformation buf is empty");

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